[日本語] [English]

Neurotic

プログラム src.py と、ファイル model.pth が与えられた。
src.py は、以下の処理をするものだった。

まず、nn.Linear(8, 8, bias=False) とは何かを調べると、 8次元の入力を行列の掛け算により8次元の出力に変換する処理 (bias=False なので定数の加算はしない) のようだった。

Linear — PyTorch 1.10.0 documentation

次に、nn.Sequential とは何かを調べると、渡された処理をそれぞれ順に行う処理のようだった。

Sequential — PyTorch 1.10.0 documentation

これらを組み合わせた nn.Sequential(*([nn.Linear(8, 8, bias=False)] * 7)) は「8次元の入力を行列の掛け算により8次元の出力に変換する処理」を7回繰り返す処理ということだとわかった。

次に、model.pth をバイナリエディタで見ると、先頭に PK が見えた。
そこで、これはzipアーカイブであると推測し、7-Zipで展開した。
すると、archive/data/93839392490432 という256バイトのファイルがあり、これが nn.Linear で用いられる行列のデータであると推測した。
そして、この行列のデータをテキストに変換する以下のプログラムを作成した。

bin2mat.pl

さらに、src.py の出力としてコメントで書かれているデータもBase64デコードすると256バイトになったので、同様に行列を表すテキストに変換した。

ここで、実験のためにflagの最初の部分 buckeye{CyberChefで To Decimal をかける。

To Decimal - CyberChef

Raspberry Pi の wolfram コマンドを利用して、この変換結果に model.pth から読み取った行列の7乗を掛けてみた。

model_test.txt

結果は以下のようになった。

Out[4]= {{0.438170130153532794, -0.007831040597014949, -0.104243176889190001,

>     0.344312929055393102, -0.413639742721401102, 0.082283533362897931,

>     0.013686747264994923, -0.068815595488821103}}

これは、出力データから読み取った以下の行列の1行目と近い値である。

{0.4381701052188873291015625, -0.007831037044525146484375, -0.10424315929412841796875, 0.3443129360675811767578125, -0.4136398136615753173828125, 0.082283549010753631591796875, 0.0136867575347423553466796875, -0.06881560385227203369140625}

出力データから読み取った行列に、model.pth から読み取った行列の7乗の逆行列を掛け、さらにその結果を四捨五入した。

model_reverse.txt

以下の結果が得られた。

Out[6]= {{98, 117, 99, 107, 101, 121, 101, 123},

>    {119, 52, 49, 116, 95, 49, 116, 115},

>    {95, 52, 108, 108, 95, 109, 52, 116},

>    {114, 49, 120, 95, 109, 117, 108, 116},

>    {49, 112, 108, 49, 99, 97, 116, 49}, {48, 110, 63, 63, 63, 63, 95, 52},

>    {108, 119, 121, 52, 121, 53, 95, 104}, {52, 115, 95, 98, 51, 51, 110, 125}}

この結果をCyberChefで変換することで、flagが得られた。

Find / Replace, From Decimal - CyberChef

buckeye{w41t_1ts_4ll_m4tr1x_mult1pl1cat10n????_4lwy4y5_h4s_b33n}

writeup by MikeCAT

BuckeyeCTF 2021