聊一聊隨機數(shù)安全那些事兒
0x00 簡介
和朋友聊到一個比較有意思的現(xiàn)象,在最近兩年的校招面試中,大部分同學連一點基礎(chǔ)的密碼學知識都沒有, 即便是有一些滲透功底的同學。
所以這里想和大家聊一些簡單的密碼學基礎(chǔ)知識,不涉及算法實現(xiàn),更多的是和常見的漏洞場景聯(lián)系起來,讓問題更容易理解,有點拋磚引玉的意思。
本文主要聊一下隨機數(shù),隨機數(shù)其實是非常廣泛的,可以說也是密碼技術(shù)的基礎(chǔ)。
對隨機數(shù)的使用不當很可能會導致一些比較嚴重的安全問題, 并且這些安全問題通常會比較隱蔽。
0x01 隨機數(shù)
概述
隨機數(shù)在計算機應用中使用的比較廣泛,最為熟知的便是在密碼學中的應用。本文主要是講解隨機數(shù)使用導致的一些Web安全風。
我們先簡單了解一下隨機數(shù)

分類
隨機數(shù)分為真隨機數(shù)和偽隨機數(shù),我們程序使用的基本都是偽隨機數(shù),其中偽隨機又分為強偽隨機數(shù)和弱偽隨機數(shù)。
真隨機數(shù),通過物理實驗得出,比如擲錢幣、骰子、轉(zhuǎn)輪、使用電子元件的噪音、核裂變等
偽隨機數(shù),通過一定算法和種子得出。軟件實現(xiàn)的是偽隨機數(shù)
強偽隨機數(shù),難以預測的隨機數(shù)
弱偽隨機數(shù),易于預測的隨機數(shù)
特性
隨機數(shù)有3個特性,具體如下:
隨機性:不存在統(tǒng)計學偏差,是完全雜亂的數(shù)列
不可預測性:不能從過去的數(shù)列推測出下一個出現(xiàn)的數(shù)
不可重現(xiàn)性:除非將數(shù)列本身保存下來,否則不能重現(xiàn)相同的數(shù)列
隨機數(shù)的特性和隨機數(shù)的分類有一定的關(guān)系,比如,弱偽隨機數(shù)只需要滿足隨機性即可,而強位隨機數(shù)需要滿足隨機性和不可預測性,真隨機數(shù)則需要同時滿足3個特性。
引發(fā)安全問題的關(guān)鍵點在于不可預測性。
偽隨機數(shù)的生成
我們平常軟件和應用實現(xiàn)的都是偽隨機數(shù),所以本文的重點也就是偽隨機數(shù)。
偽隨機數(shù)的生成實現(xiàn)一般是算法+種子。
具體的偽隨機數(shù)生成器PRNG一般有:
線性同余法
單向散列函數(shù)法
密碼法
ANSI X9.17
比較常用的一般是線性同余法,比如我們熟知的C語言的rand庫和Java的java.util.Random類,都采用了線性同余法生成隨機數(shù)。
應用場景
隨機數(shù)的應用場景比較廣泛,以下是隨機數(shù)常見的應用場景:
驗證碼生成
抽獎活動
UUID生成
SessionID生成
Token生成
CSRF Token
找回密碼Token
游戲(隨機元素的生成)
洗牌
俄羅斯方塊出現(xiàn)特定形狀的序列
游戲爆裝備
密碼應用場景
生成密鑰:對稱密碼,消息認證
生成密鑰對:公鑰密碼,數(shù)字簽名
生成IV: 用于分組密碼的CBC,CFB和OFB模式
生成nonce: 用于防御重放攻擊; 分組密碼的CTR模式
生成鹽:用于基于口令的密碼PBE等
0x02 隨機數(shù)的安全性
相比其他密碼技術(shù),隨機數(shù)很少受到關(guān)注,但隨機數(shù)在密碼技術(shù)和計算機應用中是非常重要的,不正確的使用隨機數(shù)會導致一系列的安全問題。
隨機數(shù)的安全風險
隨機數(shù)導致的安全問題一般有兩種
應該使用隨機數(shù),開發(fā)者并沒有使用隨機數(shù);
應該使用強偽隨機數(shù),開發(fā)者使用了弱偽隨機數(shù)。
第一種情況,簡單來講,就是我們需要一個隨機數(shù),但是開發(fā)者沒有使用隨機數(shù),而是指定了一個常量。當然,很多人會義憤填膺的說,sb才會不用隨機數(shù)。但是,請不要忽略我朝還是有很多的。主要有兩個場景:
開發(fā)者缺乏基礎(chǔ)常識不知道要用隨機數(shù);
一些應用場景和框架,接口文檔不完善或者開發(fā)者沒有仔細閱讀等原因。
比如找回密碼的token,需要一個偽隨機數(shù),很多業(yè)務直接根據(jù)用戶名生成token;
比如OAuth2.0中需要第三方傳遞一個state參數(shù)作為CSRF Token防止CSRF攻擊,很多開發(fā)者根本不使用這個參數(shù),或者是傳入一個固定的值。由于認證方無法對這個值進行業(yè)務層面有效性的校驗,導致了OAuth的CSRF攻擊。
第二種情況,主要區(qū)別就在于偽隨機數(shù)的強弱了,大部分(所有?)語言的API文檔中的基礎(chǔ)庫(常用庫)中的random庫都是弱偽隨機,很多開發(fā)自然就直接使用。但是,最重要也最致命的是,弱偽隨機數(shù)是不能用于密碼技術(shù)的。
還是第一種情況中的找回密碼場景,關(guān)于token的生成, 很多開發(fā)使用了時間戳作為隨機數(shù)(md5(時間戳),md5(時間戳+用戶名)),但是由于時間戳是可以預測的,很容易就被猜解。不可預測性是區(qū)分弱偽隨機數(shù)和強偽隨機數(shù)的關(guān)鍵指標。
當然,除了以上兩種情況,還有一些比較特別的情況,通常情況下比較少見,但是也不排除:
種子的泄露,算法很多時候是公開的,如果種子泄露了,相當于隨機數(shù)已經(jīng)泄露了;
隨機數(shù)池不足。這個嚴格來說也屬于弱偽隨機數(shù),因為隨機數(shù)池不足其實也導致了隨機數(shù)是可預測的,攻擊者可以直接暴力破解。
漏洞實例
wooyun上有很多漏洞,還蠻有意思的,都是和隨機數(shù)有關(guān)的。
PS:個人實力有限,以下實例基本都來自wooyun漏洞實例,在這里謝謝各位大牛,如有侵權(quán),請聯(lián)系刪除。
1.應該使用隨機數(shù)而未使用隨機數(shù)
Oauth2.0的這個問題特別經(jīng)典,除了wooyun實例列出來的,其實很多廠商都有這個問題。
Oauth2.0中state參數(shù)要求第三方應用的開發(fā)者傳入一個CSRF Token(隨機數(shù)),如果沒有傳入或者傳入的不是隨機數(shù),會導致CSRF登陸任意帳號:
唯品會賬號相關(guān)漏洞可通過csrf登錄任意賬號
人人網(wǎng)-百度OAuth 2.0 redirect_uir CSRF 漏洞
2.使用弱偽隨機數(shù)
1) 密碼取回
很多密碼找回的場景,會發(fā)送給用戶郵件一個url,中間包含一個token,這個token如果猜測,那么就可以找回其他用戶的密碼。
1.Shopex 4.8.5密碼取回處新生成密碼可預測漏洞
直接使用了時間函數(shù)microtime()作為隨機數(shù),然后獲取MD5的前6位。
- substr(md5(print_r(microtime(),true)),0,6);
PHP 中microtime()的值除了當前服務器的秒數(shù)外,還有微秒數(shù),微妙數(shù)的變化范圍在0.000000 -- 0.999999 之間,一般來說,服務器的時間可以通過HTTP返回頭的DATE字段來獲取,因此我們只需要遍歷這1000000可能值即可。但我們要使用暴力破解的方式發(fā)起1000000次網(wǎng)絡請求的話,網(wǎng)絡請求數(shù)也會非常之大??墒莝hopex非常貼心的在生成密碼前再次將microtime() 輸出了一次:
- $messenger = &$this->system->loadModel('system/messenger');echo microtime()."<br/>";
2.奇虎360任意用戶密碼修改
直接是MD5(unix時間戳)
3.涂鴉王國弱隨機數(shù)導致任意用戶劫持漏洞,附測試POC
關(guān)于找回密碼隨機數(shù)的問題強烈建議大家參考拓哥的11年的文章《利用系統(tǒng)時間可預測破解java隨機數(shù)| 空虛浪子心的靈魂》
2) 其他隨機數(shù)驗證場景
CmsEasy最新版暴力注入(加解密缺陷/繞過防注入)
弱偽隨機數(shù)被繞過
Espcms v5.6 暴力注入
Espcms中一處SQL注入漏洞的利用,利用時發(fā)現(xiàn)espcms對傳值有加密并且隨機key,但是這是一個隨機數(shù)池固定的弱偽隨機數(shù),可以被攻擊者遍歷繞過
Destoon B2B 2014-05-21最新版繞過全局防御暴力注入(官方Demo可重現(xiàn))
使用了microtime()作為隨機數(shù),可以被預測暴力破解
Android 4.4之前版本的Java加密架構(gòu)(JCA)中使用的Apache Harmony 6.0M3及其之前版本的SecureRandom實現(xiàn)存在安全漏洞,具體位于classlib/modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
類的engineNextBytes函數(shù)里,當用戶沒有提供用于產(chǎn)生隨機數(shù)的種子時,程序不能正確調(diào)整偏移量,導致PRNG生成隨機序列的過程可被預測。
Android SecureRandom漏洞詳解
安全建議
上面講的隨機數(shù)基礎(chǔ)和漏洞實例更偏重是給攻擊者一些思路,這里更多的是一些防御和預防的建議。
業(yè)務場景需要使用隨機數(shù),一定要使用隨機數(shù),比如Token的生成;
隨機數(shù)要足夠長,避免暴力破解;
保證不同用處的隨機數(shù)使用不同的種子
對安全性要求高的隨機數(shù)(如密碼技術(shù)相關(guān))禁止使用的弱偽隨機數(shù):
不要使用時間函數(shù)作為隨機數(shù)(很多程序員喜歡用時間戳) Java:system.currenttimemillis() php:microtime()
不要使用弱偽隨機數(shù)生成器 Java: java.util.Random PHP: rand() 范圍很小,32767 PHP: mt_rand() 存在缺陷
強偽隨機數(shù)CSPRNG(安全可靠的偽隨機數(shù)生成器(Cryptographically Secure Pseudo-Random Number Generator)的各種參考
6.強偽隨機數(shù)生成(不建議開發(fā)自己實現(xiàn))
產(chǎn)生高強度的隨機數(shù),有兩個重要的因素:種子和算法。算法是可以有很多的,通常如何選擇種子是非常關(guān)鍵的因素。 如Random,它的種子是System.currentTimeMillis(),所以它的隨機數(shù)都是可預測的, 是弱偽隨機數(shù)。
強偽隨機數(shù)的生成思路:收集計算機的各種信息,鍵盤輸入時間,內(nèi)存使用狀態(tài),硬盤空閑空間,IO延時,進程數(shù)量,線程數(shù)量等信息,CPU時鐘,來得到一個近似隨機的種子,主要是達到不可預測性。
0x03 附
參考資料:
http://www.inbreak.net/archives/349
http://drops.wooyun.org/papers/1066
《白帽子講Web安全》
《圖解密碼技術(shù)》