DeconstruCT.F 2023 Writeup

この大会は2023/8/5 17:07(JST)~2023/8/7 5:07(JST)に開催されました。
今回もチームで参戦。結果は325点で712チーム中263位でした。
ただこの大会、問題盗用等で問題になった模様。
途中からやる気もなくなりましたが、
自分で解けた問題をWriteupとして書いておきます。

Avail Your Good Boy Points (Misc, Easy)

ルールにフラグが書いてあった。

dsc{y0u_4re_4_g00D_80Y}

where-are-the-cookies (Web, Easy)

$ curl https://ch291050125115.ch.eng.run/robots.txt 
User-agent: *
Disallow: /cookiesaretotallynothere                                                                                                                               

$ curl https://ch291050125115.ch.eng.run/cookiesaretotallynothere -v
*   Trying 15.207.137.16:443...
* Connected to ch291050125115.ch.eng.run (15.207.137.16) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=*.shell.eng.run
*  start date: May  3 00:00:00 2023 GMT
*  expire date: Jun  1 23:59:59 2024 GMT
*  subjectAltName: host "ch291050125115.ch.eng.run" matched cert's "*.ch.eng.run"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M01
*  SSL certificate verify ok.
* using HTTP/2
* h2h3 [:method: GET]
* h2h3 [:path: /cookiesaretotallynothere]
* h2h3 [:scheme: https]
* h2h3 [:authority: ch291050125115.ch.eng.run]
* h2h3 [user-agent: curl/7.88.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x5648edebd9e0)
> GET /cookiesaretotallynothere HTTP/2
> Host: ch291050125115.ch.eng.run
> user-agent: curl/7.88.1
> accept: */*
> 
< HTTP/2 200 
< date: Sat, 05 Aug 2023 08:31:19 GMT
< content-type: text/html; charset=utf-8
< content-length: 25
< server: nginx/1.25.1
< x-powered-by: Express
< set-cookie: caniseethecookie=bm8==; Path=/; HttpOnly; Secure; SameSite=Strict
< etag: W/"19-1g63qbCXThU+tYI+45oRq6XoS80"
< 
* Connection #0 to host ch291050125115.ch.eng.run left intact
No cookies for you today!

$ echo bm8= | base64 -d 
no

yesをセットする。

$ echo -n yes | base64  
eWVz

$ curl https://ch291050125115.ch.eng.run/cookiesaretotallynothere -b 'caniseethecookie=eWVz' 
You found the cookie! &#127850; Oh, I also found this unrelated string, might be useful to you: dsc{1_f0unD_Th3_c0oK135}
dsc{1_f0unD_Th3_c0oK135}

Gibberish (Forensics, Easy)

flag.txtの内容をbase64デコードして保存する。

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

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

with open('flag.bin', 'wb') as f:
    f.write(b64decode(enc))

ELFバイナリになっているので、実行してみる。

$ ./flag.bin      
Password: 

パスワードを聞かれる。

$ strings flag.bin
        :
Password: 
goodbye
mlh{nc_c4n_4ls0_trnsmit_f1les}
Wrong password.
        :
dsc{nc_c4n_4ls0_trnsmit_f1les}

Hash Roll (Forensics, Easy)

zipにパスワードがかかっているので、クラックする。

$ zip2john encrypted1.zip > zip.hash
$ john --wordlist=dict/rockyou.txt zip.hash
Using default input encoding: UTF-8
Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 256/256 AVX2 8x])
Cost 1 (HMAC size) is 143716 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
diosesamor       (encrypted1.zip/flag.jpg)     
1g 0:00:00:00 DONE (2023-08-05 18:10) 11.11g/s 45511p/s 45511c/s 45511C/s 123456..oooooo
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

$ 7z x encrypted1.zip

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=ja_JP.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz (A0655),ASM,AES-NI)

Scanning the drive for archives:
1 file, 143908 bytes (141 KiB)

Extracting archive: encrypted1.zip
--
Path = encrypted1.zip
Type = zip
Physical Size = 143908

    
Enter password (will not be echoed):
Everything is Ok

Size:       146035
Compressed: 143908

展開されたflag.jpgの画像にフラグが書かれていた。

dsc{N3v3r_9OnNA_gIv3_y0u_up}

Magicplay (Forensics, Medium)

PNGの先頭4バイト、IHDRチャンク名、sRGBチャンク名、gAMAチャンク名、pHYsチャンクが壊れているので、修正する。
修正した画像にフラグが書いてあった。

dsc{COrrupt3d_M4g1C_f1Ag}

BLURY (Cryptography, HARD)

※この問題は取り下げになった模様。
AES CBC暗号だが、最後の暗号ブロックと一部の暗号、平文の全体しかわからない。フラグはIV。
最後のブロックの暗号化の復号と、最後のブロックの平文のXORが最後から2番目のブロックになることから、ブルートフォースでkeyを求める。それから最後のブロックから順に暗号を求め、最初のブロックの暗号の復号と最初のブロックの平文のXORがフラグになる。

#!/usr/bin/env python3
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
from base64 import *
import binascii

key_head = b'3N7g309d6Y7enT'
message = b'Security is not a joke, mind it. But complete security is a myth'

with open('ciphertext.txt', 'r') as f:
    ct = b64decode(b64decode(f.read()))

pt_blocks = [message[i:i+16] for i in range(0, len(message), 16)]
ct_blocks = [ct[i:i+32].decode() for i in range(0, len(ct), 32)]
print('[+] ct_blocks:', ct_blocks)

ct = binascii.unhexlify(ct_blocks[-1])
pt_tail = strxor(binascii.unhexlify(ct_blocks[-2][-4:]), pt_blocks[-1][-2:])

found = False
for c1 in range(32, 127):
    for c2 in range(32, 127):
        key = key_head + bytes([c1 ,c2])
        aes = AES.new(key, AES.MODE_ECB)
        pt = aes.decrypt(ct)
        if pt[-2:] == pt_tail:
            found = True
            print('[+] key:', key.decode())
            break
    if found:
        break

pt_blocks = pt_blocks[::-1]
ct_blocks = [binascii.hexlify(ct).decode()]
for i in range(len(pt_blocks)):
    aes = AES.new(key, AES.MODE_ECB)
    pt = aes.decrypt(binascii.unhexlify(ct_blocks[i]))
    ct_blocks.append(binascii.hexlify(strxor(pt, pt_blocks[i])).decode())

flag = binascii.unhexlify(ct_blocks[-1])
ct_blocks = ct_blocks[:-1][::-1]
print('[+] ct_blocks:', ct_blocks)

flag = flag.decode()
print('[*] flag:', flag)

実行結果は以下の通り。

[+] ct_blocks: ['54**************************36d4', '3a**************************1658', 'e7**************************bb2c', 'dabc02a058f8c3936a5fd6ddd3c50491']
[+] key: 3N7g309d6Y7enT1p
[+] ct_blocks: ['54453ced1207bb9f67894d2c8ae336d4', '3a4911ae86c1f5138c2d8e17e7721658', 'e764f66e54397534f7d049506acabb2c', 'dabc02a058f8c3936a5fd6ddd3c50491']
[*] flag: {W3ak_IV_5uckS5}
DSC{W3ak_IV_5uckS5}