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 1 year has passed since last update.

BYUCTF 2023 writeup

Last updated at Posted at 2023-05-25

Chain

You know sometimes you just run out of ideas for challenge descriptions...

ghidraによる解析

main()が見つからなかったので,Decompileを見ながらメイン処理っぽい関数をSymbol TreeのFunctionsから探す.

それっぽい関数(FUN_00010610)が見つかる.
Chain_1.png

FUN_000106a0 Decompileソースコード
undefined4 FUN_000106a0(void)

{
  size_t sVar1;
  int iVar2;
  int local_1c4;
  uint local_1c0 [45];
  byte abStack_10c [256];
  int local_c;
  
  local_c = 0;
  memset(local_1c0,0,0xb4);
  local_1c0[0] = 0xc2;
  local_1c0[1] = 0x9c;
  local_1c0[2] = 0x65;
  local_1c0[3] = 0x83;
  local_1c0[4] = 0x95;
  local_1c0[5] = 0x66;
  local_1c0[6] = 0xfa;
  local_1c0[7] = 0x15;
  local_1c0[8] = 0x5e;
  local_1c0[9] = 0x58;
  local_1c0[10] = 0x2f;
  local_1c0[11] = 0x23;
  local_1c0[12] = 0xac;
  local_1c0[13] = 0x4f;
  local_1c0[14] = 0xa1;
  local_1c0[15] = 0x4c;
  local_1c0[16] = 0x7d;
  local_1c0[17] = 0x1e;
  local_1c0[18] = 0x69;
  local_1c0[19] = 0x80;
  local_1c0[20] = 0x8c;
  local_1c0[21] = 0x4a;
  local_1c0[22] = 0x26;
  local_1c0[23] = 0x5b;
  local_1c0[24] = 0x5f;
  local_1c0[25] = 0x91;
  local_1c0[26] = 0x30;
  local_1c0[27] = 0xcf;
  local_1c0[28] = 0xc0;
  local_1c0[29] = 0x4d;
  local_1c0[30] = 0x97;
  local_1c0[31] = 0x9b;
  local_1c0[32] = 0xba;
  local_1c0[33] = 0x20;
  local_1c0[34] = 0x77;
  local_1c0[35] = 0x4c;
  local_1c0[36] = 0xf5;
  local_1c0[37] = 0xef;
  local_1c0[38] = 0x97;
  local_1c0[39] = 0x96;
  local_1c0[40] = 0x31;
  local_1c0[41] = 0x30;
  local_1c0[42] = 0x8c;
  local_1c0[43] = 0xe2;
  puts("Password? ");
  fgets((char *)abStack_10c,0xff,stdin);
  sVar1 = strlen((char *)abStack_10c);
  if (sVar1 == 0x2d) {
    for (local_1c4 = 0; local_1c4 < 0x2c; local_1c4 = local_1c4 + 1) {
      if ((uint)((byte)FUN_000105ac[*(int *)(&DAT_00021040 + local_1c4 * 4)] ^
                abStack_10c[local_1c4]) != (local_1c0[local_1c4] & 0xff)) {
        iVar2 = printf("Wrong!");
        goto LAB_00010914;
      }
    }
    iVar2 = puts("Correct!");
  }
  else {
    iVar2 = puts("Wrong!");
  }
LAB_00010914:
  if (local_c != 0) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail(iVar2,local_c,0);
  }
  return 0;
}

入力abStack_10cがforループ中のif条件を満たし続ければ"Correct!"を表示するので,正しい入力自体がflagになりそう.

  • if(sVar1 == 0x2d)
    入力長は45文字

  • local_1c4 = 0; local_1c4 < 0x2c; local_1c4 = local_1c4 + 1
    ループ変数local_1c4をインクリメント

  • if((uint)((byte)FUN_000105ac[*(int *)(&DAT_00021040 + local_1c4 * 4)] ^ abStack_10c[local_1c4]) != (local_1c0[local_1c4] & 0xff))
    変数を整理すると,

    • FUN_000105ac 関数
    • DAT_00021040 配列   #別箇所で定義
      アセンブラコードの一部
      Chain_3.png
    • local_1c0 配列(FUN_00010610 の最初の方で初期化)

    入力とXORする値について,

    • (&DAT_00021040 + local_1c4 * 4)
      配列DAT_00021040の先頭アドレスにループ変数local_1c4*4(配列がint型配列のため*4)を加算
      →出力はポインタ
    • (int *)(&DAT_00021040 + local_1c4 * 4)
      上記で出たポインタをint型ポインタ(int *)にキャスト
    • *(int *)(&DAT_00021040 + local_1c4 * 4)
      上記で出たポインタが指すアドレスに格納されている値を取得
    • (byte)FUN_000105ac[*(int *)(&DAT_00021040 + local_1c4 * 4)]
      関数に[]?
      結論を述べると,関数FUN_000105acのアドレス+配列DAT_00021040のlocal_1c4番目の要素の値が指すアドレスから1バイト分読みとった値になる.
      読み取ってくる値は関数FUN_000105acに記載されているアセンブラ命令に対応するマシン語の一部.

    (byte)FUN_000105ac[*(int *)(&DAT_00021040 + local_1c4 * 4)]に該当するアセンブリコードの詳細は以下

アセンブリコード詳細

Chain_4.png

[レジスタ]はレジスタが指すアドレスに格納されている値を取得.

ldr r3,[PTR_PTR_FUN_0001094c]

PTR_PTR_FUN_0001094cFUN_000105ac(イメージできなかった関数)を指すポインタのポインタ.
[]より,r3FUN_000105acを指すアドレスがロードされる.

ldr r3,[r3,#0x0]

1行目を踏まえると,r3FUN_000105acの先頭アドレス

ldr r1,[PTR_DAT_00010950]

PTR_DAT_00010950DAT_00021040(別箇所で定義されていた配列)を指すポインタ.
よって,r1DAT_00021040の先頭アドレス

ldr r2,[r11,#local_1c4]

[r11,#local_1c4]には事前に0が格納されているため,r20

ldr r2,[r1,r2,lsl #offset DAT_00021040]

[r1, r2, lsl #offset DAT_00021040]r1+(r2<<#offset)のアドレスに格納されている値をロードしてくる.
r1=DAT_00021040の先頭アドレス, r2=0より,ここでは配列DAT_00021040の最初の要素(0x0E)になる.

add r3,r3,r2
ldrb r3,[r3,#0x0]

r3=関数FUN_000105acのアドレス, r2=0x0Eより,関数がマップされている先頭アドレス+0x0Eのアドレスから1バイトロードしている.(ここがDecompileの関数名[]の処理と推測)
FUN_000105ac付近のアセンブリコードは以下
Chain_5.png
[000105ac+0x0E=000105ba]の値は0xa0(画像赤枠)
0xa0local_1c0[local_1c4]のXORを計算すると(1ループ目と仮定してlocal_1c4=0),0xa0 ^ 0xc2 = 0x62
asciiコードだとbになり,byuctfの頭文字.

解答用ソースコード

ソースコード
#!/usr/bin/env python3

local_1c0 = [0xc2, 0x9c, 0x65, 0x83, 0x95, 0x66, 0xfa, 0x15, 0x5e, 0x58, 0x2f, 0x23, 0xac, 0x4f, 0xa1, 0x4c, 0x7d, 0x1e, 0x69, 0x80, 0x8c, 0x4a, 0x26, 0x5b, 0x5f, 0x91, 0x30, 0xcf, 0xc0, 0x4d, 0x97, 0x9b, 0xba, 0x20, 0x77, 0x4c, 0xf5, 0xef, 0x97, 0x96, 0x31, 0x30, 0x8c, 0xe2]
  # 配列 local_1c0
DAT_00021040 = [0x0E, 0x03, 0x1C, 0x13, 0x17, 0x21, 0x12, 0x04, 0x27, 0x09, 0x0D, 0x22, 0x1E, 0x15, 0x0B, 0x24, 0x1D, 0x0A, 0x18, 0x2B, 0x19, 0x00, 0x1B, 0x2A, 0x08, 0x1F, 0x20, 0x25, 0x02, 0x1A, 0x0C, 0x29, 0x07, 0x05, 0x11, 0x28, 0x14, 0x16, 0x23, 0x0F, 0x01, 0x10, 0x2C, 0x06, 0x26]
  # 配列 DAT_00021040(4バイト単位で1バイト分しか値が格納されていないため,非ゼロの値を抽出)
FUN_000105ac = [0x24, 0x00, 0x9f, 0xe5, 0x24, 0x10, 0x9f, 0xe5, 0x00, 0x30, 0x41, 0xe0, 0xa3, 0x1f, 0xa0, 0xe1, 0x43, 0x11, 0x81, 0xe0, 0xc1, 0x10, 0xb0, 0xe1, 0x1e, 0xff, 0x2f, 0x01, 0x10, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x53, 0xe3, 0x1e, 0xff, 0x2f, 0x01, 0x13, 0xff, 0x2f, 0xe1, 0xf8, 0x10, 0x02, 0x00, 0xf8, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00]
  # 関数 FUN_000105acの先頭から格納されているマシン語16進表記を適当な分とってくる.

for i in range(44):
    print(chr(FUN_000105ac[DAT_00021040[i]]^local_1c0[i]), end="")

print("")

flag

byuctf{1_h0p3_ARM_wasn't_t00_b4d_0f_4_tw1st}

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?