Really Awesome CTF 2021 Writeup

この大会は2021/8/14 4:00(JST)~2021/8/17 4:00(JST)に開催されました。
今回もチームで参戦。結果は2300点で602チーム中88位でした。
自分で解けた問題をWriteupとして書いておきます。

Discord (Miscellaneous 50)

Discordに入り、#generalチャネルのトピックを見ると、フラグが書いてあった。

ractf{so_here_we_are_again}

Triangles (OSINT 100)

画像の場所を地図上で指し示す問題。
画像検索すると、"Palazzo Cosentini"であることがわかる。
36.9233815,14.7276226の位置にあるので、Google Mapの位置と見比べながら位置を指定する。赤丸の位置でSubmitしたら、フラグが通った。
f:id:satou-y:20210825080952p:plain

Lego Car Generator (Pwn / Reversing 350)

Ghidraでデコンパイルする。

bool main(int param_1,undefined8 *param_2)

{
  undefined8 uVar1;
  FILE *pFVar2;
  FILE *pFVar3;
  size_t __size;
  void *__ptr;
  int *piVar4;
  char *pcVar5;
  uint uVar6;
  uint uVar7;
  size_t sVar8;
  long in_FS_OFFSET;
  bool bVar9;
  undefined local_40 [8];
  long local_38;
  
  local_38 = *(long *)(in_FS_OFFSET + 0x28);
  if (param_1 < 3) {
    bVar9 = false;
    fprintf(stderr,"usage: %s <in file> <out file>\n",*param_2);
  }
  else {
    pFVar3 = fopen((char *)param_2[1],"rb");
    pFVar2 = stderr;
    if (pFVar3 == (FILE *)0x0) {
      uVar1 = param_2[1];
      piVar4 = __errno_location();
      pcVar5 = strerror(*piVar4);
      fprintf(pFVar2,"failed to open input file %s: %s\n",uVar1,pcVar5);
      bVar9 = true;
    }
    else {
      fseek(pFVar3,0,2);
      __size = ftell(pFVar3);
      rewind(pFVar3);
      __ptr = malloc(__size);
      fread(__ptr,1,__size,pFVar3);
      fclose(pFVar3);
      uVar7 = rdseed();
      rdseedIsValid();
      printf("Seed: 0x%08X\n",(ulong)uVar7);
      uVar7 = rngInit(local_40,uVar7);
      if (__size != 0) {
        sVar8 = 0;
        uVar6 = 0;
        do {
          if (uVar6 == 0) {
            uVar7 = rngNext32(local_40);
          }
          uVar6 = uVar6 + 1 & 3;
          *(byte *)((long)__ptr + sVar8) = *(byte *)((long)__ptr + sVar8) ^ (byte)(uVar7 >> 0x18);
          sVar8 = sVar8 + 1;
          uVar7 = uVar7 >> 0x18 | uVar7 << 8;
        } while (__size != sVar8);
      }
      pFVar3 = fopen((char *)param_2[2],"wb");
      pFVar2 = stderr;
      bVar9 = pFVar3 == (FILE *)0x0;
      if (bVar9) {
        uVar1 = param_2[2];
        piVar4 = __errno_location();
        pcVar5 = strerror(*piVar4);
        fprintf(pFVar2,"failed to open ouput file %s: %s\n",uVar1,pcVar5);
      }
      else {
        fwrite(__ptr,1,__size,pFVar3);
        fclose(pFVar3);
      }
      free(__ptr);
    }
  }
  if (*(long *)(in_FS_OFFSET + 0x28) == local_38) {
    return bVar9;
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

void rngInit(undefined4 *param_1,undefined4 param_2)

{
  *param_1 = param_2;
  return;
}

void rngNext32(int *param_1)

{
  *param_1 = *param_1 * 0x17433a5b + -0x481e7b5d;
  return;
}

4バイトごとにLCGが走る。4バイトの暗号化のkeyは、LCGで生成された数値を8ビットごとにabcdと定義すると以下のように変わる。

1バイト目:abcd→a
2バイト目:bcda→b
3バイト目:cdab→c
4バイト目:dabc→d

フラグがractf{から始まることを前提に復号する。

def rngNext32(r):
    return (r * 0x17433a5b - 0x481e7b5d) & 0xffffffff

with open('secret', 'rb') as f:
    enc = f.read()

pre_flag = 'ractf{'

rng = 0
for i in range(4):
    rng *= 256
    rng += ord(enc[i]) ^ ord(pre_flag[i])

flag = ''
for i in range(len(enc) / 4 + 1):
    for j in range(4):
        if i * 4 + j < len(enc):
            flag += chr(ord(enc[i*4+j]) ^ ((rng >> (24 - j * 8)) & 0xff))
    rng = rngNext32(rng)

print flag

復号すると以下の文字列になる。

ractf{CL04K_3NGa6ed}sikeyouthoughttheflagwasthislong

フラグは先頭部分で通った。

ractf{CL04K_3NGa6ed}