WEB|[GWCTF 2019]枯燥的抽奖

发布时间 2023-05-06 15:43:25作者: scarecr0w7


页面提示需要输入以lw1ar7AWmn开头的20位字符串才能获得flag,查看页面源码发现check.php

访问check.php,发现源码

伪随机数

mt_srand($_SESSION['seed']);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}

可以发现这里是使用mt_rand()来随机生成字符串,但是mt_rand()存在一个问题,同一个种子下随机生成的随机数值是相同的,只要获得了seed值就可以生成相同的字符串

CTF| web篇之伪随机数
mt_rand()存在的问题:
由于mt_rand()的生成的随机数只跟seed和调用该函数的次数有关。假设使用mt_srand(1111111)进行了一次播种操作,接下来调用mt_rand()函数,第一次生成的数值为a,第二次生成的为b,第三次生成的为c。任何一个人拿到这样的一串代码,所执行的结果都是跟刚刚描述的一样。所以当你的seed数值被他人知道后,就可以预测出你接下来的数值是多少,这就是该函数的一个问题,他并不能起到一个真随机数的作用。

获取seed

php_mt_seed可以根据一串int 或者一串由许多4个一组的数字组成的数据爆破出seed

根据已有字符串转换数据

php_mt_seed需要的是一串由许多4个一组的数字组成的数据,所以需要根据已有字符串进行转换

str1 = "lw1ar7AWmn"
str2 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
length = 61
result = ''

for i in range(0, len(str1)):
    for j in range(0, len(str2)):
        if str1[i] == str2[j]:
            result += str(j) + ' ' + str(j) + ' ' + '0' + ' ' + str(length) + ' '
            break

print(result)

11 11 0 61 22 22 0 61 27 27 0 61 0 0 0 61 17 17 0 61 33 33 0 61 36 36 0 61 58 58 0 61 12 12 0 61 13 13 0 61

4个一组的数字格式
前面两个数是随机数的结果区间,后两位是随机数的随机范围区间,中间以一个空格为间隔
前面两个数是随机数的结果区间:str1在str2的位置,两位都一位
后两位是随机数的随机范围区间:str2的范围,每组都是一样,str2有62位,因为从0开始计数所以为61

爆破seed

./php_mt_seed 11 11 0 61 22 22 0 61 27 27 0 61 0 0 0 61 17 17 0 61 33 33 0 61 36 36 0 61 58 58 0 61 12 12 0 61 13 13 0 61

使用php_mt_seed爆破出seed为156489612

计算完整字符串

<?php
mt_srand(156489612);
$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$str='';
$len1=20;
for ( $i = 0; $i < $len1; $i++ ){
    $str.=substr($str_long1, mt_rand(0, strlen($str_long1) - 1), 1);       
}
echo $str;
?>

计算出20位完整字符串为lw1ar7AWmnI0Pp0fPEOC

获取flag

flag{8f018bcf-6b8d-4228-b246-8cd0eaeb83d0}