Codefest CTF 2019 Writeup

この大会は2019/8/24 23:30(JST)~2019/8/25 15:30(JST)に開催されました。
今回は個人で参戦。結果は1000点で319チーム中38位でした。
解けた問題をWriteupとして書いておきます。

Image Corruption (Max Score: 100)

開けないbmpが添付されている。バイナリエディタで見てみる。
f:id:satou-y:20190831075142p:plain
matrixという文字がたくさん入っているので、matrixとXORしてみる。

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

key = 'matrix'

flag = ''
for i in range(len(enc)):
    code = ord(enc[i]) ^ ord(key[i%len(key)])
    flag += chr(code)

with open('flag.bmp', 'wb') as f:
    f.write(flag)

フラグが書かれたbmpファイルになった。
f:id:satou-y:20190831075423j:plain

CodefestCTF{f1l35_h4v3_m461c_by735}

Mail capture (Max Score: 100)

添付ファイルにはこう書いてある。

begin 664 flag_encoded
E0V]D969E<W1#5$9[-V@Q-5\Q-5\T7V,P,#%?,VYC,&0Q;CE]"@``
`
end

uuencodeとすぐにわかったので、uudecodeする。

with open('encoded_file', 'r') as f:
    enc = f.read()

flag = enc.decode('uu')
print flag
CodefestCTF{7h15_15_4_c001_3nc0d1n9}

Weird encoding (Max Score: 200)

添付ファイルにはこう書いてある。

0x85+1x1+0x14
0x7+1x1+0x7+1x1+0x9+1x2+0x3+1x4+0x3+1x1+0x6+1x5+0x1+1x1+0x2+1x1+0x1+1x2+0x13+1x2+0x3+1x1+0x8+1x1+0x5+1x2+0x8
0x1+1x5+0x18+1x3+0x3+1x1+0x16+1x2+0x1+1x1+0x5+1x2+0x2+1x1+0x3+1x1+0x4+1x2+0x3+1x3+0x3+1x1+0x2+1x2+0x4+1x3+0x8
0x3+1x1+0x7+1x1+0x11+1x2+0x1+1x1+0x3+1x5+0x12+1x1+0x2+1x1+0x7+1x1+0x10+1x1+0x3+1x2+0x1+1x1+0x5+1x3+0x4+1x1+0x1+1x2+0x2+1x1+0x4
0x3+1x1+0x3+1x1+0x7+1x2+0x3+1x1+0x2+1x1+0x2+1x1+0x7+1x1+0x11+1x2+0x2+1x2+0x5+1x2+0x10+1x1+0x3+1x1+0x2+1x1+0x3+1x2+0x2+1x1+0x4+1x4+0x7
0x3+1x1+0x3+1x1+0x3+1x1+0x1+1x3+0x10+1x1+0x7+1x1+0x7+1x1+0x3+1x1+0x3+1x1+0x1+1x2+0x2+1x3+0x8+1x5+0x4+1x1+0x3+1x9+0x1+1x3+0x7
0x3+1x1+0x3+1x3+0x1+1x1+0x1+1x4+0x9+1x1+0x6+1x2+0x2+1x1+0x7+1x2+0x3+1x1+0x2+1x1+0x4+1x1+0x10+1x1+0x6+1x1+0x7+1x1+0x7+1x4+0x4
0x5+1x1+0x1+1x1+0x1+1x1+0x1+1x1+0x4+1x2+0x7+1x2+0x3+1x4+0x11+1x1+0x4+1x1+0x2+1x1+0x3+1x2+0x6+1x1+0x3+1x1+0x6+1x1+0x7+1x1+0x1+1x1+0x1+1x5+0x7
0x7+1x1+0x1+1x1+0x1+1x1+0x2+1x3+0x7+1x5+0x16+1x1+0x4+1x1+0x2+1x1+0x1+1x3+0x3+1x6+0x2+1x1+0x2+1x1+0x1+1x5+0x5+1x1+0x2+1x1+0x4+1x1+0x7
0x18+1x5+0x13+1x6+0x27+1x1+0x14+1x1+0x2+1x2+0x2+1x1+0x5+1x1+0x2
0x1+1x1+0x5+1x1+0x4+1x1+0x3+1x1+0x8+1x1+0x8+1x1+0x9+1x1+0x8+1x1+0x5+1x1+0x17+1x1+0x10+1x3+0x9
0x68+1x1+0x11+1x1+0x19

0, 1で何か表示していると推測する。各行0が何個、1が何個ということを示していると、つじつまが合いそう。各行0, 1の合計は100になる。絵に起こしてみる。

def parse(s):
    ret = ''
    elms = s.split('+')
    for e in elms:
        c = e.split('x')[0]
        num = int(e.split('x')[1])
        ret += c * num
    return ret

with open('encoded_img', 'r') as f:
    lines = f.readlines()

for line in lines:
    s = line.rstrip()
    zo = parse(s)
    print zo

実行結果は以下の通り。

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000
0000000100000001000000000110001111000100000011111010010110000000000000110001000000001000001100000000
0111110000000000000000001110001000000000000000011010000011001000100001100011100010011000011100000000
0001000000010000000000011010001111100000000000010010000000100000000001000110100000111000010110010000
0001000100000001100010010010000000100000000000110011000001100000000001000100100011001000011110000000
0001000100010111000000000010000000100000001000100010110011100000000111110000100011111111101110000000
0001000111010111100000000010000001100100000001100010010000100000000001000000100000001000000011110000
0000010101010000110000000110001111000000000001000010010001100000010001000000100000001010111110000000
0000000101010011100000001111100000000000000001000010010111000111111001001011111000001001000010000000
0000000000000000001111100000000000001111110000000000000000000000000001000000000000001001100100000100
0100000100001000100000000100000000100000000010000000010000010000000000000000010000000000111000000000
0000000000000000000000000000000000000000000000000000000000000000000010000000000010000000000000000000

わかりづらいので、文字を置換してみる。

□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■□□□□□□□□□□□□□□
□□□□□□□■□□□□□□□■□□□□□□□□□■■□□□■■■■□□□■□□□□□□■■■■■□■□□■□■■□□□□□□□□□□□□□■■□□□■□□□□□□□□■□□□□□■■□□□□□□□□
□■■■■■□□□□□□□□□□□□□□□□□□■■■□□□■□□□□□□□□□□□□□□□□■■□■□□□□□■■□□■□□□■□□□□■■□□□■■■□□□■□□■■□□□□■■■□□□□□□□□
□□□■□□□□□□□■□□□□□□□□□□□■■□■□□□■■■■■□□□□□□□□□□□□■□□■□□□□□□□■□□□□□□□□□□■□□□■■□■□□□□□■■■□□□□■□■■□□■□□□□
□□□■□□□■□□□□□□□■■□□□■□□■□□■□□□□□□□■□□□□□□□□□□□■■□□■■□□□□□■■□□□□□□□□□□■□□□■□□■□□□■■□□■□□□□■■■■□□□□□□□
□□□■□□□■□□□■□■■■□□□□□□□□□□■□□□□□□□■□□□□□□□■□□□■□□□■□■■□□■■■□□□□□□□□■■■■■□□□□■□□□■■■■■■■■■□■■■□□□□□□□
□□□■□□□■■■□■□■■■■□□□□□□□□□■□□□□□□■■□□■□□□□□□□■■□□□■□□■□□□□■□□□□□□□□□□■□□□□□□■□□□□□□□■□□□□□□□■■■■□□□□
□□□□□■□■□■□■□□□□■■□□□□□□□■■□□□■■■■□□□□□□□□□□□■□□□□■□□■□□□■■□□□□□□■□□□■□□□□□□■□□□□□□□■□■□■■■■■□□□□□□□
□□□□□□□■□■□■□□■■■□□□□□□□■■■■■□□□□□□□□□□□□□□□□■□□□□■□□■□■■■□□□■■■■■■□□■□□■□■■■■■□□□□□■□□■□□□□■□□□□□□□
□□□□□□□□□□□□□□□□□□■■■■■□□□□□□□□□□□□□■■■■■■□□□□□□□□□□□□□□□□□□□□□□□□□□□■□□□□□□□□□□□□□□■□□■■□□■□□□□□■□□
□■□□□□□■□□□□■□□□■□□□□□□□□■□□□□□□□□■□□□□□□□□□■□□□□□□□□■□□□□□■□□□□□□□□□□□□□□□□□■□□□□□□□□□□■■■□□□□□□□□□
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■□□□□□□□□□□□■□□□□□□□□□□□□□□□□□□□

フラグのASCIIアートのような感じになった。

CodefestCTF{This_15_7h3_f14g}

Linux RE 2 (Max Score: 500)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  size_t sVar1;
  long in_FS_OFFSET;
  char local_78;
  char local_77;
  char local_76;
  char local_75;
  char local_74;
  char local_73;
  char local_72;
  char local_71;
  char local_70;
  char local_6f;
  byte local_6e;
  char local_6d;
  byte local_6c;
  char local_6b;
  byte local_6a;
  char local_69;
  char local_68;
  byte local_67;
  char local_66;
  byte local_65;
  char local_64;
  byte local_63;
  char local_62;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  __isoc99_scanf(&DAT_00400a88,&local_78);
  sVar1 = strlen(&local_78);
  if (sVar1 == 0x17) {
    if (local_74 == 'l') {
      if ((int)local_75 + 1 == (int)local_72) {
        if ((int)local_73 + 1 == (int)local_71) {
          if (local_71 == 'e') {
            if (local_75 == 'u') {
              if (local_76 == 'o') {
                if (local_78 == 's') {
                  if (local_77 == 'h') {
                    if (local_70 == '_') {
                      if ((int)(char)local_6c + 1 == (int)local_6d) {
                        if ((int)(char)local_6e + 2 == (int)local_6f) {
                          if ((local_6c ^ local_6e) == 0x17) {
                            if (local_6c == 100) {
                              if (local_6b == '_') {
                                if ((int)(char)local_67 + 8 == (int)local_68) {
                                  if ((int)local_69 + -2 == (int)local_68) {
                                    if ((local_67 ^ local_6a) == 0x16) {
                                      if (local_68 == 'm') {
                                        if (local_66 == '_') {
                                          if ((int)local_62 + 3 == (int)local_64) {
                                            if ((int)local_64 + 0x10 == (int)(char)local_63 + 0x10)
                                            {
                                              if ((local_65 ^ local_63) == 0x1b) {
                                                if (local_62 == 'l') {
                                                  puts("Congratulations! Correct password!");
                                                }
                                                else {
                                                  puts("Sorry! Wrong password!");
                                                }
                                              }
                                              else {
                                                puts("Sorry! Wrong password!");
                                              }
                                            }
                                            else {
                                              puts("Sorry! Wrong password!");
                                            }
                                          }
                                          else {
                                            puts("Sorry! Wrong password!");
                                          }
                                        }
                                        else {
                                          puts("Sorry! Wrong password!");
                                        }
                                      }
                                      else {
                                        puts("Sorry! Wrong password!");
                                      }
                                    }
                                    else {
                                      puts("Sorry! Wrong password!");
                                    }
                                  }
                                  else {
                                    puts("Sorry! Wrong password!");
                                  }
                                }
                                else {
                                  puts("Sorry! Wrong password!");
                                }
                              }
                              else {
                                puts("Sorry! Wrong password!");
                              }
                            }
                            else {
                              puts("Sorry! Wrong password!");
                            }
                          }
                          else {
                            puts("Sorry! Wrong password!");
                          }
                        }
                        else {
                          puts("Sorry! Wrong password!");
                        }
                      }
                      else {
                        puts("Sorry! Wrong password!");
                      }
                    }
                    else {
                      puts("Sorry! Wrong password!");
                    }
                  }
                  else {
                    puts("Sorry! Wrong password!");
                  }
                }
                else {
                  puts("Sorry! Wrong password!");
                }
              }
              else {
                puts("Sorry! Wrong password!");
              }
            }
            else {
              puts("Sorry! Wrong password!");
            }
          }
          else {
            puts("Sorry! Wrong password!");
          }
        }
        else {
          puts("Sorry! Wrong password!");
        }
      }
      else {
        puts("Sorry! Wrong password!");
      }
    }
    else {
      puts("Sorry! Wrong password!");
    }
  }
  else {
    puts("Sorry! Wrong password!");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;

ここから整理しながら条件を見ていく。

長さ0x17 = 23
local_75 + 1 == (int)local_72
(int)local_73 + 1 == (int)local_71
(int)(char)local_6c + 1 == (int)local_6d
(int)(char)local_6e + 2 == (int)local_6f
(local_6c ^ local_6e) == 0x17
(int)(char)local_67 + 8 == (int)local_68
(int)local_69 + -2 == (int)local_68
(local_67 ^ local_6a) == 0x16
(int)local_62 + 3 == (int)local_64
int)local_64 + 0x10 == (int)(char)local_63 + 0x10
(local_65 ^ local_63) == 0x1b

local_62 = 'l'
local_63 = 'o'
local_64 = 'o'
local_65 = 't'
local_66 = '_'
local_67 = 'e'
local_68 = 'm'
local_69 = 'o'
local_6a = 's'
local_6b = '_'
local_6c = 'd'
local_6d = 'e'
local_6e = 's'
local_6f = 'u'
local_70 = '_'
local_71 = 'e'
local_72 = 'v'
local_73 = 'd'
local_74 = 'l'
local_75 = 'u'
local_76 = 'o'
local_77 = 'h'
local_78 = 's'

あとは下から並べると、フラグになる。

CodefestCTF{shouldve_used_some_tool}

Feedback - Codefest'19 (Max Score: 100)

アンケートに答えたら、フラグが表示された。

CodefestCTF{Th4nk3_f0r_pl4ying}