なんか怪しいファイルと通信記録を捉えました! あれ? ここにあった超重要機密ファイルの名前が変わっているぞ...?
※ 問題のテーマからするとファイルを削除する機能があるはずですが、デバッグのしやすさのためにファイルを削除する機能は外してあります
いかにもなファイルctf4b_super_secret.txt.lock
とこれまたいかにもな実行ファイルransom
、そしてなんらかの通信のキャプチャであるtcpdump.pcap
が渡される。
とりあえずransom
をGhidraで読む。
するとだいたい以下の流れで処理をしていそうだ。
ctf4b_super_secret.txt
を開き内容を読み込むctf4b_super_secret.txt
として出力するとりあえずパケットキャプチャから鍵を取り出す。
鍵はただのソケット通信で送られており暗号化などはされていないため16文字のASCII printableなデータがないかをかたっぱしから探していけば割とすぐ見つかった。
次に暗号化の処理を見ていく。
undefined8 encrypt(char *seed,char *plain,byte *encrypted_size)
{
long in_FS_OFFSET;
byte key [264];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
genkey(seed,key);
enc(key,plain,encrypted_size);
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
undefined8 genkey(char *seed,byte *key)
{
uint uVar1;
size_t seedlen;
int iVar2;
int local_18;
int local_14;
int local_10;
seedlen = strlen(seed);
local_18 = 0;
for (local_14 = 0; local_14 < 0x100; local_14 = local_14 + 1) {
key[local_14] = (byte)local_14;
}
for (local_10 = 0; local_10 < 0x100; local_10 = local_10 + 1) {
iVar2 = (uint)key[local_10] + local_18 + (int)seed[local_10 % (int)seedlen];
uVar1 = (uint)(iVar2 >> 0x1f) >> 0x18;
local_18 = (iVar2 + uVar1 & 0xff) - uVar1;
swap(key + local_10,key + local_18);
}
return 0;
}
undefined8 enc(byte *key,char *plain,byte *encrypted)
{
size_t sVar1;
uint local_24;
uint local_20;
long local_18;
local_24 = 0;
local_20 = 0;
local_18 = 0;
sVar1 = strlen(plain);
for (; (ulong)local_18 < sVar1; local_18 = local_18 + 1) {
local_24 = local_24 + 1 & 0xff;
local_20 = key[(int)local_24] + local_20 & 0xff;
swap(key + (int)local_24,key + (int)local_20);
encrypted[local_18] = plain[local_18] ^ key[(byte)(key[(int)local_20] + key[(int)local_24])];
}
return 0;
}
まず最初に生成した鍵を実際に暗号化に用いる鍵に変換する処理genkey
が行われ、その後実際に暗号化する処理enc
が実行されるという2ステップによって暗号化を行われている。
enc
の中では鍵の順番を入れ替えたりはしているものの基本的にはただのxor暗号なので、暗号化の処理をもう一度行えば平文に戻る。
ということで、暗号化関数をそのままPythonに移植してソルバを仕上げた。
#!/usr/bin/env python3
KEY_SEED = b"rgUAvvyfyApNPEYg"
def genkey(seed, key):
seedlen = len(seed)
local_18 = 0
for i in range(0x100):
key[i] = i & 0xff
for i in range(0x100):
iVar2 = key[i] + local_18 + seed[i % seedlen]
uVar1 = (iVar2 >> 0x1f) >> 0x18
local_18 = (iVar2 + uVar1 & 0xff) - uVar1
key[i], key[local_18] = key[local_18], key[i]
return key
def enc(key, plain, encrypted):
local_24 = 0
local_20 = 0
#local_18 = 0
sVar1 = len(plain)
for local_18 in range(sVar1):
local_24 = local_24 + 1 & 0xff
local_20 = key[local_24] + local_20 & 0xff
key[local_24] ,key[local_20] = key[local_20], key[local_24]
encrypted[local_18] = plain[local_18] ^ key[(key[local_20] + key[local_24]) & 0xff]
return encrypted
def encrypt(seed, plain, encrypted):
key = [0] * 256
key = genkey(seed,key)
enc(key,plain,encrypted)
with open('ctf4b_super_secret.txt.lock', 'r') as f:
locked = f.read()
locked_raw = eval("b'" + locked + "'")
key = genkey(KEY_SEED, [0] * 256)
flag = enc(key, locked_raw, [0] * 256)
print(''.join(map(chr, flag)))
ctf4b{rans0mw4re_1s_v4ry_dan9er0u3_s0_b4_c4refu1}
みなさまランサムウェアには気をつけましょう