浅谈PHP随机数安全的分析
之前在身边有很多学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随机数安全的分析的更多相关文章
- 浅谈NLP 文本分类/情感分析 任务中的文本预处理工作
目录 浅谈NLP 文本分类/情感分析 任务中的文本预处理工作 前言 NLP相关的文本预处理 浅谈NLP 文本分类/情感分析 任务中的文本预处理工作 前言 之所以心血来潮想写这篇博客,是因为最近在关注N ...
- 浅谈C#随机数发生器
我们在做能自动生成试卷的考试系统时,常常需要随机生成一组不重复的题目,在.net Framework中提供了一个专门用来产生随机数的类System.Random. 对于随机数,大家都知道,计算机不 可 ...
- 浅谈java性能分析
浅谈java性能分析,效能分析 在老师强烈的要求下做了效能分析,对上次写过的词频统计的程序进行分析以及改进. 对于效能分析:我个人很浅显的认为就是程序的运行效率,代码的执行效率等等. java做性能测 ...
- 浅谈ELK日志分析平台
作者:珂珂链接:https://zhuanlan.zhihu.com/p/22104361来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 小编的话 “技术干货”系列文章 ...
- 【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)
[分析]浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang) 今天无意中看到有关Invoke和BeginInvoke的一些资料,不太清楚它们之间 ...
- 浅谈Unity的渲染优化(1): 性能分析和瓶颈判断(上篇)
http://www.taidous.com/article-667-1.html 前言 首先,这个系列文章做个大致的介绍,题目"浅谈Unity",因为公司和国内大部分3D手游开发 ...
- 浅谈c#的三个高级参数ref out 和Params C#中is与as的区别分析 “登陆”与“登录”有何区别 经典SQL语句大全(绝对的经典)
浅谈c#的三个高级参数ref out 和Params c#的三个高级参数ref out 和Params 前言:在我们学习c#基础的时候,我们会学习到c#的三个高级的参数,分别是out .ref 和 ...
- 【转】 浅谈Radius协议
浅谈Radius协议 2013-12-03 16:06 5791人阅读 评论(0) 收藏 举报 分类: Radius协议分析(6) 从事Radius协议开发有段时间了,小弟不怕才疏学浅,卖弄一下, ...
- 转:浅谈Radius协议 -来自CSDN:http://blog.csdn.net/wangpengqi/article/details/17097221
浅谈Radius协议 2013-12-03 16:06 5791人阅读 评论(0) 收藏 举报 分类: Radius协议分析(6) 从事Radius协议开发有段时间了,小弟不怕才疏学浅,卖弄一下, ...
随机推荐
- 我们使用 Kafka 生产者在发消息的时候我们关注什么(Python 客户端 1.01 broker)
之前使用 Kafka 的客户端消费者比较多一点,而且也是无脑订阅使用也没有深入了解过具体的参数.总的来说使用不够细节. 这次公司项目活动期间暴露非常多的问题,于是有了这篇文章. 首先我们来拆解一下 K ...
- 转载:scala中的implicit
掌握implicit的用法是阅读Spark源码的基础,也是学习Scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把 ...
- SSM ehcache 配置 mapper 文件出错
异常 十二月 26, 2017 1:44:49 下午 org.apache.tomcat.util.digester.SetPropertiesRule begin 警告: [SetPropertie ...
- CSP-S 复赛之前的任务计划
一. 最短路算法复习 ★1.Dijkstra: 2. SPFA: 3. Floyd: 二. DP 复习 ★1.背包问题: 2.区间 DP: 3.状压 DP: 三. 数据结构 ★1. 线段树: 2. 树 ...
- Multi-Temporal SAR Data Large-Scale Crop Mapping Based on U-Net Model(利用U-net对多时相SAR影像获得作物图)
对哨兵1号的多时相双极化SAR数据进行预处理,得到18个日期的VV和VH共36景影像,通过ANOVA和JM距离分析,选其中ANOVA得到的F值最高的6景影像.真值用LC8数据和地面调查,目视解译得到标 ...
- [CMS]ThinkCMF框架存在任意内容包含漏洞
原出处:https://www.freebuf.com/vuls/217586.html 0x00 简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3 ...
- vmware exsi安装部署
本文章参考:https://blog.csdn.net/fishinhouse/article/details/80980051 1.VMware-ESXi-6.5.0镜像下载 网盘链接:https: ...
- leetcode 61. 旋转链表
题目描述: 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: 1->2->3->4->5->NULL, k = 2 输 ...
- 2018-2019-2 《网络对抗技术》Exp8 Web基础 20165326
Web基础 实验要求 本实践的要求: Web前端HTML,能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML. Web前端javascipt.理 ...
- git clone速度太慢的解决办法
最近发现使用git clone的速度比较慢,于是找到了办法分享给大家: 思路: git clone特别慢是因为github.global.ssl.fastly.net域名被限制了. 只要找到这个域名对 ...