之前在身边有很多学PHP的朋友写一些小程序的时候,很多时候会使用PHP随机数函数rand()和mt_rand()函数去生成随机数

可是,随机数真的随机吗?这篇文章讲从多个实例中探讨随机数,当然,有写作不当的地方,还望斧正!

关于随机函数rand()和mt_rand()

rand()和mt_rand()两个函数皆是PHP中生成随机数的函数,可相比之下,mt_rand()的生成速度缺是rand()的四倍!在没有参数的情况下,两者生成的数值范围也是不一样的。

echo mt_getrandmax()." and ".getrandmax();

可以看到页面上的输出,mt_rand()相比较rand()默认取值的范围更大。而且经过测试,在不同的PHP版本中,rand随机数种子相同的时候,随机数缺不相同!

左边web页面使用的是PHP7.0.12,而右边的Powershell却是使用的PHP5.2.17。从上所述,只有mt_rand()所生成的随机数是无版本差异的!

而这两个生成随机数的时候,是可以通过srand()和mt_srand()设置随机数的种子

 <?php
mt_srand(666);
srand(666);
echo "rand 函数在种子是666时产生的随机数序列:<br/>";
for($i=1;$i<5;$i++){
echo rand()."<br/>";
}
echo '<br/>';
echo "mt_rand 函数在种子是666时产生的随机数序列:<br/>";
for($i=1;$i<5;$i++){
echo mt_rand()."<br/>";
}
?>

运行如下图所示

当你发现,设置的种子为666的时候,不管你刷新多少次,页面中生成的随机数值都不会变!

所以,当种子泄露的时候,随机数的安全就不堪一击了。

可有什么方法能够得到种子?

目前我们唯一能知道的就是随机数是不会变的,而之前有说过mt_srand()生成的随机数范围在0-2147483647之间,我们就可以通过最普通的爆破方式

去获取随机数的种子,这里推荐使用php_mt_seed,项目地址:http://www.openwall.com/php_mt_seed/

这里踩到个坑,生成后的随机数分为PHP7.x版本的和5.x版本,具体原因还不知道,但是在php7.x版本以上,mt_srand()函数定义的种子将不能超过int,也就是2147483647,但可以等于该值

所以,为了更好的研究,下面将会使用PHP5.2.17的版本

首先通过mt_rand()创建一个随机数,然后利用脚本爆破

php -r "echo mt_rand();"

爆破出来的种子所生成的随机数正好是一样的

那么,页面只播种一次,生成的多个随机数也会一样吗

事实证明,一次播种,全页不愁。

竟然已经了解了随机数的相关安全性,下面就放上一些CTF中,或者在某个CMS中出现的有关随机数的审计

审计案例①(mt_rand()安全性)

此案例是出自第三届陕西网络空间安全技术大赛

 <?php
error_reporting(0);
function cpassword($pw_length = 10){
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++)
{
$randpwd .= chr(mt_rand(33, 126));
}
return $randpwd;
} session_start();
mt_srand(time());
$pwd=cpassword(10);
if($pwd === $_GET['pwd'])
{
echo "Good job, you get the key is:".$pwd;
}
else{
echo "Wrong!";
} $_SESSION['userLogin']=cpassword(32).rand();
?>

从给出的代码中可以看到

$pwd=cpassword(10);

程序通过时间戳播种,然后通过cpassword建立一个密码,并验证密码是否正确,否则就输出flag

通过之前研究发现mt_rand()生成的随机数是有固定的,只需要知道mt_srand(time());的结果行了

写个脚本,直接用time函数生成的时间戳设置种子,再发送数据内容过去,就能获取到flag

脚本如下

 <?php
function do_get($url, $params) {
$url = "{$url}?" . http_build_query ( $params );
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, 'GET' );
curl_setopt ( $ch, CURLOPT_TIMEOUT, 60 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $params );
$result = curl_exec ( $ch );
curl_close ( $ch );
return $result;
} function cpassword($pw_length = 10){
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++)
{
$randpwd .= chr(mt_rand(33, 126));
}
return $randpwd;
} mt_srand(time());
$pwd=cpassword(10);
echo 'send:'.$pwd.'<br/>';
$url="http://localhost/index.php";
$params=array('pwd'=>$pwd);
$result=do_get($url,$params);
echo 'result:'.json_encode($result);
?>

审计案例① POC

发送的密码与服务器所生成的密码是一样的!

假如按照刚才的生成密码的函数

 function cpassword($pw_length = 10){
$randpwd = "";
for ($i = 0; $i < $pw_length; $i++)
{
$randpwd .= chr(mt_rand(33, 126));
}
return $randpwd;
}

这次给出生成后的密码,现在怎样才能得到mt_srand()设置的种子

生成的密码:

{|M}2x0:kW

按照程序执行流程,应该先得到每个字符在chr(33)~chr(126)中的位置索引

 <?php
$str = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
$ss = "{|M}2x0:kW";
for($i=0;$i<strlen($ss);$i++){
$pos = strpos($str,$ss[$i]);
echo $pos." ".$pos." "."0 ".(strlen($str)-1)." ";
//整理成方便 php_mt_seed 测试的格式
//php_mt_seed VALUE_OR_MATCH_MIN [MATCH_MAX [RANGE_MIN RANGE_MAX]]
}
?>

PHP code

通过这个脚本换成方便php_mt_seed测试的格式

90 90 0 93 91 91 0 93 44 44 0 93 92 92 0 93 17 17 0 93 87 87 0 93 15 15 0 93 25 25 0 93 74 74 0 93 54 54 0 93

最终得到种子数1555747516

审计案例②(rand()函数安全性)

 <?php
include('config.php');
session_start(); if($_SESSION['time'] && time() - $_SESSION['time'] > 60){
session_destroy();
die('timeout');
} else {
$_SESSION['time'] = time();
} echo rand();
if(isset($_GET['go'])){
$_SESSION['rand'] = array();
$i = 5;
$d = '';
while($i--){
$r = (string)rand();
$_SESSION['rand'][] = $r;
$d .= $r;
}
echo md5($d);
}else if(isset($_GET['check'])){
if($_GET['check'] === $_SESSION['rand']){
echo $flag;
} else {
echo 'die';
session_destroy();
}
} else {
show_source(__FILE__);
}
?>

PHP code

这是出自0ctf的一道赛题

首先我们先了解rand()生成的随机数是有规律可循的

可以参考这篇文章:http://www.sjoerdlangkemper.nl/2016/02/11/cracking-php-rand/

state[i] = state[i-3] + state[i-31]
return state[i] >> 1

下面这个程序形象的预测了rand()的随机数

 <?php
$randStr = array();
for($i=0;$i<60;$i++){ //先产生 32个随机数
$randStr[$i]=rand(0,30);
if($i>=31) {
//echo "$randStr[$i]=(".$randStr[$i-31]."+".$randStr[$i-3].") mod 31"."<br/>";
if ($randStr[$i] == $randStr[$i-31]+$randStr[$i-3]){
echo "$randStr[$i]=(".$randStr[$i-31]."+".$randStr[$i-3].") mod 31"."<br/>";
}
}
}
?>

PHP code

浅谈PHP随机数安全的分析的更多相关文章

  1. 浅谈NLP 文本分类/情感分析 任务中的文本预处理工作

    目录 浅谈NLP 文本分类/情感分析 任务中的文本预处理工作 前言 NLP相关的文本预处理 浅谈NLP 文本分类/情感分析 任务中的文本预处理工作 前言 之所以心血来潮想写这篇博客,是因为最近在关注N ...

  2. 浅谈C#随机数发生器

    我们在做能自动生成试卷的考试系统时,常常需要随机生成一组不重复的题目,在.net Framework中提供了一个专门用来产生随机数的类System.Random. 对于随机数,大家都知道,计算机不 可 ...

  3. 浅谈java性能分析

    浅谈java性能分析,效能分析 在老师强烈的要求下做了效能分析,对上次写过的词频统计的程序进行分析以及改进. 对于效能分析:我个人很浅显的认为就是程序的运行效率,代码的执行效率等等. java做性能测 ...

  4. 浅谈ELK日志分析平台

    作者:珂珂链接:https://zhuanlan.zhihu.com/p/22104361来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 小编的话 “技术干货”系列文章 ...

  5. 【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)

    [分析]浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang) 今天无意中看到有关Invoke和BeginInvoke的一些资料,不太清楚它们之间 ...

  6. 浅谈Unity的渲染优化(1): 性能分析和瓶颈判断(上篇)

    http://www.taidous.com/article-667-1.html 前言 首先,这个系列文章做个大致的介绍,题目"浅谈Unity",因为公司和国内大部分3D手游开发 ...

  7. 浅谈c#的三个高级参数ref out 和Params C#中is与as的区别分析 “登陆”与“登录”有何区别 经典SQL语句大全(绝对的经典)

    浅谈c#的三个高级参数ref out 和Params   c#的三个高级参数ref out 和Params 前言:在我们学习c#基础的时候,我们会学习到c#的三个高级的参数,分别是out .ref 和 ...

  8. 【转】 浅谈Radius协议

    浅谈Radius协议 2013-12-03 16:06 5791人阅读 评论(0) 收藏 举报  分类: Radius协议分析(6)  从事Radius协议开发有段时间了,小弟不怕才疏学浅,卖弄一下, ...

  9. 转:浅谈Radius协议 -来自CSDN:http://blog.csdn.net/wangpengqi/article/details/17097221

    浅谈Radius协议 2013-12-03 16:06 5791人阅读 评论(0) 收藏 举报  分类: Radius协议分析(6)  从事Radius协议开发有段时间了,小弟不怕才疏学浅,卖弄一下, ...

随机推荐

  1. 微信小程序--安装教程

    首先 奉上腾讯官方文档 方便参考:https://mp.weixin.qq.com/debug/wxadoc/design/index.html  个人认为没说啥特别有用的信息(可能是我看的太粗糙了) ...

  2. UOJ73 【WC2015】未来程序

    题目描述:给出输入和暴力程序,求输出.共10个测试点. 测试点1: 输入\(a,b,c\),求\(a\times b \ \mathrm{mod} \ c\) \(a,b,c\)属于long long ...

  3. UOJ426. 【集训队作业2018】石像 [状压DP,min_25筛]

    UOJ 思路 (以下思路是口胡,但正确性大概没有问题.) 刚学min_25筛的时候被麦老大劝来做这题? 结果发现这题是个垃圾二合一?? 简单推一下式子可以得到答案就是这个: \[ \sum_{T=1} ...

  4. Vue 一个组件引用另一个组件

    有些时候需要这么做,比如,我想在首页加载轮播组件,但是又不想全局注册(因为不是每个页面都需要轮播功能) 方法1: <template> <div> <!-- 3.在tem ...

  5. docker nginx angular 刷新错误,404错误

    主要是router问题,两个解决方案 一个是修改angular项目的router选项,一个是修改Nginx的route 选项 一般情况下项目部署了,不愿意修改angular项目的router选项,所以 ...

  6. PC 端常用软件

    WPS  金山文档  有道云笔记  格式工厂 运行精灵 UC 遨游 360 Firefox 浏览器 光影魔术手 美图秀秀 2345好压 火绒安全软件 有道云笔记 悟空游戏厅 微信 QQ 迅雷 百度网盘 ...

  7. 下载GO的开源开发工具LITEIDE

    下载GO的开源开发工具LITEIDE LITEIDE是免费且开源的GO IDE,支持WINDOWS, LINUX, MACOS https://sourceforge.net/projects/lit ...

  8. TP5.1框架最后登录时间不会更新

      最后登录时间:2019-5-1 14:44 发现系统管理员时间总是停留在这个时间,后来才发现原来是时间没有自动更新. 手册地址:https://www.kancloud.cn/manual/thi ...

  9. 007 搜索API

    1.说明 这个API用于在elasticsearch中搜索内容,用户可以通过发送以查询字符串为参数的get请求进行搜索,也可以在post请求的消息体中进行查询. 2.多索引 允许搜索所有的索引或某些特 ...

  10. Flutter页面跳转返回数据

    Dart中的异步请求和等待和ES6中的方法很像,直接使用async...await就可以实现. 核心代码: _navigateToAddress(BuildContext context) async ...