[月次配信] Tomcat-AJP脆弱性分析及び対応方法:Ghostcat(CVE-2020-1938)


概要

Apache Software FoundationサーブレットコンテナのApache Tomcatの全てのバージョン(9.x/8.x/7.x/6.x)でAJP(PORT:8009)を利用して、/web/ROOTディレクトリ下位のファイルを読み込める「潜在的(Potential)」なリモートコード実行脆弱性(Ghostcat, CVE-2020-1938)が発見された。ウェブアプリケーションプログラム内にファイルアップロード及び保存の許可が必要であるため、「潜在的」と表現した。

2020年1月3日初めに中国のセキュリティ業者のChaitin Techから発見されて、Ghostcatと名前を付けた。脆弱性が公開された後、2020年2月EOSされた6.xバージョンを除外した全てのバージョンのセキュリティパッチが行われていたが、2020年3月現在まで、GitHubに20個のPOCが公開されて攻撃頻度が急激に増加することになった。

AJPはTomcatをインストール際にポートが基本的に有効化するため、下記の図のようにインターネットにつながっている機器の情報を提供しているFOFA(FOFA.SO)によると、日本内でも基本ポートでサービス使用しているサーバが45,680件(2020年3月12月基準)で、脆弱性に漏出されている。その為、今回はリモートコード実行可能性があって、攻撃の危険度が高いApache Tomcat-AJP脆弱性、CVE-2020-1938について調べてみよう。

【▲ インターネット上に公開されているAJPポートの使用数値(参考:FOFA)】

脆弱性分析

影響を受けるソフトウェア

CVE 脆弱なバージョン 危険度
CVE-2020-1938 Apache Tomcat 6.x High
Apache Tomcat 7.0.0 ~ 7.0.99
Apache Tomcat 8.5.0 ~ 8.5.50
Apache Tomcat 9.0.0 M1 ~ 9.0.30

CVE-2020-1938攻撃メカニズム

AJP(Apache Jserv Protocol)はApache ServeとJAVA EEサーバ間の連携のためのプロトコルで、様々なウェブサーバからアプリケーションサーバへのロードバランスを具現するための目的で使用される。セッションはそれぞれのアプリケーションサーバのインスタンス名を持つルーティングメカニズムを使用してアプリケーションサーバにリダイレクトされた場合、サーバのためのリバースプロキシでウェブサーバが動作されることになる。

【▲ Apache Tomcatの環境設定ファイルの基本設定】

AJP RequestがApacheからTomcatに送信される際、ユーザーの入力値を検証なく、実行されると、任意でファイルを読み込んだり実行ができるようになる。前もって説明していた潜在的なリモートコード実行条件である、ファイルのアップロードができる環境であれば任意のファイルがアップロードされた後、AJP脆弱性を利用して攻撃コードを実行できるようになる構造である。

CVE-2020-1938はAJP RequestメッセージがTomcatに送信される際、発生する。AJP Requestメッセージを処理する際にTomcatからはorg.apache.coyote.ajp.AjpProcessor.javaを呼び出し、prepareRequest()を通じてAJPメッセージを取り出してRequestオブジェクトをAtrribute(属性)で設定する。

Requestメッセージヘッダーではファイルの拡張子によって、*.JSPファイルはJspServlet.javaで処理されてそれ以外のファイルはDefaultServlet.javaから処理される。任意のファイルが実行されるためにはDefaultServlet.javaが処理すべきファイルもJspServlet.javaから処理させるのが脆弱性の核心である。

CVE-2020-1938脆弱性の詳細分析


【▲ AJP Request送信過程】

上記の図の流れの中でAJP Requestから使用するクラスメンバーであるAttribute(属性)を調べてみると事前に定義されていない属性を使用する場合「SC_A_REQ_ATTRIBUTE」に設定される。「SC_A_REQ_ATTRIBUTE」を処理するためのプロセスに脆弱性があるため、攻撃を実施する際にAJP RequestのAttribute値を「SC_A_REQ_ATTRIBUTE」に設定して送信する。


【▲ AJP Request Attributeの定義】


【▲ AjpProcessor.javaクラスからの脆弱性発生コード】

下記のAJP Headerパケットからattribute_name(javax.sevlet.include.request_uri, javax.sevlet.include.servlet_path)とattribute_value(index, /attack.txt) 値を上記のコードからそれぞれ変数nとvに保存してAttributeの要請ではないかと確認後、Requestメッセージとしてカプセル化してgetadapter()関数を通じて、servlet過程に送る。この過程で入力されたn, v値に対して別途の検証は行わなく、攻撃ができるようになる。


【▲ AJP RequestのパケットHeader情報】

一般ファイルの場合、上記の過程から作られたRequest値がDefaultServlet.javaクラスに送信され、service()関数を呼び出した後、GET Methodに送信される。service()関数はdoget()関数を呼び出し、doget()関数はserveResource()関数を通じて必要なソースコードが得られる。

serveResource()関数はHttpServeltRequest値をgetRelativePath関数を通じてRequestDispatcher.INCLUDE_PATH_INFOとRequestDispatcher.INCLUDE_SERVLET_PATHをpathInfoと serveretPathに保存するともらえる戻り値を通じてgetResource()関数に保存する変数を作成する。getResource()関数からは当該パスのファイルの実行結果を持ってくる。


【▲ http servletコード】


【▲ jspServlet.javaからreuqest処理】

JSPファイルの場合、defaultServlet.javaクラスではなく、jspServlet.javaクラスを呼び出してRequestメッセージを送信することになる。
メッセージの処理方法は前もって調べていたdefaultServlet.javaと同じく、Requestメッセージに保存されているinclude_path_info attributeをjspUriに入れて、Requestメッセージに追加した後、serviceJspFileから当該のパスのリソースを持ってきてコンパイラに送信されて、サーバに転送される。この過程で変更されたAttributeであれば、変更されたURIパス上のファイルが実行される。


【▲ 攻撃に使用されるAttribute属性値】

CVE-2020-1938を実際に攻撃コードとして作成するためには、前に説明した3つのAttribute設定の中でjavax.servlet.include.path_infoを除いた2つの属性値を変更して送信しなければならない。Githubに公開されたPOCの中で1つを分析してTomcat-AJP脆弱性をより詳細に確認してみよう。


【▲ POCコード内に「SC_A_REQ_ATTRIBUTE」値を設定した場合】

POCコードを確認してみると、脆弱性が存在している「SC_A_REQ_ATTRIBUTE」を実行するために、「SC_A_REQ_ATTRIBUTE」値に10(0A)を入力して送信している。


【▲ POCコード(ajpshooter.py)のshoot()関数】

攻撃試し

ファイルがアップロードできる環境でjspServlet.javaを通じてリモートコード実行脆弱性が実際できるかPOCコードを利用して下記の環境でテストをやってみた。

区分 環境とバージョン
Server OS CentOS 7 (192.168.0.138)
Client OS Windows 7 (192.168.0.131)
Server Apache 2.4.41
サーブレットコンテナ Tomcat 8.5.49
AJP Module mod_jk

① Wgetコマンドを利用してWebshellファイルをダウンロードする攻撃コードが含まれているファイルを作成


【▲ attack.txtファイルの内容】

② 作成した攻撃コードを/webapps/ROOTパスにアップロード


【▲ サーバにアップロードされたattack.txtファイル】


【▲ attack.txt実行結果(1)】


【▲ attack.txt実行結果(2)】

対応方法

Tomcatセキュリティパッチ適用

脆弱性なバージョン   セキュリティパッチ パッチ日付
Apache Tomcat 6.x EOS EOS
Apache Tomcat 7.0.0 ~ 7.0.99 Apache Tomcat 7.0.100 2020. 02. 14
Apache Tomcat 8.5.0 ~ 8.5.50 Apache Tomcat 8.5.51 2020. 02. 11
Apache Tomcat 9.0.0 M1 ~ 9.0.30 Apache Tomcat 9.0.31 2020. 02. 11

Apache Tomcatのバージョンの確認方法は2つがある。
① version.shで確認する:「インストールパス」/bin/version.sh実行


【▲ ./version.sh実行結果】

下図のセキュリティパッチ結果の通りjava/org/apache/coyote/ajp/AjpProcessor.javaのprepareRequest()に既存では定義していないattributeコードに対して、req_attributから別途検証なして実行していた脆弱性はgetAllowedArbitraryRequestAttributesPattern()を通じて検証する機能が追加された。


【▲ 脆弱性セキュリティパッチ結果】

AJPポートの無効化(臨時案)

1) 「インストールパス」/conf/server.xml
2) AJPを有効有無を決定する設定値変更(注釈処理)
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
3) 保存及び再起動

【▲ AJPの無効化方法】

AJPの資格証明設定

AJPが必ず使用されていてアップデートが困難な場合、requiredSecretオプションを使用して資格証明を設定する。

1) 「インストールパス」/conf/server.xml
2) AJPを有効有無を決定する設定値変更(注釈処理)
<Connector protocol="AJP/1.3" 
     address="[TomcatサーバIP]"
     port="8009" 
     redirectPort="8443" 
     requiredSecret="[AJP認証属性]"  />
3) 保存及び再起動

【▲ AJPの資格証明の設定方法】

SNORT適用

区分 検知ポリシー
1 alert tcp any any -> $HOME_NET 8009 (msg:"IGRSS.2.04201 Apache, Tomcat, CVE-2020-1938, Attempted User Privilege Gain"; flow:to_server,established; content:"

【▲ CVE-2020-1938 Snort】

まとめ

今回はomcat-AJP脆弱性分析及び対応方法:Ghostcat(CVE-2020-1938)について調べてみた。
Tomcatはウェブアプリケーションで日本国内でも幅広く使用されているため、この分析レポートを参考し、適切な対処を行うことを推奨する。

参考資料

[1] Apache Tomcat脆弱性セキュリティアップデート推奨
- https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=35279 (1次)
- https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=35292 (2次)
[2] 全世界AJP使用統計 : fofa pro
- https://fofa.so/result?q=port%3D%228009%22&qbase64=cG9ydD0iODAwOSI%3D
[3] CVE-2020-1938 POC
- https://github.com/00theway/Ghostcat-CNVD-2020-10487
[4] CVE-2020-1938:Apache Tomcat 服务器任意文件读取/包含漏洞通告
- https://www.tuicool.com/articles/J77VNzM
[5] 协议 1938 AJP request 漏洞 2020 SC CVE Constants
- https://www.icode9.com/content-4-648068.html
[6] 모든 톰캣에 되는 웹 공격이라고!?! Ghostcat: Tomcat Ajp 프로토콜 취약점 cve-2020-1938
- https://www.youtube.com/watch?v=y-xtEk7NciE
[7] CVE-2020-1938: Ghostcat - Apache Tomcat AJP File Read/Inclusion Vulnerability
-https://www.tenable.com/blog/cve-2020-1938-ghostcat-apache-tomcat-ajp-file-readinclusion-
vulnerability-cnvd-2020-10487
[8] (CVE-2020-1938)Apache Tomcat 文件包含漏洞
- http://www.0-sec.org/0day/Tomcat/CVE-2020-1938.html
[9] req_Attributeヘッダーの定義
- https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html