[SECCON Beginners CTF 2022] WinTLS

TLSってなんだぁ?

実行ファイルchall.exeが渡される。

GhidraでDefined Stringsを見るといかにもな文字列が2つ見つかる。

  • c4{fAPu8#FHh2+0cyo8$SWJH3a8X
  • tfb%s$T9NvFyroLh@89a9yoC3rPy&3b}

いい感じに繋ぎ合わせたらフラグになりそうな感じがする。いい感じに繋ぐ処理を探すべくそれらの文字列を参照する関数を見るとt1t2がヒットした。
これらはほぼ同じ処理をしている。

void t1(char *param_1)

{
  longlong lVar1;
  char local_118 [260];
  uint local_10;
  int local_c;

  local_118._0_8_ = 0;
  local_118._8_8_ = 0;
  local_118._16_8_ = 0;
  local_118._24_8_ = 0;
  local_118._32_8_ = 0;
  local_118._40_8_ = 0;
  local_118._48_8_ = 0;
  local_118._56_8_ = 0;
  local_118._64_8_ = 0;
  local_118._72_8_ = 0;
  local_118._80_8_ = 0;
  local_118._88_8_ = 0;
  local_118._96_8_ = 0;
  local_118._104_8_ = 0;
  local_118._112_8_ = 0;
  local_118._120_8_ = 0;
  local_118._128_8_ = 0;
  local_118._136_8_ = 0;
  local_118._144_8_ = 0;
  local_118._152_8_ = 0;
  local_118._160_8_ = 0;
  local_118._168_8_ = 0;
  local_118._176_8_ = 0;
  local_118._184_8_ = 0;
  local_118._192_8_ = 0;
  local_118._200_8_ = 0;
  local_118._208_8_ = 0;
  local_118._216_8_ = 0;
  local_118._224_8_ = 0;
  local_118._232_8_ = 0;
  local_118._240_8_ = 0;
  local_118._248_8_ = 0;
  local_c = 0;
  TlsSetValue(TLS,"c4{fAPu8#FHh2+0cyo8$SWJH3a8X");
  for (local_10 = 0; (local_10 < 0x100 && (param_1[(int)local_10] != '\0')); local_10 = local_10 + 1
      ) {
    if (((int)local_10 % 3 == 0) || ((int)local_10 % 5 == 0)) {
      lVar1 = (longlong)local_c;
      local_c = local_c + 1;
      local_118[lVar1] = param_1[(int)local_10];
    }
  }
  local_118[local_c] = '\0';
  check(local_118);
  return;
}

void t2(longlong param_1)

{
  longlong lVar1;
  char local_118 [263];
  char local_11;
  uint local_10;
  int local_c;

  local_c = 0;
  TlsSetValue(TLS,"tfb%s$T9NvFyroLh@89a9yoC3rPy&3b}");
  for (local_10 = 0;
      (local_10 < 0x100 && (local_11 = *(char *)(param_1 + (int)local_10), local_11 != '\0'));
      local_10 = local_10 + 1) {
    if (((int)local_10 % 3 != 0) && ((int)local_10 % 5 != 0)) {
      lVar1 = (longlong)local_c;
      local_c = local_c + 1;
      local_118[lVar1] = local_11;
    }
  }
  local_118[local_c] = '\0';
  check(local_118);
  return;
}

bool check(char *param_1)

{
  int iVar1;
  char *_Str1;

  _Str1 = (char *)TlsGetValue(TLS);
  iVar1 = strncmp(_Str1,param_1,0x100);
  return iVar1 != 0;
}

t1、t2どちらでも、最初にTlsSetValueで謎の文字列をセットした後、t1では添字が3か5で割り切れる場合、t2はそうでない場合にlocal_118に文字を追加し、最後にcheck(local_118)を呼び出している。
checkではTlsGetValueで取得した値と引数を比較した結果をstrncmpしているだけである。

つまり、謎の文字列とt1、t2それぞれの条件で取り出した文字列で比較を行っているだけである。(なおその際にTLSは文字列をやりとりする手段としてだけ用いられている。TLSってなんだぁ?)

フラグを復元するのは簡単で、添字が3か5で割り切れる場合にはt1の文字列、そうでない場合はt2の文字列を順に足していくだけでよい。

#!/usr/bin/env python3
s1 = b"c4{fAPu8#FHh2+0cyo8$SWJH3a8X"
s2 = b"tfb%s$T9NvFyroLh@89a9yoC3rPy&3b}"

flag = ''
i = 0
c1, c2 = 0, 0
while c1 <= len(s1) and c2 <= len(s2):
  if (i % 3 == 0) or (i % 5 == 0):
    flag += chr(s1[c1])
    c1 += 1
  else:
    flag += chr(s2[c2])
    c2 += 1

  i += 1
  print(flag)

ctf4b{f%sAP$uT98Nv#FFHyrh2o+Lh0@8c9yoa98$ySoCW3rJPH3y&a83Xb}