CyberSecurityRumble CTF Writeup

この大会は2021/11/27 5:00(JST)~2021/11/29 5:00(JST)に開催されました。
今回もチームで参戦。結果は544点で238チーム中54位でした。
自分で解けた問題をWriteupとして書いておきます。

Flag Checker, Baby (pwn)

適当な31バイトの文字列を入力すれば、フラグが連なって表示されるはず。

$ nc challs.rumble.host 53921
Enter the flag: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
Wrong flag: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
CSR{should_have_used_strlcpy_instead}
CSR{should_have_used_strlcpy_instead}

Result (cry, misc)

添付のPDFはzipcodeのパスワードらしい。それを前提にクラックする。

$ pdf2john.pl result.pdf > hash.txt

hash.txtの先頭の"result.pdf:"を削除し、数字を前提にパスワードクラックする。

>hashcat.exe -m 10700 hash.txt -a 3 --increment ?d?d?d?d?d?d
hashcat (v6.2.4) starting

OpenCL API (OpenCL 3.0 ) - Platform #1 [Intel(R) Corporation]
=============================================================
* Device #1: Intel(R) UHD Graphics 630, 3200/6484 MB (1621 MB allocatable), 24MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 127

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates

Optimizers applied:
* Zero-Byte
* Single-Hash
* Single-Salt
* Brute-Force
* Uses-64-Bit
* (null)

ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.

Watchdog: Hardware monitoring interface not found on your system.
Watchdog: Temperature abort trigger disabled.

Host memory required for this attack: 935 MB

The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.

Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 10700 (PDF 1.7 Level 8 (Acrobat 10 - 11))
Hash.Target......: $pdf$5*6*256*-4*1*16*a7e7f3044ae023f1d1fac448bf2559...6165be
Time.Started.....: Sat Nov 27 09:15:17 2021 (3 secs)
Time.Estimated...: Sat Nov 27 09:15:20 2021 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?d [1]
Guess.Queue......: 1/6 (16.67%)
Speed.#1.........:        3 H/s (4.72ms) @ Accel:4 Loops:1 Thr:64 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 10/10 (100.00%)
Rejected.........: 0/10 (0.00%)
Restore.Point....: 1/1 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:9-10 Iteration:63-64
Candidate.Engine.: Device Generator
Candidates.#1....: 6 -> 6

The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.

Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 10700 (PDF 1.7 Level 8 (Acrobat 10 - 11))
Hash.Target......: $pdf$5*6*256*-4*1*16*a7e7f3044ae023f1d1fac448bf2559...6165be
Time.Started.....: Sat Nov 27 09:15:27 2021 (13 secs)
Time.Estimated...: Sat Nov 27 09:15:40 2021 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?d?d [2]
Guess.Queue......: 2/6 (33.33%)
Speed.#1.........:        7 H/s (20.95ms) @ Accel:4 Loops:1 Thr:64 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 100/100 (100.00%)
Rejected.........: 0/100 (0.00%)
Restore.Point....: 10/10 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:9-10 Iteration:63-64
Candidate.Engine.: Device Generator
Candidates.#1....: 62 -> 67

The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.

Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 10700 (PDF 1.7 Level 8 (Acrobat 10 - 11))
Hash.Target......: $pdf$5*6*256*-4*1*16*a7e7f3044ae023f1d1fac448bf2559...6165be
Time.Started.....: Sat Nov 27 09:15:47 2021 (17 secs)
Time.Estimated...: Sat Nov 27 09:16:04 2021 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?d?d?d [3]
Guess.Queue......: 3/6 (50.00%)
Speed.#1.........:       58 H/s (25.92ms) @ Accel:4 Loops:1 Thr:64 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 1000/1000 (100.00%)
Rejected.........: 0/1000 (0.00%)
Restore.Point....: 100/100 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:9-10 Iteration:63-64
Candidate.Engine.: Device Generator
Candidates.#1....: 623 -> 676

The wordlist or mask that you are using is too small.
This means that hashcat cannot use the full parallel power of your device(s).
Unless you supply more work, your cracking speed will drop.
For tips on supplying more work, see: https://hashcat.net/faq/morework

Approaching final keyspace - workload adjusted.

Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 10700 (PDF 1.7 Level 8 (Acrobat 10 - 11))
Hash.Target......: $pdf$5*6*256*-4*1*16*a7e7f3044ae023f1d1fac448bf2559...6165be
Time.Started.....: Sat Nov 27 09:16:11 2021 (22 secs)
Time.Estimated...: Sat Nov 27 09:16:33 2021 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?d?d?d?d [4]
Guess.Queue......: 4/6 (66.67%)
Speed.#1.........:      452 H/s (33.10ms) @ Accel:4 Loops:1 Thr:64 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 10000/10000 (100.00%)
Rejected.........: 0/10000 (0.00%)
Restore.Point....: 1000/1000 (100.00%)
Restore.Sub.#1...: Salt:0 Amplifier:9-10 Iteration:63-64
Candidate.Engine.: Device Generator
Candidates.#1....: 6234 -> 6764

$pdf$5*6*256*-4*1*16*a7e7f3044ae023f1d1fac448bf25592c*48*67171ef681ef91ed5bea716fa5eceda89b8659e1e7e4c5b810be37befb1ddd6ccc0217015a1eebce2c84e57607d22225*48*9b5a9e500fb87e9d4171e22fa77eb5a72ba857d2e2eaa4674ec8ed69831c77fdf400be271c304f6875dd1c5272a3fef0*32*e6e5cbe1bef4ba12e74a43e8a079970ed93664333955e76d22396fe69367d3fc*32*3de89fe5d937cf8a0b1105dd7c60a0c24bd3ca0e815b59cd02a59581d36165be:73760

Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 10700 (PDF 1.7 Level 8 (Acrobat 10 - 11))
Hash.Target......: $pdf$5*6*256*-4*1*16*a7e7f3044ae023f1d1fac448bf2559...6165be
Time.Started.....: Sat Nov 27 09:16:40 2021 (1 min, 35 secs)
Time.Estimated...: Sat Nov 27 09:18:15 2021 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Mask.......: ?d?d?d?d?d [5]
Guess.Queue......: 5/6 (83.33%)
Speed.#1.........:      584 H/s (158.60ms) @ Accel:4 Loops:1 Thr:64 Vec:1
Recovered........: 1/1 (100.00%) Digests
Progress.........: 55296/100000 (55.30%)
Rejected.........: 0/55296 (0.00%)
Restore.Point....: 0/10000 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:8-9 Iteration:63-64
Candidate.Engine.: Device Generator
Candidates.#1....: 72345 -> 79214

Started: Sat Nov 27 09:15:08 2021
Stopped: Sat Nov 27 09:18:17 2021

パスワードは73760。このパスワードでPDFを開くと、フラグが書いてあった。

CSR{BigBigEntropy}

Personal Encryptor with Nonbreakable Inforation-theoretic Security (cry)

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

・ALPHABET = string.ascii_letters + "{}_!$&-%?()"
・inpt: 暗号化回数(1~1000)を入力
・inptの数だけ以下繰り返し
 ・key = keygen(len(FLAG))
  ・rnd_bytes: FLAGの長さのランダム文字列
  ・keyを以下のようにして算出
   ・ALPHABET[rnd_bytes[i] % len(ALPHABET)]
 ・encrypt(key, FLAG)→表示
  ・FLAGの各文字はALPHABETの文字に含まれている必要あり
  ・FLAGの各文字について以下のようして暗号化
   ・FLAGとkeyのALPHABETのインデックスの和(ALPHABETの長さで割った余り)
    →ALPHABETのインデックスとしてALPHABETの対応する文字

ALPHABETは63の長さ。rnd_bytesの各文字の最大は255。

>>> 255 % 63
3

0~3の確率が他より高い。1000回試し、4つ連続した文字の出現回数の合計の多いものを探す。1000回だけだと、データ量が不足するので、わかっているフラグのハッシュ値と同じになるまで繰り返す。

#!/usr/bin/env python3
import socket
import string
import hashlib

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

def get_char(ciphers, index):
    counts = {}
    for cipher in ciphers:
        c = cipher[index]
        if c not in counts:
            counts[c] = 1
        else:
            counts[c] += 1
    sums = []
    for i in range(len(ALPHABET)):
        sum = 0
        for j in range(4):
            sum += counts[ALPHABET[(i + j) % len(ALPHABET)]]
        sums.append(sum)
    index = sums.index(max(sums))
    return ALPHABET[index]


h = '59f03b531db63fe65b7b8522badee65488d7a63fd97c3134766faf3d0fde427c'
ALPHABET = string.ascii_letters + '{}_!$&-%?()'

ciphers = []
while True:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('challs.rumble.host', 17171))

    count = 1000
    data = recvuntil(s, b'>')
    print(data + str(count))
    s.sendall(str(count).encode() + b'\n')

    for i in range(count):
        data = recvuntil(s, b'\n').rstrip()
        #print(data)
        ciphers.append(data)

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

    FLAG = ''
    for i in range(len(ciphers[0])):
        FLAG += get_char(ciphers, i)
    print('Flag? =', FLAG)

    if hashlib.sha256(FLAG.encode()).hexdigest() == h:
        print('Found!')
        print('FLAG =', FLAG)
        break

実行結果は以下の通り。

Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = ETQKBnHwyGABeSEP}
Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = ETQLB}RwGRAB!SCG{
Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = cSRLA!AwGRAC!SCG!
Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = DSR{A!AM!RAB!TCG}
Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = DSR{B!AS!SAB!TCG}
Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = DSR{B!AS!SAB!TCG}
Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = DSR{B!AS!SAB!TCH}
Welcome to our `Personal Encryptor with Nonbreakable Information-theoretic Security` DEMO.
With this PoC we show our unbreakable cipher.
Request as many ciphertexts as you want. You won't be able to decrypt!
To encrypt own messages please buy the full version.
How many ciphertexts would you like>1000
Thanks for trying our demo version. Good bye.
Flag? = CSR{B!AS!SAB!TCH}
Found!
FLAG = CSR{B!AS!SAB!TCH}
CSR{B!AS!SAB!TCH}