6/20/2019

TCP SACK Panicについて知っておくべきこと

SANS Diaryより

Netflixは、Linux(そして場合によってはFreeBSD)が選択的確認応答(SACK: Selective TCP Acknowledgement)オプションを処理する方法にいくつかの脆弱性を発見しました [1]。最も深刻な脆弱性はカーネルパニックを引き起こし、システムを応答不能にします。この脆弱性へのパッチの適用は重要です。この脆弱性が悪用されると、公開されているサーバーや悪意のあるサービスに接続している可能性のあるクライアントをシャットダウンするために利用される可能性があります。

CVE 影響するOS 説明/影響
CVE-2019-11477 Linux > 2.6.29 SACK処理整数オーバーフロー。 カーネルパニックにつながる
CVE-2019-11478 Linux < 4.14.127 SACKの低速または過剰なリソース使用
CVE-2019-5599 FreeBSD RACK Send Map SACK Slowness
CVE-2019-11479 Linux (全バージョン) 低いMSS値による過剰なリソース消費

現在のLinuxシステムを使用していて、選択的確認応答を有効にして(一般的なデフォルト)、TCPセグメントオフロード(最近のサーバでも一般的なデフォルト)を使用してネットワークカードを使用している場合、あなたは脆弱です。パッチが公開されました。あるいは、SACKを無効にすることもできます。

Netflixはその勧告にLinuxカーネル用のパッチを含めました。次のLinuxカーネルバージョンにはパッチが含まれています: 4.4.182、4.9.182、4.14.127、4.19.52、5.1.11

SACKとは何か?

ネットワークに接続されている各ホストは、特定の最大サイズ(MTU)のパケットを送信することができる。このサイズは、使用されているネットワークテクノロジによって異なります。イーサネットの場合、通常のサイズは1500バイトです。しかし、イーサネットの場合は9,000バイトにもなります。このスペースの一部はヘッダーに使用されます。標準の20バイトのIPヘッダー、および20バイトのTCPヘッダーを使用すると、TCPパケットは通常最大1,460バイトのデータ(「最大セグメントサイズ」)を保持できます。TCPはデータストリームをこのサイズを超えないように十分に小さいセグメントに分割し、ホストは断片化の可能性を減らすために、それぞれの最大セグメントサイズを互いに通信します。

TCP接続でパケットを順序付けるために、送信される各バイトにシーケンス番号が割り当てられ、TCPヘッダーにはパケットに含まれる最初のバイトのシーケンス番号がリストされます。受信機は、それが期待する次のシーケンス番号を通信することによって、それがどのシーケンス番号を受信したかを確認します。

完全なセグメントを承認するだけでは、少し効率が悪くなります。受信者は、既にいくつかの順序の乱れたデータを受信したことを送信者と通信することはできません。代わりに、最後に受信したセグメントの最後のセットを認識し続けます。

この非効率を避けるために、SACKが導入されました。受信者が順序がバラバラのセグメントを受信したことを送信者に通知することを可能にします。「私はシーケンス番号10まですべてを受け取り、次に11を期待しますが、20-30も受け取りました」。 このようにして、送信者は11-19だけを再送し、次に31に進むことが分かります。

TCPセグメントオフロードとは何か?

TCPセグメントオフロードは、最新のネットワークカードに含まれている機能です。 CPUがTCPセグメントをバッファして組み立て直すためにしなければならない作業を減らすために、ネットワークカードはTCP処理の一部を引き受けます。この場合、オペレーティングシステムはネットワークのMTUを超える大きな「パケット」を受信します。

TCP SACK Panicとは何か?

オペレーティングシステムは、データが送信(および確認)されるか受信されるまでデータを保存する必要があります。Linuxは「ソケットバッファ」と呼ばれるデータ構造を使います。Linuxでは、このソケットバッファは最大17セグメントを保持できます。パケットが送信され確認応答されると、データが構造から削除されるか、データの一部が統合される場合があります。データを移動すると、場合によっては17を超えるセグメントが格納され、その結果カーネルパニックが発生する可能性があります。

これを防ぐために私は何ができるか?

  1. LinuxでSACKを無効にする

    再起動せずにSACKを一時的に無効にすることができます。rootとして実行します。

    setenforce 0
    echo 0 > /proc/sys/net/ipv4/tcp_sack
    

    1行目はSELinuxを使用している場合にのみ必要です。2行目のステートメントがブロックされる可能性があるからです。

    この変更を永続的なものにするには、/etc/sysctl.confに次の行を追加します(または/etc/sysctl.d内の新しいファイルとすれば、おそらくよりきれいになります)。

    net.ipv4.tcp_sack = 0
    net.ipv4.tcp_dsack = 0
    net.ipv4.tcp_fack = 0
    

    再起動せずに変更を適用するには、「sysctl -p」を実行して下さい(そしてまた、SELinuxを無効にする必要があるかもしれません)。


  2. ファイアウォールのルール

    この不正利用には、非常に小さい最大セグメントサイズ設定が必要です。iptablesで小さなMSSをアドバタイズするパケットをブロックすることができます。

    iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
    

    RFC 879によると、TCPは最低576のMTUを必要とし、最低MSSは536です。

    自分が脆弱であることをどうやって知ることができますか?


  3. 脆弱なシステムの発見

    脆弱なシステムを見つけるために利用できる簡単なスキャンツールはありません。これまでのところ、脆弱なシステムを見つけるのに使用される可能性がある利用可能なPoCエクスプロイトはありません。簡単なテストとして、SACKをサポートしている(そしてLinuxを実行している)システムを探すことができます。次のtcpdumpコマンドが役立ちます。

    tcpdump -i eth0 -n 'ip[8]<65 and tcp[13]&0x2f=2' | grep 'sackOK'
    

    このコマンドは、(これをLinuxシステムに限定するために)65未満のTTLで設定されたSYNまたはSYN-ACKフラグを持つシステムを識別するのに役立ちます。SackOKオプションには様々な位置に表示される可能性があるため、単純なフィルタはありません。そのため、「grep」で少し騙しました。

    TCPオフロードが有効になっているかどうかを確認するには、Linuxでethtoolコマンドを使用できます(ethtool -k interface_name)。[Twitterでこれを指摘してくれたAlanに感謝します。]

ベンダー声明/パッチ

Redhat: https://access.redhat.com/security/vulnerabilities/tcpsack
Ubuntu: https://usn.ubuntu.com/4017-1/
Debian: https://www.debian.org/security/2019/dsa-4465
SUSE: https://www.suse.com/de-de/support/kb/doc/?id=7023928
Cloudflare: https://twitter.com/jgrahamc/status/1140724787242819585
Amazon: https://aws.amazon.com/security/security-bulletins/AWS-2019-005/

[1] https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-001.md