第4回 SECCON Beginners CTF Write up

会社の同僚に誘われて第4回 SECCON Beginners CTFに参加してきました。

大した内容ではないですがこういうのは書いておくのが大事らしいです。ということで残しておきます。

結果

チームvulmとして参加、943チーム中137位でした。

seccon_score

4人チームですが、自分以外が業務でセキュリティ(広義)を扱っているので基本的にメンバー任せになってしまいました。

自分はネットワーク周りの問題があれば…、ということで参加しましたが生憎ネットワーク関連の問題はありませんでした。

write-up

最終的に自分が解けたのは2問だけですが、格闘途中の記録も残しておきます。

回答済

  • git-leak
  • Mail_Address_Validator

未回答

  • c(heck)_url
  • depixelization

git-leak

後輩が誤って機密情報をコミットしてしまったらしいです。ひとまずコミットを上書きして消したからこれで大丈夫ですよね? 想定難易度: Easy

gitの過去commit内にflagがありそうなので適当に漁ります。

$ git reflog
7387982 (HEAD -> master) HEAD@{0}: reset: moving to 7387982
e0b545f HEAD@{1}: reset: moving to ORIG_HEAD
53edfaa HEAD@{2}: revert: Revert "feat: めもを追加"
e0b545f HEAD@{3}: reset: moving to HEAD
e0b545f HEAD@{4}: reset: moving to HEAD
e0b545f HEAD@{5}: reset: moving to HEAD
e0b545f HEAD@{6}: reset: moving to HEAD
e0b545f HEAD@{7}: commit (amend): feat: めもを追加
80f3044 HEAD@{8}: commit (amend): feat: めもを追加
b3bfb5c HEAD@{9}: rebase -i (finish): returning to refs/heads/master
b3bfb5c HEAD@{10}: commit (amend): feat: めもを追加
7387982 (HEAD -> master) HEAD@{11}: rebase -i: fast-forward
36a4809 HEAD@{12}: rebase -i (start): checkout HEAD~2
7387982 (HEAD -> master) HEAD@{13}: reset: moving to HEAD
7387982 (HEAD -> master) HEAD@{14}: commit: feat: めもを追加
36a4809 HEAD@{15}: commit: feat: commit-treeの説明を追加
9ac9b0c HEAD@{16}: commit: change: 順番を変更
8fc078d HEAD@{17}: commit: feat: git cat-fileの説明を追加
d3b47fe HEAD@{18}: commit: feat: fsckを追記する
f66de64 HEAD@{19}: commit: feat: reflogの説明追加
d5aeffe HEAD@{20}: commit: feat: resetの説明を追加
a4f7fe9 HEAD@{21}: commit: feat: git logの説明を追加
9fcb006 HEAD@{22}: commit: feat: git commitの説明追加
6d21e22 HEAD@{23}: commit: feat: git addの説明を追加
656db59 HEAD@{24}: commit: feat: add README.md
c27f346 HEAD@{25}: commit (initial): initial commit

$ git reset --hard 7387982
HEAD is now at 7387982 feat: めもを追加

$ ls
README.md  flag.txt  note.md

$ cat flag.txt
ctf4b{0verwr1te_1s_n0t_c0mplete_1n_G1t}

Mail_Address_Validator

サーバで動いているスクリプトが下記。

#!/usr/bin/env ruby
require 'timeout'

$stdout.sync = true
$stdin.sync = true

pattern = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
...

定義されているパターンにマッチしない文字列を与えると、タイムアウトしてflagが取得できる。

すでに入力文字列忘れてしまったのですが、確かこんな感じの文字列だったかと。

$ nc mail-address-validator.quals.beginners.seccon.jp 5100
I check your mail address.
please puts your mail address.
test@ihfiauhiuthiueahiuthewiuhgailwhgiuahlwhguawe
ctf4b{1t_15_n0t_0nly_th3_W3b_th4t_15_4ff3ct3d_by_ReDoS}

c(heck)_url

127.0.0.1にアクセスできればflagが取得できる問題。

localhostは当然使えず、サニタイジングされるのでa-zA-Z0-9:しか利用できない。

$url = preg_replace("/[^a-zA-Z0-9\/:]+/u", "👻", $url); //Super sanitizing

これは結局別のメンバーが回答してくれた(16進で渡すのが正解)。

自分は : を見てipv6を渡せば良いのでは?という固定観念に囚われてしまい、一敗。

depixelization

メンバ内で、OpenCVの利用経験があるのが自分だけだったため担当した問題。

depixelization_output

上記の様な画像が与えられました。

import cv2
import numpy as np

flag = "**********flag**********"
images = np.full((100, 85, 3), (255,255,255), dtype=np.uint8)

for i in flag:
    # char2img
    img = np.full((100, 85, 3), (255,255,255), dtype=np.uint8)
    cv2.putText(img, i, (0, 80), cv2.FONT_HERSHEY_PLAIN, 8, (0, 0, 0), 5, cv2.LINE_AA)

    # pixelization
    cv2.putText(img, "P", (0, 90), cv2.FONT_HERSHEY_PLAIN, 7, (0, 0, 0), 5, cv2.LINE_AA)
    cv2.putText(img, "I", (0, 90), cv2.FONT_HERSHEY_PLAIN, 8, (0, 0, 0), 5, cv2.LINE_AA)
    cv2.putText(img, "X", (0, 90), cv2.FONT_HERSHEY_PLAIN, 9, (0, 0, 0), 5, cv2.LINE_AA)
    simg = cv2.resize(img, None, fx=0.1, fy=0.1, interpolation=cv2.INTER_NEAREST) # WTF :-o
    img = cv2.resize(simg, img.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

    # concat
    if images.all():
        images = img
    else:
        images = cv2.hconcat([images, img])

cv2.imwrite("output.png", images)

中身の処理はそこまで難しいものではなく、
flag文字列に対してP,I,Xの文字列で上塗りし、縦横1/10に圧縮して元のサイズに引き延ばしている。

非可逆なのに何故か塗りつぶされた画像から復元しようとして延々と嵌っていた。

import cv2
import numpy as np

str = "qwertyuiopasdfghjklzxcvbnm1234567890!+*/-_"
...

こんな感じで取りうるアルファベットや特殊文字に同じ処理をかけて、類似文字でマッチングさせるのが早そうだったものの気づかず。二敗。