0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ksnctf Riddle Writeup

Last updated at Posted at 2021-03-01

ksnctf の Riddle 200 points の writeup

まず英語のなぞなぞに答える
1問目
Which creature in the morning goes on four feet, at noon on two, and in the evening upon three?
human --> Wrong...
HUMAN --> Wrong...
Human --> Correct!
先頭だけ大文字だ

2問目
What is the largest island in the world?
Greenland --> Correct!

3問目
Answer to the Ultimate Question of Life, The Universe, and Everything.
42 --> Correct!

最後の問題
What is the flag?

ここからデバッガ出動
まず入力文字の長さチェックのところ
image.png

正解の長さは 0x15 = 21文字
でもstringsでは21文字のデータは発見できない

IDA で xor をさがしてみる
image.png

怪しい xor を発見
.text:00401963 sub_4017D0 xor [eax+esi], cl

デバッガで追ってみる
image.png
スタックの Human の H (0x48) と 0xF9 を xor してる
image.png
xorの結果スタックの H (0x48) が 0xB1 に変化してる

続けると
H=0x48 ^ 0xF9 --> 0xB1
u=0x75 ^ 0xB3 --> 0xC6

IDA で B1C6 を検索してみる
ない
IDA で C6B1 を検索してみる
あった(Ghidraだと検索時にエンディアンを指定できるのに!)
image.png
近くにファイナルアンサーもいる?
いた。ちょうど21文字
image.png
xor のかたわれはどこ?

IDA で F9B3 を検索してみる
ない
IDA で B3F9 を検索してみる
ない

ん? そう簡単にはいかないか?

Ghidra でデコンパイルしてみる

void __cdecl FUN_004017d0(void *p_input_str,int str_len)
{
  char cVar1;
  uint k;
  int i;
  byte x;
  byte bVar2;
  uint j;
  undefined tmp;
  
  i = 0;
  do {
    (&S)[i] = (char)i;
    i = i + 1;
  } while (i < 0x100);
  x = 0;
  k = 0;
  do {
    j = k & 0x8000000f;
    if ((int)j < 0) {
      j = (j - 1 | 0xfffffff0) + 1;
    }
    x = x + "M6eMYngDGFbYE9HQ"[j] + (&S)[k];
    tmp = (&S)[x];
    (&S)[x] = (&S)[k];
    j = k + 1 & 0x8000000f;
    (&S)[k] = tmp;
    if ((int)j < 0) {
      j = (j - 1 | 0xfffffff0) + 1;
    }
    x = x + "M6eMYngDGFbYE9HQ"[j] + (&DAT_00405579)[k];
    tmp = (&S)[x];
    (&S)[x] = (&DAT_00405579)[k];
    j = k + 2 & 0x8000000f;
    (&DAT_00405579)[k] = tmp;
    if ((int)j < 0) {
      j = (j - 1 | 0xfffffff0) + 1;
    }
    x = x + "M6eMYngDGFbYE9HQ"[j] + (&DAT_0040557a)[k];
    tmp = (&S)[x];
    (&S)[x] = (&DAT_0040557a)[k];
    j = k + 3 & 0x8000000f;
    (&DAT_0040557a)[k] = tmp;
    if ((int)j < 0) {
      j = (j - 1 | 0xfffffff0) + 1;
    }
    x = x + "M6eMYngDGFbYE9HQ"[j] + (&DAT_0040557b)[k];
    tmp = (&S)[x];
    (&S)[x] = (&DAT_0040557b)[k];
    (&DAT_0040557b)[k] = tmp;
    k = k + 4;
  } while ((int)k < 0x100);
  i = 0;
  x = 0;
  bVar2 = 0;
  if (0 < str_len) {
    do {
      x = x + 1;
      k = (uint)x;
      cVar1 = (&S)[k];
      bVar2 = bVar2 + cVar1;
      (&S)[k] = (&S)[bVar2];
      (&S)[bVar2] = cVar1;
      *(byte *)(i + (int)p_input_str) =
           *(byte *)(i + (int)p_input_str) ^ (&S)[(byte)((&S)[k] + cVar1)];
      i = i + 1;
    } while (i < str_len);
  }
  return;
}

RC4かな?

「見えるぞ、私にも敵が見える」

少し乱暴だけど Ghidra で RC4 のソルバー書いてみる

# Key-scheduling algorithm (KSA)
S = []
i = 0
while i < 0x100:
    S.append(i & 0xff)
    i = i + 1

# 00403818 4d 36 65 ...    ds         "M6eMYngDGFbYE9HQ"
key = getBytes(toAddr(0x00403818), 16)
i = 0
j = 0
temp = 0
while i < 0x100:
    j = ord(key.tostring()[ i % len(key) ]) + S[i] + j & 0xff  
    temp = S[i]
    S[i] = S[j]
    S[j] = temp
    i = i + 1

# Pseudo-random generation algorithm (PRGA)
# 0x004051f4 is the address of the encrypted string found by IDA
enc = getBytes(toAddr(0x004051f4),21)
ans = []
i = 0
j = 0
k = 0
while k < 21:
    i = i + 1 & 0xff
    j = j + S[i] & 0xff
    temp = S[i]
    S[i] = S[j]
    S[j] = temp
    ans.append(ord(enc.tostring()[k]) ^ S[ S[i] + S[j] & 0xff])
    k = k + 1

print(''.join(map(chr,ans)))

ビンゴ!
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?