2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

#概要
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について調べてみよう。
image.png
【▲ インターネット上に公開されている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サーバ間の連携のためのプロトコルで、様々なウェブサーバからアプリケーションサーバへのロードバランスを具現するための目的で使用される。セッションはそれぞれのアプリケーションサーバのインスタンス名を持つルーティングメカニズムを使用してアプリケーションサーバにリダイレクトされた場合、サーバのためのリバースプロキシでウェブサーバが動作されることになる。
image.png
【▲ Apache Tomcatの環境設定ファイルの基本設定】

image.png

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脆弱性の詳細分析
image.png
【▲ AJP Request送信過程】

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

image.png
【▲ AJP Request Attributeの定義】

image.png
【▲ 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値に対して別途の検証は行わなく、攻撃ができるようになる。

image.png
【▲ 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()関数からは当該パスのファイルの実行結果を持ってくる。

image.png
【▲ http servletコード】

image.png
【▲ jspServlet.javaからreuqest処理】

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

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

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

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

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

image.png
【▲ 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ファイルをダウンロードする攻撃コードが含まれているファイルを作成

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

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

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

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

image.png
【▲ 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実行

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

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

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

###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脆弱性セキュリティアップデート推奨

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?