2018-05-04 13:53:29 +02:00
#!/usr/bin/env python3
2016-08-02 15:43:11 +02:00
# -*-coding:UTF-8 -*
2017-05-09 11:13:16 +02:00
2016-08-02 15:43:11 +02:00
"""
2017-05-09 11:13:16 +02:00
The SQLInjectionDetection Module
== == == == == == == == == == == == == == == ==
This module is consuming the Redis - list created by the Web module .
It test different possibility to makes some sqlInjection .
2016-08-02 15:43:11 +02:00
"""
import time
2018-07-30 11:56:50 +02:00
import datetime
import redis
2018-04-16 14:50:04 +02:00
import urllib . request
2016-08-02 15:43:11 +02:00
import re
from pubsublogger import publisher
from Helper import Process
from packages import Paste
from pyfaup . faup import Faup
2019-09-19 12:08:11 +02:00
# 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 "
2016-08-02 15:43:11 +02:00
def analyse ( url , path ) :
2019-09-19 12:22:21 +02:00
if is_sql_injection ( url ) :
2019-09-19 12:08:11 +02:00
faup . decode ( url )
url_parsed = faup . get ( )
2016-08-02 15:43:11 +02:00
paste = Paste . Paste ( path )
2019-09-19 12:08:11 +02:00
print ( " Detected SQL in 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 )
publisher . warning ( to_print )
#Send to duplicate
p . populate_set_out ( path , ' Duplicate ' )
msg = ' infoleak:automatic-detection= " sql-injection " ; {} ' . format ( path )
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 )
2016-08-10 09:06:37 +02:00
# Try to detect if the url passed might be an sql injection by appliying the regex
# defined above on it.
2016-08-02 15:43:11 +02:00
def is_sql_injection ( url_parsed ) :
2018-04-16 14:50:04 +02:00
line = urllib . request . unquote ( url_parsed )
2016-08-02 15:43:11 +02:00
2019-09-19 12:22:21 +02:00
return re . search ( SQLI_REGEX , line , re . I ) is not None
2016-08-02 15:43:11 +02:00
if __name__ == ' __main__ ' :
# If you wish to use an other port of channel, do not forget to run a subscriber accordingly (see launch_logs.sh)
# Port of the redis instance used by pubsublogger
publisher . port = 6380
# Script is the default channel used for the modules.
publisher . channel = ' Script '
# Section name in bin/packages/modules.cfg
config_section = ' SQLInjectionDetection '
# Setup the I/O queues
p = Process ( config_section )
# Sent to the logging a description of the module
publisher . info ( " Try to detect SQL injection " )
2018-07-30 11:56:50 +02:00
server_statistics = redis . StrictRedis (
host = p . config . get ( " ARDB_Statistics " , " host " ) ,
port = p . config . getint ( " ARDB_Statistics " , " port " ) ,
db = p . config . getint ( " ARDB_Statistics " , " db " ) ,
decode_responses = True )
2016-08-02 15:43:11 +02:00
faup = Faup ( )
# Endless loop getting messages from the input queue
while True :
# Get one message from the input queue
message = p . get_from_set ( )
if message is None :
publisher . debug ( " {} queue is empty, waiting " . format ( config_section ) )
time . sleep ( 10 )
continue
else :
# Do something with the message from the queue
url , date , path = message . split ( )
2016-08-10 09:06:37 +02:00
analyse ( url , path )