我對Padding Oracle Attack的分析和思考


道哥的《白帽子講web安全》有一章提到Padding Oracle Attack的攻擊方式,據說這貨在2011年的Pwnie Rewards上還被評為"最具價值的服務器漏洞"。

抱着書看了半天,感覺也不是很理解,和密碼學結合的比較緊,有一些理論的東西在里面。這里做個學習筆記,研究一下。

 

1. 相關閱讀材料

https://github.com/GDSSecurity/PadBuster  PadBuster - Automated script for performing Padding Oracle attacks

http://hi.baidu.com/aullik5/item/49ab45de982a67db251f40f6  道哥的分析

http://www.di-mgt.com.au/cryptopad.html  Padding原則

http://hi.baidu.com/306211321/item/faa44923c3c07d98b7326387  分組密碼的鏈接模式

http://blog.gdssecurity.com/labs/2010/9/14/automated-padding-oracle-attacks-with-padbuster.html  作者寫的分析

http://www.cnblogs.com/JeffreyZhao/archive/2010/09/25/1834245.html  老趙寫的分析(和ASP.NET結合)

http://www.isg.rhul.ac.uk/~kp/secretIV.pdf  國外的牛牛寫的分析(拓展Padding Oracle的知識面)

http://www.icylife.net/yunshu/attachments/Padding-Oracle-Attack.pdf  雲舒寫的分析

http://netifera.com/research/poet/PaddingOraclesEverywhereEkoparty2010.pdf  EKOPARTY 2010的演講PPT

http://netsecurity.51cto.com/art/201101/244089_1.htm  51CT上看到的分析

 

 

 

 

 

2. 前引知識

2.1 分組的填充Padding

分組密碼Block Cipher需要在加載前確保每個每組的長度都是分組長度的整數倍。一般情況下,明文的最后一個分組很有可能會出現長度不足分組的長度:

這個時候,普遍的做法是在最后一個分組后填充一個固定的值,這個值的大小為填充的字節總數。即假如最后還差3個字符,則填充0x03。

這種Padding原則遵循的是常見的PKCS#5標准。http://www.di-mgt.com.au/cryptopad.html#PKCS5

 

 

2.2 CBC(Cipher Block Chaining CBC)模式

這是一種分組鏈接模式,目的是為了使原本獨立的分組密碼加密過程形成迭代,使每次加密的結果影響到下一次加密。這行可以強化加密算法的"敏感性",即實現所謂的"雪崩效應",在香濃理論中這就是"擾亂原則"。

之前在《密碼學》課后做的筆記:http://hi.baidu.com/306211321/item/faa44923c3c07d98b7326387

這里我個人感覺要注意的一點是:

在鏈接模式中,初始化IV的長度要和對稱加密算法的分組長度一致。原因是鏈接模式中的異或操作是等長操作。

 

 

 

 

 

3. Padding Oracle Attack攻擊的原理

因為Padding Oracle Attack是針對CBC鏈接模式的攻擊,和具體的加密算法無關(分組)。所以這里我們選擇DES為例進行闡述。

假設明文為: LittleHann(明文長度為10  8 < 10 < 16 即使用2個分組)

經過DES加密(CBC模式)后,其密文為: EFC2807233F9D7C097116BB33E813C5E

加密程序: http://pan.baidu.com/s/1e2o7

密文采用了"ASCII十六進制的表示方法",即兩個字符表示一個字節的十六進制數。這是因為密碼學算法中得到的密文經常會出現不可打印字符,為了保證在網絡上傳輸的正確而不受不同系統間編碼方案的影響,就有必要對密文進行"可視化"轉化(即轉化成可打印字符)。除了"ASCII十六進制的表示方法"之外,還可以采用"base64編碼方法"。

PS:

這里插個題外話:PHP的DES及其他密碼學算法的加密是通過"PHP加密擴展庫Mcrypt"來實現的。

http://www.php100.com/cover/php/2651.html

http://baike.baidu.com/link?url=U8OtBP-IcYLRGrfWpSNhHskzrnA0qPNTsIrgGZcZSjLTGBPfpEI35ry51JtAXFxVuVsXKBK_UUZoXbZWgM-xLK

 

整個加密過程如下:

初始化向量IV與明文(第一組明文)XOR后,再經過運算得到的結果作為新的IV,用於下一分組(分組2),如果迭代下去。

解密過程是加密過程的逆過程:

這里要注意,前幾個分組的解密結果對我們都沒有意義,我們重點關注的是最后一個分組的解密結果。看這張圖可能會清楚一點:

注意到最后一個分組的末尾的數值為0x04,即表示填充了4個Padding。如果最后的Padding不正確(值和數量不一致),則解密程序往往會拋出異常(Padding Error)。而利用應用的錯誤回顯,我們就可以判斷出Paddig是否正確。

 

這里有幾個概念要先理清一下:

1. 基於密碼學算法的攻擊,往往第一個要搞清楚的是,我們在攻擊誰,或者准確的說我們的攻擊點在哪里?在一個密碼學算法中,有很多的參數(指攻擊者可以控制的參數),攻擊者往往是針對其中某一個或某一些參數進行破解,窮舉等攻擊。

在Padding Oracle Attack攻擊中,攻擊者輸入的參數是IV+Cipher,我們要通過對IV的"窮舉"來請求服務器端對我們指定的Cipher進行解密,並對返回的結果進行判斷。

 

2. 和SQL注入中的Blind Inject思想類似。我覺得Padding Oracle Attack也是利用了這個二值邏輯的推理原理,或者說這是一種"邊信道攻擊(Side channel attack)"。http://en.wikipedia.org/wiki/Side_channel_attack

這種漏洞不能算是密碼學算法本身的漏洞,但是當這種算法在實際生產環境中使用不當就會造成問題。

和盲注一樣,這種二值邏輯的推理關鍵是要找到一個"區分點",即能被攻擊者用來區分這個的輸入是否達到了目的(在這里就是尋找正確的IV)。

比如在web應用中,如果Padding不正確,則應用程序很可能會返回500的錯誤(程序執行錯誤);如果Padding正確,但解密出來的內容不正確,則可能會返回200的自定義錯誤(這只是業務上的規定),所以,這種區別就可以成為一個二值邏輯的"注入點"。

 

3. 攻擊成立的兩個重要假設前提:

1. 攻擊者能夠獲得密文(Ciphertext),以及附帶在密文前面的IV(初始化向量)
2. 攻擊者能夠觸發密文的解密過程,且能夠知道密文的解密結果

 

4. 可能出現的情況

明文分組和填充就是Padding Oracle Attack的根源所在,但是這些需要一個前提,那就是應用程序對異常的處理。當提交的加密后的數據中出現錯誤的填充信息時,不夠健壯的應用程序解密時報錯,直接拋出"填充錯誤"異常信息(這個錯誤信息在不同的應用中是不同的體現,在web一般是報500錯誤)。

攻擊者就是利用這個異常來做一些事情,假設有這樣一個場景,一個WEB程序接受一個加密后的字符串作為參數,這個參數包含用戶名、密碼。參數加密使用的最安全的CBC模式,每一個block有一個初始化向量IV(注意:這個IV在服務器第一次生成這個密文的時候就產生了,並保存在服務器上,攻擊者需要在提交數據的時候也提交這個IV,后面我們會看到,攻擊者實際上就是在"窮舉"這個IV)。

當提交參數時,服務端的返回結果會有下面3種情況:
a. 參數是一串正確的密文,分組、填充、加密都是對的(程序運行本身沒出問題),包含的內容也是正確的(業務邏輯是對的),那么服務端解密、檢測用戶權限都沒有問題,返回HTTP 200。
b. 參數是一串錯誤的密文,包含不正確的bit填充(程序運行本身出現致命錯誤),那么服務端解密時就會拋出異常,返回HTTP 500 server error。
c. 參數是一串正確的密文(程序運行本身沒出問題),包含的用戶名是錯誤的(業務邏輯是錯的),那么服務端解密之后檢測權限不通過,但是依舊會返回HTTP 200戒者HTTP 302,而不是HTTP 500。

攻擊者無需關心用戶名是否正確,只需要提交錯誤的密文(因為這里有4中變量情況,為了構造出二值邏輯推理,我們要定住其中2個情況,即讓業務邏輯恆錯,對Bit Padding的情況進行邏輯推理),根據HTTP Code即可做出攻擊。

 

 

我們繼續回到原理分析上來。

假設有這樣一個應用 http://sampleapp/home.jsp?UID=0000000000000000EFC2807233F9D7C097116BB33E813C5E

(中間用箭頭隔開了,前面的16個字母(即8字節 ASCII十六進制表示法兩個字母為一個字節)為攻擊者輸入的IV。后面的32個字母(即16字節)為攻擊者輸入的密文)

 

我們向服務器發送這樣一個請求:

Request: http://sampleapp/home.jsp?UID=0000000000000000EFC2807233F9D7C097116BB33E813C5E

Respose: 500 - Internal Server Error

此時在解密時Padding是不正確的(填充的值和填充的數量不一致)

例如:

程序判斷Padding是否出錯一般是去檢驗末尾的那個字節的值,這里是0x3D,顯然不對。這里我們再次回憶一下Padding原則:

1個字節的Padding為0x01

2個字節的Padding為0x02

3個字節的Padding為0x03

4個字節的Padding為0x04

5個字節的Padding為0x05

6個字節的Padding為0x06

7個字節的Padding為0x07

8個字節的Padding為0x08(當原始的明文正好是分組的整數倍的時候,Padding一個整組的填充值)

也就是說,Padding的值只可能是0x01~0x08之間。

 

接下來就是最關鍵的部分了,也是我一開始看比較難理解的地方。

我們接下來要利用選擇密文攻擊的思想,不斷調整,修正IV。來對Intermediary Value進行猜測。

1) Padding 0x01

我們不斷地調整IV的值,以希望解密后,最后一個字節的值為正確的Padding Byte,這里是0x01。因為Intermediary Value是固定的(我們此時不知道Intermediary Value),因此從0x00~0xFF之間,只可能有一個IV的值與Intermediary Value的最后一個字節進行XOR后,結果是0x01(思考: 因為0x01只有最后1 bit為1,其他都是0,所以根據XOR的性質,只能存在一個值能XOR得到0x01)。攻擊者通過遍歷這255個值,可以找出IV需要的最后一個字節。

Request: http://sampleapp/home.jsp?UID=0000000000000066EFC2807233F9D7C097116BB33E813C5E

Respose: 200 OK

通過XOR運算,可以馬上推導出此Intermediary Byte的值:

if(Inermediary Byte) ^ 0x66  == 0x01
{
       Inermediary Byte = 0x66 ^ 0x01                 
}
so:
        Inermediary Byte = 0x67

在回過頭來看看加密過程:

初始化向量IV與明文進行XOR運算得到了Inermediary Value,因此將剛才得到的Inermediary Byte(0x67)與"真實"的IV的最后一個字節0x0F(攻擊者事先獲取到的)進行XOR運算,即能得到明文:

 

0x67 ^ 0x0F = 0x68 : H

 

即得到明文(第一個分組)的最后一個字母H!

這里咱們要稍微停一下,把思路理一理:

1. 我們在得出明文的那次XOR計算中用到的IV(0x0F)和我們攻擊者不斷"注入"的IV(0x01~0xFF)不是一回事,要區分開來。在計算明文的那個IV(0x0F)是我們事先就獲取到的,回想我們之前說的這個Padding Oracle Attack攻擊的成立條件:

這個IV(0x0F)是服務器端在發送密文的時候(可能是cookie形式)附帶在密文的頭部發給我們的。 一般情況下,如果跨系統發送這種"帶鹽"的密文,都要把"鹽(IV)"附帶在密文的頭部或其他位置一起發送給接收方。這里我們接收到的IV就是0x0F,在不同的環境中這個IV必然是不一樣的,關鍵是要理解原理。

 

2. 為什么我們可以不斷嘗試IV?

按理來說,IV不是在服務器第一次生成這段密文的時候就生成好了嗎?然后在每次發送的時候都附帶在密文的頭部,不會再變了......

的確是這樣,但這說的是在正常的解密情況下發生的事,而我們攻擊者現在做的事並不是在解密(事實上攻擊者這個時候也不知道IV和KEY),我們只是在通過不斷的修改IV來對目標解密系統進行"試探",從返回的結果來進行"側信道攻擊",從而進行二值邏輯推理。

這就是一種所謂的"選擇密文攻擊"方式,好像也有叫Bit-Flipping Attack:

http://www.vnsecurity.net/2010/03/codegate-2010-challenge-8-bit-flipping-attack-on-cbc-mode/

 

繼續回到思路分析上來:

在正確"匹配"了Padding 0x01之后,需要做的是繼續推導出剩下的Intermediary Byte。根據Padding 原則,在需要Padding兩個字節的時候,其值應該是0x02。

 

2) Padding 0x02

這個時候我們要注意,之前說過,這個攻擊過程是個循環迭代的過程,上一步的結果就是作為下一步的基礎。

我們之前已經知道Intermediary Byte的最后一個字節為0x61,因此可以"更新"IV(攻擊者輸入的IV)的第8個字節為 0x66 ^ 0x02 = 0x64。

(思考: 這個Padding Oracle Attack的過程中,攻擊者需要不斷地調整輸入IV的值,之前因為在Padding 0x01中,我們只是在假設Padding 0x01的情況,在這個假設下,我們通過得出IV的最字節,從而計算出Intermediary Byte,進而算出明文的最后一個字節"H"。這里要注意的是,這個假設的IV沒有任何意義,只是我們進行"選擇密文攻擊"過程中的一個路人甲而已。而接下來我們要繼續假設Padding 0x02的情況,為了使在假設Padding 0x02中,Intermediary Value的最后一個字節依然為"0x67(之前算出來的)",所以我們要對IV的最后一個字節進行迭代更新: 0x66 ^ 0x02 = 0x64)。

這個時候,本質上攻擊者是固定住了IV的最后一個字節不變,開始循環"盲注"倒數第二個字節。開始依照第一步時的方法對倒數第二個字節進行"盲注"邏輯判斷。

Request: http://sampleapp/home.jsp?UID=0000000000007064EFC2807233F9D7C097116BB33E813C5E

Respose: 200 OK

通過遍歷可以得出,IV的第7個字節為0x70。

if(Inermediary Byte) ^ 0x70  == 0x02
{
       Inermediary Byte = 0x70 ^ 0x02                
}
so:
        Inermediary Byte = 0x72

對應的Intermediary Byte為0x72。知道了Intermediary Byte的倒數第二個字節為0x72,就可以得出明文的的倒數第二個字節:

0x72 ^ 0x17 = 0x65 : e

(這里的IV: 0x17是我們從服務端接收到的附帶在密文頭部的IV的倒數第二個字節)
接下來,要繼續對IV進行假設,同理,這次"選擇密文攻擊"的假設是Padding 0x03,對IV進行迭代更新,然后對IV的倒數第三個字節進行"窮舉"循環探測。

Padding 0x03

Padding 0x04

Padding 0x05

Padding 0x06

Padding 0x07

 

Padding 0x08

最終得到這個分組的明文LittleH。這是第一個分組的明文。

注意,Padding Oracle Attack是以單個分組進行的。到了這一步,我們會發現,我們的攻擊目標其實就是那個臨時中間值變量Intermediary Value,得到了這個值,再加上我們本來就可以獲取到IV(服務器端生成的附在密文頭部的那個IV),我們可以通過XOR運算得到這個分組的明文。

 

對於多個分組的密文來說,我們繼續觀察一下CBC的解密流程:

第二個分組使用的IV(對於第一組來說是附帶在密文頭部的那段)是第一組分組的密文。因此我們就把第一組的密文帶入帶第二組的計算中。繼續第對二組的Intermediary Value進行邏輯推導,最終得到第二組的密文:ann。

多分組的密文可以依次類推,由此即可以僅根據密文和IV還原出明文。

 

 

 

 

4. Padding Oracle Attack的攻擊利用場景

一旦我們通過暴力破解得到中間值Intermediary Value之后,IV便可以用來生成我們想要的任意值。新的IV可以被放在前一個示例的前面,這樣便可以得到一個符合我們要求的,包含兩個數據塊的密文了。這個過程可以不斷重復,這樣便能生成任意長度的數據了。

使用PadBuster加密任意的值

https://github.com/GDSSecurity/PadBuster

 

 

 

5. 模擬實驗

這是道哥寫的python腳本,可以用來模擬實驗出Padding Oracle Attack的原理:

http://pan.baidu.com/s/1eitwK

可以參考源代碼來進行深入的學習,加深理解。

 

 

6. 后記

自己按照書上講的理解了一下,如有不對之處,望指正。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM