RNG 挑战赛 Python

RNG Challenge Python

提问人:Shark44 提问时间:9/10/2023 更新时间:9/11/2023 访问量:235

问:

我正在尝试解决一个 CTF 挑战,其中的目标是猜测生成的数字。由于这个数字很大,每个数字只有 10 次尝试,我认为你不能应用二叉搜索或任何类型的算法来解决它,它与以某种方式获得随机函数的种子并能够生成下一个数字有关,但我不知道从哪里开始获得正确的种子。你有什么想法吗? 以下是挑战的代码:

#!/usr/bin/env python3

import signal
import os
import random

TIMEOUT = 300

assert("FLAG" in os.environ)
FLAG = os.environ["FLAG"]
assert(FLAG.startswith("CCIT{"))
assert(FLAG.endswith("}"))


def handle():
    for i in range(625):
        print(f"Round {i+1}")
        guess_count = 10
        to_guess = random.getrandbits(32)
        while True:
            print("What do you want to do?")
            print("1. Guess my number")
            print("2. Give up on this round")
            print("0. Exit")
            choice = int(input("> "))
            if choice == 0:
                exit()
            elif choice == 1:
                guess = int(input("> "))
                if guess == to_guess:
                    print(FLAG)
                    exit()
                elif guess < to_guess:
                    print("My number is higher!")
                    guess_count -= 1
                else:
                    print("My number is lower!")
                    guess_count -= 1
            elif choice == 2:
                print(f"You lost! My number was {to_guess}")
                break
            if guess_count == 0:
                print(f"You lost! My number was {to_guess}")
                break


if __name__ == "__main__":
    signal.alarm(TIMEOUT)
    handle()

python 随机 ctf

评论

1赞 pjs 9/11/2023
循环中的数字 625 很有趣。Python 的默认 PRNG 是 Mersenne Twister,它维护 624 个字的状态。
0赞 President James K. Polk 9/11/2023
另一个问题是找到 python 的 mersenne twister 实现使用的确切算法细节。我不想不得不倾注数百行 C 代码,试图弄清楚内部到底发生了什么才能获得输出。此外,如果对这个实现进行哪怕是微小的更改,它都可能使一切中断。random.getrandbits(32)
0赞 President James K. Polk 9/11/2023
@KellyBundy:鉴于它是一个 CTF,并且 FLAG 在代码中以纯文本形式存在,答案一定是它在玩家无法控制的某个服务器上运行。与他之前的问题类似,在使用 CTF 求解器程序连接到服务器后,上述程序的标准输入和标准输出连接到套接字的两半。
0赞 President James K. Polk 9/11/2023
是的,它来自 .这就是来自 python 程序的环境,如果它以某种方式在您自己的 PC 上,那么它将以纯文本形式提供。os.environ["FLAG"]

答:

4赞 Kelly Bundy 9/11/2023 #1

不要试图猜测前 624 个数字,放弃它们。你被告知它们是什么,将它们输入到 randcrack 中,如其示例所示。让它预测下一个 32 位数字并猜测。

对于更大的挑战,您可以在没有该工具的情况下尝试。这里有一些见解,“预测”下一个数字,即显示它是如何从状态计算出来的:

import random

for _ in range(5):
    s = random.getstate()[1]
    y = s[s[-1]]
    y ^= (y >> 11);
    y ^= (y << 7) & 0x9d2c5680;
    y ^= (y << 15) & 0xefc60000;
    y ^= (y >> 18);
    print('predict:', y)
    print('actual: ', random.getrandbits(32))
    print()

示例输出:

predict: 150999088
actual:  3825261045

predict: 457032747
actual:  457032747

predict: 667801614
actual:  667801614

predict: 3817694986
actual:  3817694986

predict: 816636218
actual:  816636218

首先,我得到状态,它是 624 个 32 位的字和一个索引。的计算是从这里开始的。第一个数字是错误的,因为在现实中,它上面更复杂的代码第一次运行。y

如果你能弄清楚如何反转这些计算,你可以从给定的前 624 个数字重建原始状态,然后用 设置该状态并生成下一个数字。该工具似乎确实可以反转,但它看起来并不微不足道。random.setstate

评论

0赞 Shark44 9/11/2023
请问你有没有可以检查的论文或东西?我想试着理解它背后的数学原理。无论如何,感谢您的回答:)
0赞 Kelly Bundy 9/11/2023
@Shark44我不知道。我想为 randcrack 创建一个 GitHub 问题是合理的,要求他们添加有关其工作原理的文档。