常見(jiàn)HTTPS攻擊方法解析
0x00 背景
研究常見(jiàn)的https攻擊方法
Beast crime breach,并針對(duì)https的特性提出一些安全部署https的建議。
針對(duì)于HTTPS的攻擊,多存在于中間人攻擊的環(huán)境中,主要是針對(duì)于HTTPS所使用的壓縮算法和CBC加密模式,進(jìn)行side-channel-attack。這幾類(lèi)攻擊的前置條件都比較苛刻,且都需要受害主機(jī)提交很多次請(qǐng)求來(lái)收集破譯關(guān)鍵數(shù)據(jù)的足夠信息。
常見(jiàn)的攻擊方法,主要有,BEAST、Lucky-13、RC4 Biases、CRIME、TIME、BREACH等。主要對(duì)其中幾種進(jìn)行介紹。
0x01 CRIME
Compression Ratio Info-leak Made Easy
攻擊原理
攻擊者控制受害者發(fā)送大量請(qǐng)求,利用壓縮算法的機(jī)制猜測(cè)請(qǐng)求中的關(guān)鍵信息,根據(jù)response長(zhǎng)度判斷請(qǐng)求是否成功。
如下面的https頭,攻擊這可以控制的部分為get請(qǐng)求地址,想要猜測(cè)的部分為Cookie。那么攻擊者只需要在GET地址處,不斷變換猜測(cè)字符串,進(jìn)行猜測(cè)。
GET /sessionid=a HTTP/1.1
Host: bank.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0)
Gecko/20100101 Firefox/16.0
Cookie: sessionid=d3b0c44298fc1c149afbf4c8996fb924GET /sessionid=a HTTP/1.1
Host: bank.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0)
Gecko/20100101 Firefox/16.0
Cookie: sessionid=d3b0c44298fc1c149afbf4c8996fb924
比如上面的情況Response長(zhǎng)度為 1000byte。
GET /sessionid=d HTTP/1.1
Host: bank.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0)
Gecko/20100101 Firefox/16.0
Cookie: sessionid=d3b0c44298fc1c149afbf4c8996fb924
當(dāng)攻擊者猜對(duì)了cookie的第一個(gè)字母,Response的長(zhǎng)度會(huì)縮小到9999byte。
當(dāng)Response被SSL加密之后,如果使用RC4加密模式,長(zhǎng)度并不會(huì)發(fā)生隨機(jī)改變。使用BCB加密模式時(shí),因?yàn)閜adding的原因,長(zhǎng)度會(huì)有略微的改變。
受影響的加密算法
Deflate = LZ77 + HuffMan GZip = Headers + Data Compressed using Deflate
攻擊前提
攻擊者可以獲取受害者的網(wǎng)絡(luò)通信包。(中間人攻擊,ISP供應(yīng)商)
瀏覽器和服務(wù)器支持均支持并使用壓縮算法。
攻擊這可以控制受害者發(fā)送大量請(qǐng)求并可以控制請(qǐng)求內(nèi)容。
防御方法
客戶(hù)端可以升級(jí)瀏覽器來(lái)避免這種攻擊。
▪ Chrome: 21.0.1180.89 and above
▪ Firefox: 15.0.1 and above
▪ Opera: 12.01 and above
▪ Safari: 5.1.7 and above
服務(wù)器端可以通過(guò)禁用一些加密算法來(lái)防止此類(lèi)攻擊。
Apache • SSLCompression flag = “SSLCompression off” • GnuTLSPriorities flag = “!COMP-DEFLATE"
禁止過(guò)于頻繁的請(qǐng)求。
修改壓縮算法流程,用戶(hù)輸入的數(shù)據(jù)不進(jìn)行壓縮。
隨機(jī)添加長(zhǎng)度不定的垃圾數(shù)據(jù)。
TLS 1.0.
SPDY protocol (Google).
Applications that uses TLS compression.
Mozilla Firefox (older versions) that support SPDY.
Google Chrome (older versions) that supported both TLS and SPDY.
POC
這個(gè)poc并不是模擬真實(shí)環(huán)境下的中間人攻擊,只是在python中利用CRIME的思想驗(yàn)證了攻擊的可行性。
- import string
- import zlib
- import sys
- import random
- charset = string.letters + string.digits
- COOKIE = ''.join(random.choice(charset) for x in range(30))
- HEADERS = ("POST / HTTP/1.1\r\n"
- "Host: thebankserver.com\r\n"
- "Connection: keep-alive\r\n"
- "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\r\n"
- "Accept: */*\r\n"
- "Referer: https://thebankserver.com/\r\n"
- "Cookie: secret="+COOKIE+"\r\n"
- "Accept-Encoding: gzip,deflate,sdch\r\n"
- "Accept-Language: en-US,en;q=0.8\r\n"
- "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
- "\r\n")
- BODY = ("POST / HTTP/1.1\r\n"
- "Host: thebankserver.com\r\n"
- "Connection: keep-alive\r\n"
- "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\r\n"
- "Accept: */*\r\n"
- "Referer: https://thebankserver.com/\r\n"
- "Cookie: secret=")
- cookie = ""
- def compress(data):
- c = zlib.compressobj()
- return c.compress(data) + c.flush(zlib.Z_SYNC_FLUSH)
- def getposset(perchar,chars):
- posset = []
- baselen = len(compress(HEADERS+perchar))
- for i in chars:
- t = len(compress(HEADERS+ perchar+i))
- if (t<=baselen):
- posset += i
- return posset
- def doguess():
- global cookie
- while len(cookie)<30:
- posset = getposset(BODY+cookie,charset)
- trun = 1
- tem_posset = posset
- while 1<len(posset):
- tem_body = BODY[trun:]
- posset = getposset(tem_body+cookie,tem_posset)
- trun = trun +1
- if len(posset)==0:
- return False
- cookie += posset[0]
- print posset[0]
- return True
- while BODY.find("\r\n")>=0:
- if not doguess():
- print "(-)Changebody"
- BODY = BODY[BODY.find("\r\n") + 2:]
- print "(+)orign cookie"+COOKIE
- print "(+)Gotten cookie"+cookie
#p#
0x02 TIME
Timing Info-leak Made Easy
攻擊原理
攻擊者控制受害者發(fā)送大量請(qǐng)求,利用壓縮算法的機(jī)制猜測(cè)請(qǐng)求中的關(guān)鍵信息,根據(jù)response響應(yīng)時(shí)間判斷請(qǐng)求是否成功。其實(shí)TIME和CRIME一樣都利用了壓縮算法,只不過(guò)CRIME是通過(guò)長(zhǎng)度信息作為輔助,而TIME是通過(guò)時(shí)間信息作為輔助。
Unable to render embedded object: File (1.jpg) not found.
如上圖當(dāng)數(shù)據(jù)長(zhǎng)度,大于MTU時(shí)會(huì)截?cái)酁閮蓚€(gè)包發(fā)送,這樣就會(huì)產(chǎn)生較大的相應(yīng)時(shí)間差異。攻擊者吧包長(zhǎng)控制在MTU左右,不斷嘗試猜測(cè)COOKIE。 Unable to render embedded object: File (QQ圖片20140724174303.jpg) not found.
如上圖所示,我們通過(guò)添加Padding來(lái)吧數(shù)據(jù)包大小增加到和MTU相等,Case 1中我們添加的extraByte和需要猜測(cè)的數(shù)據(jù)重合,因?yàn)閴嚎s算法的原因,并不會(huì)增加包的長(zhǎng)度,而Case 2中extraByte和需要猜測(cè)的數(shù)據(jù)并不一致,導(dǎo)致了分包。攻擊這可以通過(guò)響應(yīng)時(shí)間的不同來(lái)區(qū)分Case1 Case2兩種情況。
攻擊前提
攻擊這可以控制受害者發(fā)送大量請(qǐng)求并可以控制請(qǐng)求內(nèi)容。
穩(wěn)定的網(wǎng)絡(luò)環(huán)境。
防御方法
在解密Response過(guò)程中加入隨機(jī)的短時(shí)間延遲。
阻止短時(shí)間內(nèi)的頻繁請(qǐng)求。
0x03 BEAST
Browser Exploit Against SSL/TLS
攻擊原理
攻擊者控制受害者發(fā)送大量請(qǐng)求,利用CBC加密模式猜測(cè)關(guān)鍵信息。
CBC模式工作的方法是當(dāng)加密第i塊的時(shí)候,和第i-1塊的密文異或。更正式地表達(dá)如下:
Ci= E(Key, Ci-1 ⊕ Mi)
很顯然,當(dāng)你加密第一塊的時(shí)候,沒(méi)有前一塊的密文和它異或,因此,標(biāo)準(zhǔn)的做法是產(chǎn)生一個(gè)隨機(jī)的初始化向量(IV),并且用它和第一塊明文異或。第一塊M0的加密如下:
C0= E(Key, IV ⊕ M0).
然后,接著第一塊M1加密如下:
C1= E(Key, C0 ⊕ M1).
現(xiàn)在,除非C0 碰巧和IV一樣(這是非常不可能的),那么,即使M0 = M1,對(duì)于加密函數(shù)來(lái)說(shuō),兩個(gè)輸入是不同的,因此,C0≠ C1。 CBC有兩種的基本的使用方法:
1. 對(duì)于每條記錄都認(rèn)為是獨(dú)立的;為每一個(gè)記錄產(chǎn)生一個(gè)IV
2. 把所有的記錄當(dāng)作一個(gè)鏈接在一起的大對(duì)象,并且在記錄之間繼續(xù)使用CBC的狀態(tài)。這意味著最后一條記錄n的IV是n-1條記錄的密文。
SSLV3和TLS1.0選擇的是第二個(gè)用法。這好像本來(lái)就是個(gè)錯(cuò)誤
CBC有兩種的基本的使用方法:
1. 對(duì)于每條記錄都認(rèn)為是獨(dú)立的;為每一個(gè)記錄產(chǎn)生一個(gè)IV
2. 把所有的記錄當(dāng)作一個(gè)鏈接在一起的大對(duì)象,并且在記錄之間繼續(xù)使用CBC的狀態(tài)。這意味著最后一條記錄n的IV是n-1條記錄的密文。
SSL 3.0和TLS1.0選擇的是第二個(gè)用法。因此產(chǎn)生了加密算法的安全問(wèn)題。
攻擊者可以把想要猜測(cè)的數(shù)據(jù)段替換掉成:
X ⊕ Ci-1 ⊕ P
當(dāng)這個(gè)注入的內(nèi)容被加密,X會(huì)被異或,結(jié)果傳給加密算法的明文塊如下:
Ci-1 ⊕ P
如果P==Mi , 新的密文塊將和Ci一樣,這意味著,你的猜測(cè)是正確的。
攻擊前提
攻擊者可以獲取受害者的網(wǎng)絡(luò)通信包。(中間人攻擊,ISP供應(yīng)商)
攻擊者需要能得到發(fā)送敏感數(shù)據(jù)端的一部分權(quán)限。以便將自己的信息插入SSL/TLS會(huì)話(huà)中。
攻擊者需要準(zhǔn)確的找出敏感數(shù)據(jù)的密文段。
攻擊這可以控制受害者發(fā)送大量請(qǐng)求并可以控制請(qǐng)求內(nèi)容。
防御方法
使用RC4加密模式代替BCB加密模式。
部署TLS 1.1或者更高級(jí)的版本,來(lái)避免SSL 3.0/TLS 1.0帶來(lái)的安全問(wèn)題。
在服務(wù)端設(shè)置每傳輸固定字節(jié),就改變一次加密秘鑰。
影響范圍
TLS 1.0. SPDY protocol (Google). Applications that uses TLS compression. Mozilla Firefox (older versions) that support SPDY. Google Chrome (older versions) that supported both TLS and SPDY.
POC
僅在python上模擬了攻擊思想的實(shí)現(xiàn),編碼中只實(shí)現(xiàn)了第一個(gè)字母的猜測(cè)。
- import sys
- import string
- import random
- from Crypto.Cipher import AES
- key = 'lyp62/22Sh2RlXJF'
- mode = AES.MODE_CBC
- vi = '1234567812345678'
- charset = string.letters + string.digits
- cookie = ''.join(random.choice(charset) for x in range(30))
- HEADERS = ("POST / HTTP/1.1\r\n"
- "Host: thebankserver.com\r\n"
- "Connection: keep-alive\r\n"
- "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1\r\n"
- "Accept: */*\r\n"
- "Referer: https://thebankserver.com/\r\n"
- "Cookie: secret="+cookie+"\r\n"
- "Accept-Encoding: gzip,deflate,sdch\r\n"
- "Accept-Language: en-US,en;q=0.8\r\n"
- "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n"
- "\r\n")
- global pad_num
- def add_padding(plaintext):
- global pad_num
- pad_num = 16 - len(plaintext) % 16
- for i in range(0,pad_num):
- plaintext += chr(pad_num)
- return plaintext
- def check_padding(plaintext):
- global pad_num
- for i in range(1,pad_num+1):
- if (plaintext[-i]!=chr(pad_num)):
- return False
- return True
- def encrypto(plaintext):
- global pad_num
- obj = AES.new(key,mode,vi)
- if (len(plaintext) % 16):
- plaintext = add_padding(plaintext)
- else:
- pad_num=0
- ciphertext = obj.encrypt(plaintext)
- if (check_padding(ciphertext)):
- return ciphertext
- else:
- return 0
- def decrypto(ciphertext):
- obj = AES.new(key,mode,vi)
- plaintext = obj.decrypt(ciphertext)
- return plaintext
- def findcookie():
- global HEADERS
- return HEADERS.find('secret=')+7
- guess_cookie=''
- pos_cookie=findcookie()
- pos_block_s = pos_cookie + 16 - pos_cookie%16
- HEADERS = HEADERS[:pos_cookie] + (16 - pos_cookie % 16 + 15)*'a' +HEADERS[pos_cookie:]
- encry_head = encrypto(add_padding(HEADERS))
- per_per_block = encry_head[pos_block_s - 16:pos_block_s] #Ci-1
- per_block = encry_head[pos_block_s:pos_block_s+16] #x
- aft_block = encry_head[pos_block_s+16:pos_block_s+32] #Ci+1
- for i in charset:
- guess_block = 'a' * 15 + i
- insert_block = ''.join(chr(ord(a) ^ ord(b) ^ ord(c)) for a,b,c in zip(per_block,per_per_block,guess_block))
- temp_header = HEADERS[:pos_block_s+16] + insert_block + HEADERS[pos_block_s+16:]
- encry_temp_header = encrypto(add_padding(temp_header))
- if (aft_block == encry_temp_header[pos_block_s+32:pos_block_s+48]):
- print "(+)first byte is:"+i
- print "(+)orign cookie:"+cookie
攻擊者首先使用降級(jí)攻擊,來(lái)讓瀏覽器使用ssl v3.0,再通過(guò)ssl v3.0 CBC-mode 存在的缺陷,竊取到用戶(hù)傳輸?shù)拿魑摹?p#
0x04 POODLE
降級(jí)攻擊
ssl v3.0是一個(gè)存在了很久的協(xié)議了,現(xiàn)在大多數(shù)瀏覽器為了兼容性都會(huì)支持這個(gè)協(xié)議,但是并不會(huì)首先使用這個(gè)協(xié)議,中間人攻擊者可以駁回瀏覽器協(xié)商高版本協(xié)議的請(qǐng)求,只放行ssl v3.0協(xié)議。
Padding Oracle攻擊
針對(duì)于CBC的攻擊之前已經(jīng)有一些了,比如,Beast,Lucky17之類(lèi)的,詳細(xì)可以看這里
首先來(lái)看CBC-mod的加解密流程。
解密流程
加密流程
校驗(yàn)流程
MAC1 = hash(明文)
密文 = Encode(明文+MAC1+Padding,K) 明文 = Decode(密文,k) - MAC1-Padding(padding的長(zhǎng)度由最后一個(gè)字節(jié)標(biāo)識(shí))
MAC2 = hash(明文) 如果 MAC1 == MAC2 則校驗(yàn)成功 否則失敗
知二求三
Padding Oracle 攻擊一般都會(huì)滿(mǎn)足一個(gè)知二求三的規(guī)律,如下圖
(1) VI
(2) 解密后的數(shù)據(jù),叫它 midText把
(3) Plaintext
這三個(gè)值我們得到其中兩個(gè)就可以推出另外一個(gè),因?yàn)樗麄冊(cè)谝黄餢or了嘛。
http://drops.wooyun.org/wp-content/uploads/2014/12/file0004.jpg
在Poodle攻擊中,我們會(huì)把最后一個(gè)數(shù)據(jù)塊替換成我們想要猜測(cè)的數(shù)據(jù)塊。如下圖所示。
這樣導(dǎo)致的直接后果就是,CBC完整性驗(yàn)證失敗,數(shù)據(jù)包被駁回。我們假設(shè)最后一個(gè)數(shù)據(jù)塊均為padding組成(其實(shí)我們可以通過(guò)控制包的長(zhǎng)度來(lái)達(dá)到這一目的,比如增加path的長(zhǎng)度)
那么當(dāng)且僅當(dāng)Plaintext[7] == 7(block為16為時(shí)為15) 的時(shí)候CBC完整性校驗(yàn)才會(huì)通過(guò)。如果不為7,多刪或者少刪的padding,都會(huì)影響到MAC的正確取值,從而導(dǎo)致校驗(yàn)失敗。
那么,我們只需要不斷地更改(1) IV 最后一位的值 ,直到(3) Plaintext最后一位為 7 (CBC驗(yàn)證通過(guò))的時(shí)候,我們就可以推出 (2) mid text 的最后一位。
#p#
0x05 安全配置建議
此處的安全配置以nginx為例,主要在Nginx.conf中配置。
使用較為安全的SSL加密協(xié)議。
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
使用嚴(yán)格的加密方法設(shè)置。
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4';
優(yōu)先依賴(lài)服務(wù)器密碼。
ssl_prefer_server_ciphers on;
啟用HSTS協(xié)議。
add_header Strict-Transport-Security max-age=15768000;
重定向的配置
server { listen 80; add_header Strict-Transport-Security max-age=15768000; return 301 https://www.yourwebsite.com$request_uri; }
使用2048位的數(shù)字證書(shū)
openssl dhparam -out dhparam.pem 2048 ssl_dhparam /path/to/dhparam.pem;
【編輯推薦】