mirror of
https://github.com/ail-project/ail-framework.git
synced 2024-11-27 00:07:16 +00:00
Merge pull request #396 from stamparm/master
Improvement of SQLi detection
This commit is contained in:
commit
ed217656ec
1 changed files with 24 additions and 114 deletions
|
@ -14,7 +14,6 @@ It test different possibility to makes some sqlInjection.
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
import redis
|
import redis
|
||||||
import string
|
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import re
|
import re
|
||||||
from pubsublogger import publisher
|
from pubsublogger import publisher
|
||||||
|
@ -22,131 +21,42 @@ from Helper import Process
|
||||||
from packages import Paste
|
from packages import Paste
|
||||||
from pyfaup.faup import Faup
|
from pyfaup.faup import Faup
|
||||||
|
|
||||||
# Config Var
|
# Reference: https://github.com/stamparm/maltrail/blob/master/core/settings.py
|
||||||
|
SQLI_REGEX = r"information_schema|sysdatabases|sysusers|floor\(rand\(|ORDER BY \d+|\bUNION\s+(ALL\s+)?SELECT\b|\b(UPDATEXML|EXTRACTVALUE)\(|\bCASE[^\w]+WHEN.*THEN\b|\bWAITFOR[^\w]+DELAY\b|\bCONVERT\(|VARCHAR\(|\bCOUNT\(\*\)|\b(pg_)?sleep\(|\bSELECT\b.*\bFROM\b.*\b(WHERE|GROUP|ORDER)\b|\bSELECT \w+ FROM \w+|\b(AND|OR|SELECT)\b.*/\*.*\*/|/\*.*\*/.*\b(AND|OR|SELECT)\b|\b(AND|OR)[^\w]+\d+['\") ]?[=><]['\"( ]?\d+|ODBC;DRIVER|\bINTO\s+(OUT|DUMP)FILE"
|
||||||
regex_injection = []
|
|
||||||
word_injection = []
|
|
||||||
word_injection_suspect = []
|
|
||||||
|
|
||||||
# Classic atome injection
|
|
||||||
regex_injection1 = "([[AND |OR ]+[\'|\"]?[0-9a-zA-Z]+[\'|\"]?=[\'|\"]?[0-9a-zA-Z]+[\'|\"]?])"
|
|
||||||
regex_injection.append(regex_injection1)
|
|
||||||
|
|
||||||
# Time-based attack
|
|
||||||
regex_injection2 = ["SLEEP\([0-9]+", "BENCHMARK\([0-9]+", "WAIT FOR DELAY ", "WAITFOR DELAY"]
|
|
||||||
regex_injection2 = re.compile('|'.join(regex_injection2))
|
|
||||||
regex_injection.append(regex_injection2)
|
|
||||||
|
|
||||||
# Interesting keyword
|
|
||||||
word_injection1 = [" IF ", " ELSE ", " CASE ", " WHEN ", " END ", " UNION ", "SELECT ", " FROM ", " ORDER BY ", " WHERE ", " DELETE ", " DROP ", " UPDATE ", " EXEC "]
|
|
||||||
word_injection.append(word_injection1)
|
|
||||||
|
|
||||||
# Database special keywords
|
|
||||||
word_injection2 = ["@@version", "POW(", "BITAND(", "SQUARE("]
|
|
||||||
word_injection.append(word_injection2)
|
|
||||||
|
|
||||||
# Html keywords
|
|
||||||
word_injection3 = ["<script>"]
|
|
||||||
word_injection.append(word_injection3)
|
|
||||||
|
|
||||||
# Suspect char
|
|
||||||
word_injection_suspect1 = ["\'", "\"", ";", "<", ">"]
|
|
||||||
word_injection_suspect += word_injection_suspect1
|
|
||||||
|
|
||||||
# Comment
|
|
||||||
word_injection_suspect2 = ["--", "#", "/*"]
|
|
||||||
word_injection_suspect += word_injection_suspect2
|
|
||||||
|
|
||||||
def analyse(url, path):
|
def analyse(url, path):
|
||||||
faup.decode(url)
|
if is_sql_injection(url.decode()):
|
||||||
url_parsed = faup.get()
|
faup.decode(url)
|
||||||
|
url_parsed = faup.get()
|
||||||
resource_path = url_parsed['resource_path']
|
|
||||||
query_string = url_parsed['query_string']
|
|
||||||
|
|
||||||
result_path = 0
|
|
||||||
result_query = 0
|
|
||||||
|
|
||||||
if resource_path is not None:
|
|
||||||
## TODO: # FIXME: remove me
|
|
||||||
try:
|
|
||||||
resource_path = resource_path.decode()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
result_path = is_sql_injection(resource_path)
|
|
||||||
|
|
||||||
if query_string is not None:
|
|
||||||
## TODO: # FIXME: remove me
|
|
||||||
try:
|
|
||||||
query_string = query_string.decode()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
result_query = is_sql_injection(query_string)
|
|
||||||
|
|
||||||
if (result_path > 0) or (result_query > 0):
|
|
||||||
paste = Paste.Paste(path)
|
paste = Paste.Paste(path)
|
||||||
if (result_path > 1) or (result_query > 1):
|
print("Detected SQL in URL: ")
|
||||||
print("Detected SQL in URL: ")
|
print(urllib.request.unquote(url))
|
||||||
print(urllib.request.unquote(url))
|
to_print = 'SQLInjection;{};{};{};{};{}'.format(paste.p_source, paste.p_date, paste.p_name, "Detected SQL in URL", paste.p_rel_path)
|
||||||
to_print = 'SQLInjection;{};{};{};{};{}'.format(paste.p_source, paste.p_date, paste.p_name, "Detected SQL in URL", paste.p_rel_path)
|
publisher.warning(to_print)
|
||||||
publisher.warning(to_print)
|
#Send to duplicate
|
||||||
#Send to duplicate
|
p.populate_set_out(path, 'Duplicate')
|
||||||
p.populate_set_out(path, 'Duplicate')
|
|
||||||
|
|
||||||
msg = 'infoleak:automatic-detection="sql-injection";{}'.format(path)
|
msg = 'infoleak:automatic-detection="sql-injection";{}'.format(path)
|
||||||
p.populate_set_out(msg, 'Tags')
|
p.populate_set_out(msg, 'Tags')
|
||||||
|
|
||||||
#statistics
|
|
||||||
tld = url_parsed['tld']
|
|
||||||
if tld is not None:
|
|
||||||
## TODO: # FIXME: remove me
|
|
||||||
try:
|
|
||||||
tld = tld.decode()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
date = datetime.datetime.now().strftime("%Y%m")
|
|
||||||
server_statistics.hincrby('SQLInjection_by_tld:'+date, tld, 1)
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("Potential SQL injection:")
|
|
||||||
print(urllib.request.unquote(url))
|
|
||||||
to_print = 'SQLInjection;{};{};{};{};{}'.format(paste.p_source, paste.p_date, paste.p_name, "Potential SQL injection", paste.p_rel_path)
|
|
||||||
publisher.info(to_print)
|
|
||||||
|
|
||||||
|
#statistics
|
||||||
|
tld = url_parsed['tld']
|
||||||
|
if tld is not None:
|
||||||
|
## TODO: # FIXME: remove me
|
||||||
|
try:
|
||||||
|
tld = tld.decode()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
date = datetime.datetime.now().strftime("%Y%m")
|
||||||
|
server_statistics.hincrby('SQLInjection_by_tld:'+date, tld, 1)
|
||||||
|
|
||||||
# Try to detect if the url passed might be an sql injection by appliying the regex
|
# Try to detect if the url passed might be an sql injection by appliying the regex
|
||||||
# defined above on it.
|
# defined above on it.
|
||||||
def is_sql_injection(url_parsed):
|
def is_sql_injection(url_parsed):
|
||||||
line = urllib.request.unquote(url_parsed)
|
line = urllib.request.unquote(url_parsed)
|
||||||
line = str.upper(line)
|
line = str.upper(line)
|
||||||
result = []
|
|
||||||
result_suspect = []
|
|
||||||
|
|
||||||
for regex in regex_injection:
|
|
||||||
temp_res = re.findall(regex, line)
|
|
||||||
if len(temp_res)>0:
|
|
||||||
result.append(temp_res)
|
|
||||||
|
|
||||||
for word_list in word_injection:
|
|
||||||
for word in word_list:
|
|
||||||
temp_res = str.find(line, str.upper(word))
|
|
||||||
if temp_res!=-1:
|
|
||||||
result.append(line[temp_res:temp_res+len(word)])
|
|
||||||
|
|
||||||
for word in word_injection_suspect:
|
|
||||||
temp_res = str.find(line, str.upper(word))
|
|
||||||
if temp_res!=-1:
|
|
||||||
result_suspect.append(line[temp_res:temp_res+len(word)])
|
|
||||||
|
|
||||||
if len(result)>0:
|
|
||||||
print(result)
|
|
||||||
return 2
|
|
||||||
elif len(result_suspect)>0:
|
|
||||||
print(result_suspect)
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
return re.search(SQLI_REGEX, url_parsed, re.I) is not None
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
Loading…
Reference in a new issue