DEDECMS僞隨機漏洞 (二) :Cookie算法與Rootkey隨機強度分析
本篇爲 《DEDECMS僞隨機漏洞 (一) :PHP下隨機函數的研究》 的續篇,研究DEDECMS的cookie生成的算法, 以及rootkey生成的算法, 確認rootkey使用的隨機算法的強度, 計算攻擊耗時。
一、Cookie算法
1.COOKIE的作用和常見的構造形式
作用: 權限鑑別、無會話狀態。
構成:
常常是以下形式 cookie = F(x,y), F爲不可逆函數, x爲鹽 , y爲和權限/用戶相關的數據
我們可以知道的部分, F-> 一般常常爲hash函數md5,sha256等
y-> 比如用戶名稱/id編號/權限簡稱
我們無法知道的部分, x
2.定位算法-動態調試
根據常識, 在登陸後, server端會返回cookie!
2.1在web站點上進行登陸,並抓包, 看到路徑/member/index_do.php
2.2分析index_do.php (dedecms路由很簡單, 路徑直接對應到了文件),在登陸接口處下斷點
2.3大致瀏覽整個函數, 並沒有發現設置cookie的操作(php原型函數-setcookie),但是發現了檢查賬號的函數, 跟入進去:
2.4關鍵字段
有的時候, 查看服務端響應或是通過js生成的cookie字段很多, 但調用接口時, 可能校驗的是cookie裏面的幾個字段, 因此我們找到關鍵的被用來鑑權的字段, 可以減少我們測試時的干擾.
針對2.1圖片的cookie通過遞減字段測試, 其實可以發現dedecms校驗cookie的關鍵字段爲:
DedeUserID=7; DedeUserID_ckMd5=4d0db47b3ba3fef5; DedeUserID=用戶ID; DedeUserIDckMd5 = substr(md5($cfgcookie_encode.用戶ID),0,16)
其中DedeUserID是很容易知道的, 或者有規律的, 1,2,3,4這樣子, 那麼其實要僞造cookie的關鍵是需要知道$cfgcookieencode(本文稱之爲rootkey)
二、 Root Key生成算法
1. 代碼定位
$cfgcookieencode是固定的? 還是在內存內動態生成的?
1.1 全文查找以下cfgcookieencode,發現在config.cache.inc.php存儲有: 這個值和我們在上面斷點看到的值一樣,大概率可以判斷,應該屬於一個固定值.
1.2 全局找一下有哪些地方操作了config.cache.inc.php,看是哪個函數寫入了這個值
這兒定位偏了, 這兒是更新服務器的時候會刷新一次root key~
1.3 繼續定位到install.php
$cfgcookieencode除了在config.cache.inc.php,也記錄在config.cache.bak.php, 那麼看下哪裏操作了config.cache.bak.php:
在上下文找到了同樣的root key生成算法:
這兒是真正第一次生成root key的地方
在安裝界面的時候其實會顯示出來給我們:
1.4 根據1.2, 1.3可知Root Key算法如下:
$chars='abcdefghigklmnopqrstuvwxwyABCDEFGHIGKLMNOPQRSTUVWXWY0123456789'; $max = strlen($chars) - 1; $length = rand(28,32); $root_key=''; for($i = 0; $i < $length; $i++) { $root_key .= $chars[mt_rand(0, $max)]; }
2. 強度分析
2.1 套用結論
基於第一篇的下面三個結論:
4.1 影響隨機數生成的因素爲兩個: 1. 種子 2. 次數 4.4 種子區間爲0到0xffffffff 4.6 同一進程下,先後被調用的rand和mt_rand, 在未播種的前提下, 會使用同一個隨機種子
可知, root_key的可能性爲 (0xffffffff-0)+1 = 2^32種可能.
揣測一下作者認爲的強度爲:
62^28 + 62^29 + 62^30 + 62^31 + 62^32
2.2 遍歷全部rootkey耗時
這兒md5和substr計算是靜態的字符串, 實際的字符串是變化的, 消耗的時間應該在計算出來的時間的周圍浮動
<?php $start = microtime(true); for ($i = 0; $i < 10000000; ++$i) { ; } $total_1 = microtime(true) - $start; $start = microtime(true); for ($i = 0; $i < 10000000; ++$i) { md5("111111111111111111111111111111"); } $total_2 = microtime(true) - $start; $start = microtime(true); for ($i = 0; $i < 10000000; ++$i) { substr(md5("111111111111111111111111111111"),0,16); } $total_3 = microtime(true) - $start; $start = microtime(true); $chars='abcdefghigklmnopqrstuvwxwyABCDEFGHIGKLMNOPQRSTUVWXWY0123456789'; $max = strlen($chars) - 1; for ($i = 0; $i < 1000000; ++$i) { $hash=''; $length = rand(28,32); for($y = 0; $y < $length; $y++) { $hash .= $chars[mt_rand(0, $max)]; } } $total_4 = microtime(true) - $start; echo ($total_2 - $total_1); echo "\n"; echo ($total_3 - $total_1); echo "\n"; echo ($total_4 - $total_1); echo "\n"; ?>
結果:
3.9920189380646 //10^7次md5() 用時
7.0076858997345 //10^7次substr(md5()) 用時
8.376072883606 // 10^6次生成key 用時
那麼單進程遍歷root key的時間需要:
((8.376072883606/10^6) * (2^32)) / 3600 ≈ 10 hour
*本文作者: 光通天下無患實驗室 Djerryz ,轉載請註明來自FreeBuf.COM