はじめに
John the Ripper (JtR) は、人気があり強力なオープンソースのパスワードセキュリティ監査およびパスワードリカバリツールです。「シングルクラック」モード、「単語リスト」モード、「インクリメンタル」モードなど、いくつかのモードを使用してパスワードクラッキングを実行できます。
これらの標準モードに加えて、JtR は信じられないほど柔軟な「外部モード」を提供します。このモードを使用すると、外部プログラムまたはスクリプトを使用してパスワード候補を生成できます。これにより、パスワード生成ロジックを完全に制御でき、他のモードでは不可能な、高度にカスタマイズされた複雑なパスワードパターンを作成できます。
この実験では、JtR の外部モードの基本を学びます。まず基本的な概念を理解し、次にパスワードを生成するための独自のカスタム C プログラムを作成、コンパイル、使用します。また、基本的なデバッグ手法を学び、より実践的なシナリオに知識を応用します。
外部モードの基本を理解する
このステップでは、John the Ripper の外部モードの基本的な概念を学びます。このモードは、定義した外部プログラムを実行することによって機能します。John the Ripper は、このプログラムの標準出力を読み取り、各行を潜在的なパスワード候補として扱います。
これらの外部モードは、通常 /etc/john/john.conf にある john.conf 設定ファイルで定義されます。各外部モードは、[List.External:ModeName] のようなセクション内で定義されます。
デフォルトの設定ファイル内の既存の外部モード定義を調べて、その構造を見てみましょう。キーボードウォークパターンに基づいてパスワード候補をシミュレートする Keyboard モードを探します。
次のコマンドを実行して、Keyboard モードの設定を表示します。
grep -A 10 "\[List.External:Keyboard\]" /etc/john/john.conf
C 言語風のコードブロックが表示されます。最も重要な関数は generate() で、パスワード候補を生成する責任があります。
外部モードを実際に動作させるには、--stdout フラグを付けて john を実行できます。これにより、John はハッシュをクラックしようとする代わりに、生成された候補を画面に出力します。Keyboard モードをテストしてみましょう。
john --stdout --external=Keyboard | head -n 5
このコマンドは、Keyboard 外部モードを選択し、その出力を head にパイプします。これにより、生成された最初の 5 つのパスワード候補が表示されます。出力は、キーボードパターンを表す一連の文字になります。
q
w
e
r
t
これは基本的な原則を示しています。John the Ripper は、外部モードで定義されたロジックを実行し、その出力をパスワードのソースとして使用します。次のステップでは、ソースとして機能する独自のプログラムを作成します。
シンプルな外部モードスクリプトの作成
このステップでは、C プログラミング言語を使用して、最初のシンプルな外部モードスクリプトを作成およびコンパイルします。目標は、固定されたパスワードリストを生成するプログラムを作成し、John the Ripper がそれを使用するように設定することです。
まず、nano エディタを使用して simple_gen.c という名前の C ソースファイルを作成します。
nano simple_gen.c
次に、以下の C コードを nano エディタにコピー&ペーストします。このプログラムは、単純に 3 つの異なるパスワードを標準出力に、それぞれ新しい行に出力します。
#include <stdio.h>
int main() {
printf("pass1\n");
printf("pass2\n");
printf("pass3\n");
return 0;
}
Ctrl+X、次に Y、そして Enter を押してファイルを保存し、nano を終了します。
次に、gcc コンパイラを使用して、この C コードを simple_gen という名前の実行可能ファイルにコンパイルします。
gcc -o simple_gen simple_gen.c
実行可能ファイルが作成されたので、John the Ripper にその使用方法を指示する必要があります。プロジェクトディレクトリに設定ファイルのローカルコピーを作成し、新しい外部モード定義を追加することでこれを行います。
cp /etc/john/john.conf ./my_john.conf
新しい my_john.conf ファイルを nano で開きます。
nano my_john.conf
ファイルの末尾までスクロールし、以下の設定ブロックを追加します。これは、simple_gen プログラムを実行する MySimple という名前の新しい外部モードを定義します。
[List.External:MySimple]
void generate()
{
exec("./simple_gen");
}
nano を保存して終了します (Ctrl+X、Y、Enter)。
最後に、新しい外部モードをテストしましょう。出力を見るために再び --stdout フラグを使用し、カスタム設定ファイルを参照するために --config フラグを使用します。
john --stdout --external=MySimple --config=./my_john.conf
C プログラムからの正確な出力が表示され、John the Ripper がカスタムスクリプトを正常に実行していることを確認できます。
pass1
pass2
pass3
カスタムパスワード生成ロジックの実装
このステップでは、スクリプトを拡張して、より動的なパスワード生成ロジックを実装します。固定リストの代わりに、ベースワードに数字のシーケンスを続けたパターンに基づいてパスワードを生成します。これは、弱いパスワードでよく見られるパターンです。
C プログラムを修正して、labex0、labex1、labex2 のようにパスワードを生成しましょう。
nano で simple_gen.c ファイルを再度開きます。
nano simple_gen.c
既存のコードを以下に置き換えます。この新しいバージョンでは、for ループを使用して、ベースワード "labex" に 0 から 199 までの数字を追加します。
#include <stdio.h>
int main() {
char *base_word = "labex";
for (int i = 0; i < 200; i++) {
printf("%s%d\n", base_word, i);
}
return 0;
}
nano を保存して終了します。次に、変更を適用するために gcc でプログラムを再コンパイルします。
gcc -o simple_gen simple_gen.c
更新されたジェネレータを --stdout フラグでテストして、新しい出力のサンプルを見てみましょう。
john --stdout --external=MySimple --config=./my_john.conf | head -n 5
出力には、新しいパターンが表示されるはずです。
labex0
labex1
labex2
labex3
labex4
いよいよ本番です。カスタム外部モードを使用して、セットアップ中に準備したパスワードハッシュをクラックします。testuser のパスワードは labex123 です。私たちのスクリプトはこの候補を生成するため、一致が見つかるはずです。
クラッキングプロセスを開始するには、次のコマンドを実行します。--stdout を削除し、ハッシュファイル hashes.txt へのパスを追加したことに注意してください。
john --external=MySimple --config=./my_john.conf ./hashes.txt
John はスクリプトを実行し、候補を生成し、それらをハッシュに対してテストします。パスワードはすぐに検出されるはずです。出力は次のようになります。
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
labex123 (testuser)
1g 0:00:00:00 DONE (2024-05-20 08:30) 100.0g/s 12300p/s 12300c/s 12300C/s labex123..labex130
Use the "--show" option to display all of the cracked passwords reliably
Session completed
クラックされたパスワードを確認するには、--show オプションを使用します。
john --show ./hashes.txt
これにより、ユーザー名の横にクラックされたパスワードが表示されます。
testuser:labex123:1001:1001::/home/testuser:/bin/sh
1 password hash cracked, 0 left
外部モードスクリプトのデバッグ
このステップでは、外部モードスクリプトをデバッグするための基本的なテクニックを学びます。スクリプトが期待どおりに動作しない場合、別のプログラム(John the Ripper)によって実行されているため、診断が難しいことがあります。
一般的で効果的なデバッグ方法の 1 つは、スクリプトからログメッセージを別のファイルに書き出すことです。これにより、実行フローを追跡し、変数値を検査できます。
C プログラムを修正して、debug.log という名前のログファイルに書き込むようにしましょう。nano で simple_gen.c を開きます。
nano simple_gen.c
コードを以下のバージョンに置き換えます。このコードは debug.log を書き込み用に開き、実行中に fprintf を使用してステータスメッセージを書き込みます。
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *log_file = fopen("debug.log", "w");
if (log_file == NULL) {
// Cannot open log file, exit
return 1;
}
fprintf(log_file, "Debug: Script started.\n");
char *base_word = "labex";
for (int i = 0; i < 200; i++) {
printf("%s%d\n", base_word, i);
fprintf(log_file, "Debug: Generated candidate %s%d\n", base_word, i);
}
fprintf(log_file, "Debug: Script finished.\n");
fclose(log_file);
return 0;
}
nano を保存して終了し、プログラムを再コンパイルします。
gcc -o simple_gen simple_gen.c
次に、John the Ripper を再度実行します。パスワード候補を見る必要はないので、標準出力を /dev/null にリダイレクトできます。重要なのは、スクリプトが実行され、ログファイルが作成されることです。
john --stdout --external=MySimple --config=./my_john.conf > /dev/null
コマンドはしばらく実行されて終了します。これで、プロジェクトディレクトリに debug.log ファイルが作成されているはずです。その内容を見てみましょう。
cat debug.log | head -n 5
プログラムに追加したデバッグメッセージが表示されるはずです。
Debug: Script started.
Debug: Generated candidate labex0
Debug: Generated candidate labex1
Debug: Generated candidate labex2
Debug: Generated candidate labex3
このテクニックは、John the Ripper 自身の出力の干渉なしに、不正なループ、間違った変数値、ファイルアクセスエラーなど、ロジックの問題を見つけるのに非常に役立ちます。
特定シナリオへの外部モードの適用
このステップでは、より実践的なシナリオに知識を適用します。ハードコードされたベースワードを使用する代わりに、スクリプトはファイルからベースワードのリストを読み込み、それぞれに対してバリエーションを生成します。これは、はるかに強力で現実的なアプローチです。
まず、いくつかの潜在的なベースワードを含む簡単な単語リストファイル words.txt を作成しましょう。
echo "admin" > words.txt
echo "user" >> words.txt
echo "guest" >> words.txt
次に、C プログラムを修正してこのファイルを読み込むようにします。プログラムは、単語リストのファイル名をコマンドライン引数として受け取る必要があります。nano で simple_gen.c を開きます。
nano simple_gen.c
コードを以下のバージョンに置き換えます。このバージョンは、コマンドラインからファイル名を読み込み、そのファイルを開き、読み込んだ各単語に対して、単語自体、単語に "123" を続けたもの、単語に "2024" を続けたものの 3 つのパスワード候補を生成します。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <wordlist_file>\n", argv[0]);
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
char line[256];
while (fgets(line, sizeof(line), file)) {
// Remove newline character from the end of the line
line[strcspn(line, "\n")] = 0;
// Generate variations for the word
printf("%s\n", line);
printf("%s123\n", line);
printf("%s2024\n", line);
}
fclose(file);
return 0;
}
保存、終了、そしてプログラムを再コンパイルします。
gcc -o simple_gen simple_gen.c
次に、my_john.conf ファイルを更新して、words.txt ファイル名をスクリプトへの引数として渡す必要があります。このために MyAdvanced という新しい外部モードを作成しましょう。nano で my_john.conf を開きます。
nano my_john.conf
ファイルの末尾までスクロールし、この新しいセクションを追加します。exec 関数に "words.txt" が 2 番目のパラメータとして渡されていることに注意してください。
[List.External:MyAdvanced]
void generate()
{
exec("./simple_gen", "words.txt");
}
nano を保存して終了します。最後に、新しい高度な外部モードをテストします。
john --stdout --external=MyAdvanced --config=./my_john.conf
出力は、words.txt ファイル内の単語から生成され、指定されたバリエーションがそれぞれに適用されたパスワード候補のリストになるはずです。
admin
admin123
admin2024
user
user123
user2024
guest
guest123
guest2024
これで、John the Ripper 用の柔軟でファイル駆動型のパスワードジェネレータを正常に作成しました。
まとめ
この実験を完了された皆さん、おめでとうございます!John the Ripper の強力な外部モードを効果的に探求することができました。
この実験では、以下のことを学びました。
- John the Ripper の外部モードの基本的な概念と、外部プログラムを使用してパスワード候補を生成する方法。
- 簡単な C プログラムをパスワードジェネレータとして書き込み、コンパイルし、使用する方法。
john.confファイルでカスタム外部モードを構成する方法。- パターンに基づいた動的なパスワード生成ロジックを実装する方法。
- カスタムモードを使用してパスワードハッシュを正常にクラックする方法。
- ファイルへのログ記録による、外部スクリプトのデバッグのための基本的かつ効果的なテクニック。
- ファイルからベースワードを読み込む、より高度で実用的なスクリプトを作成する方法。
習得したスキルは、特定のターゲットやシナリオに合わせて高度に専門化されたパスワードクラッキングルールを作成するための基盤となります。Python や Perl などの他のスクリプト言語を使用したり、さらに複雑なパスワードのミューテーションや生成ロジックを実装したりすることで、このトピックをさらに探求することができます。


