OGNL表达式注入分析
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这些方法去解析执行的,一共有ASTChain、ASTConst、ASTCtor、ASTInstanceof、ASTList、ASTMethod、ASTStaticField、ASTStaticMethod.....等多种方法,其中最根本的就是chain

进入chain的getValue方法

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

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

最后进入OgnlRuntime.callMethod

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

OGNL表达式注入分析的更多相关文章
- Java Web表达式注入
原文:http://netsecurity.51cto.com/art/201407/444548.htm 0×00 引言 在2014年6月18日@终极修炼师曾发布这样一条微博: 链接的内容是一个名为 ...
- ref:一种新的攻击方法——Java Web表达式注入
ref:https://blog.csdn.net/kk_gods/article/details/51840683 一种新的攻击方法——Java Web表达式注入 2016年07月06日 17:01 ...
- Ognl表达式语言
l OGNL表达式 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目. Struts2框架使用OGNL作为默认的表达式语言. ...
- Java实战之01Struts2-04拦截器、上传下载、OGNL表达式
十二.Struts2中的拦截器 1.拦截器的重要性 Struts2中的很多功能都是由拦截器完成的.比如:servletConfig,staticParam,params,modelDriven等等. ...
- Struts2之 OGNL表达式和值栈
技术分析之OGNL表达式概述(了解) 1. OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写 * 所谓对象图,即以任意 ...
- Struts2知识点小结(三)--值栈与ognl表达式
1.问题一 : 什么是值栈 ValueStack 回顾web阶段 数据交互问题? 客户端提交数据 到 服务器端 request接受数据+BeanUtils实体封装 ...
- Struts2中OGNL表达式的用法
今天分享的是Struts2框架中的一种ognl表达式语言,主要分两个目标去学习 1.理解struts2传值的优先级 2.ognl与el的区别 一:ognl表达式语言简介 OGNL的全称是O ...
- 一文详解SpEL表达式注入漏洞
摘要:本文介绍了SpEL表达式以及常见的SpEL注入攻击,详细地介绍了部分漏洞攻击实例以及常用的漏洞检测与防御手段. 本文分享自华为云社区<SpEL表达式注入漏洞分析.检查与防御>,作者: ...
- java代码审计-SpEL表达式注入
0x01 前言 Spring Expression Language(简称 SpEL)是一种功能强大的表达式语言.用于在运行时查询和操作对象图:语法上类似于Unified EL,但提供了更多的特性,特 ...
- Ognl表达式基本原理和使用方法
Ognl表达式基本原理和使用方法 1.Ognl表达式语言 1.1.概述 OGNL表达式 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个 ...
随机推荐
- Spring Boot学生信息管理系统项目实战-4.学生管理
1.获取源码 源码是捐赠方式获取,详细请QQ联系我 :) 2.实现效果 2.1 导出导入模板 2.2 导入学生数据 3.项目源码 只挑重点讲,详细请看源码. 学生管理包含了学生信息的增删改查,这里我只 ...
- 利用nssm将jar包安装为windows服务
1.介绍 假设我们有一个spring boot程序打包成jar文件放到windows服务器运行,第一种方式jar -jar xx方式在cmd运行.这样有个缺点,被别人误关闭了咋办?服务器重启了咋办? ...
- 变量,六大数据类型之字符串、列表、元祖----day02
1.变量:可以改变的量,实际具体指的是内存中的一块存储空间 (1)变量的概念 (2)变量的声明 (3)变量的命名 (4)变量的交换 *常量就是不可改变的量,python当中没有明确定义常量的关键字,所 ...
- 【Azure Function App】在VS Code中,创建好Function App后部署到Azure中,无法选择Subscriptions
问题描述 在VS Code中,创建好Function App后部署到Azure中,无法选择Subscriptions 问题解答 对于无法使用 VS Code 部署 Function App 到 Azu ...
- 文心一言 VS 讯飞星火 VS chatgpt (205)-- 算法导论15.4 1题
一.求〈1,0,0,1,0,1,0,1〉和〈0,1,0,1,1,0,1,1,0〉的一个LCS.需要写代码的时候,请用go语言. 文心一言,代码正常运行: 在Go语言中,求两个序列的最长公共子序列(Lo ...
- 数据库运维 | 携程分布式图数据库NebulaGraph运维治理实践
作者简介:Patrick Yu,携程云原生研发专家,关注非关系型分布式数据存储及相关技术. 背景 随着互联网世界产生的数据越来越多,数据之间的联系越来越复杂层次越来越深,人们希望从这些纷乱复杂的数据中 ...
- [Linux] 无显示器 无键盘 网线直连传输文件
有显示器可以操作 这种情况下要简单的多,基本思想是,网线直连之后让其中一方当作网关,分配好ip地址,比如说192.168.8.1,网关也是192.168.8.1即可,如果要填写子网掩码就写255.25 ...
- 十四: Mysql数据结构选择的合理性
Mysql数据结构选择的合理性 从MySQL的角度讲,不得不考虑一个现实问题就是磁盘I/O. 如果我们能让索引的数据结构尽量减少硬盘的I/O操作,所消耗的时间也就越小.可以说,磁盘的I/O操作次数对索 ...
- Java 继承成员变量和继承方法的区别
1 package com.bytezreo.duotai3; 2 3 /** 4 * 5 * @Description 继承成员变量和继承方法的区别 6 * @author Bytezero·zhe ...
- MySQL日志15连问,redo log与biglog
1. redo log是什么? 为什么需要redo log? redo log 是什么呢? redo log 是重做日志. 它记录了数据页上的改动. 它指事务中修改了的数据,将会备份存储. 发生数据库 ...