创建自定义 John the Ripper 格式

Kali LinuxBeginner
立即练习

引言

John the Ripper (JtR) 是一个强大且流行的开源密码破解工具。它的一大关键优势在于其可扩展性。虽然它开箱即用地支持大量的哈希类型,但你有时可能会遇到 JtR 无法识别的自定义或冷门哈希方案。在这种情况下,你可以创建自己的自定义格式,来教会 JtR 如何破解它。

在本实验中,你将学习创建自定义 JtR 格式的基本概念。本实验是概念性的,侧重于结构和过程,为你提供开发功能齐全的格式所需的奠定知识。你不会编写和编译一个完全可用的格式,但你将理解所有必要的步骤。

理解 John the Ripper 格式结构

在本步骤中,你将学习 John the Ripper 格式的基本结构。理解这种结构是创建自定义格式的第一步,也是最关键的一步。

JtR 格式定义在 C 源代码文件 (.c) 中,并围绕一个名为 struct fmt_main 的核心 C 结构构建。这个结构充当了一个蓝图,告诉 JtR 关于哈希类型所需的一切信息。

struct fmt_main 中的关键字段包括:

  • fmt_label: 一个简短、唯一的字符串,你可以在命令行选项 --format= 中使用它来指定格式(例如,md5raw)。
  • fmt_tag: 一个由 JtR 内部使用的唯一标识符,用于在保存的会话文件中区分格式(例如,$dynamic_0$)。
  • algorithm_name: 一个描述哈希算法及其属性的字符串,用于信息展示。
  • plaintext_length: 格式可以处理的最大密码长度。
  • binary_size: 原始二进制哈希的大小。对于 MD5,这将是 16 字节。
  • salt_size: 如果哈希类型使用 salt,则为 salt 的大小。
  • methods: 这是一个嵌套结构,包含指向实现格式逻辑的各种函数的指针。最重要的函数是:
    • valid(): 检查输入文件中的给定哈希字符串是否对该格式有效。它是第一个守门员。
    • split(): 如果哈希字符串包含除哈希本身之外的内容(如用户名),则此函数会分离这些组件。
    • binary(): 将十六进制或 base64 的哈希字符串转换为其原始二进制表示。
    • salt(): 从哈希字符串中提取 salt。
    • crypt_all(): 核心函数。它接收一组候选密码,对它们进行哈希处理,并为比较做准备。
    • cmp_all(): 将 crypt_all() 中新计算出的哈希与目标哈希进行比较,以查看是否匹配。

此步骤纯粹是理论性的。你不需要执行任何命令。在下一步中,我们将检查一个真实的格式文件,以了解此结构如何实际工作。

识别现有格式定义

在本步骤中,你将定位 John the Ripper 源代码树中现有格式的源代码。研究这些文件是学习如何构建自己的格式的最佳方式。

本实验的设置脚本已经将 JtR 源代码克隆到了 ~/project/john 目录中。

首先,导航到存放源文件的 src 目录。

cd ~/project/john/src

现在,列出所有定义格式的文件。按照惯例,这些文件以 _fmt_plug.c 结尾。

ls *_fmt_plug.c

你将看到一个长长的文件列表,每个文件对应 JtR 支持的不同哈希类型。

7z_fmt_plug.c             des_fmt_plug.c          lotus5_fmt_plug.c         ...
afs_fmt_plug.c            django_fmt_plug.c       mdc2_fmt_plug.c
aix_smd5_fmt_plug.c       dmg_fmt_plug.c          md4_fmt_plug.c
aix_ssha_fmt_plug.c       dominosec_fmt_plug.c    md5_fmt_plug.c
...and many more...

让我们来看一个相对简单的文件 md5_fmt_plug.c,以查看我们之前讨论过的 struct fmt_main。我们将使用 cat 结合 head 来仅查看文件顶部部分。

cat md5_fmt_plug.c | head -n 50

在输出中,你将能够看到 struct fmt_main fmt_MD5 的定义,包括其标签、标签、算法名称和方法指针,正如我们在上一步中所描述的那样。

创建一个简单的自定义格式(概念性)

在本步骤中,我们将概念性地为简单的自定义格式创建一个新的 C 源代码文件。这个练习将演示你将如何构建一个新格式文件。

我们的目标是创建一个能够识别带有特殊前缀 labex_md5$ 的哈希的格式。例如,一个像 labex_md5$87e4e494b2399b0921d44e03693518f9 这样的哈希。

确保你仍然在 ~/project/john/src 目录中。我们将使用 nano 文本编辑器来创建我们的新文件。

nano labex_md5_fmt_plug.c

现在,将以下 C 代码复制并粘贴到 nano 编辑器中。这是一个简化的骨架,并非一个功能齐全的格式,但它展示了核心组件。

#if FMT_EXTERNS_H
extern struct fmt_main fmt_labex_md5;
#elif FMT_REGISTERS_H
john_register_one(&fmt_labex_md5);
#else

#include <string.h>
#include "arch.h"
#include "common.h"
#include "formats.h"

#define FORMAT_LABEL        "labex-md5"
#define FORMAT_NAME         "LabEx Custom MD5"
#define ALGORITHM_NAME      "MD5 32/64"
#define PLAINTEXT_LENGTH    32
#define BINARY_SIZE         16
#define SALT_SIZE           0
#define TAG_PREFIX          "labex_md5$"
#define TAG_LENGTH          (sizeof(TAG_PREFIX) - 1)

// This function checks if a hash string is valid for our format
static int valid(char *ciphertext, struct fmt_main *self)
{
    if (strncmp(ciphertext, TAG_PREFIX, TAG_LENGTH))
        return 0;
    char *p = ciphertext + TAG_LENGTH;
    if (hexlenu(p, 0) != 32)
        return 0;
    return 1;
}

struct fmt_main fmt_labex_md5 = {
    {
        FORMAT_LABEL,
        FORMAT_NAME,
        ALGORITHM_NAME,
        BENCHMARK_COMMENT,
        BENCHMARK_LENGTH,
        0,
        PLAINTEXT_LENGTH,
        BINARY_SIZE,
        BINARY_ALIGN,
        SALT_SIZE,
        SALT_ALIGN,
        MIN_KEYS_PER_CRYPT,
        MAX_KEYS_PER_CRYPT,
        FMT_CASE | FMT_8_BIT,
        { NULL },
        { TAG_PREFIX },
        NULL
    }, {
        /* init */      init,
        /* done */      done,
        /* reset */     reset,
        /* prepare */   prepare,
        /* valid */     valid,
        /* split */     split,
        /* binary */    binary,
        /* salt */      salt,
        { NULL },
        /* source */    source,
        {
            /* get_hash* */ get_hash_0,
            /* get_hash* */ get_hash_1,
            /* get_hash* */ get_hash_2,
            /* get_hash* */ get_hash_3,
            /* get_hash* */ get_hash_4,
            /* get_hash* */ get_hash_5,
            /* get_hash* */ get_hash_6
        },
        /* cmp_all */   cmp_all,
        /* cmp_one */   cmp_one,
        /* cmp_exact */ cmp_exact
    }
};

#endif

粘贴代码后,保存文件并按 Ctrl+X,然后按 Y,最后按 Enter 退出 nano

你现在已经创建了一个新格式的源代码文件。最重要的部分是 valid() 函数,它只是检查我们的 labex_md5$ 前缀并确保后面的哈希是 32 个字符长。

使用新格式编译 John the Ripper(概念性)

现在你已经有了一个概念性的格式文件,本步骤将解释如何将其集成到 John the Ripper 的构建过程中并进行编译。

首先,确保你位于 src 目录中。

cd ~/project/john/src

编译 JtR 的第一步是运行 configure 脚本。此脚本会检查你的系统是否具备所需的库,并设置构建环境。

./configure

配置完成后,你可以使用 make 命令编译源代码。我们将使用 make clean 来移除任何先前的构建,并使用 make -sj4 来运行编译,使用 4 个并行任务,这可以加快过程。

make -s clean && make -sj4

编译将花费一到两分钟。

重要提示: 在实际场景中,仅仅创建 .c 文件是不够的。你还需要编辑一个配置文件(例如 Makefile.in),告知构建系统在链接最终的 john 可执行文件时包含你的新 labex_md5_fmt_plug.o 对象文件。为了在本实验中简化,我们跳过了这一修改。因此,编译会成功,但我们的新格式实际上 不会 被包含在最终的二进制文件中。这说明了开发过程中一个关键的步骤。

测试自定义格式(概念性)

在最后一步中,我们将讨论如何使用新编译的 John the Ripper 可执行文件来测试你的自定义格式。

编译后的 john 二进制文件位于 ~/project/john/run/ 目录中。让我们导航到那里。

cd ~/project/john/run

你可以列出编译后的 JtR 版本所支持的所有格式。

./john --list=formats

滚动浏览列表。你会注意到我们的 labex-md5 格式 不存在。这是符合预期的,因为正如上一步所述,我们没有修改构建文件来包含它。

现在,让我们创建一个示例哈希文件和一个单词列表,看看如果格式成功编译,我们如何使用它。

首先,在你的项目根目录中创建一个名为 hashes.txt 的文件,其中包含一个匹配我们自定义格式的哈希。哈希 87e4e494b2399b0921d44e03693518f9 是密码 "labex" 的 MD5 哈希。

echo "labex_md5$87e4e494b2399b0921d44e03693518f9" > ~/project/hashes.txt

接下来,创建一个包含正确密码的简单单词列表。

echo "labex" > ~/project/wordlist.txt

最后,这是你将运行的命令,用于使用自定义格式破解哈希。

./john --format=labex-md5 --wordlist=~/project/wordlist.txt ~/project/hashes.txt

当你运行此命令时,JtR 将报告一个错误,因为格式未知,这证实了我们对编译过程的理解。

Unknown format name: "labex-md5"

这完成了我们关于创建和测试自定义 JtR 格式的概念性讲解。

总结

在本实验中,你探索了为 John the Ripper 创建自定义格式的概念性过程。你对扩展 JtR 功能所涉及的关键步骤有了基础性的理解。

你学习了:

  • 定义每个 JtR 格式的核心 struct fmt_main 结构。
  • 如何在 JtR 源代码中定位和检查现有的格式定义。
  • 使用基本的 valid() 函数创建新格式源文件的过程。
  • 使用 ./configuremake 编译 JtR 的标准流程。
  • 修改构建文件以包含新格式的关键步骤(此步骤被故意省略)。
  • 如何使用 --format 标志和示例哈希文件来测试格式。

虽然本次实验并未产生一个功能齐全的自定义格式,但它为你提供了必要的知识和清晰的路线图,以便开发自己的格式来应对独特的密码哈希方案。