记录我对Padding Oracle攻击的分析和思考之抄写
一、相關閱讀資料
? ? ? ??
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.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)模式
? ? ? ? ? ? ? 這是一種分組鏈接模式,目的是為了使原本獨立的分組密碼加密過程形成迭代,使每次加密的結果影響到下一次加密。這可以強化加密算法的"敏感性",即實現所謂的"雪崩效應"。
三、Padding Oracle Attack攻擊的原理
? ? ? ?因為Padding Oracle Attack是針對CBC鏈接模式的攻擊,和具體的加密算法無關(分組)。這里選擇DES為例進行闡述。
? ? ? ?假設明文為:LittleHann(明文長度為10 8 < 10 < 16即使用2個分組)
? ? ? ?經過DES加密(CBC模式)后,其密文為:EFC2807233F9D7C097116BB22E813C5E
? ? ? ?加密程序:http://pan.baidu.com/s/1e2o7
? ? ? ?密文采用了"ASCII十六進制的表示方法",即兩個字符表示一個字節的十六進制數。這是因為密碼學算法中得到的密文經常會出現不可打印字符,為了保證在網絡上傳輸的正確而不受不同系統間編碼方案的影響,就有必要對密文進行"可視化"轉化。除了"ASCII十六進制的表示方法"之外,還可以采用"base64編碼方法".
注: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)。而利用應用的錯誤回顯,我們就可以判斷出Padding是否正確。
? ? ? ? ? ? ? a)在Padding Oracle Attack攻擊中,攻擊者輸入的參數是IV+Cipher,我們要通過對IV的"窮舉"來請求服務器端對我們指定的Cipher進行解密,并對返回的結果進行判斷。
? ? ? ? ? ? ? b)和SQL注入中的Blind Inject思想類似。
? ? ? ? ? ? ? c)攻擊成立的兩個重要假設前提:
1.攻擊者能夠獲得密文(Ciphertext),以及附帶在密文前面的IV(初始化向量); 2.攻擊者能夠觸發密文的解密過程,且能夠知道密文的解密結果。 ? ? ? d)可能出現的情況
? ? ? ? ? ? ? 明文分組和填充就是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 Response: 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(Intermediary Byte) ^ 0x66 == 0x01 {Intermediary Byte = 0x66 ^ 0x01 } so:Intermediary Byte = 0x67 ? ? ? ? ? ? 在回過頭來看看加密過程:
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? 初始化向量IV與明文進行XOR運算得到了Intermediary Value,因此將剛才得到的Intermediary 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和KEY),我們只是在通過不斷的修改IV來對目標解密系統進行"試探",從返回的結果來進行"側信道攻擊",從而進行二值邏輯推理。
? ? ? ? ? ? ? ? ? ? ? ?在正確"匹配"了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(Intermediary Byte) ^ 0x70 == 0x02 {Intermediary Byte = 0x70 ^ 0x02 } so:Intermediary 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.防御方法
? ?Padding Oracle Attack的關鍵在于攻擊者能夠獲知解密的結果是否符合Padding。在實現和使用CBC模式的分組加密算法時,注意這一點即可。比如加上try catch機制。
?6.模擬實驗
? ? ?這是道哥寫的python腳本,可以用來模擬實驗出Padding Oracle Attack的原理:?http://pan.baidu.com/s/1eitwK
總結
以上是生活随笔為你收集整理的记录我对Padding Oracle攻击的分析和思考之抄写的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摘录HTTP头部信息的注释
- 下一篇: 记录如何防止跨站点脚本攻击之抄写