我是靠谱客的博主 大气汽车,最近开发中收集的这篇文章主要介绍译-Cracking PHP rand()-token 能破解吗?,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

2016 OCTF初赛 有一道WEB题有意思,这道题的出题思路基于此paper,下面我就翻译一下

                                              Cracking PHP rand()

     在WEb应用中经常需要用到一些随机生成的字符串,例如:session token,CSRF token,例如

当你需要重置密码时,发送到你邮箱的重置链接里就有一个token(防范CSRF攻击),所以这些token

必须保证安全难以被猜到,这些字符串用函数rand()来生成,有时就多次嵌套调用rand()来提高复杂度,

并把输出转换为一个字符串,这样一个随机的token就生成了,我这次就来研究一下到底有没有可能性来

破解rand().

rand() 是怎么工作的?

在PHP里面,通过rand()来生成伪随机数字。那么就需要由srand来设置的“随机数列产生器(seed)”的

初始状态,当调用rand()时,如果你没有调用srand来初始化“seed”,rand()就会用一些难以猜测的数字作

为seed来产生随机数字,因此seed完全决定了rand()会产生什么随机数字。“随机数字生成器”在最初由seed

初始化后,会保持一个状态,然后每次调用rand()就会改变这一状态作为下次调用使用,不同的进程使用不同

的“随机数字生成器”,windows中seed 是32为的,linux中是1024位的。

看看我们的实例程序

这个程序本来用来防止csrf攻击的token,事实上它没有那么安全

public static function gen($len = 5)
{
$token = '';
while($len--){
$choose = rand(0, 2);
if ($choose === 0)
$token .= chr(rand(ord('A'), ord('Z')));
else if($choose === 1)
$token .= chr(rand(ord('a'), ord('z')));
else
$token .= chr(rand(ord('0'), ord('9')));
}
return $token;
}

 这个程序先用rand()产生随机数字,来决定使用大写字符还是小写字符还是数字,然后在选择具体的字符。

每次我们打开index.php时,就会产生一个随机的token,我们的工作就是预测这个token,然后用预测到的

token来进行csrf攻击。

Seed Cracking

既然sand()是产生的为随机数列是由seed产生的,那么我们就可以通过遍历初始所有可能的数字作为参数给

srand,如果我们遍历找到了正确的srand参数,那么rand()产生的伪随机数字就可以被预测到了。

特别提醒:

      在linux中上述方法只只用于全新的进程,如果我们需要预测的进程已经执行了多次rand(),那么每次遍历

我们需要执行相同次数的rand()才行。在windows中就不存在这种问题了,所有作为srand输入的“随机数列生

成器”状态都是一样的。

如果你得到一个全新的进程的token,那么下面的程序就能破解它了

for ($i = 0; $i < PHP_INT_MAX; $i++) {
srand($i);
if (Token::gen(10) == "2118Jx9w3e") {
die("Found: $i n");
}
}

 如果搜索4294967295种可能的参数给srand,这大约会花费12小时。幸运的是,自从PHP只调用libc时,

我们就可以重新把php 编码抓换成更高效率的c代码来i加快速度。我已经出了两个版本,一个是glibc rand

一个是widows rand这都是以token.php为基础的(从 php ext/standard/rand.c 中借用了大量代码)

。然后就遍历所有可能的seed。这样的话在windows下会话费大约10分钟,linux下大约一个小时就能

搞定。一旦你破解了seed,你通过把自己的“随机数列生成器”设置成和服务器的在用一个状态,那么后

续你们产生的随机数列就是一样的了,这样你就可以预测服务器会给其他用户分配那些token,这样就可以

用来攻击了。

 Linux 下的 破解

windows 下破解seed和破解“随机数列生成器”状态差不多是一回事,可以linux下就不同了。

Glibc rand()通过保存了一系列的数字,且像下面的代码一样来计算下一次调用的状态:

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

 所以每次输出大约是第3和第31次调用后效果的重叠,看看下面的随机字符串

  • 6ZF5kNgonV
  • 9h3byovpGR
  • gGt0A94U92

当下一次调用rand()的时候首先决定是大小写字符还是数字,这是被前面3和31次调用决定的。那

就是gGt0A94U92后面那个9,和9h3byovpGR里面的y。我们我们预测下次rand(0,2)的输出很

大可能可能就是⌊10/10 + 25/26 × 3⌋ = 2 mod 3。那意味着我们会得到一个数字如果我们能预

测这个数字是多少,那么这个数字是有前3次的调用输出(一个数字)和前31次调用输出(一个字母)

决定的。事实上它会是 ⌊2/3 + 1/3 × 10⌋ = 0 mod 10 and ⌊3/3 + 2/3 × 10⌋ = 6 mod 10.

也就是0 和 6之间. 事实上它是 4:

  • 43J2d2ew31

 

你看到了对于linux rand 我们虽然不能准确的快速的破解rand,但是它也并没有我们想象的那么安

全,事实上如果给我们足够多的token我们也许能准确预测,当然我没有实验。

总结

     我们需要创建绝对安全的token,如果我们用rand,在很多使用情境中“随机代码生成器”能被各种

方法破解,token就能被预测,虽然在linux下预测有点麻烦,但严格意义上它确实不安全。但是如果在

windows下,分分钟就能破解你的token。

翻译自:http://www.sjoerdlangkemper.nl/2016/02/11/cracking-php-rand/

 

转载于:https://www.cnblogs.com/QQisadog/p/5499816.html

最后

以上就是大气汽车为你收集整理的译-Cracking PHP rand()-token 能破解吗?的全部内容,希望文章能够帮你解决译-Cracking PHP rand()-token 能破解吗?所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部