ksnctf Riddle Writeup

ksnctf の Riddle 200 points の writeup 

https://ksnctf.sweetduet.info/problem/11

まず英語のなぞなぞに答える
１問目
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!
先頭だけ大文字だ

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

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

最後の問題
What is the flag?

ここからデバッガ出動
まず入力文字の長さチェックのところ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/0dee185d-d631-f3e0-eaeb-93ca2954eb16.png)

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

IDA で xor をさがしてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/74e5cf11-9de1-7e58-fcd5-d7a3b7df4707.png)

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

デバッガで追ってみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/91e7a33c-6635-0854-6a2d-0faf63778139.png)
スタックの Human の H (0x48) と 0xF9 を xor してる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/7ad8deaa-9011-dd48-1991-28d3fdb2f0c0.png)
xorの結果スタックの H (0x48) が 0xB1 に変化してる

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

IDA で B1C6 を検索してみる
ない
IDA で C6B1 を検索してみる
あった（Ghidraだと検索時にエンディアンを指定できるのに！）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/952c534e-eaff-9e9c-d8e9-257ea4c2a8ad.png)
近くにファイナルアンサーもいる？
いた。ちょうど21文字
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/87208ef2-a4e4-014a-0f50-c1750836d620.png)
xor のかたわれはどこ？

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

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

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

```c
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かな？

https://yasulib.hatenablog.jp/entry/20180127/1517041821

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

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

```python
# 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/d724e6d0-ff38-d008-ae22-faa3d15b2b02.png)