Infiniroot Blog: We sometimes write, too.

Of course we cannot always share details about our work with customers, but nevertheless it is nice to show our technical achievements and share some of our implemented solutions.

How to detect Ghostcat AJP vulnerability (CVE-2020-1938) in Apache Tomcat

Published on April 2nd 2020


Ghostcat is a security vulnerability which affects the AJP connector of all Tomcat versions, at least since version 6 (probably even older). It's CVE number is CVE-2020-1938 and was discovered by security researchers of Chaitlin Tech.

AJP Connector?

Tomcat has two possible connectors how to handle incoming HTTP requests:

As mentioned above, the AJP connector of Tomcat itself is affected. Now it depends on your setup whether or not you're affected. Are you using Apache and mod_jk as reverse proxy in front of your Tomcat and the Tomcat AJP port cannot be accessed from remote? In this case you're fine.

If you're using the HTTP connector, you're fine, too (speaking of remote attacks). If you're using any other web server than Apache (e.g. Nginx), then mod_jk does not exist and forcibly the HTTP connector is used. 

Basic rule: AJP Connector port accessible from remote/Internet: You're vulnerable to remote attacks!

How to find out which connector is used in Apache?

Check your Apache configs (usually /etc/apache2 or /etc/httpd) and look for "ajp13_worker":

ck@tomcat:~$ grep ajp13_worker /etc/apache2/sites-enabled/*
/etc/apache2/sites-enabled/000-default.conf:       JkMount /app/* ajp13_worker
/etc/apache2/sites-enabled/000-default.conf:       JkMount /app_conf/* ajp13_worker
/etc/apache2/sites-enabled/000-default-ssl.conf:                JkMount /app/* ajp13_worker
/etc/apache2/sites-enabled/000-default-ssl.conf:                JkMount /app_conf/* ajp13_worker

In this case, both default hosts (http and https) are using "JkMount" (which invokes mod_jk) to mount the relative paths /app/ and /app_conf/ to the ajp13_worker.

And how does the ajp13_worker connect to the Tomcat instance? For this, the default "worker properties" of Apache's AJP13 can be checked out:

ck@tomcat:~$ cat /etc/libapache2-mod-jk/workers.properties | grep "^worker"
workers.tomcat_home=/usr/share/tomcat8
workers.java_home=/usr/lib/jvm/default-java
worker.list=ajp13_worker
worker.ajp13_worker.port=8009
worker.ajp13_worker.host=localhost

worker.ajp13_worker.type=ajp13
worker.ajp13_worker.lbfactor=1
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=ajp13_worker

VoilĂ  - the Tomcat AJP connector defaults (port 8009) are defined in here!

One last validation remains: Is Tomcat actually listening on the default AJP connector port?

root@tomcat:~# netstat -lntup|grep 8009
tcp6       0      0 :::8009                 :::*                    LISTEN      1276/java

There is the confirmation: This setup uses the AJP connector, the connector is listening to all interfaces (not just localhost) and is therefore vulnerable to remote attacks.

Check Tomcat for the vulnerability

Now that it is known that this setup is using AJP to talk to Tomcat, it's time to find out whether or not this installed Tomcat is (still) vulnerable or if a patch has already been installed. To help figuring this out quickly, the finders of the vulnerability created a program (xray) which sends a payload to Tomcat and informs in the output whether or not this Tomcat is vulnerable.

ck@tomcat:~$ wget https://github.com/chaitin/xray/releases/download/0.20.0/xray_linux_amd64.zip
ck@tomcat:~$ unzip xray_linux_amd64.zip

Execute the binary (for security reasons never as root!) and check the output:

ck@tomcat:~$ ./xray_linux_amd64 servicescan --target 127.0.0.1:8009

 __   __  _____              __     __
 \ \ / / |  __ \      /\     \ \   / /
  \ V /  | |__) |    /  \     \ \_/ /
   > <   |  _  /    / /\ \     \   /
  / . \  | | \ \   / ____ \     | |
 /_/ \_\ |_|  \_\ /_/    \_\    |_|


Version: 0.20.0/61c3f07b/COMMUNITY

[INFO] 2020-04-02 15:04:23 +0200 [default:single.go:76] set plugins parallel to 10
[WARN] 2020-04-02 15:04:23 +0200 [phantasm:phantasm.go:119] poc poc-go-smb-cve-2020-0796 does not exist
[INFO] 2020-04-02 15:04:23 +0200 [default:single.go:239] processing 127.0.0.1:8009
[INFO] 2020-04-02 15:04:23 +0200 [default:single.go:344] wait for task done
[INFO] 2020-04-02 15:04:23 +0200 [go-poc:tomcat-cve-2020-1938.go:280] ajp protocol found in 127.0.0.1:8009, status code 404
[INFO] 2020-04-02 15:04:23 +0200 [go-poc:tomcat-cve-2020-1938.go:140] found tomcat version 8.0.32
[Vuln: poc-go-tomcat-cve-2020-1938]
Target           "127.0.0.1:8009"
method           "version_match"
read_file        "/gtxhao.jsp"
status_code      "404"
body             [...]

If the output shows [Vuln: poc-go-tomcat-cve-2020-1938] then you know: This Tomcat is vulnerable to Ghostcat.

Fixed versions

The following Tomcat versions "fix" the Ghostcat vulnerability:

But how exactly did Tomcat fix this? According to the release notes of these versions:

AJP defaults changed to listen the loopback address, require a secret and to be disabled in the sample server.xml file. If you are using the AJP protocol, please refer to the Migration Guide and update your configuration.

The fixes are basically a workaround to set the AJP connector to listen on the loopback (lo) interface.

As many distributions have not yet released an official security update for the affected Tomcat packages, this is a workaround which can be applied on all affected systems: Simply adjust server.xml that the AJP connector listens on 127.0.0.1 instead of the primary interface (using the address parameter). As long as your Apache reverse proxy runs on the same server, there won't be any problem.