てきとうなメモ

本の感想とか技術メモとか

POODLE攻撃

読んだ。中間者攻撃でかつ被害者に何度もリクエストを投げさせないといけないようなので、攻撃はちょっと難しそうな気がする。

脆弱性の原因はSSLv3とCBCの組合せにある。

CBCはブロック暗号で平文を(P_1, \cdots, P_n)として暗号文を(C_0, \cdots ,C_n)とすると
{\displaystyle
C_i = \begin{cases}
IV  & (i = 0) \\
E_k(C_{i-1} \oplus P_i) & (1 \leq i \leq n) \\
\end{cases}
}
となる。E_kは暗号化鍵をkとする暗号化関数。

復号する場合は、D_k(kを鍵とする復号関数)を用いて
{\displaystyle
P_i = D_{k}(C_i) \oplus C_{i-1}
}
で復号できる。

ブロック暗号なので、ブロックのサイズに足りない部分はパディングされる。で、SSLv3だとどうも1ブロックまるごとパディングとその長さ情報にすることができるようだ。また、パディングの内容は特に制限されず受信側では長さチェックのみされるみたい。RFCをみても特に長さ以外の制限はないようだ。

block-ciphered struct {
   opaque content[SSLCompressed.length];
   opaque MAC[CipherSpec.hash_size];
   uint8 padding[GenericBlockCipher.padding_length];
   uint8 padding_length;
} GenericBlockCipher;

...

padding
Padding that is added to force the length of the plaintext to be a multiple of the block cipher's block length.
padding_length
The length of the padding must be less than the cipher's block length and may be zero. The padding length should be such that the total size of the GenericBlockCipher structure is a multiple of the cipher's block length.
https://tools.ietf.org/html/rfc6101#section-5.2.3.2

1ブロックをまるごとパディングにした場合、ブロックのサイズをLとすると、L-1バイト目までは任意の値、Lバイト目が(L-1)となる。

パディングのブロックは最後のブロックなのでC_nになるが、攻撃者はこのブロックをi番目のブロックC_iに書き換えてサーバに送信する。パディングの部分はMACの対象になっておらず、改ざんされても検知できない。

サーバはこれを復号してパディングの長さチェックをし、通常(255/256の確率で)は長さチェックでエラーになるが、偶然(1/256の確率で)正常なパディングとみなされる場合がある。この場合、パディングブロックC_nの最後のバイトC_n[L-1]がパディングの長さL-1になっているので以下の式が成り立つ

D_k(C_n)[L-1] \oplus C_{n-1}[L-1] = D_k(C_i)[L-1] \oplus C_{n-1}[L-1] = L-1

さらに、CBCの復号の式により
{\displaystyle
\begin{align}
P_i[L-1] & = D_k(C_i)[L-1] \oplus C_{i-1}[L-1]\\
                 & = (L-1) \oplus C_{n-1}[L-1] \oplus C_{i-1}[L-1]
\end{align}
}

暗号文C_{n-1}[L-1],C_{i-1}[L-1]は中間者である攻撃者には見えているので、P_i[L-1]が攻撃者には読めてしまうことになる。1/256の確率を1にするための方法は明記されていなかったが、IVが変化するのならば何回もリクエストを送れば、平均256回で当たりそうだ。

で、1バイトは判明したが他のバイトも解読したいとなると、BEAST攻撃と同じようにずらして解読したい1バイトがブロックの最後にくるようにすれば良い。

こうすることで平均(解読したいバイト列の長さ)*256回のリクエストで解読することが可能。

脆弱性の原因としては、パディングがMACの対象になっておらず改ざん可能なこととパディングの値が任意の値でOKなことかな。TLSv1.0では任意の値は設定できなくなっておりpadding_lengthで埋めることになっている。