[月次配信] 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.ｘバージョンを除外した全てのバージョンのセキュリティパッチが行われていたが、2020年3月現在まで、GitHubに20個のPOCが公開されて攻撃頻度が急激に増加することになった。

AJPはTomcatをインストール際にポートが基本的に有効化するため、下記の図のようにインターネットにつながっている機器の情報を提供しているFOFA(FOFA.SO)によると、日本内でも基本ポートでサービス使用しているサーバが45,680件(2020年3月12月基準)で、脆弱性に漏出されている。その為、今回はリモートコード実行可能性があって、攻撃の危険度が高いApache Tomcat-AJP脆弱性、CVE-2020-1938について調べてみよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/0d032245-1fad-82f5-75a2-0d6d828651c8.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/361aa61f-eae5-00b4-e208-851d861b2b16.png)
【▲ Apache Tomcatの環境設定ファイルの基本設定】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/9456e3b9-0c96-013e-9aa3-86c94986a198.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/6787d6de-a792-288e-39e1-517f403dc173.png)
【▲ AJP Request送信過程】


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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/7f7769c3-bed8-d1b6-1c49-86c8a7c15d9e.png)
【▲ AJP Request Attributeの定義】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/e6253eec-9806-55f4-44ed-2d0fa308c9c9.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/e4b08cca-ec72-b77a-cb91-19bd1e957962.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/ab091b45-7ca4-11d6-6217-b346f8a8fd8e.png)
【▲ http servletコード】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/7d548c55-1bdb-db03-8dce-a2de7138db4d.png)
【▲ jspServlet.javaからreuqest処理】

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/44d1fa58-9927-7525-94aa-56ed4113bb5c.png)
【▲ 攻撃に使用されるAttribute属性値】

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/928a3d92-a3ea-ecff-50da-d03d2bdef515.png)
【▲ POCコード内に「SC_A_REQ_ATTRIBUTE」値を設定した場合】

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/28a40c13-0415-4657-a88f-f859c2ffa342.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/3302463f-0279-71b9-7cc6-525cdc379b78.png)
【▲ attack.txtファイルの内容】

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/97ae22a0-ebc2-bfad-b4e6-985c78afecaa.png)
【▲ サーバにアップロードされたattack.txtファイル】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/e565a2d2-07b6-ff52-190c-78bcf4ca8939.png)
【▲ attack.txt実行結果(1)】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/26fed610-36cd-4c5b-f543-02704e8f64c8.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/9ccb39dd-ccee-aad3-8888-a76dca42987b.png)
【▲ ./version.sh実行結果】

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570011/054425e9-60a1-a121-1188-b73a779f66e2.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:"|12 34|"; depth:2; content:"|02|"; within:1; distance:2; byte_test:1,!&,0xF9,0,relative; byte_extract:2,1,protocol_len,relative; content:"HTTP"; within:protocol_len; nocase; content:"javax.servlet.include.request_uri|00|"; fast_pattern:only; content:"javax.servlet.include.servlet_path|00|"; nocase; sid:204201;) |

【▲ 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