CpawCTF level3 Q23.[Reversing]またやらかした!をクリアした
はじめに
最近、cpawCTFに挑戦しています。今回から、挑戦した問題の解説記事を書いていこうと思います。
今回は、Level 3 の「rev200」という実行ファイルを解析する問題に挑戦しました。
解析開始
まずは file コマンドを使用して、rev200 の情報を確認します。
$ file rev200
実行結果は以下の通りです。
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=e87140105d6b5c8ea9b0193380ab3b79bfdcd85b, not stripped
出力結果から、このファイルは 32bit の ELF 実行ファイルであり、not stripped であることが分かります。
not stripped とは、シンボル情報が削除されていない状態を指します。そのため、関数名などの情報が残っており、Ghidra などのリバースエンジニアリングツールで解析しやすくなっています。
Ghidraで静的解析を行う

まずは Ghidra にファイルを読み込み、main 関数を確認します。
逆コンパイル結果は以下のようになっていました。
undefined4 main(void)
{
int iVar1;
uint *puVar2;
int local_84;
uint local_7c [28];
local_7c[0] = 0x7a;
local_7c[1] = 0x69;
local_7c[2] = 0x78;
local_7c[3] = 0x6e;
local_7c[4] = 0x62;
local_7c[5] = 0x6f;
local_7c[6] = 0x7c;
local_7c[7] = 0x6b;
local_7c[8] = 0x77;
local_7c[9] = 0x78;
local_7c[10] = 0x74;
local_7c[0xb] = 0x38;
local_7c[0xc] = 0x38;
local_7c[0xd] = 100;
puVar2 = local_7c + 0xe;
for (iVar1 = 0xe; iVar1 != 0; iVar1 = iVar1 + -1) {
*puVar2 = 0;
puVar2 = puVar2 + 1;
}
for (local_84 = 0; local_84 < 0xe; local_84 = local_84 + 1) {
local_7c[local_84 + 0xe] = local_7c[local_84] ^ 0x19;
}
return 0;
}
コードを見ると、配列 local_7c に文字コードと思われる値を格納し、それぞれに対して 0x19 との XOR 演算を行っています。
また、演算結果は local_7c[0xe] 以降に格納されていますが、出力処理が存在しません。
そのため、XOR 演算後の値を表示するために、以下のような printf を追加します。
printf("%c",local_7c[local_84 + 0xe]);
最終的に、XOR を実行している for ループ内で結果を出力するように修正し、プログラムを実行するとフラグを確認することができました。
まとめ
今回の問題では、Ghidra を用いて静的解析を行い、プログラムが文字列に対して XOR 演算を行っていることを確認しました。
CTF の Reversing 問題では、このように文字列のエンコードや簡単な暗号化処理が使われることが多いため、XOR 演算はぜひ覚えておきたいテクニックの一つです。
比較的シンプルな問題でしたが、Ghidra の基本的な使い方や逆コンパイル結果の読み方を学ぶ良い練習になりました。
Discussion