题目提示爆个🔨,不爆了,所以这题还是得智取

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-03 13:56:57
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-03 15:47:33
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


error_reporting(0);
include("flag.php");
if(isset($_GET['r'])){
    $r = $_GET['r'];
    mt_srand(hexdec(substr(md5($flag), 0,8)));
    $rand = intval($r)-intval(mt_rand());
    if((!$rand)){
        if($_COOKIE['token']==(mt_rand()+mt_rand())){
            echo $flag;
        }
    }else{
        echo $rand;
    }
}else{
    highlight_file(__FILE__);
    echo system('cat /proc/version');
}

随机数种子是 $flag 的 md5 值的前 8 位的 16 进制转 10 进制,$rand 是输入的 r 的值减去生成的第一个随机数,需要COOKIE中的token==第二和第三个随机数才会显示flag,否则只会显示 $rand。

问了一下 Gemini 得知有 php_mt_seed 这样一款工具可以反向爆破出 php 的随机数种子,先通过传入 ?r=0 获取随机数,得到 -1514623366,由于

$rand = intval($r)-intval(mt_rand());

当 intval($r) = 0 时 $rand = -intval(mt_rand())
故实际的随机数为 1514623366。(实际上就算你没发现这点 php_mt_seed 也不支持你输入负数)

由于使用了不支持的头文件在 Windows 下使用 MinGW64 中的 gcc 似乎无法正常编译

.\gcc.exe "C:\Users\Ayx\Downloads\php_mt_seed-main\php_mt_seed.c"
C:\Users\Ayx\Downloads\php_mt_seed-main\php_mt_seed.c:15:10: fatal error: sys/times.h: No such file or directory
   15 | #include <sys/times.h>
      |          ^~~~~~~~~~~~~
compilation terminated.

在 Kali Linux 下使用 git clone 拉取 GitHub 仓库并使用 make 命令编译,不要直接使用 gcc 编译,应该是没有开启 O2 优化之类的会导致运行效率非常差。

┌──(ayx㉿AyxPower)-[~]
└─$ git clone https://github.com/openwall/php_mt_seed.git
Cloning into 'php_mt_seed'...
remote: Enumerating objects: 119, done.
remote: Counting objects: 100% (119/119), done.
remote: Compressing objects: 100% (69/69), done.
remote: Total 119 (delta 65), reused 103 (delta 50), pack-reused 0 (from 0)
Receiving objects: 100% (119/119), 55.62 KiB | 1.50 MiB/s, done.
Resolving deltas: 100% (65/65), done.

┌──(ayx㉿AyxPower)-[~]
└─$ cd php_mt_seed/

┌──(ayx㉿AyxPower)-[~/php_mt_seed]
└─$ ls
Makefile  php_mt_seed.c  README

┌──(ayx㉿AyxPower)-[~/php_mt_seed]
└─$ make
gcc -Wall -march=native -mtune=generic -O2 -fomit-frame-pointer -funroll-loops -fopenmp php_mt_seed.c -o php_mt_seed
php_mt_seed.c:47:2: warning: #warning AVX-512 not enabled. Try gcc -mavx512f (on Intel Knights Landing, Skylake-X, or some newer). [-Wcpp]
   47 | #warning AVX-512 not enabled. Try gcc -mavx512f (on Intel Knights Landing, Skylake-X, or some newer).
      |  ^~~~~~~

(warning 是因为我的 Ryzen 7 7435H CPU 不支持 AVX-512)
如果你直接使用 gcc 编译的话就会这样(可以对比一下和下面用 make 编译的版本的速度区别):

┌──(ayx㉿AyxPower)-[~]
└─$ ./php_mt_seed.out 1514623366
Pattern: EXACT
Version: 3.0.7 to 5.2.0
Found 0, trying 0x78000000 - 0x7bffffff, speed 130.5 Mseeds/s
seed = 0x794cd53c = 2035078460 (PHP 3.0.7 to 5.2.0)
seed = 0x794cd53d = 2035078461 (PHP 3.0.7 to 5.2.0)
Found 2, trying 0xfc000000 - 0xffffffff, speed 129.6 Mseeds/s
Version: 5.2.1+
Found 2, trying 0x08000000 - 0x09ffffff, speed 1.1 Mseeds/s ^C

编译出可执行文件后给它加上可执行权限(chmod +x),然后调用它爆破随机数种子

┌──(ayx㉿AyxPower)-[~/php_mt_seed]
└─$ chmod +x php_mt_seed

┌──(ayx㉿AyxPower)-[~/php_mt_seed]
└─$ ./php_mt_seed
Usage: ./php_mt_seed VALUE_OR_MATCH_MIN [MATCH_MAX [RANGE_MIN RANGE_MAX]] ...

┌──(ayx㉿AyxPower)-[~/php_mt_seed]
└─$ ./php_mt_seed 1514623366
> ^C

┌──(ayx㉿AyxPower)-[~/php_mt_seed]
└─$ ./php_mt_seed 1514623366
Pattern: EXACT
Version: 3.0.7 to 5.2.0
Found 0, trying 0x78000000 - 0x7bffffff, speed 20132.7 Mseeds/s
seed = 0x794cd53c = 2035078460 (PHP 3.0.7 to 5.2.0)
seed = 0x794cd53d = 2035078461 (PHP 3.0.7 to 5.2.0)
Found 2, trying 0xfc000000 - 0xffffffff, speed 24869.8 Mseeds/s
Version: 5.2.1+
Found 2, trying 0x94000000 - 0x95ffffff, speed 376.2 Mseeds/s
seed = 0x95820833 = 2508326963 (PHP 7.1.0+)
Found 3, trying 0xfe000000 - 0xffffffff, speed 366.1 Mseeds/s
Found 3

题目的代码输出了 /proc/version 文件的内容,包含这些版本信息:

Linux version 5.4.0-163-generic (buildd@lcy02-amd64-067) (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)) #180-Ubuntu SMP Tue Sep 5 13:21:23 UTC 2023

根据 Gemini 的说法 Ubuntu 20.04 官方 apt 软件源默认提供的 PHP 版本是 PHP 7.4,所以我们选择使用找到的三个随机数种子中的最后一个 2508326963(PHP 7.1.0+),由于浏览器中的 PHP Playground 基于 wasm 之类的原因是 32 位的,输入超过 32 位 int 类型上限的数字作为随机数种子会报错,所以使用本地的 64 位 php 运行代码计算第一个随机数和第二个、第三个随机数的和。

PS C:\phpstudy_pro\Extensions\php\php7.3.4nts> .\php.exe -r "mt_srand((int)2508326963);echo mt_rand();echo '|';echo mt_rand()+mt_rand();"
1514623366|2335728148

其实网页版 PHP Playground 也不是不能用,只是需要在随机数种子前加上 (int) 强制类型转换,而且会报一条 Warning

<?php mt_srand((int)2508326963);echo mt_rand();echo "|";echo mt_rand()+mt_rand();?>

在 URL 后拼接 /?r=1514623366(第一个随机数),点击 HackBar 中的 MODIFY HEADER 并将 Cookie 设为 token=2335728148(第二个和第三个随机数的和),点击 EXECUTE 即可获得 flag ctfshow{7e19dc1e-0d07-47ce-a791-29b87681650c}。

Image