3 个不稳定版本
0.2.1 | 2024 年 3 月 30 日 |
---|---|
0.2.0 | 2024 年 3 月 29 日 |
0.1.0 | 2023 年 6 月 9 日 |
#4 在 #暴力破解
每月 113 下载量
27KB
473 行
Bash $RANDOM
破解器
一个工具,可以在 2-3 个样本后暴力破解 Bash 的 $RANDOM
变量的内部种子,在几秒钟内预测所有未来的值以破坏随机性。
为了上下文,bash shell 有一个动态变量 bash
,你可以随时访问以接收一个随机的 15 位数字
$ echo $RANDOM $RANDOM $RANDOM
3916 29151 6095
要为此随机数生成器设置种子,你可以直接设置该变量以在每次获得相同的值
$ RANDOM=1337; echo $RANDOM $RANDOM $RANDOM
24879 21848 15683
$ RANDOM=1337; echo $RANDOM $RANDOM $RANDOM
24879 21848 15683
根据你的 bash 版本,有 2 种不同的计算方法,这可能会导致一个种子给出两个不同的输出。
所有版本 >= 5.1 都将添加一个小的额外步骤,对这个工具来说被认为是“新”版本,而任何较低的版本被认为是“旧”版本。你可以使用此工具中的 --version
(-v
) 参数显式设置,否则它将简单地尝试两者。
示例
$ bashrand crack -n 3 $RANDOM $RANDOM $RANDOM
Seed: 2137070299 +3 (old)
Next 3 values: [22404, 16453, 2365]
$ echo $RANDOM $RANDOM $RANDOM
22404 16453 2365
用法
使用 bashrand crack
并为其提供 2-3 个 $RANDOM
变量,以便它可以暴力破解种子。之后,您可以使用 bashrand get
来提前获取序列的任意部分,提供在第一步中找到的种子。也可以参考上面的示例。
$ bashrand --help
Bash $RANDOM Cracker
Usage: bashrand [OPTIONS] <COMMAND>
Commands:
crack Provide random numbers to brute-force the seed
get Get random numbers from a seed
seeds Get next N seeds from a seed
collide Find a seed where both old and new versions are the same
help Print this message or the help of the given subcommand(s)
Options:
-v, --version <VERSION>
Which bash version to use for generation (check with `bash --version`)
[default: both]
Possible values:
- old: Bash versions 5.0 and older
- new: Bash versions 5.1 and newer
- both: Try both old and new versions if unsure
-n, --number <NUMBER>
Number of values to generate
[default: 10]
$ bashrand crack --help
Provide random numbers to brute-force the seed
Usage: bashrand crack [OPTIONS] <NUMBERS> <NUMBERS>...
Arguments:
<NUMBERS> <NUMBERS>...
2-3 $RANDOM numbers as input for brute-forcing the seed
2 => multiple possible seeds, 3 => single seed
$ bashrand get --help
Get random numbers from a seed
Usage: bashrand get [OPTIONS] <SEED>
Arguments:
<SEED>
Seed to use for generating random numbers
子命令 seeds
和 collide
用于更高级的使用,如果您想了解更多,可以查看它们。
安装
cargo install bashrand
或者 从发布 页面下载并解压预编译的二进制文件。
逆向工程(如何?)
要实现 $RANDOM
算法,首先需要理解该算法。幸运的是,Bash 是开源的,这意味着所有清晰和文档化的代码都是可用的。我使用 这个仓库 查找与生成此变量相关的内容,并在这里找到了定义 (链接)
INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
它将该变量分配给两个函数: get_random()
和 assign_random
。第一个是在你像 echo $RANDOM
那样访问变量时发生的,第二个是在你为自己分配变量值时发生的,例如 RANDOM=1337
。
get_random()
是最有趣的,因为我们想要预测它的输出。它调用 get_random_number()
函数,该函数又调用 /lib/sh/random.c
文件内的 brand()
。这里开始变得有趣了
#define BASH_RAND_MAX 32767 /* 0x7fff - 16 bits */
/* Returns a pseudo-random number between 0 and 32767. */
int brand () {
unsigned int ret;
rseed = intrand32 (rseed);
if (shell_compatibility_level > 50)
ret = (rseed >> 16) ^ (rseed & 65535);
else
ret = rseed;
return (ret & BASH_RAND_MAX);
}
首先,注意 BASH_RAND_MAX
变量,它是对输出的 15 位掩码。另外,shell_compatibility_level
是 bash 版本,意味着如果它大于版本 50(5.0),它将使用不同的计算方法。然而,在两种情况下,它首先从 intrand32()
获取随机数,这已经包含了算法的核心!
bits32_t h, l, t;
u_bits32_t ret;
/* Can't seed with 0. */
ret = (last == 0) ? 123459876 : last;
h = ret / 127773;
l = ret - (127773 * h);
t = 16807 * l - 2836 * h;
ret = (t < 0) ? t + 0x7fffffff : t;
return (ret);
这些是一些简单的计算,我们可以在任何编程语言中重新创建。重要的是,它使用一个 last
变量作为其计算中的唯一参数,该参数由调用函数中的 rseed = intrand32(rseed)
提供。这意味着有一个内部种子,每次调用此函数时都会迭代。如果我们能够同步这个种子,我们将能够通过复制算法来预测任何未来的值。
初始种子值 很复杂,使用了大量不可预测的数据来计算。如果你记得,也可以使用 assign_random()
来设置种子。查看这个函数,它接受我们设置的值,并将其传递给 sbrand()
,这是一个非常简单的函数,它只是直接将种子设置为提供的值
/* Set the random number generator seed to SEED. */
void sbrand (seed) unsigned long seed; {
rseed = seed;
last_random_value = 0;
}
从理论上讲,如果种子是手动设置的,我们现在可以简单地尝试许多种子,直到找到一个与输出匹配的种子。但那些没有手动设置的种子怎么办?这种情况更为常见。幸运的是,内部种子只是一个32位整数,可以使用这样的快速算法轻松地进行暴力破解。经过一些测试,我们发现对于较新的bash版本,搜索空间实际上只有30位,对于旧版本的bash,则有31位。
这个程序实现了这种暴力破解方法,可以在几秒钟内搜索整个空间,并显示找到的种子及其预测的未来值。
依赖项
~3.5MB
~64K SLoC