Learning cyber security by playing and enjoying CTFs

Cyber Security関係の雑記帳です。表明されているお気持ちなどは全て個人的なものであり、筆者が所属もしくは関係する組織・団体の意向とは一切関係ありません。

防衛省サイバーコンテスト2024 参加記+Writeup (Pickup)

1. はじめに

 昨年 8 月に続き、2024/2/25(土)9:00 JST ~ 21:00 JST に開催された「防衛省サイバーコンテスト2024」に参加しました。*1

 途中食事休憩などを挟みながらもほぼフルタイムで稼働、Web とNetwork が壊滅的でしたがそれ以外の分野ではどうにか全完し、396/560pts(15th / 314teams)という結果でした。

 Web と Network がマトモに出来ていればワンチャン上位も狙えたはずで、なんとも残念。しかしこれをあえて「伸びしろが大きい」と前向きに捉え、近いうちに「Web/Network 強化ソロ合宿」を敢行*2することで供養したいと思っています。

2. 参加記と全体的な感想

2.1. 参加記

 まずは、テンションを上げるため、スイーツを準備。

 メンタル不調は成績に直結する*3ので、お気持ちコントロールは大事です。

 そして BGM は youtube で喜歌劇「こうもり」。浮気にまつわるトラブルなど含めすったもんだの末に最後は「全部シャンパンのせい」にするのが「全部大泉のせい」みたいで好きです。*4

 閑話休題。ケーキを食してスタートした後、フルーツゼリー*5もやってしまい意識朦朧とするなどハプニングを重ねつつ、Crypto と Forensics を全完した段階でお気持ちもだいぶ楽になってきました。しかし、Web と Network がほとんど解けないのは辛かったです。まぁ自業自得*6なのですが。

2.2. 全体的な感想

 設問数は Welcome を除いて 31 問、前回と同じく難易度別に 10 点・20 点・30 点の配点がされておりました。SECCON Beginners CTF や Wani CTF と同様、解きやすい問題が多く、最近のCTF に見られる「難化傾向」とは対極にあるようでした。

 問題セットとしては 「問題自体はシンプルだが、解こうとすると凡庸な方法では解けない、パンチが効いたやつ」という傾向ではなく*7、どちらかというと一昔前の CTF や、picoCTF の easy ~ medium クラス問の雰囲気に近いのかなと感じました。

 また、大会中大きな不具合には遭遇しませんでしたが、一部設問に記載ミスがあったり、コンテストの問題としてはやや物足りないもの*8があったりと、官公庁主催の大会としてはビミョーかなと思えるところもありましたので、次回はそのあたりが良い方向へ修正されることを期待しています*9

3. Writeup(Pickup)

 解いた問題の中で、特に面白い💕と思った 3 問をピックアップして紹介します。

3.1 Une Maison (Misc, 10pts)

設問

画像 maison.jpg の中にフラグが隠されています。探してみてください。

 「maison.jpg」として、6000×4000 / 1.77MB という大きな画像が提示されます。

検討

 英語力がカスなので、「maison」を「メイソン」*10と読んでしまい、フリーメイソンのシンボルマークと XOR してみようと試みるも失敗。

 そういえば「めぞん一刻」という作品があったな、と思い出し、これは「メゾン」だ、と気づいて軌道修正しました。

 Google Lens でこの画像を調べると、類似画像が多数。しかしよく見ると、ルーフバルコニー付近に違和感が。

 謎にバーコードっぽくなっている所があるので、怪しいと判断しました。

解法

 バーコードの部分を切り出し、バーコードリーダーに投げたらフラグをゲットできました。

フラグ

flag{$50M!}

3.2 Twisted Text (Programming, 30pts)

設問

添付の画像 Twisted.png は、画像の中心からの距離 r [pixel] に対して

θ = - (r ^ 2) / (250 ^ 2) [rad]

だけ回転されています(反時計回りを正とします)。逆変換を施してフラグを復元してください。

検討

 Programming の問題なので、プログラムを作って逆変換すれば解けそうな気がしてきました。計算法を誤って精度を落とすとズレが生じそうですが、フラグが読めればよいのであまり気にしないことにします。

 ということで、逆変換するプログラムで雑に画像を作ればフラグが読めそうな感じがしましたのでそういう方針としました。

解法

 雑に逆変換をするプログラムを作りました。

 途中で止まって何でだろうと悩みましたが、回転させた際に画面の外にハミ出すものがあり得るので、それらはドロップして描けるものだけを描くようにしました。

「solve.py」

import math
import cv2
import numpy as np

L = 1280
ct = cv2.imread('Twisted.png')

def R(P):
  return math.sqrt(P[0]**2+P[1]**2)

def rotate(P):
  px, py = P[0]-L/2, P[1]-L/2
  r = R((px, py))
  theta = (r ** 2) / (250 ** 2)
  qx = math.cos(theta)*px - math.sin(theta)*py+L/2
  qy = math.sin(theta)*px + math.cos(theta)*py+L/2
  return (int(qx), int(qy))

pt =  np.zeros((L, L, 3))
for i in range(L):
  for j in range(L):
    _i, _j = rotate((i,j))
    try:
      pt[_i][_j] = ct[i][j]
    except:
      pass

cv2.imwrite('pt.png',pt)

以下の画像が出力されました。 真ん中のあたりで flag が読めそうです。

フラグ

flag{LHZGhq3WTXvo}

3.3 Serial Port Signal (Misc, 30pts)

設問

Tx.csv は、とあるシリアル通信の内容を傍受し、電気信号の Hi, Low をそれぞれ数字の 1 と 0 に変換したものです。通信内容を解析してフラグを抽出してください。

解答形式:flag{XXXXXXXX} (半角英数字)

「Tx.csv」という、CSV ファイルが提供されます。「microseconds」「logic」の 2 行からなり、「logic」行は 0 または 1 の値が入っています。

検討

 以前別の CTF で似たような問題を解いたことがあり、その時は連続する同じ値のいくつかの塊で1つのビットを表すので、まずはバイナリデータを取り出して、その後ゴニョゴニョやってデコードするという方針で行くことにしました。

解法

 まずは、バイナリデータ(0と1からなる文字列)に変換します。ざっと眺めると 5 個か 6 個の塊で1つのビットを表しているようでしたので、以下のようなコードを作ってみました。

「solve1.py」

s = open("Tx.csv","r").read().split("\n")
s = s[1:-2]

data = ""
current = ""
seq = 0

for x in s:
  valuei = int(x.split(",")[0])
  values = x.split(",")[1]
  if values != current:
    data += current * ((seq+1)//5)
    seq = 0
    current = values
  else:
    seq += 1

print(data)

 ここで 7bit 毎に切り出したり 0 と 1 を入れ替えたり、色々とゴニョゴニョやってみてもうまくいかず詰まってしまいました。

 思い切って 2pt 支払い第一ヒントを見ると、「UART」である旨お告げを受けました。ググってみると

「Startbit」+「データ(7bitか8bit)」+「パリティbit」+「Stop bit」

という形らしいので、辻褄が合うよう試行錯誤切り出してみると、データは 7bit で次のプログラムでデコードできるようになりました。

「solve2.py」

data = "000010010101010011010001101101000110110101111011010000001011010101010101000001010010010111000101011100101110010000001011011001111101001111110011101111000101110101101111010100100111001010110101010101010010110101011000011101010110010001010111000100010101011111010101100011"

flag=""

for i in range(0,len(data),10):
  flag += chr(int(data[i+1:i+8][::-1],2))
print(flag)

 実行すると、「Hello UART: synt{IjUZC5TD}」と表示されますが、フラグっぽい部分は ROTxx っぽい*11ので CyberChef で変換しました(ROT13でした)。

フラグ

flag{VwHMP5GQ}

4. おわりに:反省会

  • 😄Good: Web と Network 以外全完でき、前回よりも順位 up。
  • 😣Bad:Web と Network がほとんど出来ず壊滅。
  • 🏴‍☠️Next:苦手分野を強化!得意分野はもっと強化!

 前回(2023年)が 8 月開催でしたので、ひょっとして夏頃に「2024年第2回」があるのでしょうか?いずれにしても、次回もタイミングが合えば参加したいと思います。

*1:名義は前回と同様、「灰原武尊」(読み方は「はいばら たける」)です。

*2:おそらく、HTB をひたすらやる、というやつになります。

*3:直近で参加した closed な大会では惨敗でした。

*4:余談ですが、この劇中で一番報われないのはパトロンの座をオルロフスキー侯に奪われ色々とやり場を失ったフランク刑務所長だと思っています。

*5:実際のフルーツが入っているのではなく、着色料と香料によるものです。

*6:SECCON 電脳会議聴講して Web やる気になったにもかかわらずサボっていたツケです。反省。

*7:もちろん、あくまで自分が解いた問題の中では、の話ですが。

*8:例えば Short RSA Public Key は modulus が小さすぎて private key (N の素因数分解)は yafu で瞬殺で、crypto の middle 問としてはちょっと物足りない気がしました。

*9:問題のエスパー的な難化を期待はしておらず、むしろエスパー要素の排除を期待しています。

*10:メイソンから始まるメイソウというやつですね。

*11:「synt{」に既視感があると思ったら、去年の crypto easy 問でも ROT13 が出ていました。