Three Minutes with the HTTP TRACE Method

Brian King //

All of our scanning tools tell us that we should disable the HTTP TRACE and TRACK methods. And we all think that’s because there’s something an attacker can do with it to steal secrets from legitimate users. But there’s another thing TRACE can do for an attacker, and it’s got nothing to do with other users.

OWASP says you should disable HTTP TRACE because it can be used for Cross Site Tracing:

https://www.owasp.org/index.php/Cross_Site_Tracing

CERT says it can be “combined with cross-domain browser vulnerabilities to read sensitive header information from third-party domains.”

https://www.kb.cert.org/vuls/id/867593

Deadliest (!) Web Attacks says you can read cookies

https://deadliestwebattacks.com/2010/05/18/cross-site-tracing-xst-the-misunderstood-vulnerability/

All of those are correct, but a little old. In modern browsers, XMLHttpRequest won’t send a “TRACE” request anymore, and the CORS framework prevents XHR requests to foreign sites that don’t explicitly allow them. So these old attacks don’t work so well anymore.

CORS Blocks GET Requests, and Your Browser Blocks TRACE Requests

But! It’s still a useful information-getter. Remember that the TRACE verb is handled by the web server. Your request may pass through something else on the way to the web server. If that something else adds headers, then your TRACE response will include those headers, and you’ll gain a little information you didn’t already have.

What sits in front of a web server that might be interesting? A Web Application Firewall (WAF), which may be filtering requests to detect and kill attacks before they get to the web server.

Those are not the headers I sent…

The X-Forwarded-For header is one of the headers added by some WAFs, and it is sometimes used by the WAF itself to decide if it should filter that request or not. If the header is present, and contains the IP address of the WAF, then the request must have come from the WAF, and it must not be malicious, right?

Well, what if we add one of those to the request we send?

Hey, Look. My X-Forwarded-For Made It Through.

This WAF doesn’t just create the X-Forwarded-For header, it adds the requesting system’s IP address (my public IP address, ending in 103) to whatever may already be there. If you know the IP address of the WAF (and you do because you’re talking to it), you can try to tell the WAF that your request is actually the WAF’s request, and should be ignored. If it believes you, then you’ve bypassed the WAF.

This is the most straightforward WAF bypass. This is not a new discovery at all, but the TRACE verb here shows you why it can work.

If you want to play with it at home, here’s the HTML I used for the XHR illustration above:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<head><title>TRACE Form</title><script type="text/javascript">
function sendAny(myMethod) {
var xhr = new XMLHttpRequest();
xhr.open(myMethod, "http://bhis.co",false);
xhr.send();
document.getElementById("demo").innerHTML = xhr.responseText;
}
</script></head>
<body><div id="demo"><h2>Response Goes Here</h2></div>
<form name="weLikeStandards" action="#">
<input type=button OnClick="sendAny('TRACE');" value="Send Trace Request">
<input type=button OnClick="sendAny('GET');" value="Send GET Request">
</form>
<a href="http://validator.w3.org/check?uri=referer"><img
      src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01 Transitional" height="31" width="88"></a>
</body></html>