**說到隨機函數的應用,做爲一個菜鳥,理解的也不是很深入,在這裏之做爲一個筆記來記錄,之後慢慢將其掌握以後,再在內容上面進行加深。php
隨機函數的做用,經常是用來生成驗證碼、隨機文件名、訂單號,若是用來作安全驗證的話經常用來生成加密key、token等等。**linux
一、rand()
經常使用的隨機函數,默認生成0-getrandmax()之間的隨機數,不過由於性能問題,已經被mt_rand()函數替代
相關函數:
rand(int $min,int $max)
srand(int $seed),生成時間種子,同一個時間種子下隨機生成的隨機數值是相同的。
getrandmax()獲取最大隨機數,這裏獲取的隨機數會隨系統的不一樣而不一樣。如linux最大2147483647
二、mt_rand
經常使用的隨機函數,默認生成0-mt_getrandmax()之間的隨機數, Mersenne Twister 算法生成隨機整數
相關函數:
mt_srand(),生成種子,同一個種子下隨機生成的隨機數值是相同的。
該函數是產生隨機值的更好選擇,返回結果的速度是 rand() 函數的 4 倍(手冊是是這麼寫的),我我的並不認同的,我感受他說的4倍是不少年前的事了。由於mt_rand()使用的Mersenne Twister algorythm是1997的事,因此在不少年前,和rand()在速度上的差別多是(4倍),自2004年,rand()已經開始使用algorythm,因此如今它們速度上沒有太大的區別.
有時候手冊也是騙人的,就像一會要說的這個函數形成的問題。
三、uniqid()
生成惟一ID的函數,精確到了微妙,較mt_rand精確。適用場景生成token和生成uuid
具體細節沒作研究
四、openssl_random_pseudo_bytes()
適用於生成token,具體詳情沒作研究git
--
今天重點記錄一下mt_rand帶來的問題,和在CTF中的具體解法。對於這個函數的介紹是有兩個版本的,一個是英文版,一個是中文版,去對比一下,在英文版中會多出一個警告:github
Caution:This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you need a cryptographically secure value, consider using random_int(), random_bytes(), or openssl_random_pseudo_bytes() instead.
意思是注意函數的安全,不能用來生成密碼安全值,不要引用於加密,若是須要能夠適用等等函數代替。其實函數自己是沒有問題的,只是使用的方式不當而已。
我沒有挖漏洞的經驗,因此也不清楚大佬說的這方面的漏洞多很少,但以我我的而言,確定只會選擇看中文版的介紹,而且使用此函數去生成密碼安全值。這樣就不知道警告,也就會形成安全問題。算法
首先咱們要知道,每一次調用mt_rand()函數的時候,都會檢查一下系統有沒有播種。(播種是由mt_srand()函數完成的),當隨機種子生成後,後面生成的隨機數都會根據這個隨機種子生成。因此前面也說到,同一個種子下隨機生成的隨機數值是相同的。同時,也解釋了咱們破解隨機種子的可行性。若是每次調用mt_rand()函數都須要生成一個隨機種子的話,那根本就沒辦法破解。
作一個簡單的測試,測試隨機數種子相同,後面的每次執行的隨機數也相同
腳本:安全
<?php mt_srand(45678913); echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; ?>
兩次執行結果:
能夠看到獲得的隨機數是相同的。
同時咱們應該注意,mt_srand()函數播種的時候,只有在第一次調用mt_rand()函數的時候纔會使用。因此若是咱們知道了第一次生成的隨機數值,就可能爆破出隨機數種子。網絡
--
接下來就來驗證一下
首先爆破出隨機數種子,利用工具php_mt_srand
工具連接:https://github.com/lepiaf/php_mt_seed
這個工具的具體用法,也再也不着解釋,提及來仍是挺複雜的,在這裏推薦一個文章吧,看完就看一瞭解個大概,同時還有助於理解隨機數php7
https://×××w.openwall.com/php_mt_seed/README
爆破隨機數種子,咱們將獲得的第一組數進行爆破
獲得三組seed值,裏面就有咱們使用的隨機數種子,固然在正常狀況下咱們是不知道這個數值的,因此還須要去驗證。dom
--
如何驗證?
一、只須要將這個種子經過mt_srand()函數生成數值後再調用幾組mt_rand()函數生成幾組隨機數\
二、而後將隨機數和咱們剛開始獲得的隨機數對比便可。
測試第一組
ide
測試第二組
測試第三組
能夠看到只有第二組的隨機數和原來的相同,到這裏便成功獲取到了seed值。
題目來自於成都大學網絡***演練平臺--隨機數
題目連接:http://ctf.cdusec.org/challenges
題目很是簡單,直接就給出了題目隨機數的源碼以及前幾組隨機數:
<?php echo "PHP 5.4.26"; mt_srand(xxxxxxxx); #We can't tell you what is xxxxxxxx! echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo "echo flag{".mt_rand()."}" ?> 984489752 619387123 2070958802 2105559368 1909473866 1679323715 1910332168 640569646 1103001695 1871111424 flag So, Please guess the flag!
理解了上面所說的爆破步驟的話,對這個題目簡直太容易了。
一、由於咱們不知道××××表明那些數字,可是給出了第一組隨機數。上面也說了,只有第一次調用mt_rand()函數的時候纔會自動播種,接下來的就會根據這個種子生成隨機數。因此咱們來利用第一組爆破
二、將seed數值帶入到腳本mt_srand()函數當中,去跑flag,由於只要獲得seed,接下來無論怎麼跑,跑幾回,獲得的幾組數值都是相同的。這裏獲得兩組seed值,測試兩次,將獲得的flag遞交看一下那個正確便可。
隨機數這個東西在系統之間和php版本之間是有削微的區別的,好比就CTF這道題目而言,開始我並無注意php版本問題,當時的測試環境是php7的版本,一樣的作法,答案倒是不一樣的,因此結果也一直出不來。
同時也告訴咱們,細節決定成敗。
由於是剛剛學習這一知識點,可能講解的也不夠詳細或者有些許錯誤。哪位大佬看到不許確的但願給指出,謝謝!
相關連接:
http://php.net/manual/en/function.mt-rand.php
http://php.net/manual/zh/function.mt-rand.php