User user = new User(); //实例化表达式解析对象 ExpressionParser parser = new SPELExpressionParser(); //实例化上下文,将user对象作为参数传入,这样就可以操作user对象的属性了 StandardEvaluationContext context = new StandardEvaluationContext(user); /** 如果不想在实例化上下文的时候就传入对象的话就可以使用下面的代码进行等价替换
StandardEvaluationContext context = new StandardEvaluationContext(); context.setRootObject(user);
//通过setVariable方法存放入上下文中的对象,就可以通过 #+key+属性的方式进行调用 String name = (String)parser.parseExpression("#user.userName").getValue(context); //通过setVariable方法传入的对象和通过setRootObject方法传入的对象是不一样的,通过setRootObject传入的对象可以直接通过“属性名称”来进行调用,而通过setVariable方法传入的对象,只能通过“#+key+属性的方式进行调用”
调用成员方法的例子:
1 2 3 4 5 6 7 8
User user = new User(); ExpressionParser parser = new SPELExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext(user); context.setVariable("user",user); //如下可以使用 #+Key+MethodName的形式进行调用 //这种方法不仅可以调用动态方法,也可以调用静态方法 String result = (String) parser.parseExpression("#user.sayHi('jack')").getValue(context); System.out.println(result);
调用静态方法的例子1:
1 2 3 4
ExpressionParser parser = new SPELExpressionParser(); //使用“T(Type)”来表示java.lang.Class类的实例,即如同java代码中直接写类名。此方法一般用来引用常量或静态方法 String result = parser.parseExpression("T(com.SPEL.pojo.User).sayBye('Jack')").getValue(String.class); System.out.println(result);
调用静态方法的例子2:
1 2 3 4 5 6 7 8 9
ExpressionParser parser = new SPELExpressionParser(); StandardEvaluationContext context = new StandardEvaluationContext(); //通过反射拿到User类的sayBye方法对象, Method sayBye = User.class.getMethod("sayBye", String.class); //将sayBye方法对象注册进上下文中 context.registerFunction("sayBye",sayBye); //然后就可以通过#+MehtondName的形式进行调用 String result = (String) parser.parseExpression("#sayBye('jack')").getValue(context); System.out.println(result);
漏洞成因
既然可以调用静态类的静态方法或其它类的成员方法,若该字符串可被用户控制,即可导致漏洞产生。
1 2 3 4
public static void main(String[] args) { ExpressionParser parser = new SpelExpressionParser(); parser.parseExpression("T(java.lang.Runtime).getRuntime().exec('calc')").getValue(); }
1 2 3 4
public static void main(String[] args) { ExpressionParser parser = new SpelExpressionParser(); parser.parseExpression("new java.lang.ProcessBuilder("open", "-a","Calculator").start()").getValue(); }
<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>${timestamp}</div><div>There was an unexpected error (type=${error}, status=${status}).</div><div>${message}</div></body></html>