スマートフォン解析 top

TOP > タイガーチームセキュリティレポート > OpenSSLのAES-NIにおけるパディングオラクルの脆弱性(CVE-2016-2107)

タイガーチームセキュリティレポート

OpenSSLのAES-NIにおけるパディングオラクルの脆弱性(CVE-2016-2107)

2016年5月に公開された「Padding oracle in AES-NI CBC MAC check」の検証をしました。 この問題は、2013年に公開された「Lucky 13 padding attack (CVE-2013-0169)」の修正の際に入り込んだバグが原因であります。

1.0.2h未満のOpenSSL/1.0.2x系と、1.0.1t未満のOpenSSL/1.0.1系に影響があります。 AES-NIにおけるCBC MAC checkに不備が存在するため、AES-CBC暗号スイートが有効なサーバにて、中間者攻撃が可能な場合、パディングオラクル攻撃を使って通信内容を復号可能です。 脆弱性の有無が確認できるPoCが公開されているため、以下の検証を実施しました。


■検証PoC:
https://github.com/FiloSottile/CVE-2016-2107

このPoCは、TLSのAES-CBC暗号スイートで接続した後に、任意のサイズのパディングを送付しています。

脆弱性のあるOpenSSL/1.0.1s:
$ openssl s_client -connect www.example.com:443 -quiet
(省略)
HEAD / HTTP/1.0

HTTP/1.1 200 OK
Date: Mon, 28 Nov 2016 06:54:51 GMT
Server: Apache/2.2.31 (Unix) mod_ssl/2.2.31 OpenSSL/1.0.1s   ←サーバで利用中のOpenSSLバージョン1.0.1s
(省略)
$
$ CVE-2016-2107 www.example.com:443
2016/11/28 15:48:31 Vulnerable: true                         ←脆弱性ありのため「true」と表示される
$

脆弱性が対策されたOpenSSL/1.0.1t:
$ openssl s_client -connect www.example2.com:443 -quiet
(省略)
HEAD / HTTP/1.0

HTTP/1.1 200 OK
Date: Mon, 28 Nov 2016 07:14:12 GMT
Server: Apache/2.2.31 (Unix) mod_ssl/2.2.31 OpenSSL/1.0.1t   ←サーバで利用中のOpenSSLバージョン1.0.1t
(省略)
$
$ CVE-2016-2107 www.example2.com:443
2016/11/28 16:22:24 Vulnerable: false                         ←脆弱性なしのため「false」と表示される
$

このようにPoCを実行すると、CVE-2016-2107の脆弱性の有無が判明します。 何故、判明してしまうのでしょうか。別のPoCを用いてTLS通信の中を覗いてみると、Alertのメッセージに差異があることが確認できます。


■検証PoC:
https://www.exploit-db.com/exploits/39768/

脆弱性のあるOpenSSL:
$ java -jar TLS-Attacker-1.2.jar client -workflow_input rsa-overflow.xml -connect www.example.com:443
(省略)
ALERT message:
  Level: FATAL
  Description: RECORD_OVERFLOW
$

脆弱性が対策されたOpenSSL:
$ java -jar TLS-Attacker-1.2.jar client -workflow_input rsa-overflow.xml -connect www.example2.com:443
(省略)
ALERT message:
  Level: FATAL
  Description: BAD_RECORD_MAC
$

Alert(Alert Protocol)は、SSL/TLS通信においてエラーが発生した際、 相手に異常を伝えるプロトコルです。検出されたAlertの 意味は以下の通りです。

・BAD_RECORD_MAC…レコードの受信時にMACを検証し、異常があった場合にAlertを返す。
・RECORD_OVERFLOW…レコード受信後、長さが異常である場合にAlertを返す。
 参照: https://www.ipa.go.jp/security/rfc/RFC5246-07JA.html#0722

SSL/TLS通信では、暗号化された送信データ(レコード)が、 「本当に目的の相手から送信されたものなのか?途中で改ざんされていないか?」を確認するため、復号の際にレコード内のMACを検証します。 もし、MACに異常があった場合は、途中経路で改ざんなどの攻撃を受けた可能性があるとして「BAD_RECORD_MAC」を返します。

対策済みのOpenSSLでは「BAD_RECORD_MAC」ですが、 未対策のOpenSSLでは「RECORD_OVERFLOW」となっているため、 MACの検証がスルーされていることがわかります。これはどういうことでしょうか。


ブロック暗号は、一定のブロックサイズごとに暗号化を行う方式です。 入力データがブロックサイズ未満である場合、パディングを付与してブロックサイズを満たすよう調整します。

例えば、AESで暗号化する場合は16byte(128bit)のブロックサイズごとに処理されます。 データが5byte、MACが20byteの場合、全体のブロックサイズは16byteの倍数の32byteとなります。 このままでは入力データがブロックサイズ未満であるため、以下のように6byte分パディングされ、 最後にパディングの値[6]を示す1byteがパディング長としてが付与されます。

32byte[black size] = [XXXXX]+[          MAC          ]+[666666]+[6]
                     5(data)+         20(MAC)         + 6(pad) +1(pad-len)

もし、データがブロックサイズ(16byte)の倍数である場合、 1ブロック分、パディングのみで構成されたブロックが発生します。

32byte[black size] = [XXXXXXXXXXXXXXXX]+[          MAC          ]
                     12(data)          +         20(MAC)

16byte[black size] = [151515151515151515151515151515]+[15]     ←パディングのみで構成されたブロック
                     15(pad)                         +1(pad-len)

パディングのみで構成されたブロックは、MACがないため、 パディングが改ざんされたかどうかをチェックする仕組みがありません。そのため、パディングの内容が改ざんされた場合も受け入れてしまう可能性があります。


OpenSSLの修正箇所を見ると、復号の際にMACやパディングを検証するコードにret &= constant_time_ge(maxpad, pad);という行が追加されています。

             pad = plaintext[len - 1];
             maxpad = len - (SHA_DIGEST_LENGTH + 1);
             maxpad |= (255 - maxpad) >> (sizeof(maxpad) * 8 - 8);
             maxpad &= 255;

+            ret &= constant_time_ge(maxpad, pad);

これは「パディング長の値(pad)が、最大のパディング長(maxpad)よりも長い場合に0xFFを返す」と言う内容です。 パディングの値とパディングに対するチェックがなかったため、任意のパディングを挿入する事ができました。 その結果、検証PoCで送信されているような、任意のサイズのパディング(パディングのみで構成されたブロックが発生する程の長いパディング)が送信された場合、 MACのチェックがスルーされ「BAD_RECORD_MAC」ではなく、「RECORD_OVERFLOW」を確認できたという事です。

※イメージ:
32byte[black size] = [XXXXX]+[          MAC          ]+[AAAAAAA]
                     5(data)+         20(MAC)         +7(pad)
32byte[black size] = [AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]+[A]     ←パディングのみで構成されたブロック
                     31(pad)                          +1(pad-len)


今回の脆弱性はサービス提供妨害や情報漏洩などを引き起こすものではないですが、 脆弱性を利用する事で、OpenSSLのバージョンを秘匿している場合でも、 未対策のバージョンのOpenSSLを利用しているかどうか判断ができます。

脆弱性のあるOpenSSL:
$ openssl s_client -connect www.example.com:443 -quiet
(省略)
HEAD / HTTP/1.0

HTTP/1.1 200 OK
Date: Mon, 28 Nov 2016 08:06:10 GMT
Server: Apache                             ←バージョン情報は非表示
(省略)
$
$ CVE-2016-2107 www.example.com:443
2016/11/28 15:48:31 Vulnerable: true       ←脆弱性ありのため「true」と表示される
$

バージョンの隠蔽は、攻撃者に対して情報収集を多少しにくくする効果がありますが、 根本的な問題の解決にはなりません。 古いソフトウェアを使用していると、他の攻撃の手がかりにされたり、 攻撃者に管理が適当で脆弱なサーバであるという印象を抱かせ、 将来的に深刻な脆弱性が出た際に狙われる可能性があります。 そのため、脆弱性が公表された場合は、パッチを当てるもしくはアップグレードを推奨します。


参考情報:
[1] OpenSSL Security Advisory [3rd May 2016]
https://www.openssl.org/news/secadv/20160503.txt
[2] Yet Another Padding Oracle in OpenSSL CBC Ciphersuites
https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/
[3] CVE-2016-2107
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-2107


タイガーチームサービス事業部 R&D部