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

Written by - 0 comments

Published on - Listed in Security Tomcat Linux Apache


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:

  • HTTP Connector. This connector usually listens on port tcp/8080 (default) and is used for direct HTTP access. Reverse proxies can also connect to this port.
  • AJP Connector. This connector listens per default on port tcp/8009 and is usually used with an Apache web server as reverse proxy using the mod_jk module.

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:

  • Tomcat 7: 7.0.100
  • Tomcat 8: 8.5.51
  • Tomcat 9: 9.0.31

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.


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Observability   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder