Space Heroes CTF Writeup
2022/04/01 ~ 2022/04/03まで開催されたSpace Heroes CTFのwriteup。
チーム DCDC で出場した。
- 個人得点:754pt
- チーム得点:2454pt
- チーム順位:62位 / 778チーム
forensics問しか解いてないけど、OpenCVでガチャガチャやったので備忘として残しておく。
Forensics
Star Pcap (100pt)
pcapファイルが渡される。
中身はICMPのみが取得されているただのパケットキャプチャファイルだが、ICMP codeがASCIIと同期している。
ICMP Codeを読めばフラグ。
shctf{L0g1c-i$-th3-begiNNing-0f-wi$doM}
Netflix and CTF (100pt)
pcapファイルが渡される。
中身はHTTP通信を中心として取得されているただのパケットキャプチャファイル。
定期的にPOSTしており、/keypress/Lit_〇
ではキーを押下したタイミングでPOSTが投げられているっぽい。
Lit_〇の部分を抜粋して結合するとフラグ。
shctf{T1m3-is-th3-ultimat3-curr3Ncy}
The Legend of the Chozo (100pt)
corruptedData.chrという謎のファイルが渡される。
バイナリを読むと普通にPNGファイルのファイルヘッダをいい感じに修正すればOK。
修正前:
00000000: 5047 890a 4e0d 0a1a 0d48 4400 5200 0049 PG..N....HD.R..I
00000010: 0000 00f0 0000 0139 0806 0000 00ae c5ad .......9........
----snip to EOF---
修正後:
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
00000010: 0000 00f0 0000 0139 0806 0000 00ae c5ad .......9........
----snip to EOF---
修正するとファイルを開けるようになる。
画像の中にフラグ。
shctf{CH0Z0_rU1N5}
Interstellar Mystery (254pt)
- master0-3.qcow2
- master0-4.qcow2
という2つのファイルが渡される。
qcow2はqemuで使われているディスクイメージを単一のファイルにまとめたもの。
virtualboxを使っている人はvmdkとかを想像するとわかりやすいかも。
これをLinuxにマウントしていく。
sudo mkdir /mnt/master0-3
sudo mkdir /mnt/master0-4
sudo modprobe nbd max_part=8
sudo qemu-nbd --connect=/dev/nbd0 ./master0-3.qcow2
sudo qemu-nbd --connect=/dev/nbd1 ./master0-4.qcow2
sudo mount /dev/nbd0 /mnt/master0-3
# mount: /mnt/master0-3: wrong fs type, bad option, bad superblock on /dev/nbd0, missing codepage or helper program, or other error.
sudo mount /dev/nbd1 /mnt/master0-4
参考: https://gist.github.com/shamil/62935d9b456a6f9877b5
master0-3.qcow2がマウントできなかったが、master0-4.qcow2のほうはマウントできた。
中にはe
というバイナリファイルだけがあった。
stringsで文字列抽出し、フラグフォーマットであるshctf
をgrepで抜き出すとフラグ。
これ想定解なのか?
shctf{btrfs_is_awsome}
Buzz’s Secret Watch (Part 1) (100pt)
なんか8つの点がチカチカする動画が渡される。
下にGifにした奴を貼っておく。
8bit = 1byteなのでまあこの辺の点数帯ならASCII文字を表したいんだろうなあと容易に想像ができる。
人力で読める長さだけど、めんどくさすぎるのでOpenCVでパーサを書いた。
import cv2
import numpy as np
coordinates = [(360,699), (394,697), (430,700), (469,698), (501,700), (537,694), (575,696), (604,697)]
def onMouse(event, x, y, flags, params):
if event == cv2.EVENT_LBUTTONDOWN:
print(f"({x},{y})")
print(f"COLOR: B,G,R({img[y,x,:]})")
#MOV_PATH = "./buzzsaw.avi"
MOV_PATH = "./buzz-bin.avi"
cap = cv2.VideoCapture(MOV_PATH)
while True:
ret, img = cap.read()
#cv2.imshow("cap", img)
hsv = img
lower_green= np.array([0, 150, 0], dtype = "uint8")
upper_green= np.array([30, 255, 30], dtype = "uint8")
chk_green= cv2.inRange(hsv, lower_green, upper_green)
contours, hierarchy = cv2.findContours(chk_green, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#cv2.imshow("green_point",chk_green)
img_contour = cv2.drawContours(hsv, contours, -1, (255, 0, 0), 3)
#cv2.imshow("green_path", img_contour)
lamps = []
arr = [0]*8
for contour in contours:
for i,coordinate in enumerate(coordinates):
retval = cv2.pointPolygonTest(contour, coordinate, False)
if retval == 1 or retval == 0:
arr[i]=1
#cv2.waitKey(0)
if sum(arr) != 0:
print("".join(map(str, arr)))
#cv2.setMouseCallback("cap", onMouse)
# EMERG BRERK
if cv2.waitKey(1) & 0xFF == ord("q"):
break
cap.release()
cv2.destroyAllWindows()
OpenCV使ってなさ過ぎて普通に時間がかかった。
やっていることとしては単純で、動画を1フレーム毎に以下のようなチェックをしている。
- 緑の物体が出てきたら輪郭検出を実施
- 輪郭内に指定した座標群(coordinates)が入っているかどうかをチェック。
前に個人が作ったようなCaptchaもどきを邪悪な方法で攻略しようとしたとき以来、OpenCVを触っていなかったためいい再学習の機会になった。
実際に動かしてみると、やはり明滅で出力されているのがASCII文字列だった。
shctf{Sh3r1ff-tH1s-is-n0-t1m3-t0-pAn1c}
Buzz’s Secret Watch (Part 2) (100pt)
Part 1に続きほぼ同じフォーマットの動画が渡される。
変更点は点滅がクソクソ早くなったことと動画の時間がかなり長くなっていること。
人力の解読はほぼ不可能なレベルになっていた。
解法だが、Part 1で書いたパーサで一撃で解けた。めんどくさがらずにちゃんと書いてよかったね。
出力はELF形式のバイナリだったが、バイナリをstringsで文字列抽出するとフラグが出てくる。
shctf{Th1s-Isnt-Fly1ng-THis-Is-FAlliNg-W1th-Styl3}
お気持ち
OpenCV完全に忘れててつらい。
新年度だし今年は色々とがんばっていき!