Digital Overdose Conference 2022 CTF Writeup

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

Shhhhhh it’s a Sekret (Stu's Investigation Extravaganza! 50)

公開鍵をインポートしてみる。

$ gpg --import key.asc
gpg: 鍵2A6264BD39D4EC07: 公開鍵"cybersecstu <ctfsaresometimefun@mail.com>"をインポートしました
gpg: 処理数の合計: 1
gpg:               インポート: 1

署名に使ったメールアドレスはctfsaresometimefun@mail.com。

DOCTF{ctfsaresometimefun@mail.com}

Part 1 - Ingress (Misc 50)

$ cat brut.log | grep DOCTF{ | head -1
2021-04-20 08:28:00 NGINX POST wp-login.php - 443 - 13.105.95.112 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(DOCTF{w34k_p455w0rd5_637_pwnd})+Chrome/84.0.4147.105+Safari/537.36 - 401 0 0 28
DOCTF{w34k_p455w0rd5_637_pwnd}

Get down with the Gitness (Misc 100)

$ git clone https://github.com/punk-security/DOCON22_CTF1
Cloning into 'DOCON22_CTF1'...
remote: Enumerating objects: 682, done.
remote: Counting objects: 100% (682/682), done.
remote: Compressing objects: 100% (243/243), done.
remote: Total 682 (delta 392), reused 682 (delta 392), pack-reused 0
Receiving objects: 100% (682/682), 74.68 KiB | 483.00 KiB/s, done.
Resolving deltas: 100% (392/392), done.
$ cd DOCON22_CTF1/
$ git log -p | grep DOCTF | grep -v REDACTED
-the fl4g is: DOCTF{REDACTING_IN_GIT_IS_HARDZ}
+the fl4g is: DOCTF{REDACTING_IN_GIT_IS_HARDZ}
DOCTF{REDACTING_IN_GIT_IS_HARDZ}

1 - Ready ? (OSINT 10)

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

DOCTF{R34DY}

vault (Reverse 100)

$ gdb -q ./vault
Reading symbols from ./vault...(no debugging symbols found)...done.
gdb-peda$ start

[----------------------------------registers-----------------------------------]
RAX: 0x5555555551e9 (<main>:	endbr64)
RBX: 0x0 
RCX: 0x555555555370 (<__libc_csu_init>:	endbr64)
RDX: 0x7fffffffdee8 --> 0x7fffffffe244 ("CLUTTER_IM_MODULE=xim")
RSI: 0x7fffffffded8 --> 0x7fffffffe22d ("/mnt/hgfs/Shared/vault")
RDI: 0x1 
RBP: 0x555555555370 (<__libc_csu_init>:	endbr64)
RSP: 0x7fffffffddf8 --> 0x7ffff7a03c87 (<__libc_start_main+231>:	mov    edi,eax)
RIP: 0x5555555551e9 (<main>:	endbr64)
R8 : 0x7ffff7dced80 --> 0x0 
R9 : 0x7ffff7dced80 --> 0x0 
R10: 0x0 
R11: 0x0 
R12: 0x555555555100 (<_start>:	endbr64)
R13: 0x7fffffffded0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x5555555551d9 <__do_global_dtors_aux+57>:	nop    DWORD PTR [rax+0x0]
   0x5555555551e0 <frame_dummy>:	endbr64 
   0x5555555551e4 <frame_dummy+4>:	
    jmp    0x555555555160 <register_tm_clones>
=> 0x5555555551e9 <main>:	endbr64 
   0x5555555551ed <main+4>:	push   rbp
   0x5555555551ee <main+5>:	mov    rbp,rsp
   0x5555555551f1 <main+8>:	sub    rsp,0x40
   0x5555555551f5 <main+12>:	mov    rax,QWORD PTR fs:0x28
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffddf8 --> 0x7ffff7a03c87 (<__libc_start_main+231>:	mov    edi,eax)
0008| 0x7fffffffde00 --> 0x1 
0016| 0x7fffffffde08 --> 0x7fffffffded8 --> 0x7fffffffe22d ("/mnt/hgfs/Shared/vault")
0024| 0x7fffffffde10 --> 0x100008000 
0032| 0x7fffffffde18 --> 0x5555555551e9 (<main>:	endbr64)
0040| 0x7fffffffde20 --> 0x0 
0048| 0x7fffffffde28 --> 0x52ff018447034528 
0056| 0x7fffffffde30 --> 0x555555555100 (<_start>:	endbr64)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Temporary breakpoint 1, 0x00005555555551e9 in main ()
gdb-peda$ disas main
Dump of assembler code for function main:
=> 0x00005555555551e9 <+0>:	endbr64 
   0x00005555555551ed <+4>:	push   rbp
   0x00005555555551ee <+5>:	mov    rbp,rsp
   0x00005555555551f1 <+8>:	sub    rsp,0x40
   0x00005555555551f5 <+12>:	mov    rax,QWORD PTR fs:0x28
   0x00005555555551fe <+21>:	mov    QWORD PTR [rbp-0x8],rax
   0x0000555555555202 <+25>:	xor    eax,eax
   0x0000555555555204 <+27>:	mov    BYTE PTR [rbp-0x3a],0x7d
   0x0000555555555208 <+31>:	mov    BYTE PTR [rbp-0x39],0x30
   0x000055555555520c <+35>:	mov    BYTE PTR [rbp-0x38],0x7b
   0x0000555555555210 <+39>:	mov    BYTE PTR [rbp-0x37],0x43
   0x0000555555555214 <+43>:	mov    BYTE PTR [rbp-0x36],0x46
   0x0000555555555218 <+47>:	mov    BYTE PTR [rbp-0x35],0x43
   0x000055555555521c <+51>:	mov    BYTE PTR [rbp-0x34],0x52
   0x0000555555555220 <+55>:	mov    BYTE PTR [rbp-0x33],0x30
   0x0000555555555224 <+59>:	mov    BYTE PTR [rbp-0x32],0x50
   0x0000555555555228 <+63>:	mov    BYTE PTR [rbp-0x31],0x52
   0x000055555555522c <+67>:	mov    BYTE PTR [rbp-0x30],0x34
   0x0000555555555230 <+71>:	mov    BYTE PTR [rbp-0x2f],0x46
   0x0000555555555234 <+75>:	mov    BYTE PTR [rbp-0x2e],0x4f
   0x0000555555555238 <+79>:	mov    BYTE PTR [rbp-0x2d],0x54
   0x000055555555523c <+83>:	mov    BYTE PTR [rbp-0x2c],0x33
   0x0000555555555240 <+87>:	mov    BYTE PTR [rbp-0x2b],0x44
   0x0000555555555244 <+91>:	mov    BYTE PTR [rbp-0x2a],0x48
   0x0000555555555248 <+95>:	mov    BYTE PTR [rbp-0x29],0x4b
   0x000055555555524c <+99>:	mov    edi,0x12
   0x0000555555555251 <+104>:	call   0x5555555550e0 <malloc@plt>
   0x0000555555555256 <+109>:	mov    QWORD PTR [rbp-0x28],rax
   0x000055555555525a <+113>:	lea    rdi,[rip+0xda7]        # 0x555555556008
   0x0000555555555261 <+120>:	mov    eax,0x0
   0x0000555555555266 <+125>:	call   0x5555555550d0 <printf@plt>
   0x000055555555526b <+130>:	mov    rax,QWORD PTR [rbp-0x28]
   0x000055555555526f <+134>:	mov    rsi,rax
   0x0000555555555272 <+137>:	lea    rdi,[rip+0xda4]        # 0x55555555601d
   0x0000555555555279 <+144>:	mov    eax,0x0
   0x000055555555527e <+149>:	call   0x5555555550f0 <__isoc99_scanf@plt>
   0x0000555555555283 <+154>:	movzx  eax,BYTE PTR [rbp-0x2b]
   0x0000555555555287 <+158>:	mov    BYTE PTR [rbp-0x20],al
   0x000055555555528a <+161>:	movzx  eax,BYTE PTR [rbp-0x2e]
   0x000055555555528e <+165>:	mov    BYTE PTR [rbp-0x1f],al
   0x0000555555555291 <+168>:	movzx  eax,BYTE PTR [rbp-0x37]
   0x0000555555555295 <+172>:	mov    BYTE PTR [rbp-0x1e],al
   0x0000555555555298 <+175>:	movzx  eax,BYTE PTR [rbp-0x2d]
   0x000055555555529c <+179>:	mov    BYTE PTR [rbp-0x1d],al
   0x000055555555529f <+182>:	movzx  eax,BYTE PTR [rbp-0x36]
   0x00005555555552a3 <+186>:	mov    BYTE PTR [rbp-0x1c],al
   0x00005555555552a6 <+189>:	movzx  eax,BYTE PTR [rbp-0x38]
   0x00005555555552aa <+193>:	mov    BYTE PTR [rbp-0x1b],al
   0x00005555555552ad <+196>:	movzx  eax,BYTE PTR [rbp-0x2a]
   0x00005555555552b1 <+200>:	mov    BYTE PTR [rbp-0x1a],al
   0x00005555555552b4 <+203>:	movzx  eax,BYTE PTR [rbp-0x30]
   0x00005555555552b8 <+207>:	mov    BYTE PTR [rbp-0x19],al
   0x00005555555552bb <+210>:	movzx  eax,BYTE PTR [rbp-0x35]
   0x00005555555552bf <+214>:	mov    BYTE PTR [rbp-0x18],al
   0x00005555555552c2 <+217>:	movzx  eax,BYTE PTR [rbp-0x29]
   0x00005555555552c6 <+221>:	mov    BYTE PTR [rbp-0x17],al
   0x00005555555552c9 <+224>:	movzx  eax,BYTE PTR [rbp-0x2c]
   0x00005555555552cd <+228>:	mov    BYTE PTR [rbp-0x16],al
   0x00005555555552d0 <+231>:	movzx  eax,BYTE PTR [rbp-0x34]
   0x00005555555552d4 <+235>:	mov    BYTE PTR [rbp-0x15],al
   0x00005555555552d7 <+238>:	movzx  eax,BYTE PTR [rbp-0x32]
   0x00005555555552db <+242>:	mov    BYTE PTR [rbp-0x14],al
   0x00005555555552de <+245>:	movzx  eax,BYTE PTR [rbp-0x31]
   0x00005555555552e2 <+249>:	mov    BYTE PTR [rbp-0x13],al
   0x00005555555552e5 <+252>:	movzx  eax,BYTE PTR [rbp-0x33]
   0x00005555555552e9 <+256>:	mov    BYTE PTR [rbp-0x12],al
   0x00005555555552ec <+259>:	movzx  eax,BYTE PTR [rbp-0x39]
   0x00005555555552f0 <+263>:	mov    BYTE PTR [rbp-0x11],al
   0x00005555555552f3 <+266>:	movzx  eax,BYTE PTR [rbp-0x2f]
   0x00005555555552f7 <+270>:	mov    BYTE PTR [rbp-0x10],al
   0x00005555555552fa <+273>:	movzx  eax,BYTE PTR [rbp-0x3a]
   0x00005555555552fe <+277>:	mov    BYTE PTR [rbp-0xf],al
   0x0000555555555301 <+280>:	mov    BYTE PTR [rbp-0xe],0x0
   0x0000555555555305 <+284>:	mov    rcx,QWORD PTR [rbp-0x28]
   0x0000555555555309 <+288>:	lea    rax,[rbp-0x20]
   0x000055555555530d <+292>:	mov    edx,0x12
   0x0000555555555312 <+297>:	mov    rsi,rcx
   0x0000555555555315 <+300>:	mov    rdi,rax
   0x0000555555555318 <+303>:	call   0x5555555550a0 <strncmp@plt>
   0x000055555555531d <+308>:	test   eax,eax
   0x000055555555531f <+310>:	jne    0x55555555533b <main+338>
   0x0000555555555321 <+312>:	lea    rax,[rbp-0x20]
   0x0000555555555325 <+316>:	mov    rsi,rax
   0x0000555555555328 <+319>:	lea    rdi,[rip+0xcf1]        # 0x555555556020
   0x000055555555532f <+326>:	mov    eax,0x0
   0x0000555555555334 <+331>:	call   0x5555555550d0 <printf@plt>
   0x0000555555555339 <+336>:	jmp    0x555555555347 <main+350>
   0x000055555555533b <+338>:	lea    rdi,[rip+0xd02]        # 0x555555556044
   0x0000555555555342 <+345>:	call   0x5555555550b0 <puts@plt>
   0x0000555555555347 <+350>:	mov    eax,0x0
   0x000055555555534c <+355>:	mov    rdx,QWORD PTR [rbp-0x8]
   0x0000555555555350 <+359>:	xor    rdx,QWORD PTR fs:0x28
   0x0000555555555359 <+368>:	je     0x555555555360 <main+375>
   0x000055555555535b <+370>:	call   0x5555555550c0 <__stack_chk_fail@plt>
   0x0000555555555360 <+375>:	leave  
   0x0000555555555361 <+376>:	ret    
End of assembler dump.

strncmpの比較をしているところにブレークポイントを置き、実行する。

gdb-peda$ b *0x0000555555555318
Breakpoint 2 at 0x555555555318
gdb-peda$ r
Starting program: /mnt/hgfs/Shared/vault 
Enter the Password: hoge

[----------------------------------registers-----------------------------------]
RAX: 0x7fffffffddd0 ("DOCTF{H4CK3RPR00F}")
RBX: 0x0 
RCX: 0x555555559260 --> 0x65676f68 ('hoge')
RDX: 0x12 
RSI: 0x555555559260 --> 0x65676f68 ('hoge')
RDI: 0x7fffffffddd0 ("DOCTF{H4CK3RPR00F}")
RBP: 0x7fffffffddf0 --> 0x555555555370 (<__libc_csu_init>:	endbr64)
RSP: 0x7fffffffddb0 --> 0x307d0000000000c2 
RIP: 0x555555555318 (<main+303>:	call   0x5555555550a0 <strncmp@plt>)
R8 : 0x0 
R9 : 0x0 
R10: 0x0 
R11: 0x55555555601f --> 0x7373656363755300 ('')
R12: 0x555555555100 (<_start>:	endbr64)
R13: 0x7fffffffded0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x55555555530d <main+292>:	mov    edx,0x12
   0x555555555312 <main+297>:	mov    rsi,rcx
   0x555555555315 <main+300>:	mov    rdi,rax
=> 0x555555555318 <main+303>:	call   0x5555555550a0 <strncmp@plt>
   0x55555555531d <main+308>:	test   eax,eax
   0x55555555531f <main+310>:	jne    0x55555555533b <main+338>
   0x555555555321 <main+312>:	lea    rax,[rbp-0x20]
   0x555555555325 <main+316>:	mov    rsi,rax
Guessed arguments:
arg[0]: 0x7fffffffddd0 ("DOCTF{H4CK3RPR00F}")
arg[1]: 0x555555559260 --> 0x65676f68 ('hoge')
arg[2]: 0x12 
arg[3]: 0x555555559260 --> 0x65676f68 ('hoge')
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffddb0 --> 0x307d0000000000c2 
0008| 0x7fffffffddb8 ("{CFCR0PR4FOT3DHK`\222UUUU")
0016| 0x7fffffffddc0 ("4FOT3DHK`\222UUUU")
0024| 0x7fffffffddc8 --> 0x555555559260 --> 0x65676f68 ('hoge')
0032| 0x7fffffffddd0 ("DOCTF{H4CK3RPR00F}")
0040| 0x7fffffffddd8 ("CK3RPR00F}")
0048| 0x7fffffffdde0 --> 0x7fffff007d46 
0056| 0x7fffffffdde8 --> 0x2b6b04de17511900 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 2, 0x0000555555555318 in main ()

strncmpの第一引数にフラグが入っている。

DOCTF{H4CK3RPR00F}

Area 51 (Steganography 50)

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

DOCTF{SP3CTR0GR4M5_4R3_C00L_1F_0NLY_1_KN3W_H0W_T0_CR34T3_1T_MY53LF}

Matryoshka (Steganography 50)

何重にもzip圧縮されているので、スクリプトで解凍していく。

#!/usr/bin/env python3
import zipfile
import os

fname = '8fb0444894b78f857dd600b7f35c0af4.zip'

while True:
    with zipfile.ZipFile(fname) as zf:
        next_fname = zf.namelist()[0]
        zf.extractall('.')
    os.remove(fname)
    fname = next_fname
    if not fname.endswith('.zip'):
        break

最後にBOMB_FLAGファイルが展開され、中にはこう書いてあった。

Welcome to the bottom! Here's your flag: DOCTF{G00D_3FF0RT_BUT_1$_1T_0V3R?}

Nicos
DOCTF{G00D_3FF0RT_BUT_1$_1T_0V3R?}

Honey Maker (Cryptography 50)

HTMLソースを見ると、コメントにこう書いてある。

   <!-- honey maker ctf-->
      <!--looks like you've found me!
              \     /
          \    o ^ o    /
            \ (     ) /
 ____________(%%%%%%%)____________
(     /   /  )%%%%%%%(  \   \     )
(___/___/__/           \__\___\___)
   (     /  /(%%%%%%%)\  \     )
    (__/___/ (%%%%%%%) \___\__)
            /(       )\
          /   (%%%%%)   \
               (%%%)
                 !
         wWWWw               wWWWw
   vVVVv (___) wWWWw         (___)  vVVVv
   (___)  ~Y~  (___)  vVVVv   ~Y~   (___)
    ~Y~   \|    ~Y~   (___)    |/    ~Y~
    \|   \ |/   \| /  \~Y~/   \|    \ |/
   \\|// \\|// \\|/// \\|//  \\|// \\\|///
jgs^^^^^^https://youtu.be/ptBkmMk5YCc^^^^^^-->
      <!--honey maker ctf ends here-->

https://youtu.be/ptBkmMk5YCcの動画を眺めてみる。6:12くらいのところでフラグが表示された。

DOCTF{STINGER}

uncommitted (Cryptography 50)

点字と推測し、デコードする。

SORRYIHAVEAPARTNER
DOCTF{SORRYIHAVEAPARTNER}

Mendel(la) effect (Cryptography 50)

https://www.nacalai.co.jp/information/trivia2/09.htmlのDNAの遺伝暗号表を元に復号する。

ATGGCAGGAATCTGCTGA
M  A  G  I  C  (STOP)
DOCTF{MAGIC}

Frog festivities (Cryptography 50)

image.pngにはjumpyと書かれており、2段で横26マスの表になっている。Keyed Caesar Cipherと推測し、https://www.boxentriq.com/code-breaking/keyed-caesar-cipherで復号する。

ribbit
DOCTF{ribbit}

Based (Cryptography 100)

base64文字列のようなので、デコードする。

$ cat based.txt | base64 -d
Grandpa sent me on a treasure hunt to get a lost flag but the map wasnt completed. All I saw was the city of ROT and a coded message: Jung lbh jvfu sbe vf ng ...- .. --. . -. . .-. . ... -.-. .- ... - .-.. . hfr gur xrl QBgjb naq cebivqr gur cuenfr TPICG{MpcHpkskKbifj}

"cuenfr"までモールス信号を除き、シーザー暗号と推測し、https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号してみる。

Jung lbh jvfu sbe vf ng [モールスコード] hfr gur xrl QBgjb naq cebivqr gur cuenfr
    ↓ROT13
What you wish for is at [モールスコード] use the key DOtwo and provide the phrase 

モールスコード部分をhttps://morsecode.world/international/translator.htmlでデコードしてみる。

VIGENERESCASTLE

フラグ部分をVigenere暗号と推測し、復号してみる。鍵はQBGJB。

DOCTF{WowYoureBased}

Fight the corruption (Cryptography 100)

1箇所ASCII文字になっていない箇所があり、さらにDER形式に変換すると、先頭にゴミが入っている。ゴミを削除後、不明な1バイトをブルートフォースで、PEM形式にして例外が発生しないものを探す。探し当てることができたら、そのパラメータを使って、復号する。

#!/usr/bin/env python3
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
from base64 import *
from string import *
import re

def der_to_pem(der):
    pem = b'-----BEGIN PRIVATE KEY-----\r\n'
    b64 = b64encode(der)
    for i in range(0, len(b64), 64):
        pem += b64[i:i+64] + b'\r\n'
    pem += b'-----END PRIVATE KEY-----\r\n'
    return pem.decode()

with open('challenge.pem', 'rb') as f:
    data = f.read()

index = data.index(b'fhWn')
b64str = ascii_letters + digits + '+/'

for c in b64str:
    tmp_data = data[:index-4] + c.encode() + data[index:]
    tmp_data = tmp_data.replace(b'\r\n', b'')
    tmp_data = tmp_data.replace(b'-----BEGIN PRIVATE KEY-----', b'')
    tmp_data = tmp_data.replace(b'-----END PRIVATE KEY-----', b'')
    der_data = b64decode(tmp_data)[26:]
    pem_data = der_to_pem(der_data)
    try:
        privkey = RSA.importKey(pem_data)
        print('[+] unknown char:', c)
        break
    except:
        continue

n = privkey.n
d = privkey.d

with open('SECRET.enc', 'rb') as f:
    c = bytes_to_long(f.read())

m = pow(c, d, n)
msg = long_to_bytes(m)
index_begin = msg.index(b'DOCTF')
index_end = msg.index(b'}', index_begin)
flag = msg[index_begin:index_end + 1].decode()
print('[*] flag:', flag)

実行結果は以下の通り。

[+] unknown char: Y
[*] flag: DOCTF{1M4G1N3_TH1S_W0ULD_H4PP3N_1N_PR0DUCTI0N}
DOCTF{1M4G1N3_TH1S_W0ULD_H4PP3N_1N_PR0DUCTI0N}