Codefest CTF 2020 Writeup

この大会は2021/3/19 21:30(JST)~2021/3/20 21:30(JST)に開催されました。
今回もチームで参戦。結果は1000点で297チーム中99位でした。
自分で解けた問題をWriteupとして書いておきます。

Anime is love (Forensics)

後ろにzipのようなデータが付いているが、先頭1バイトだけ壊れている。先頭1バイトだけ'P'に置き換え切り出す。zipはパスワードがかかっている。

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


PASSWORD FOUND!!!!: pw == dragonballz
$ unzip -P dragonballz flag.zip
Archive:  flag.zip
  inflating: flag.txt
$ file flag.txt
flag.txt: PDF document, version 1.5
$ mv flag.txt flag.pdf

flag.pdfもパスワードがかかっている。

$ pdfcrack -w dict/rockyou.txt flag.pdf

PDF version 1.5
Security Handler: Standard
V: 2
R: 3
P: -4
Length: 128
Encrypted Metadata: True
FileID: 913b55437f279060de3ce628a75bcb31
U: a6bec5540721787125585728adfcd98928bf4e5e4e758a4164004e56fffa0108
O: 2c0a99521e0c171fc40d8bc4c04a20d47e177bd203f642347e18a68224ef2488
found user-password: 'naruto'

このパスワードでpdfを開くと、フラグが書かれていた。

codefest{y0u_4r3_g00d_4t_m4g1c_byt35}

EnCrypted Bitmap (Crypto 500)

AESで暗号化されているが、bmpなので形式だけ合わせれば読めるかもしれない。他のbmpの形式を付け、まず画像の幅だけ総当たりで探す。

import struct

with open('chall.encrypted.bmp', 'rb') as f:
    enc = f.read()

HEAD = '\x42\x4d\x36\x04\x00\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00'
HEIGHT = '\x80\x00\x00\x00'
NEXT = '\x01\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x0e\x00\x00\xc4\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'


for w in range(1, 513):
    fname = 'out_w/chall_%03d.bmp' % w
    dec = HEAD
    dec += struct.pack('I', w)
    dec += HEIGHT
    dec += NEXT
    dec += enc[0x36:]
    with open(fname, 'wb') as f:
        f.write(dec)

幅が345の時に読める文字が出てきた。今度は高さを総当たりで探す。

import struct

with open('chall.encrypted.bmp', 'rb') as f:
    enc = f.read()

HEAD = '\x42\x4d\x36\x04\x00\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00'
NEXT = '\x01\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x0e\x00\x00\xc4\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
WIDTH = 345

for h in range(1, 513):
    fname = 'out_h/chall_%03d.bmp' % h
    dec = HEAD
    dec += struct.pack('I', WIDTH)
    dec += struct.pack('I', h)
    dec += NEXT
    dec += enc[0x36:]
    with open(fname, 'wb') as f:
        f.write(dec)

正確にはわからないが、256の時にはフラグが見えた。
f:id:satou-y:20210327070029j:plain

codefest{ecb_is_unsafe}

RSA 1.0 (Cryptography)

pow(m, e, p*q*r) = c

rの値はわかるので、rをmodulusにした暗号に変える。

c % r = pow(m, e, r)
phi = r - 1

mがrより小さければ、簡単に復号できる。

from Crypto.Util.number import *

n = 750663646847528873168937831391907810647591913965562495296199585082759057318274521553757550724463451891668175905206221877858317290777877060166997790624527965837837993129383290402509996587556406778482067347232022225466937668396768390983554357611376057823852179263682649072729435912583278183812954787442057976301035654942470184201720410477691326653029842426252391647509934740335989269071438620690320401576861478427178128804784352142271832603194431176323445880836139
pq = 80970512687406090889060992576336286518763523653333428346066206717567693624044162491796922556346210471950404967161997779545603412053582932354160368128117099634532601019309976159157713252768640669410333127578132624183514430252557952811102781031315190048386214745340936679285725364013916829276058253922234988379
c = 221975957171552618997196127189899209276336291387640550554967727731818563960555600691881715668156105819191779108737770660990397331961689607338541452069797368288215716485835439777459317512238532636172979397173548812054679237802827275184091619620252887678664409116710340000218841023351238456144820005968602870644031701303645229364391309952172259686888808938835775360009896210855708140351244441167461823250549764537506364091367096196182191704433664638829177854628679
e = 65537

r = n // pq

new_c = c % r
phi = r - 1
d = inverse(e, phi)
m = pow(new_c, d, r)
flag = long_to_bytes(m)
print flag
codefest{p4dding_i5_r3quir3d}