TMCTF2019 Writeup Wildcard 100

どうも。duckです。
TMCTFやりました。

ぱっと見Cryptoがなくてテンション下がりましたが1題解けたのでWriteup書きます。

・Wildcard 100
配られたのは3と6の手書き画像が3万個くらいあるファイル。
Dropbox - data.zip - Simplify your life
こんなん。

f:id:falconctf:20190908184541j:plain
3と6の狂気

問題文によると、
1.3と6の画像を分ける。
2.そのあとそれぞれのユニークなファイルを数える。
3.flagはTMCTF{3の画像の数_6の画像の数}

としろとのことなのでやりました。
MISCとかに近い感じですね。

1.3と6を分ける
人力で分けるのはつらすぎるので、問題文に書いてある通りクラスタリングアルゴリズムを使います。
まあ端的に言えば機械学習です。
いい感じのサイトを見つけたのでコードを使わせていただく。
scikit-learnで国旗画像をクラスタリングして似ているものを探す │ Web備忘録
modifyしたやつ。

import os
import shutil
import numpy as np
from PIL import Image
from skimage import data
from sklearn.cluster import KMeans

# 1. RGBに変換して保存する
for path in os.listdir('./data'):
    img = Image.open(f'./data/{path}')
    img = img.convert('RGB')
    img.save(f'./convert/{path}')

# 2. 3次元配列の画像データを2次元配列のデータに変換
array=np.array([path for path in os.listdir('./convert')])
feature = np.array([data.imread('./convert/'+path) for path in array])
feature = feature.reshape(len(feature), -1).astype(np.float64)

# 3. 学習(2種類のグループにクラスタリングする)
model = KMeans(n_clusters=2).fit(feature)

# 4. 学習結果のラベル
labels = model.labels_

# 5. 学習結果(クラスタリング結果の表示 + ラベルごとにフォルダ分け)
for label, path in zip(labels, os.listdir('./convert')):
    os.makedirs(f"./cluster/{label}", exist_ok=True)
    shutil.copyfile(f"./data/{path}",f"./cluster/{label}/{path}")
    print(label, path)

ちなみにこれサーキットラーンっていうライブラリ使ってます。
あとはてテンサーフローとかも有名ですよね。

まあそれはさておき、これで3と6のデータをよりわけることができましたとさ。
3が16768個で6が17254個でした。
はじめてやったけど教師なし学習ってこんなにきれいに分けられるのね。少しビビった。

2.ユニークなファイルを数える
どうすんだこれ。
バイナリで比較すりゃいいかと思って↓のコード書いた。

import numpy as np

def openread(path):
    a = open(path,"rb")
    img = a.read()
    a.close()
    return img

path='./0'
array=np.array([openread(path) for path in os.listdir(path)])
set = set(array)
print(len(set))

結果的にはこれでできてなかった。
phoenixによると、バイナリが違うのに画像として同じファイルが3の画像に一個あったらしいので
それを考慮して
flag:TMCTF{14962_347}

正直作問ミスかと思いました。phoenixがいてよかった。
引き続きN1CTFのWriteupも書かなきゃ。(終了まであと2時間あるけど諦め体制)