BUUCTF-Web-[GXYCTF2019]禁止套娃
本文为记录个人信安小白的刷题路程,大佬勿喷,也同时希望文章能对您有所帮助
打开靶机,
F12查看,Burp抓包都没有获得什么信息,
使用dirsear扫描网站,
可以看到有flag.php
文件,但是没有文件可以通过URL下载,
但是可以看到几乎全是/.git/
目录下的文件,推测为git泄露,
使用GitHack
工具,
我的是kali虚拟机root模式下下载的,
1 | git clone https://github.com/lijiejie/GitHack |
这个支持python3环境,
获得index.php
源码文件,下面进行代码审计,
1 |
|
重点理解第二层检查,这个检查会有字符串直接输入的限制,
1 | if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) |
[a-z,_]+
匹配 1个或多个小写字母或下划线(即函数名,如 a, get_flag, readfile)。
例如:abc, my_func 都符合。
( 和 )
匹配 左括号(
和右括号)
,表示函数调用。
(?R)?
(?R)
表示递归匹配整个正则表达式(即可以嵌套函数()
)。
?
表示递归部分是可选的(即允许 a()
或 a(b())
或 a(b(c()))
等)。
实例:
1 | a(b(c())) // 匹配成功 |
分解:
a(
→ 匹配 [a-z,_]+\(
b(
→ 递归 (?R)
匹配 [a-z,_]+\(
c()
→ 递归 (?R)
匹配 [a-z,_]+\(\)
最终 a(b(c()))
被替换为空,只剩 ;
(如果输入是 a(b(c()));
)。
解法一:
构造payload:
1 | ?exp=highlight_file(next(array_reverse(scandir(current(localeconv()))))); |
(1)localeconv()
作用:返回本地化数字和货币格式信息(关联数组)。
关键点:它的返回值是一个数组,且第一个元素是 ‘.’(当前目录)。这个函数默认返回的结果第一个数组元素就是’.’
(2)current(localeconv())
作用:获取数组的第一个元素(即 ‘.’)。
结果:返回 ‘.’(当前目录)。
(3)scandir(current(localeconv()))
作用:扫描当前目录(’.’)并返回文件列表,如:
1 | [0 => ".", 1 => "..", 2 => "flag.php", 3 => "index.php"] |
(4)array_reverse(scandir(…))
作用:反转数组,使flag.php
更容易被next()
获取:
1 | [0 => "index.php", 1 => "flag.php", 2 => "..", 3 => "."] |
(5)next(array_reverse(…))
作用:移动数组指针,返回第二个元素(即 “flag.php”)。
结果:返回 “flag.php”。
(6)highlight_file(next(…))
作用:高亮显示 flag.php 的源代码,直接输出 flag。
获得flag
解法二:
发现其中并没有过滤session_id
函数
构造payload:
1 | ?exp=highlight_file(session_id(session_start())); |
并且传入Cookie:PHPSESSID=flag.php
(HackBar和Burp都可以)
(1)session_start()
作用:启动PHP Session
,如果请求中包含PHPSESSID Cookie
,则使用该值作为Session ID
。
返回值:始终返回 true
(但这里不重要,重点是它初始化了 Session
)。
(2)session_id()
无参数调用时:返回当前Session ID
。
session_id()
返回当前 Session ID
,即 “flag.php”。
(3)highlight_file()
作用:高亮显示指定文件的源代码(这里用于读取flag.php
)。
获得flag