問題概要
配布された obfuscator.c(難読化ツール)と data.h(難読化済みデータ)からフラグを取り出すことが目標です。

flag obfuscation - AlpacaHack
The flag checker has been obfuscated!
前提知識
IPv6アドレスとは?
IPv6は 2001:db8::1 のようなコロン区切りの16進数で表現されるネットワークアドレスです。
実体は 128ビット(= 16バイト) の数値です。
つまり「16バイトのデータ」は何でもIPv6アドレスとして表現できます。 この問題では、この性質を使ってバイナリデータを隠しています。
配布ファイルの確認
| ファイル | 内容 |
|---|---|
obfuscator.c | バイナリをIPv6アドレスに変換するCのソースコード |
data.h | 変換済みのIPv6アドレス一覧(2464個) |
data.h の中身はこのような形式です:
char *ipv6_data[] = {
"4d5a:9000:300:0:400:0:ffff:0",
"b800::4000:0:0:0",
"::",
...
};
int ipv6_count = 2464;
難読化の仕組みを読み解く
obfuscator.c のポイントとなる処理は以下の部分です:
for (int i = 0; i < size; i += 16)
{
unsigned char chunk[16] = {0}; // 16バイトのバッファを用意
memcpy(chunk, buf + i, ...); // ファイルから16バイト読み込む
inet_ntop(AF_INET6, chunk, ipv6, sizeof(ipv6)); // IPv6文字列に変換
printf("\"%s\",\n", ipv6); // 出力
}
流れ:
- 元のバイナリファイルを 16バイトずつ 切り出す
inet_ntop(AF_NET6, ...)関数で IPv6アドレス文字列に変換 する- C言語の配列として出力する
解法
Step 1:逆変換スクリプトを作る
難読化の逆、つまり「IPv6アドレス → 16バイト」に変換すれば元のバイナリが復元できます。
Pythonの ipaddress モジュールを使うと簡単に実現できます。
import ipaddress
import re
# data.h を読み込む
with open("data.h", "r") as f:
content = f.read()
# " " で囲まれたIPv6アドレスをすべて抽出
addresses = re.findall(r'"([^"]+)"', content)
buf = bytearray()
for addr in addresses:
# IPv6アドレス → 16バイトに変換して結合
buf += ipaddress.IPv6Address(addr).packed
# 元のバイナリとして保存
with open("output.bin", "wb") as f:
f.write(buf)
実行すると output.bin が生成されます
Step 2:復元したバイナリを調べる
復元したファイルの先頭2バイトを確認すると
$ file output.bin
output.bin: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
Windowsの実行ファイルということがわかります
まずフラグっぽい文字列を検索します:
$ strings output.bin | grep -i alpaca -A 10
断片的に以下のような文字列が見つかります:
Alpaca{iH
D$ H
pv6_obfuH
scation_H
T$(H
can_evadH
D$0H
e_signatH
T$8H
D$Hure}
フラグのフォーマット Alpaca{...} であることが確認できます。ただし文字列がバラバラに見えるため、バイナリをより詳しく解析する必要があります。
Step 3:バイナリ内でのフラグ構築方法を特定する
Decompiler Explorerででコンパイルしてみます
BinaryNinjaでAlpacaと検索するとフラグが出現しました。 https://dogbolt.org/



コメント