SECCON TOWER 参加記のようなもの
SECCON TOWER 解けませんでした。しかし画像処理や機械学習の経験が無くても、ググりながら OpenCV などを使って画像の分類ができたので、その経緯をメモしておきます。
先の 12/10-11 の SECCON Online に @hiww くんに誘われて Harekaze というチームで参加していました。ただ、 pwn はバイナリが読めないので手が出せず、他の問題も分からず。そのとき丁度 TOWER が行き詰まっているようだったので、やってみることにしました。
すでにプロ各位によりセマフォア信号で base32 でエンコードされているのではという推測が立っており、 @yuiki さんにより各信号のフレームも画像に抽出されている状態でした。
したがってこれらの画像をうまく分類することを考えます。 imagemagick で対象物周辺を切り出し、「opencv 画像 類似度」で検索、テンプレートマッチングを使うとマッチ度合いが取れそうなので試してみるも精度が出ず。
OpenCVのテンプレートマッチング | @knok blog
背景の写真がノイズになっているのかな、物体だけ取り出したい。そのためまずは背景を抽出することにしました。
python/OpenCVで複数の画像から背景だけを取り出す - BlankTar
わりと綺麗に抽出できたように思います。
この背景画像との差分を取って前景を抽出します。
Python3 OpenCV3で背景差分を求める - from umentu import stupid
うまくいかない……
ここでフレームを追うごとにカメラの位置が微妙にずれていっていることに気がつきます。そこで画像の位置合わせをすることに。以下の記事に行きつきます。
Image Alignment (ECC) in OpenCV ( C++ / Python ) | Learn OpenCV
よさそうです。ついでに2値化もしておきます。
Python OpenCV3で画像の画素値を二値化して出力 - from umentu import stupid
機械学習で使いそうなそれっぽい画像ができました。
で、これをどうやって分類するかですが、 kmeans を使えばよしなに分類してくれるような、と思ったのでこれを試してみます。
scikit-learn による最も基本的なクラスタリング分析 - Qiita
scikit-learn を使えば1行でできるとのこと。今回はクラスタの数も32だと分かっているのでこれでできそうです。そしてこれに突っ込む特徴量をどうするか考えます。ふつうはメッシュ特徴量とかを取るみたいなんですが、ためしに 8x8 に縮小してみたらいい感じにボケたので、これをそのまま使ってクラスタリングしてみます。
クラスタ毎にフォルダに分けます。
これは、結構いいんじゃないか?
いくつかのフォルダ内のサムネを目視で確認したところ、大方合っているように見えます。で、各クラスタとアルファベットの対応表ですが、時間が少なかったので @yuiki さんと手分けして手作業で作成しました。そしてデコード。
頼む、うまくいってくれ〜〜という気持ちでしたがパディングが合わずデコードできないままここで時間切れに。
なお2時半くらいから始めて途中睡眠も挟んで結局最後まで解けなかったので9時間以上かかっていることになります。手でやった方が早いんじゃ……とか思いながらコーディングしてたよね、うん。
後日談
因みに問題点が2点存在していたのでパディング詰めてもだめでした。1点はAが2つのクラスタに分類されたために、BとSが1つのクラスタに分類された点で、もう1点は急いでいたので対応表に4箇所誤りがあった点です。
したがってクラスタ数を33に増やしてクラスタリングを行い、心を落ち着かせて対応表を書いたところ、QRコードが表示されました!