ちょっと興味があって、先日公開されたSSHのIntegrityを破る攻撃であるところのTerrapin-Attack (https://terrapin-attack.com) について調べて社内勉強会で発表したりしていました。せっかくなので日本語のメモを残しておきます。
概要
中間者がパケットをDROPできるというのが攻撃。サーバ・クライアントはそのパケットがDROPされたことに気が付けないので、Integrityが破られたということになる。1つパケットをDROPするので辻褄合わせのために1つ偽造しておくことになる。
原理
前提: サーバ・クライアントはメッセージ番号のカウンタを持っていて、MACの計算に使われたりする
これは論文の図がわかりやすいと思う。サーバ・クライアントはそれぞれ今いくつメッセージを送っていて、いくつのメッセージを受け取っているかをカウンタとして持っている*1。論文中ではそれぞれSnd, Rcvという名前になっていて、基本的にはサーバのSnd = クライアントRcvで逆も然り。
暗号方式によっては、このカウンタがMACの計算に使われる*2。Terrapin-Attackでは、このカウンタの値をサーバ・クライアント間でずらしておくことで、一個メッセージをDROPしたときにSnd, Rcvの値がずれないようにする=MACの計算が正常に行われるようにすることで、メッセージのDROPに気が付かせない
攻撃: IGNOREパケットを偽造する
攻撃者はSecure Connectionの確立前(=鍵共有の完了前)にIGNOREパケット*3を偽造する。図ではクライアントに対して送り付けているけど逆でもよくて、どのパケットをDROPしたいかによる。
Secure Connectionの確立前なので通信はTCP平文で行われていて、中間者がパケットの盗聴・偽造が可能。これにより、サーバのSndに対してクライアントのRcvが1多い状態になる。
攻撃: パケットをDROPする
攻撃者はSecure Connectionの確立後の最初のパケットをDROPする。図ではサーバ→クライアントのパケットをDROPしている。これにより、クライアントのRcvは上がらないがサーバのSndが1上がる。先にIGNOREパケットを偽造しておいたお陰で、ここでサーバのSndとクライアントのRcvの値が揃う。
普通はパケットが1つ消えると、次のパケットの送信でSnd, Rcvの値がずれてMACの検証に失敗して気がつけるが、次のパケットのMACの検証は成功するのでサーバ・クライアントはパケットの消失に気がつけず、攻撃が成立した。
脅威
で、Secure Connection の確立後のパケットがDROPできるのがどれだけ脅威なのか。論文によると、Secure Connection確立後の最初のパケットはEXT_INFOってやつでSSHの拡張プロトコル的なやつらしい。これでkeystroke timing countermeasureみたいなセキュア機能を有効にするんだが、それを阻止できる(クライアントからみると、サーバはEXT_INFOを送ってこないので拡張プロトコルに対応してないんだなと思わせられる)。
したがって他の攻撃を通しやすくなる、ということっぽい
対策
OpenSSH 9.6にはこの攻撃への対策が導入されている。strict KEXと命名された。
SSHハンドシェイクの最初のパケットであるKEX_INITパケットには、そのサーバ/クライアントが対応する暗号方式がalgorithm_listとして含まれるが、algorithm_listにstrictモード用の識別子 [email protected]
/ [email protected]
が追加される。これは暗号方式ではなく、自分がこれを送っていて相手がこれを送ってきたらstrict KEXをやりますという値。
strict KEXに入ると、SSHハンドシェイク中のIGNOREパケットとDEBUGパケットは無視されるようになり、このパケットを受け取ってもRcvカウンタがインクリメントされなくなる。
まとめ
……という話をしたら、じゃあKEX_INITを改竄すればいいじゃんという指摘をもらって、たしかにと思ったけど、KEX_INITの値はこのあとのKEX_DHREPLYで計算されるハッシュに利用されるので改竄されると気が付かれるようだった。逆にIGNOREはそういうハッシュに含まれないので気がつけない。このあたりTLSはTranscript Hashなるやつを採用していて対策できていると論文にあった気がするので、次はそのあたりが気になる*4
なんにせよこういう面白い話を知れるのは楽しいですね