首页 > 其他分享 >OGNL表达式注入分析

OGNL表达式注入分析

时间:2024-03-28 23:23:24浏览次数:20  
标签:name user list User context OGNL new 表达式 注入

OGNL基础

依赖

<dependency>
	<groupId>ognl</groupId>
	<artifactId>ognl</artifactId>
	<version>3.1.19</version>
</dependency>

OGNL三要素

  • Expression表达式
  • root根对象、即操作对象
  • context上下文,用于保存对象运行的属性及值,有点类似运行环境的意思,保存了环境变量

看个例子

package org.example;

public class Tester {
    public User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}
package org.example;

public class User {
    private String name;
    private int age;
    public String getName(){
        return name;
    }
    public int getAge(){
        return age;
    }
    public void setName(String name){
        this.name = name;
    }
    public void setAge(int age){
        this.age = age;
    }
    public User(String name, int age){
        this.name = name;
        this.age = age;
    }
}

package org.example;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

public class Main {
    public static void main(String[] args) throws OgnlException {
        Tester tester = new Tester();
        User user = new User("F12", 20);
        tester.setUser(user);
        // 创建context, 设置root
        OgnlContext context = new OgnlContext();
        context.setRoot(tester);
        // 设置表达式
        String expression = "user.name";
        // 解析表达式
        Object ognl = Ognl.parseExpression(expression);
        // 调用获取值
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        System.out.println(value);
    }
}

// 输出
F12

运行以上代码就是获取org.example.Tester.user.name的值,上述我们是创建了一个tester,并且让他的user属性为一个User对象,且tester设置为root,表达式为user.name也就是获取root即tester的user属性的name属性。

OGNL语法

  • .操作符

一个例子,(#a=new java.lang.String("calc")).(@java.lang.Runtime@getRuntime().exec(#a)),也可以这样(#a=new java.lang.String("calc")),(@java.lang.Runtime@getRuntime().exec(#a)),中间的点换成逗号。可以发现它执行的方式有点类似递归,他把.前面的表达式当做结果给后面的表达式执行了这里需要注意一下#前我们用括号包裹起来了,这是为了符合语法,假如去掉那一层包裹会报错

  • #操作符

用于调用非root对象

package org.example;

import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;

public class Main {
    public static void main(String[] args) throws OgnlException {
        Tester tester = new Tester();
        User user = new User("F12", 20);
        tester.setUser(user);
        // 创建context, 设置root
        OgnlContext context = new OgnlContext();
//        context.setRoot(tester);
        context.put("user", user);
        // 设置表达式
        String expression = "#user.name";
        // 解析表达式
        Object ognl = Ognl.parseExpression(expression);
        // 调用获取值
        Object value = Ognl.getValue(ognl, context, context.getRoot());
        System.out.println(value);
    }
}
// 输出
F12

用于创建Map
#{"name": "f12", "level": "noob"}
用于定义变量
如一开始的例子#a=new java.lang.String("calc"),定义了一个字符串常量

  • @操作符

用于调用静态属性、静态方法、静态变量,如上述的@java.lang.Runtime@getRuntime().exec

OGNL版本限制

在OGNL>=3.1.25版本中设置了黑名单

public static Object invokeMethod(Object target, Method method, Object[] argsArray)
    throws InvocationTargetException, IllegalAccessException
{

    if (_useStricterInvocation) {
        final Class methodDeclaringClass = method.getDeclaringClass();  // Note: synchronized(method) call below will already NPE, so no null check.
        if ( (AO_SETACCESSIBLE_REF != null && AO_SETACCESSIBLE_REF.equals(method)) ||
            (AO_SETACCESSIBLE_ARR_REF != null && AO_SETACCESSIBLE_ARR_REF.equals(method)) ||
            (SYS_EXIT_REF != null && SYS_EXIT_REF.equals(method)) ||
            (SYS_CONSOLE_REF != null && SYS_CONSOLE_REF.equals(method)) ||
            AccessibleObjectHandler.class.isAssignableFrom(methodDeclaringClass) ||
            ClassResolver.class.isAssignableFrom(methodDeclaringClass) ||
            MethodAccessor.class.isAssignableFrom(methodDeclaringClass) ||
            MemberAccess.class.isAssignableFrom(methodDeclaringClass) ||
            OgnlContext.class.isAssignableFrom(methodDeclaringClass) ||
            Runtime.class.isAssignableFrom(methodDeclaringClass) ||
            ClassLoader.class.isAssignableFrom(methodDeclaringClass) ||
            ProcessBuilder.class.isAssignableFrom(methodDeclaringClass) ||
            AccessibleObjectHandlerJDK9Plus.unsafeOrDescendant(methodDeclaringClass) ) {
            throw new IllegalAccessException("........");
        }

投影与选择

OGNL 支持类似数据库当中的选择与投影功能。

  • 投影:选出集合当中的相同属性组合成一个新的集合。语法为 collection.{XXX},XXX 就是集合中每个元素的公共属性。
  • 选择:选择就是选择出集合当中符合条件的元素组合成新的集合。语法为 collection.{Y XXX},其中 Y 是一个选择操作符,XXX 是选择用的逻辑表达式。选择操作符有 3 种:
    • ? :选择满足条件的所有元素
    • ^:选择满足条件的第一个元素
    • $:选择满足条件的最后一个元素
User p1 = new User("name1", 11);
User p2 = new User("name2", 22);
User p3 = new User("name3", 33);
User p4 = new User("name4", 44);
Map<String, Object> context = new HashMap<String, Object>();
ArrayList<User> list = new ArrayList<User>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
context.put("list", list);
System.out.println(Ognl.getValue("#list.{age}", context, list));
// [11, 22, 33, 44]
System.out.println(Ognl.getValue("#list.{age + '-' + name}", context, list));
// [11-name1, 22-name2, 33-name3, 44-name4]
System.out.println(Ognl.getValue("#list.{? #this.age > 22}", context, list));
// [org.example.User@6433a2, org.example.User@5910e440]
System.out.println(Ognl.getValue("#list.{^ #this.age > 22}", context, list));
// [org.example.User@6433a2]
System.out.println(Ognl.getValue("#list.{$ #this.age > 22}", context, list));
// [org.example.User@5910e440]

OGNL Expression解析流程

getValue处打个断点,跟进,注意这个node的类型ASTchain在OGNL表达式中,解析和执行就是通过ASTXXXX这些方法去解析执行的,一共有ASTChainASTConstASTCtorASTInstanceofASTListASTMethodASTStaticFieldASTStaticMethod.....等多种方法,其中最根本的就是chain

进入chain的getValue方法

进入evaluateGetValueBody方法,这里判断context是不是const,这里并不是

往下走进入getValueBody,获取子节点,并进入子节点的getValue方法,然后就这样一直循环

最后进入OgnlRuntime.callMethod

一直往下走,这里invoke,弹出计算器

标签:name,user,list,User,context,OGNL,new,表达式,注入
From: https://www.cnblogs.com/F12-blog/p/18102189

相关文章

  • JAVA8-Lambda表达式
    Lambda表达式是Java8中引入的一项特性,它提供了一种简洁的方法来表示只有一个方法的接口(即函数式接口)的实例。Lambda表达式通常用于创建匿名方法。这种表达式是函数式编程的核心,允许开发者写出更简洁、更灵活的代码。Lambda表达式的结构Lambda表达式的一般形式是(参数列......
  • 正则表达式的贪婪模式与非贪婪模式
    正则表达式中的贪婪模式和非贪婪模式(也称为勉强模式或懒惰模式)是量词行为的两种不同模式。这些模式影响正则表达式如何匹配字符串中的字符序列。贪婪模式(Greedy)贪婪模式是正则表达式的默认行为。在贪婪模式下,正则表达式会尽可能多地匹配字符。它会尝试匹配尽可能长的字符串片......
  • net 6 手动注入
    Program.cs EnginContex为静态类//注册服务EnginContext.SetServiceProvider(app.Services);EnginContex.cspublicsealedclassEnginContext{privatestaticIServiceProvider_serviceProvider;[MethodImpl(MethodImplOptions.Synchroni......
  • 16使用正则表达式处理字符串
    1<!DOCTYPEhtml>2<htmllang="en">3<head>4<metacharset="UTF-8">5<metaname="viewport"content="width=device-width,initial-scale=1.0">6<title>Document......
  • 【漏洞复现】万户 ezOFFICE wf_printnum.jsp SQL注入漏洞
    0x01产品简介万户OAezoffice是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品,统一的基础管理平台,实现用户数据统一管理、权限统一分配、身份统一认证。统一规划门户网站群和协同办公平台,将外网信息维护、客户服务、互动交流和日常工作......
  • Appointment(SQL注入)
    Appointment(SQL注入)1.TASK1问题:SQL的全称是?SQL是结构化查询语言的缩写。答案:StructuredQueryLanguage2.TASK2问题:最常见的一种SQL漏洞类型是什么?最常见的一种SQL漏洞类型为SQL注入漏洞答案:SQLinjection3.TASK3问题:OWASPtop10列表对注入漏洞的命名为什么?这个......
  • Csharp中表达式树
    Csharper中的表达式树这节课来了解一下表示式树是什么?在C#中,表达式树是一种数据结构,它可以表示一些代码块,如Lambda表达式或查询表达式。表达式树使你能够查看和操作数据,就像你可以查看和操作代码一样。它们通常用于创建动态查询和解析表达式。一、认识表达式树为什么要这样说?......
  • AOP中的execution表达式
    文章目录前言一、知识讲解?1AOP是什么?2execution表达式二、使用execution表达式1.execution表达式2使用示例总结前言提示:这里可以添加本文要记录的大概内容:在学习Spring中,必然要学习AOP,那么execution表达式有是必不可少的。提示:以下是本篇文章正文内容,下面案......
  • Cron 表达式解析
    Cron表达式解析Cron表达式是一种强大的工具,用于在特定时间自动执行计划任务。无论是在服务器维护、数据库备份,还是在发送定时邮件等场景,cron表达式都能提供精确的时间控制。Cron表达式的基本结构Cron表达式由6或7个由空格分隔的时间字段组成,每个字段代表了不同的时间单位:......
  • sql注入学校后台
    有运气成分,遇到两个学校,子域名查询了一下发现有登录平台,然后就直接sql了payload:admin'or1=1--+很离谱,这年头这两学校还能直接被sql进入后台。然后进学校后台后就可以直接查看到各种各样的敏感信息,还有各种权限。这里就不一一截图了。......