1
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.

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

Last updated at Posted at 2021-04-21

ヒントに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
XREF
image.png
Printf の引数だ。
Scanf の後,main.checkPassword 関数を呼んでる
main.checkPasswordは

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 に

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]だが,大問題発生

enc[]への代入が,どこにも無い。

今の私の力では Ghidra を正しい方向に導けない
デコンパイルはあきらめ,逆アセ結果を見る
image.png
stack strings の key を構築したあと,main.statictmp_4 のアドレスを取得してる
image.png
image.png
32バイトのデータ

とりあえず,xor してみる

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

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 

image.png
なんか出た。

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

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

1
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
1
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?