ぺんぎんさんのおうち

日本語勉強中のドイツ産ペンギンがいろんなことを書く

zlibに対する攻撃を考える

あるCTFでこれを使った問題が出ていたので勉強のために.

 

zlibで圧縮したものを暗号化する場合, 平文と暗号文の長さが同じになるアルゴリズムを使うのは危ないよという話. 例えばAES-CTRとかRC4とか.

16bytes等のパディングをした方が良さそう.

 

基本的な内容は以下のサイトに書いてある.

www.sjoerdlangkemper.nl

要するに, 

data = zlib.compress(SECRET + your_input) 

 dataがわかるとき, 同じ文字列が複数回含まれるデータをzlib圧縮すると圧縮後のデータ数が小さくなるのを利用してSECRETが何かを推測することができる.

 

例えば

SECRET が "koresuki" であるとして

c1 = "koresuki" + "a" * 20

c2 = "koresuki" + "b" * 20

...

"koresuki" +  [a-z]を20回繰り返した文字列 を c1, c2, ...

それぞれ圧縮して長さを見てみると

"koresuki" + "i" * 20

のときだけ小さくなる.

 

最後の文字が "i" であることがわかったので, 次は

"koresuk" + "[a-z] + i" * 20

を試すと "ki" が得られる.

 

これを繰り返していくと SECRET を得ることができる.

 

 

以上を踏まえて検証してみた.

test

 

それぞれの文字を与えたときの圧縮後のデータ長を確認して最も小さいものを候補としている.

このコードだとSECRETに連続して同じ文字が使われている場合に対応できないので注意. 

 

実行結果は

[('a', 26), ('b', 26), ('c', 26), ('d', 26), ('e', 26)]
augimugi_suko

 1文字目が復元できていないが, SECRET = "secret_mugimugi_suko" となっていればちゃんと

[('m', 31), ('a', 32), ('b', 32), ('c', 32), ('d', 32)]
mugimugi_suko

:ok_hand:

むぎむぎすこだぞ