SECCON Beginners CTF 2021 reversing 03 please_not_trace_me を Ghidra で静的解析した。
当日は,RC4 の KSA部分だけを見て,暗号化は RC4 と決めつけ,ソルバーを組んだが,flag に戻らずパニックになった。
(keyが違う?encrypted flagが違う?自分のrc4が違う?rc4以外に見落とした暗号化がある?等々)
復習中,焦らずよく見ると,RC4 と同じ部分は KSA だけで,PRGA 部分は RC4 ではないことがわかった。
作問者の方がそういうところまで狙っていたとしたら,まんまと術中にはまったということになる。
これを糧にしてもっと強くなる。
問題
please_not_trace_me
フラグを復号してくれるのは良いけど,表示してくれない!!
chall
Ghidra初期デコンパイル結果
void main(undefined4 param_1,undefined8 param_2,undefined8 param_3)
{
int local_54;
int local_50;
void *local_48;
long local_40;
long local_38;
undefined8 local_30;
megaInit();
local_30 = 9;
_global_argv = param_2;
_global_argc = param_1;
_global_envp = param_3;
do {
switch(local_30) {
case 0:
local_50 = 2;
local_30 = 0xb;
break;
case 2:
local_30 = _1_main_flag_func_0(local_38,0xffffffffffffffff,0x10,5);
break;
case 5:
if (local_50 == 6) {
local_30 = 0x12;
}
else {
local_30 = 8;
}
break;
case 6:
if (local_40 == 0) {
local_30 = 0;
}
else {
local_30 = 0xb;
}
break;
case 8:
fwrite("prease not trace me...\n",1,0x17,stderr);
/* WARNING: Subroutine does not return */
exit(1);
case 9:
local_54 = 0;
local_30 = 10;
break;
case 10:
switch(local_54) {
case 0:
local_30 = 0x16;
break;
case 1:
local_30 = 0xf;
break;
case 2:
local_30 = 0x13;
break;
case 3:
local_30 = 0x14;
break;
case 4:
local_30 = 0x11;
break;
case 5:
local_30 = 0x15;
break;
default:
local_30 = 0x12;
}
break;
case 0xb:
local_38 = ptrace(PTRACE_TRACEME,0,1,0);
local_30 = 2;
break;
case 0xf:
local_48 = malloc(0x10);
local_30 = 0x12;
break;
case 0x10:
local_50 = local_50 * 3;
local_30 = 5;
break;
case 0x11:
puts("flag decrypted. bye.");
local_30 = 0x12;
break;
case 0x12:
local_54 = local_54 + 1;
local_30 = 10;
break;
case 0x13:
generate_key(local_48);
local_30 = 0x12;
break;
case 0x14:
rc4(e,local_48);
local_30 = 0x12;
break;
case 0x15:
/* WARNING: Subroutine does not return */
exit(0);
case 0x16:
local_50 = 0;
local_40 = ptrace(PTRACE_TRACEME,0,1,0);
local_30 = 6;
}
} while( true );
}
void * rc4(char *param_1,char *param_2)
{
int iVar1;
size_t sVar2;
void *pvVar3;
size_t sVar4;
uint uVar5;
long in_FS_OFFSET;
int local_158;
int local_154;
int local_150;
int local_14c;
byte local_118 [264];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
sVar2 = strlen(param_1);
pvVar3 = malloc((long)(int)sVar2);
sVar4 = strlen(param_2);
local_158 = 0;
while (local_158 < 0x100) {
local_118[local_158] = (byte)local_158;
local_158 = local_158 + 1;
}
local_154 = 0;
local_150 = 0;
while (local_154 < 0x100) {
iVar1 = (int)param_2[local_154 % (int)sVar4] + (uint)local_118[local_154] + local_150;
uVar5 = (uint)(iVar1 >> 0x1f) >> 0x18;
local_150 = (iVar1 + uVar5 & 0xff) - uVar5;
swap(local_118 + local_154,local_118 + local_150,local_118 + local_150);
local_154 = local_154 + 1;
}
local_14c = 0;
while (local_14c < (int)sVar2) {
swap(local_118,local_118,local_118,local_118);
*(byte *)((long)pvVar3 + (long)local_14c) =
param_1[local_14c] ^ local_118[(int)(uint)(byte)(local_118[0] * '\x02')];
local_14c = local_14c + 1;
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return pvVar3;
}
rc4っぽい処理のKey
main() --> generate_key() --> _2_stringEncoder()
void _2_stringEncoder(int param_1,undefined *param_2)
{
if (param_1 == 0) {
*param_2 = 0x6e;
param_2[1] = 0x69;
param_2[2] = 99;
param_2[3] = 0x6b;
param_2[4] = 0x65;
param_2[5] = 0x6c;
param_2[6] = 0x6f;
param_2[7] = 100;
param_2[8] = 0x65;
param_2[9] = 0x6f;
param_2[10] = 0x6e;
param_2[0xb] = 0;
}
return;
}
rc4っぽい処理のEnc
main() --> megaInit() --> e_i$nit()
void e_i$nit(void)
{
e[0] = 0x80;
e[1] = 0x97;
e[2] = 0x85;
e[3] = 0xd7;
e[4] = 0x81;
e[5] = 0x98;
e[6] = 0x87;
e[7] = 0xd2;
e[8] = 0x87;
e[9] = 0xbc;
e[10] = 0x9a;
e[11] = 0xd3;
e[12] = 0x96;
e[13] = 0xbc;
e[14] = 0x87;
e[15] = 0xd0;
e[16] = 0x80;
e[17] = 0x91;
e[18] = 0x9a;
e[19] = 0x93;
e[20] = 0x97;
e[21] = 0xbc;
e[22] = 0x91;
e[23] = 0x80;
e[24] = 0xd7;
e[25] = 0xdc;
e[26] = 0x9e;
return;
}
デコンパイル結果の修正
変数名の修正
変更前 | 変更後 |
---|---|
param_2 | key |
param_1 | enc |
sVar4 | keylength |
sVar2 | enclength |
pvVar2 | flag |
local_118 | S |
local_158 | ix |
local_154 | i |
local_150 | j |
local_14c | k |
void * rc4(char *enc,char *key)
{
int iVar1;
size_t enclength;
void *flag;
size_t keylength;
uint uVar2;
long in_FS_OFFSET;
int ix;
int i;
int j;
int k;
byte S [264];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
enclength = strlen(enc);
flag = malloc((long)(int)enclength);
keylength = strlen(key);
ix = 0;
while (ix < 0x100) {
S[ix] = (byte)ix;
ix = ix + 1;
}
i = 0;
j = 0;
while (i < 0x100) {
iVar1 = (int)key[i % (int)keylength] + (uint)S[i] + j;
uVar2 = (uint)(iVar1 >> 0x1f) >> 0x18;
j = (iVar1 + uVar2 & 0xff) - uVar2;
swap(S + i,S + j,S + j);
i = i + 1;
}
k = 0;
while (k < (int)enclength) {
swap(S,S,S,S);
*(byte *)((long)flag + (long)k) = enc[k] ^ S[(int)(uint)(byte)(S[0] * '\x02')];
k = k + 1;
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return flag;
}
solver ( Ghidra Script )
RC4 algorithm
#
# SECCON Beginners CTF 2021 please_not_trace_me
#
def init_rc4(key):
S = range(256)
j = 0
for i in range(256):
j = (key[i % len(key)] + S[i] + j) & 0xFF
S[i],S[j] = S[j],S[i]
return S
def rc4(enc,S):
'''
x = 0
y = 0
'''
for i in range(len(enc)):
'''
x = (x + 1) & 0xFF
y = (S[x] + y) & 0xFF
S[x],S[y] = S[y],S[x]
enc[i] ^= S[(S[x] + S[y]) & 0xFF]
'''
enc[i] ^= S[S[0] * 2 & 0xFF]
return bytes(enc)
def do_rc4(enc,key):
S = init_rc4(key)
return rc4(enc,S)
# Extract encrypted flag
enc=[]
inst = getInstructionAt(toAddr(0x00101873))
i = 0
while i < 27:
enc.append(inst.getOpObjects(1)[0].getValue())
inst = inst.getNext()
i = i + 1
print("enc")
print(enc)
# Extract Key
key=[]
inst = getInstructionAt(toAddr(0x001014e1))
i = 0
while i < 11:
key.append(inst.getOpObjects(1)[0].getValue())
inst = inst.getNext()
inst = inst.getNext()
inst = inst.getNext()
inst = inst.getNext()
inst = inst.getNext()
inst = inst.getNext()
i = i + 1
print("key")
print(key)
print(''.join(map(chr,key)))
flag = do_rc4(enc,key)
print("flag")
print(flag)
print(''.join(map(chr,flag)))
なんか Ghidra の機嫌が悪くエラーの意味がわからん。(バグかも?)
keyってこれか?