3 个不稳定版本

0.2.1 2024 年 3 月 30 日
0.2.0 2024 年 3 月 29 日
0.1.0 2023 年 6 月 9 日

#4#暴力破解

Download history 1/week @ 2024-06-04 13/week @ 2024-07-02

每月 113 下载量

MIT/Apache

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

Bash $RANDOM Cracker - Showcase

用法

使用 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

子命令 seedscollide 用于更高级的使用,如果您想了解更多,可以查看它们。

安装

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