Foxglove Security は、2015年1月に @frohoff と @gebl が発表した"AppSecCali: Marshalling Pickles" (動画, スライド)を分析した最近の報告で、複数のゼロデイ、リモート実行できるエクスプロイットの存在を認めた。信頼されないネットワークソースで Apache Commons Collections, GroovyやSpring のようなライブラリを使ってオブジェクトをデシリアライズする Java アプリケーションの中に見つかったものである。多くのアプリケーションサーバがデータストリームやクッキー値からオブジェクトのデシリアライズをサポートするようになったため、エクスプロイットコードが HTTP リクエストを通じてファイアウォールやスキャナの裏にあるサーバで実行できるのは自明のことである。
Apache Commons Collections 3.x に対する概念実証コード は JBoss, Jenkins, Weblogic や WebSphere に効果があると言われている。Apache Struts vulnerability in 2014 で挙げられているものほど実行はたやすくないが、コードは強力で、現在検出されているより多くの箇所で見つかるだろう。
この脆弱性は Java オブジェクトのデシリアライズが任意のクラス名とデータを持ったインスタンスを作成できるという事実に起因する。Apache Commons Collections 3.x のケースでは、入力オブジェクトが他のオブジェクトタイプに変換できる Transformer クラスを含んでいる。これはデシリアライズのルーティーンにより自動的に呼び出されるもので、全く異なるオブジェクトを供給することを可能にしてしまう。ChainedTransformer と ConstantTransformer が組み合わさってオブジェクトのインスタンスを生成し、任意のメソッドを実行するために InvokerTransfomer インスタンスを使うシリアライズフォームの Constant field を作り出すものだ。
概念実証コードは作成者によって検証が行われ、Apache Commons Collections 3.2.1 の脆弱性が実在することを立証している。概念実証は Unix システム用に開発された(Runtime.exec("touch /tmp/pwned")
を実行することによってファイルが生成される); しかし基本的にはあらゆる OS でどんなコマンドでも実行できる。概念実証は Apache Commons Collections 3.x もターゲットとしている; Apache Commons Collections 4.x が異なるパッケージネームスペース(org.apache.commons.collections4
)を使用しているためである。Apache Commons Collections 4.x に対するエクスプロイットは他にあり、Groovy 2.x (2.4.4未満) や Spring 4.x と共に upstream repository に置かれている。
アップデート: Guillaume Laforge 氏が InfoQ にコンタクトを取ったところ、Groovy のエクスプロイットは2.4.4の GROOVY-7504 に含まれる CVE-2015-3253 で修正された。Apache Foundation の初リリースに合わせて今年の初めに行われたものである。この問題は Groovy の古いバージョンに現れるため、ユーザには Apache の現在のリリースをアップグレードして回避することを勧めている。
全てのケースにおいて、エンドユーザが提供したデータはオブジェクトに恣意的な連鎖をもたらす。最終的にはバイトシーケンスがデシリアライズされてコードが実行されるものだ。 ユーザが実行できる Runtime.exec()
を含むイニシャライザーがあるペイロードクラスを作り、それが実行されてオブジェクトのシリーズをラップすることでペイロードが走る。概念実証で Apache Collections クラスに対して単純な Runtime.exec()
が実行されているが、com.sun.org.apache.xalan.internal.』sltc.trax.TemplatesImpl
(OpenJDK 8 の最新バージョンにすら存在している)の JDK コピーに対して別の攻撃が可能となっている; これは auto-wiring 機構と type provider を使って Spring 攻撃用にデモされたものである。
残念ながらこれらの脆弱性を効率良く防ぐことは難しい。多くの Java アプリケーション(クラスパスで Groovy、Spring 4.x または Apache Commons Collections 3.x or 4.x を使うか保持している場合)に適用されているだけでなく、潜在的には多くの Java の操作で使われている JVM によってもオブジェクトのシリアライズが行われるためである。
エクスプロイットの実証でわかる通り、ネットワークポートを通じたデータの送信でリモートのコード実行できるため、 多くの Java アプリケーションサーバに脆弱性がある; 例えば Jenkins は Jenkins CLI インターフェースでオブジェクトのシリアライズを行うため、ポートに到達できれば誰でも脆弱性を突ける。Jenkins の現スポンサーである CloudBees は、Jenkins のリモート CLI サービスを早急に無効化することをセキュリティアドバイザリーに発令した。WebSphere のケースでは、Admin サービスへの SOAP リクエストを通じて攻撃が行われる; 事実、どの javax.management ポート(リモートのオブジェクトシリアライズを行い、バグのあるライブラリを保持している)も潜在的に脆弱である。これは JMXInvoker
サービスへリクエストをポストする JBoss のエクスプロイットで使われているのと同じルートである。RMI を実行しているどのサーバも潜在的に脆弱である - 実際のところ、インターネットに開かれている RMI ポート自体が危ういものだが。
Foxglove Security によると、回線を通ったオブジェクトが何かを特定する効果的な方法はない。Java のシリアライズされたオブジェクトは 0xaced0005
で始まり、base64 でエンコードされている場合は r00
で始まる。エクスプロイットで使用されているクラスの文字を探すことでシグネチャを生成することもありえる。以下のクラスではクラスネームが UTF-8 で表現されているからだ:
なぜこれらのどのクラスもクッキーや他のバイナリストリームを通してシリアライズされたオブジェクトに入ってくるのか現実的な理由はない; おそらくこれらのクラスは本来の機能性を侵さずに削除できない状態にあるのだろう。しかしネットワークを監視するソフトウェアは、r00
で識別される base64 エンコードオブジェクトにある文字シーケンスを探すため、HTTP ヘッダの内容とクッキーを検査することが可能だった。残念ながらレスポンスが圧縮されることもあるし、HTTP/2 を使っている場合は異なるパイプラインリクエストを通ってくるためである。
オブジェクトのデシリアライズはネットワークデータ(もしくはカスタムネットワークプロトコル)のあらゆるところから起こり得るため、脆弱性を終結させることは難しい。全てのセキュリティ構造と同様、入力を確認することがエクスプロイットを回避する要となる;Java オブジェクトの逆シリアライズ化の場合、利用を避け、代わりに JSON や XML のエンコード、Protobuf や Thrift のような特定のライブラリといった、カスタムしたシリアライズフォーマットを利用した方がいい。ただし SOAP WebSphere エクスプロイットは、シリアライズを行う Base64 エンコードのペイロードに入り込むために XML を使うということをお忘れなく;データ転送で知られたプロトコルでもエクスプロイットの可能性をゼロにはできないということだ。