<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/1404

            author: [email protected]

            0x00 背景


            在github翻來覆去看了半天,官方版的diff只在php里改動了一個位置:

            #!diff
            - ?if ( $hmac != $hash ) {  
            + ?if ( hash_hmac( 'md5', $hmac, $key ) !== hash_hmac( 'md5', $hash, $key ) ) {  
            

            WP的開發人員也只是含糊的說這個版本修復了一個可以偽造cookie的漏洞。苦思半天翻來覆去看代碼之后,甚至順帶挖出了個0day,才發現原來自己又想多了,這個洞的原理其實很簡單,那就是邊信道攻擊。

            0x01 細節


            邊信道攻擊我就不具體解釋了,這個地方補的是一個關于HMAC的邊信道攻擊,利用時間差來判斷HMAC。

            HMAC是一種加密后的hash,比如WP里用的是HMAC-MD5,外觀和md5一樣,也是長度位32的16進制字符串,但是經過一個key加密,用來防止重放攻擊等。

            通過時間差攻擊(Timing attack),可以獲取完整的HMAC從而偽造cookie。

            首先我們來看下wordpress登錄后的cookie長什么樣,拿烏云drops為例:

            wordpress_logged_in_7065d11a793a3ec8482214fcc4f0a55b=insight-labs%7C1397480887%7Cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  
            

            cookie名字wordpress_logged_in_后面的那個hash看似很神秘,其實是:

            #!php
            if ( !defined( 'COOKIEHASH' ) ) {  
            $siteurl = get_site_option( 'siteurl' );  
            if ( $siteurl )  
            define( 'COOKIEHASH', md5( $siteurl ) );  
            

            也就是說其實就是wp網站的url,比如drops的是'http://drops.wooyun.org',md5 一下你就知道了。

            但是cookie的內容就沒那么簡單了,%7c是鍵盤上的豎線 |?。

            wp的cookie用豎線作為分隔符,前面是用戶名,中間是cookie過期時間,后面是32位的hmac。

            hmac的來源比較復雜,但是如果我們能得到這個hmac,我們就可以登錄任意已知用戶了(WP并沒有在本地記錄登錄session,全靠cookie)。

            下面來看下HMAC timing attack的最基本原理,字符串對比。

            即使沒有看到php的源碼,從理性角度分析,任何程序語言的字符串對比應該都是這樣實現的:

            如果兩個字符串第一個字符不相同,那么后面的即使相同也沒有意義了,所以返回 False。

            如果第一個字符相同,那么到第二個字符,如果第二個字符也相同,判斷第三個字符...直到最后一個字符,如果其中有一個字符不一樣,那么就終止后續判斷,返回 False,如果全部一樣,就返回 True。

            看到這里大家應該都懂了,那就是判斷

            'abcdef'=='zxcvbn'
            

            'abcdef'=='abcdeg'
            

            用的時間短。

            0x02 攻擊


            構造POC:

            下面我有一個32位的md5 hash:

            f2835bb2a6ab584fc5cf268bb384c598  
            

            有個簡單的php程序

            #!php
            <?php  
            $hash='f2835bb2a6ab584fc5cf268bb384c598'  
            
            if($_GET['hmac']!=$hash){  
            exit('Go away...')  
            }
            echo 'You are admin!'  
            ?>  
            

            然后我提交:

            00000000000000000000000000000000
            

            并且記錄從提交到服務器返回結果所需要的時間(需要精確到微秒,起碼也得是毫秒級)
            之后提交

            10000000000000000000000000000000  
            ..  
            20000000000000000000000000000000  
            ..  
            30000000000000000000000000000000  
            .  
            .  
            .  
            f0000000000000000000000000000000 
            

            從0-f,然后對比一下他們所需要的時間:

            0 0.005450913  
            1 0.005829198  
            2 0.004905407  
            3 0.005286876  
            4 0.005597611  
            5 0.004814430  
            6 0.004969118  
            7 0.005335884  
            8 0.004433182  
            9 0.004440246  
            a 0.004860263  
            b 0.004561121  
            c 0.004463188  
            d 0.004406799  
            e 0.004978907  
            f 0.004887240 
            

            等等……這不是差不多么,而且明明第一位是f,但是7的時間最長,這尼瑪不是……

            enter image description here

            但是統計學告訴我們,任何微小的差異在重復多次后都會放大,所以這次我們把每個請求輪流跑500遍,然后都記錄下來,注意,要輪流跑,如果先把0跑500遍再把1跑500遍,第二次對比相同內容的時候服務器返回都飛快,似乎有某種緩存機制。

            把第一位的0-f輪流跑了500次之后,把記錄的時間差做成圖:

            enter image description here

            可以看出,多次重試增加了誤差的統計顯著性。

            從圖里可以看出,大部分情況下0-e的反應速度都在0.005毫秒以內,但是f卻大于這個時間。

            知道了第一位之后我們可以用同樣的方法去計算第二位,這次把已知的第一位放進去:

            f0000000000000000000000000000000  
            f1000000000000000000000000000000  
            f2000000000000000000000000000000  
            .  
            .  
            .  
            ff000000000000000000000000000000  
            

            相同過程就不再闡述了,不過大家可以試試看,計算所有響應時間的方式是用平均值好還是標準差好。

            通過這種攻擊方式,我們只需要16*500*32=256000次請求即可獲取完整的HMAC cookie。

            這下就能理解官方補丁的用意了,這樣雖然沒有去掉時間差(時間差總是存在的,除非用恒定時間對比算法),但是因為多加了一層hmac,攻擊者的payload被隨機化了,無法通過時間差來猜測具體字符是哪一個。

            不過在互聯網環境下,這個洞還是有點雞肋,但是如果是在同一個機房或者虛擬主機同站的話效果應該還是不錯的。

            WP的這個洞是補上了,我相信大家會舉一反三的,畢竟用 == 或者!=的地方太多了。

            PS: 小編欠飯次數+=1

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线