picoCTF gogo を Ghidra で静的解析しようとしたが。。。

ヒントにGhidraでって書いてたので，喜んでチャレンジしたが，誤った道に進んだGhidraちゃんを正しい道に導くことができなかった。この悔しさは忘れない。いつかリベンジする。

picoCTF
picoGym Practice Challenges
gogo
Category: Reverse Engineering
Description:
Hmmm this is a weird file... enter_password. There is a instance of the service running at mercury.picoctf.net:48728.
Hints:
use go tool objdump or ghidra


Solution:

ncしてみる。

```
$ nc mercury.picoctf.net 48728
Enter Password:
```

Ghidra で文字列 Enter Password: を検索する。
あった。でも末尾が0x00じゃないのでstringに変換できない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/00bd63be-5107-5379-d5db-4add7b806b48.png)
XREF
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/1af6464c-585a-c671-b3a1-27ed45c298ab.png)
Printf の引数だ。
Scanf の後，main.checkPassword 関数を呼んでる
main.checkPasswordは

```c:main.checkPassword
void main.checkPassword(int param_1,uint param_2,undefined param_3)

{
  uint *puVar1;
  uint uVar2;
  int iVar3;
  int *in_GS_OFFSET;
  undefined4 local_40;
  undefined4 local_3c;
  undefined4 local_38;
  undefined4 local_34;
  undefined4 local_30;
  undefined4 local_2c;
  undefined4 local_28;
  undefined4 local_24;
  byte local_20 [28];
  undefined4 uStack4;
  
  puVar1 = (uint *)(*(int *)(*in_GS_OFFSET + -4) + 8);
  if (register0x00000010 < (undefined *)*puVar1 ||
      (undefined *)register0x00000010 == (undefined *)*puVar1) {
    uStack4 = 0x80d4b72;
    runtime.morestack_noctxt();
    main.checkPassword();
    return;
  }
  if ((int)param_2 < 0x20) {
    os.Exit(0);
  }
  FUN_08090b18();
  local_40 = 0x38313638;
  local_3c = 0x31663633;
  local_38 = 0x64336533;
  local_34 = 0x64373236;
  local_30 = 0x37336166;
  local_2c = 0x62646235;
  local_28 = 0x39383338;
  local_24 = 0x65343132;
  FUN_08090fe0();
  uVar2 = 0;
  iVar3 = 0;
  while( true ) {
    if (0x1f < (int)uVar2) {
      if (iVar3 == 0x20) {
        return;
      }
      return;
    }
    if ((param_2 <= uVar2) || (0x1f < uVar2)) break;
    if ((*(byte *)(param_1 + uVar2) ^ *(byte *)((int)&local_40 + uVar2)) == local_20[uVar2]) {
      iVar3 = iVar3 + 1;
    }
    uVar2 = uVar2 + 1;
  }
  runtime.panicindex();
  do {
    invalidInstructionException();
  } while( true );
}
```

結構，ぐちゃぐちゃ

型
local_40 の型を byte[32] に
local_20 の型を byte[32] に

変数名
local_40 を key に
local_20 を enc に
uVar2 を i に
iVar2 を j に

```c:main.checkPassword
void main.checkPassword(int param_1,uint param_2,undefined param_3)

{
  uint *puVar1;
  uint i;
  int j;
  int *in_GS_OFFSET;
  byte key [32];
  byte enc [32];
  
  puVar1 = (uint *)(*(int *)(*in_GS_OFFSET + -4) + 8);
  if (register0x00000010 < (undefined *)*puVar1 ||
      (undefined *)register0x00000010 == (undefined *)*puVar1) {
    enc._28_4_ = 0x80d4b72;
    runtime.morestack_noctxt();
    main.checkPassword();
    return;
  }
  if ((int)param_2 < 0x20) {
    os.Exit(0);
  }
  FUN_08090b18();
  key._0_4_ = 0x38313638;
  key._4_4_ = 0x31663633;
  key._8_4_ = 0x64336533;
  key._12_4_ = 0x64373236;
  key._16_4_ = 0x37336166;
  key._20_4_ = 0x62646235;
  key._24_4_ = 0x39383338;
  key._28_4_ = 0x65343132;
  FUN_08090fe0();
  i = 0;
  j = 0;
  while( true ) {
    if (0x1f < (int)i) {
      if (j == 0x20) {
        return;
      }
      return;
    }
    if ((param_2 <= i) || (0x1f < i)) break;
    if ((*(byte *)(param_1 + i) ^ key[i]) == enc[i]) {
      j = j + 1;
    }
    i = i + 1;
  }
  runtime.panicindex();
  do {
    invalidInstructionException();
  } while( true );
}
```

param_1 が入力 文字長32
key も32バイト（stack strings）
param_1[i] ^ key[i] == enc[i]だが，大問題発生

<h3>enc[]への代入が，どこにも無い。</h3>

今の私の力では Ghidra を正しい方向に導けない
デコンパイルはあきらめ，逆アセ結果を見る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/1bb08881-59e0-91e8-2025-4fee1e8d52ee.png)
stack strings の key を構築したあと，main.statictmp_4 のアドレスを取得してる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/fca20512-d93c-4d53-b7b4-692e4efc5909.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/b3b6221b-94d7-cda9-9d72-2132326516f9.png)
32バイトのデータ

とりあえず，xor してみる

```python:solver.py
def dword_parse(value):
    return([(value & 0x000000ff) / 0x1,(value & 0x0000ff00) / 0x100,(value & 0x00ff0000) / 0x10000,(value & 0xff000000) / 0x1000000])

key=[]
addr = toAddr(0x080d4ab1)
inst = getInstructionAt(addr)
i = 0
while i < 8:
    key.extend(dword_parse(inst.getOpObjects(1)[0].getValue()))
    inst = inst.getNext()
    i = i + 1
print(key)
print("key="+''.join(map(chr,key)))


enc = getBytes(toAddr(0x0810fe00),32)
print(enc)
print("enc="+''.join(map(chr,enc)))


ans=[]
i = 0
while i < 32:
    ans.append(enc[i] ^ key[i])
    i = i + 1
print(ans)
print("ans="+''.join(map(chr,ans)))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/296c664d-f2ad-4e3b-b309-86f4c961d579.png)

key=861836f13e3d627dfa375bdb8389214e
ans=reverseengineericanbarelyforward

ncに戻ってみる

```
$ nc mercury.picoctf.net 48728
Enter Password: reverseengineericanbarelyforward
=========================================
This challenge is interrupted by psociety
What is the unhashed key?
```

進展した。
今度はkeyをunhashしろって。
これをかな？
861836f13e3d627dfa375bdb8389214e　

https://crackstation.net/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/634ab0e6-eba0-a578-fdf6-59f25f4aa44e.png)
なんか出た。

```
$ nc mercury.picoctf.net 48728
Enter Password: reverseengineericanbarelyforward
=========================================
This challenge is interrupted by psociety
What is the unhashed key?
goldfish
Flag is:  picoCTF{
```

ビンゴ
でもうれしくない。