Author: D1m0n
preface
Recently, when I reviewed the CTF problems I had done before, I found an interesting one. PHP string parsing is used in Bypass, but this problem is far more than that, there is another solution, HTTP request smuggling.
RoarCTF 2019 Easy Calc
Take a look at the source code:
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' '.'\t'.'\r'.'\n'.'\' '.'"'.'`.'\ ['.'\]'.'\ $'.'\ \'.'\ ^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m'.$str)) {
die("what are you want to do?"); }}eval('echo '.$str.'; ');
}
? >
Copy the code
For parsing, the idea is this: wrap a variable with a space around WAF, use scandir() and CHR () to see what files are in the directory, and read flag files with file_get_contents. Waf: WaF: waF: waF: waF: waF: waF
By now, many people are as confused as I was, returning 400 and getting the Flag. Here’s the suspense
What is HTTP request smuggling
HTTP request smuggling is a special attack method. Unlike other Web attacks, HTTP request smuggling is not as intuitive as other Web attacks. In complex network environments, different servers implement RFC standards in different ways and to different degrees. The widely used HTTP1.1 protocol provides two different ways to specify the end of a request: the Content-Length header and the Transfer-Encoding header. The Content-Length header is straightforward and specifies the Length of the message Content body in bytes.
The transfer-Encoding header is used to specify that the message body uses ChunkedEncode, which means that the message message consists of one or more blocks of data, each block size measured in bytes (hexadecimal), followed by a newline character, followed by the block content, and most importantly: The entire message body ends with a block of size 0, which means parsing ends when it hits a block of size 0.
As a result, if we use such as the reverse proxy server (behind the front-end server for short), the front-end and back-end systems, if not agree on the boundary between the request will generate HTTP smuggling attack, it is easy to make the attacker to bypass security controls, unauthorized access to sensitive data, and directly harm other application users.
How to implement HTTP request smuggling attack
When we send a vague to the proxy server HTTP request, due to the realization of the server in a different way, proxy server might think this is an HTTP request, and will forward it to the backend server source station, but the source server after parsing process, only think with a normal part of the request, the remaining part of the Even for a smuggled request, HTTP smuggling attacks are implemented when that part of the request affects the normal user.
CL is not zero
This case mainly applies to HTTP requests that do not contain the request body, mainly GET requests. If our front-end server allows GET requests to carry the request body, but the back-end server does not allow GET requests to carry the request body, the Content-Length header will be ignored directly, resulting in request smuggling.
GET/HTTP/1.1\r\n Host: example.com\r\n Content-Length: 51\r\n \r\n GET/HTTP/1.1\r\n Host: example.com\r\n attack: 1\r\n hhh:Copy the code
This request is a normal request for the front-end server, but when forwarded to the backend, because the backend does not recognize the Content-Length header, this request becomes two requests, and when the next request arrives, it is spliced into the previous one
GET/HTTP/1.1\r\n Host: example.com\r\n Content-Length: 51\r\n \r\n GET/HTTP/1.1\r\n Host: example.com\r\n attack: 1\r\n HHH: GET/HTTP/1.1\r\n Host: example.com\r\n Content-Length: 51\r\nCopy the code
What’s the harm in that? HTTP is a stateless protocol, and many websites use cookies to identify user status. When we construct sensitive operations such as deleting users, transferring funds, and changing passwords in the second packet, it plays a role of stealing other users’ cookies.
CL-TE
Cl-te, that is, when we send a request packet containing two request headers, the front-end server processes only Content-Length and the back-end server ignores the Content-Length header and processes only Transfer-Encoding request headers. Here’s a demo using Burpsuite’s official firing range:
POST/HTTP / 1.1 Host: ac911f721f9ee241c01763ef008600f8.web-security-academy.net Connection: close cache-control: max-age=0 sec-ch-ua: "Chromium"; v="94", "Google Chrome"; v="94", "; Not A Brand"; v="99" 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 (KHTML, like Gecko) Chrome/94.0.4606.81 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: None sec-fetch -Mode: navigate sec-fetch -User:? 1 Sec-Fetch-Dest: document Accept-Language: zh-CN,zh; Q = 0.9 cookies: session = kSvNgyDye0o1097OwEFsKJD9eu6tpo4k Content - Length: 6 Transfer - Encoding: chunked 0 ACopy the code
When we replay the packet twice with Burp, we get the result:
Explain why content-length is 6, because Burp interprets \r\n as a newline. The actual request body should look like this:
0\r\n
\r\n
A
Copy the code
When the back-end server reads 0\r\n\r\n, it assumes that the packet has been read and the last character A is parsed in the next request.
TE-CL
Te-cl, that is, when we send a request packet containing two request headers, the front-end server processes only Transfer-Encoding, and the back-end server ignores the Transfer-Encoding header and processes only Content-Length request headers:
POST/HTTP / 1.1 Host: acae1fe41e622a9bc0c7189700950000.web-security-academy.net the user-agent: Mozilla / 5.0 (Windows NT 10.0; Win64; X64) AppleWebKit (KHTML, like Gecko) Chrome/94.0.4606.81 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 cookies: session = VfTG4xpWeu1NboBIfCyqsHiWb8UjNDGZ Content - length: 4 Transfer - Encoding: Chunked 5c GPOST/HTTP/1.1 Content-Type: Application /x-www-form-urlencoded Content-Length: 15 x=1 0Copy the code
The front-end server will process the transfer-encoding for this request, and when it reads 0\r\n\r\n, it will treat it as a complete request, but the back-end server will only recognize Content-Length: 4, which makes GPOST a new request.
CL-CL
Cl-cl is two Content-Lengths, and 400 error will be returned if the two values are different. But if the server does not follow the specification strictly, what happens is that the front-end server treats the value of the first Content-Length header and the back-end server treats the value of the second content-Length header
Back to the original
Because there are two CL headers in our payload, corresponding to the cl-Cl case, both the front end and the back end receive our request packet once. Because the server is not standard, the request is still sent to the back end server, although it returns 400 errors, causing the WAF bypass problem.
instructions
About Hetian Net Safety Laboratory
Hetian Network security laboratory (www.hetianlab.com) – the leading domestic practical network security online education platform real environment, online practical network security; The experimental content covers: system security, software security, network security, Web security, mobile security, CTF, forensics analysis, penetration testing, network security awareness education and so on.
Related experimental exercises
CTF Lab – From beginning to practice – one-stop CTF learning platform