Cyber Security Rumble CTF 2022 Writeup

この大会は2022/10/9 2:00(JST)~2022/10/10 2:00(JST)に開催されました。
今回もチームで参戦。結果は200点で264チーム中163位でした。
自分で解けた問題をWriteupとして書いておきます。

REVMEPLX (rev, bby)

Ghidraでデコンパイルして、各関数を見てみる。

void print_dives(basic_string param_1)

{
  __type _Var1;
  basic_ostream *pbVar2;
  undefined4 in_register_0000003c;
  basic_string *pbVar3;
  long in_FS_OFFSET;
  int local_8c;
  basic_string local_88 [8];
  basic_string local_68 [8];
  basic_string local_48 [10];
  long local_20;
  
  pbVar3 = (basic_string *)CONCAT44(in_register_0000003c,param_1);
  local_20 = *(long *)(in_FS_OFFSET + 0x28);
  std::allocator<char>::allocator();
                    /* try { // try from 0010241a to 0010241e has its CatchHandler @ 00102619 */
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::
  basic_string<std::allocator<char>>
            ((basic_string<char,std::char_traits<char>,std::allocator<char>> *)local_88,"Jeremy",
             (allocator *)&local_8c);
  std::allocator<char>::~allocator((allocator<char> *)&local_8c);
  std::allocator<char>::allocator();
                    /* try { // try from 00102455 to 00102459 has its CatchHandler @ 00102636 */
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::
  basic_string<std::allocator<char>>
            ((basic_string<char,std::char_traits<char>,std::allocator<char>> *)local_68,"Simon",
             (allocator *)&local_8c);
  std::allocator<char>::~allocator((allocator<char> *)&local_8c);
  std::allocator<char>::allocator();
                    /* try { // try from 00102490 to 00102494 has its CatchHandler @ 0010264a */
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::
  basic_string<std::allocator<char>>
            ((basic_string<char,std::char_traits<char>,std::allocator<char>> *)local_48,"Adminiman",
             (allocator *)&local_8c);
  std::allocator<char>::~allocator((allocator<char> *)&local_8c);
  _Var1 = std::operator==(pbVar3,local_68);
  if ((char)_Var1 == '\0') {
    _Var1 = std::operator==(pbVar3,local_48);
    if ((char)_Var1 == '\0') {
      _Var1 = std::operator==(pbVar3,local_88);
      if ((char)_Var1 == '\0') {
        pbVar2 = std::operator<<((basic_ostream *)std::cout,"No diving recore of diver ");
        pbVar2 = std::operator<<(pbVar2,pbVar3);
        std::operator<<(pbVar2," found!\n");
      }
      else {
        std::operator<<((basic_ostream *)std::cout,"Your dive count is: 0\n");
        std::operator<<((basic_ostream *)std::cout,
                        "To show today\'s drydock report, please enter passcode:\n");
        std::basic_istream<char,std::char_traits<char>>::operator>>
                  ((basic_istream<char,std::char_traits<char>> *)std::cin,&local_8c);
        door_lock(local_8c);
      }
    }
    else {
      std::operator<<((basic_ostream *)std::cout,"Welcome instructor!\n");
      std::operator<<((basic_ostream *)std::cout,"Your dive count is: 410\n");
    }
  }
  else {
                    /* try { // try from 001024d2 to 001025e3 has its CatchHandler @ 0010265e */
    std::operator<<((basic_ostream *)std::cout,"Your dive count is: 81\n");
  }
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string
            ((basic_string<char,std::char_traits<char>,std::allocator<char>> *)local_48);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string
            ((basic_string<char,std::char_traits<char>,std::allocator<char>> *)local_68);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string
            ((basic_string<char,std::char_traits<char>,std::allocator<char>> *)local_88);
  if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

void door_lock(int param_1)

{
  basic_ostream *pbVar1;
  
  if (param_1 * 2 >> 8 == 0x539) {
    pbVar1 = std::operator<<((basic_ostream *)std::cout,"CSR{");
    pbVar1 = (basic_ostream *)
             std::basic_ostream<char,std::char_traits<char>>::operator<<
                       ((basic_ostream<char,std::char_traits<char>> *)pbVar1,param_1 % 0x25);
    pbVar1 = std::operator<<(pbVar1,"_submarines_");
    pbVar1 = (basic_ostream *)
             std::basic_ostream<char,std::char_traits<char>>::operator<<
                       ((basic_ostream<char,std::char_traits<char>> *)pbVar1,param_1 * 0x10c + -7);
    pbVar1 = std::operator<<(pbVar1,"_solved_n1c3!}");
    std::basic_ostream<char,std::char_traits<char>>::operator<<
              ((basic_ostream<char,std::char_traits<char>> *)pbVar1,
               std::endl<char,std::char_traits<char>>);
  }
  return;
}

door_lock関数を呼び出すためには、Diver Nameに"Jeremy"を指定する必要がある。さらにフラグを表示させるためには、passcodeにparam_1 * 2 >> 8 == 0x539を満たすparam_1を指定する必要がある。

>>> (0x539 << 8) // 2
171136

つまりpasscodeには"171136"を指定すればよい。

$ ./rev
| >>> REEF RANGERS Dive Panel <<< |
| ------------------------------- |
|    Please provide Diver Name:   |
Jeremy
Your dive count is: 0
To show today's drydock report, please enter passcode:
171136
CSR{11_submarines_45864441_solved_n1c3!}
CSR{11_submarines_45864441_solved_n1c3!}

CRYMEPLX (cry, bby)

フラグと入力文字列で、同じ鍵、nonceでAES-CTR暗号化されるので、以下の計算で復号することができる。

flag = 入力平文 ^ 入力暗号 ^ flag暗号
#!/usr/bin/env python3
import socket
from Crypto.Util.strxor import strxor

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('chall.rumble.host', 2734))

data = recvuntil(s, b'\n').rstrip()
print(data)
enc_flag = bytes.fromhex(data)

pt = 'a' * len(enc_flag)
data = recvuntil(s, b':')
print(data + pt)
s.sendall(pt.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
ct = bytes.fromhex(data)

flag = strxor(strxor(pt.encode(), ct), enc_flag).decode()
print(flag)

実行結果は以下の通り。

c7342f6c143020c957fdf2dec8209e7aff7514072a511b162f
Encrypt this string:aaaaaaaaaaaaaaaaaaaaaaaaa
e5061c763b612fcb53efccdedb24a07deb7a131325560f1933
CSR{N0nces_are_funfunfun}
CSR{N0nces_are_funfunfun}