快睡的时候,打开B站创造有位用户留言,大意便是让我帮忙看一道题,恰好当时有空,于是就打开了他发的链接,代码如下
很明显是一道PHP代码审计的题目,而且只须要绕过第三行的if即可进行任意命令实行。
办理思路

看了代码之后以为是道普通的题目,对付/a-zA-Z/这个正则表达式,我们可以利用PHP动态函数的特性,布局出字符串即可。
对付想要的字符串,我们可以通过以下三种办法来布局:
1. 异或
对付PHP中的字符串,两个字符串异或的结果是将两个字符串逐位异或,返回一个新字符串。那么我们便可以利用此特性进行布局。
例如我们须要布局phpinfo,则可以用脚本得到('0302181', '@[@[_^^')这两个字符串,脚本如下:
个中valid是可用的字符,answer是我们须要布局的字符串。那么我们得到了这个字符串,又该如何去实行呢。我们可以通过一个变量存储两字符串异或后的值,再让这个变量进行动态函数实行即可,而变量的话由于PHP的变量命名规则和C措辞相同,可以利用下划线进行命名,如下:
2. 取反布局
和第一种类似,都是基于PHP字符串位运算的特点(会逐位进行位运算)。而取反布局某些情形比异或布局要方便,由于异或的情形某些字符是无法直接通过其他字符进行异或布局的,而取反却可以利用汉字或者其他分外字符进行布局(不会有题目会限定某个汉字吧)。比如字母s我们可以通过~('和'{2})得到。而这个时候如果要用异或去布局的话,你得找到两个异或值为s的分外字符。
取反布局的脚本和异或布局类似,在此不再给出。
3. 自增布局
`++'a' == 'b'`
这个特点是利用了PHP是弱类型措辞的特性,在对变量进行操作的时候,PHP会隐式的转换其变量类型,很多代码审计的题目也是利用了这一特性。
碰着障碍
有了上面的思路后,而且也成功实行了phpinfo(),下一步是不是就可以直接布局命令实行函数去进行读取文件,当时我也是这么想的,于是我布局了passthru(), system(), shell_exec(), exec()等函数,都受到了阻碍,没有回显,通过进一步的调试之后创造是禁用了这些函数(通过在函数后面加一个打印函数不雅观察是否实行)。
在这里我勾留了良久,试过打印$GLOBALS等都没有任何有用的信息。末了通过利用glob()函数进行目录扫描,创造了flag.php文件,以及file_get_contents()进行获取,终极的payload如下
?mess=$_="`0123"^"?`~``";${$_}[_](${$_}[__]);&_=assert&__=print_r(base64_encode(file_put_contents("flag.php")))
末了再将其界面就可以得到终极的flag了。在终极的payload中我没有去一个一个的布局字符串异或,由于那太长了,而是布局了一个$_POST[_]($_POST[__])的动态函数,这样就可以在其他参数位置直接写函数了。
深入剖析
题目到这里就结束了,实在并没有多难,首先是通过特性去布局动态函数,然后创造了命令实行被禁用之后,能够知道利用其他函数去进行获取信息就行了。但是做完这道题后,不仅引发了我的思考,PHP中的命令实行就只有这些办法了吗,肯定不是。于是,我总结了几种新的命令实行技巧供大家参考。
1. 当打印函数被禁用时
如果没有了打印函数,意味着你无法看到回显,这时候即义务令实行成功了你也无法得到信息,这个时候你就得利用其他办法去获取回显了。
首先是网上很多blog利用的办法,phpinfo如果创造开启了curl,或者其他文件传输扩展的的话,可以自建一个靶机,将所有访问信息存入数据库或是文件,然后将回显信息发送到你的靶机地址,这样你去看日志就可以了,这种办法不是很方便而且有一定的局限性。这里我要先容的是一种新的办法。
如果你利用过Django或者jsp开拓web的话,你肯定知道输出一个变量可以利用{{xxx}}或是<%=xxx%>的办法,那么在PHP中是否也有这种办法呢,答案是肯定的,PHP中的<?=xxx?>就可以将一个变量输出,那么如果利用它呢,你只须要布局如下的payload
valid = "1234567890!@$%^(){}[];\'\",.<>/?-=_`~ "answer = "phpinfo"tmp1,tmp2 = '',''for c in answer: for i in valid: for j in valid: if (ord(i)^ord(j) == ord(c)): tmp1 += i tmp2 += j break else: continue breakprint(tmp1,tmp2)
这样就可以将变量$_里面的内容打印到屏幕上,而且关键的是这个输出办法默认是开启的,管理员很随意马虎就忽略这个选项。以是在做题时不妨一试。
2. 其他的命令实行办法
当system,passthru等不能用时,网上会见告你可以利用popen,proc_open这些管道命令去进行实行命令,当然这没有问题,而这里我向你先容一种新办法,利用反引号,在PHP中,被两个反引号括起来的内容将会作为shell命令实行,并将输出信息返回,以是你可以布局下面的payload进行命令实行
$_=`ls`;
3. 不能利用数字字母的命令实行
当不能利用字母数字时,当然你可以利用上述的办法布局字符串进行实行,但是这里供应一些新东西,对付linux中的shell是支持正则表达式的,当你忘却某些字符时可以通过? % 来代替,经由测试,这里的匹配办法也是按照顺序进行匹配,以是你可以查看你的linux中/bin目录下面的顺序,来获取一些可以利用的命令,比如
/???/??? => /bin/cat
那么这样的话,如果要获取/var/www/html/index.php(你得感谢apache默认目录如此之深),则可以直策应用
/???/??? /???/???/????/?????.???
来获取
总结
这篇文章只是针对这道题而延展出的一些东西,在真正做题时,情形可能更加繁芜,例如限定长度,限定参数等等情形,而我们的做法也不可能千篇一律,可能某些时候我们乃至会用到一些CVE漏洞。而本篇文章只是见告读者一些可能以前没有见过的新东西。
那么本篇文章就到此结束了。
如果想更多系统的学习CTF,可点击“http://www.hetianlab.com/pages/CTFLaboratory.jsp”,进入CTF实验室学习,里面涵盖了6个题目类型系统的学习路径和实操环境。
声明:笔者初衷用于分享与遍及网络知识,若读者因此作出任何危害网络安全行为后果自大,与合天智汇及原作者无关!