Easyphp
题目直接给了源码:
可以看到代码最后可以执行$hhh
,先GET参数"_"
的值然后进行三道检测,全部通过后才会被eval()
执行
首先如果没有从GET方法获取"_"
参数,就直接显示源码;
如果$hhh
变量的长度大于18则无法继续执行;
然后通过preg_match
进行正则匹配,基本过滤了所有可显示的字符
最后通过count_chars
函数来限制变量中不同字符的个数,count_chars(string, mode)
,当mode=3的时候是字符串模式,返回所有使用过的不同的字符,这个返回值的长度不能大于12
因为正则过滤的很死,所以先看一下还有哪些可以用的字符
1 |
|
可以看到大部分都是不可见字符,而这里还有一个值得注意的点:这些没被正则过滤的字符并不是都能被我们使用,因为最后payload是直接在url中传过去的,而url中存在一些保留字符和不安全字符,如果要使用这两种特殊的字符就需要使用单引号括起来,但是单引号已经被过滤了。
所以我们的思路就变成了对不可见字符进行异或来生成我们想要的payload
现在已经知道了 Payload 需要由那些不可见字符组成 , 那么 Payload 究竟是怎样的呢?
题目中有这么一条限制 : GET方法获取参数的值不能超过 18 个 字符 , 如果想要在 Payload 中执行一个函数 , 格式肯定 (xxx^xxx)();
这样的,这还必须是无参函数。
但即使是无参函数 , 已经使用的字符( 小括号 , 异或符号 , 结尾符) 也已经使用了6个字符 , 函数名又需要两两字符异或计算得到 , 也就是函数名最多有 ((18 - 6) / 2 = 6)个字符 , 而6个字符连个 phpinfo 都运行不了 , 这样肯定是不可行的 .
直接调用函数好像是不可行的 , 我们需要换一种思路 —— 比如使用全局变量 , 至少$
符号还是可以使用的 , 介于题目中对 Payload 长度有限制,最短的全局变量为 : $_GET
。” $
“本身可用 , 而_GET
的形式大概是 : xxxx^xxxx}
这样的 。
有了全局变量 , 就可以利用 ${}
中的代码是可以执行的特点,把要运行的函数名作为参数来动态执行。也就是${x}();
这样的形式 , 函数名的值 "x"
可以通过全局方法GET来获取
因此 , 完整的 Payload 应该为 : ${xxxx^xxxx}{x}();&x= ...
,转换后就变成了 $_GET[x]();&x= ...
并且 , "_"
参数的值为 : ${xxxx^xxxx}(x)();
, 长度为 18 个字符 , 恰好满足题目 strlen() 函数的限制
1 | import string |
生成了非常多的payload,但还有count_chars
的限制,"_"
参数最多只能用12个不同的字符,而现在${xxxx^xxxx}{x}();
在不考虑x的情况下已经使用了7个字符,所以剩下的只有5个不同的字符,刚刚好够用来构造payload
payload:_=${%80%80%80%80^%df%c7%c5%d4}{%80}();&%80=phpinfo
成功执行了,也就是我们已经绕过第一层了
第二层是get_the_flag
函数:
- 首先用
preg_match
函数检查文件后缀,ph
开头的文件全部无法通过 - 接着对文件内容进行检测,如果文件内容中出现
<?
也不能通过检测 - 最后限制了文件的类型必须是图片
从上面的phpinfo可以看到中间件是Apache2,因此对文件后缀的检查可以通过上传.htaccess
文件来绕过; 而php版本是php7.2,所以<script language='php'></script>
的写法就不能用了,想绕过<?
就需要先编码再上传了; exif_imagetype()
的检测可以通过添加文件头的方式来绕过
到了这里与之前在xman做的一道题特别像了,当时是参考的Insomnihack2019的一道题,writeup链接在这里:[https://github.com/mdsnins/ctf-writeups/blob/master/2019/Insomnihack%202019/l33t-hoster/l33t-hoster.md](https://github.com/mdsnins/ctf-writeups/blob/master/2019/Insomnihack 2019/l33t-hoster/l33t-hoster.md)
php解析的图片类型如图所示:
在这些格式中XBM
这种格式比较特殊,它的前两行是文件头,同时也是注释,用来定义图片宽和长,XBM
文件格式:
XBM
文件的文件头在php
文件和.htaccess
文件中正好都是注释,所以我们在上传的时候就可以在前面加上XBM文件头来绕过exif_imagetype
的检测