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
2016-08-02 15:43:11 +02:00
import string
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
# Config Var
regex_injection = [ ]
word_injection = [ ]
2016-08-10 09:06:37 +02:00
word_injection_suspect = [ ]
2016-08-02 15:43:11 +02:00
# 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
2016-08-10 09:06:37 +02:00
word_injection2 = [ " @@version " , " POW( " , " BITAND( " , " SQUARE( " ]
word_injection . append ( word_injection2 )
2016-08-02 15:43:11 +02:00
# Html keywords
2016-08-10 09:06:37 +02:00
word_injection3 = [ " <script> " ]
word_injection . append ( word_injection3 )
2016-08-02 15:43:11 +02:00
# Suspect char
2016-08-10 09:06:37 +02:00
word_injection_suspect1 = [ " \' " , " \" " , " ; " , " < " , " > " ]
2016-08-10 14:23:36 +02:00
word_injection_suspect + = word_injection_suspect1
2016-08-02 15:43:11 +02:00
2016-08-10 09:06:37 +02:00
# Comment
word_injection_suspect2 = [ " -- " , " # " , " /* " ]
2016-08-10 14:23:36 +02:00
word_injection_suspect + = word_injection_suspect2
2016-08-02 15:43:11 +02:00
def analyse ( url , path ) :
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 :
2018-04-16 17:00:44 +02:00
result_path = is_sql_injection ( resource_path . decode ( ' utf8 ' ) )
2016-08-02 15:43:11 +02:00
if query_string is not None :
2018-04-16 17:00:44 +02:00
result_query = is_sql_injection ( query_string . decode ( ' utf8 ' ) )
2016-08-02 15:43:11 +02:00
if ( result_path > 0 ) or ( result_query > 0 ) :
paste = Paste . Paste ( path )
if ( result_path > 1 ) or ( result_query > 1 ) :
2018-04-16 14:50:04 +02:00
print ( " Detected SQL in URL: " )
print ( urllib . request . unquote ( url ) )
2016-10-27 11:50:24 +02:00
to_print = ' SQLInjection; {} ; {} ; {} ; {} ; {} ' . format ( paste . p_source , paste . p_date , paste . p_name , " Detected SQL in URL " , paste . p_path )
2016-08-02 15:43:11 +02:00
publisher . warning ( to_print )
2016-08-08 09:17:44 +02:00
#Send to duplicate
p . populate_set_out ( path , ' Duplicate ' )
#send to Browse_warning_paste
2017-11-15 16:15:43 +01:00
p . populate_set_out ( ' sqlinjection; {} ' . format ( path ) , ' alertHandler ' )
2018-05-16 14:39:01 +02:00
msg = ' infoleak:automatic-detection= " sql-injection " ; {} ' . format ( path )
p . populate_set_out ( msg , ' Tags ' )
2018-07-30 11:56:50 +02:00
#statistics
tld = url_parsed [ ' tld ' ]
if tld is not None :
date = datetime . datetime . now ( ) . strftime ( " % Y % m " )
server_statistics . hincrby ( ' SQLInjection_by_tld: ' + date , tld , 1 )
2016-08-10 09:06:37 +02:00
else :
2018-04-16 14:50:04 +02:00
print ( " Potential SQL injection: " )
print ( urllib . request . unquote ( url ) )
2017-02-14 11:23:34 +01:00
to_print = ' SQLInjection; {} ; {} ; {} ; {} ; {} ' . format ( paste . p_source , paste . p_date , paste . p_name , " Potential SQL injection " , paste . p_path )
2016-08-02 15:43:11 +02:00
publisher . info ( to_print )
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 )
2018-04-16 17:00:44 +02:00
line = str . upper ( line )
2016-08-02 15:43:11 +02:00
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 :
2018-04-16 17:00:44 +02:00
temp_res = str . find ( line , str . upper ( word ) )
2016-08-02 15:43:11 +02:00
if temp_res != - 1 :
result . append ( line [ temp_res : temp_res + len ( word ) ] )
for word in word_injection_suspect :
2018-04-16 17:00:44 +02:00
temp_res = str . find ( line , str . upper ( word ) )
2016-08-02 15:43:11 +02:00
if temp_res != - 1 :
result_suspect . append ( line [ temp_res : temp_res + len ( word ) ] )
if len ( result ) > 0 :
2018-04-16 14:50:04 +02:00
print ( result )
2016-08-02 15:43:11 +02:00
return 2
elif len ( result_suspect ) > 0 :
2018-04-16 14:50:04 +02:00
print ( result_suspect )
2016-08-02 15:43:11 +02:00
return 1
else :
return 0
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 )