您好,登錄后才能下訂單哦!
**說到隨機函數的應用,作為一個菜鳥,理解的也不是很深刻,在這里之作為一個筆記來記錄,以后慢慢將其掌握之后,再在內容上面進行加深。
隨機函數的作用,常常是用來生成驗證碼、隨機文件名、訂單號,如果用來做安全驗證的話常常用來生成加密key、token等等。**
1、rand()
常用的隨機函數,默認生成0-getrandmax()之間的隨機數,不過因為性能問題,已經被mt_rand()函數替代
相關函數:
rand(int $min,int $max)
srand(int $seed),生成時間種子,同一個時間種子下隨機生成的隨機數值是相同的。
getrandmax()獲取最大隨機數,這里獲取的隨機數會隨系統的不同而不同。如linux最大2147483647
2、mt_rand
常用的隨機函數,默認生成0-mt_getrandmax()之間的隨機數,?Mersenne Twister 算法生成隨機整數
相關函數:
mt_srand(),生成種子,同一個種子下隨機生成的隨機數值是相同的。
該函數是產生隨機值的更好選擇,返回結果的速度是?rand()?函數的 4 倍(手冊是是這么寫的),我個人并不認同的,我感覺他說的4倍是很多年前的事了。因為mt_rand()使用的Mersenne Twister algorythm是1997的事,所以在很多年前,和rand()在速度上的差異可能是(4倍),自2004年,rand()已經開始使用algorythm,所以現在它們速度上沒有太大的區別.
有時候手冊也是騙人的,就像一會要說的這個函數造成的問題。
3、uniqid()
生成唯一ID的函數,精確到了微妙,較mt_rand精確。適用場景生成token和生成uuid
具體細節沒做研究
4、openssl_random_pseudo_bytes()
適用于生成token,具體詳情沒做研究
--
今天重點記錄一下mt_rand帶來的問題,和在CTF中的具體解法。對于這個函數的介紹是有兩個版本的,一個是英文版,一個是中文版,去對比一下,在英文版中會多出一個警告:
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
這個工具的具體用法,也不再著解釋,說起來還是挺復雜的,在這里推薦一個文章吧,看完就看一了解個大概,同時還有助于理解隨機數
https://×××w.openwall.com/php_mt_seed/README
爆破隨機數種子,我們將得到的第一組數進行爆破
得到三組seed值,里面就有我們使用的隨機數種子,當然在正常情況下我們是不知道這個數值的,所以還需要去驗證。
--
如何驗證?
1、只需要將這個種子通過mt_srand()函數生成數值后再調用幾組mt_rand()函數生成幾組隨機數\
2、然后將隨機數和我們剛開始得到的隨機數對比即可。
測試第一組
測試第二組
測試第三組
可以看到只有第二組的隨機數和原來的相同,到這里便成功獲取到了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!
理解了上面所說的爆破步驟的話,對這個題目簡直太容易了。
1、因為我們不知道××××代表那些數字,但是給出了第一組隨機數。上面也說了,只有第一次調用mt_rand()函數的時候才會自動播種,接下來的就會根據這個種子生成隨機數。所以我們來利用第一組爆破
2、將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
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。