This repo holds the source for the HTTP and LDAP servers hosted here. Both services are hosted under one Java application built here with maven.
We have released the source code of this application to promote transparency, and let researchers verify for themselves that our service does nothing nefarious.
⚠️ The application does not trigger any remote code execution.
‼️ This tool is intended for use by authorized persons or researchers only. You should only test systems on which you have explicit permission or authority. If you find vulnerable applications or libraries, you should exercise responsible disclosure.
In short, the Log4Shell vulnerability normally works by injecting a JNDI LDAP string into your logs, which triggers Log4j to reach out to the specified LDAP server looking for more information. In a malicious scenario, the LDAP server can then serve code back to the victim machine which will be automatically executed in-memory.
This application has two parts. The first is an HTTP server which generates a random UUID which uniquely identifies your session/testing, and presents you with a payload which can be used to test for the Log4Shell vulnerability.
You can then paste this payload into various inputs on your application (form fields, input boxes, User-Agent strings, etc.). If the application is vulnerable, it will reach out to our LDAP server.
The second part of this application is the LDAP server itself. This LDAP server is
run out of the same process. After receiving a connection from a vulnerable client,
it will immediately respond with an LDAP Operation Error. No code is sent from
our LDAP server to your client. You can see this interaction in LDAPServer.java
.
After sending the error, the LDAP server will simply log the UTC timestamp and the
remote IP address in the Redis cache for you to lookup later.
If any of your clients do reach out, you can view the timestamps and external IP addresses at your specific "view" URL (presented through a button on the index page).
All entries in the cache have a 30 minute time-out. This means that 30 minutes after your last request, all results will be gone from the Redis cache forever.
You can build a JAR file with the following command:
mvn clean package
You will then have a file named target/log4shell-jar-with-dependencies.jar
which contains all required dependencies as well as the testing application.
The application is self-contained in the generated JAR file, however it does require a Redis cache server at runtime. The URL for the redis cache is specified through command line arguments. The cache server will hold valid UUIDs for users as well as track known "hits" for the LDAP endpoint.
The JAR file can be executed directly. Configuration can be passed via command line arguments or a YAML configuration file. The hostname argument is used to construct the testing payloads given to the user and must be an IP address or resolvable domain name which can be reached from the victim server or application which you are testing.
# Help/usage details
$ java -jar target/log4shell-jar-with-dependencies.jar --help
Usage: log4shell-tester [-hV] [-c=<config_file>] [--hostname=<hostname>]
[--http-host=<http_host>] [--http-port=<http_port>]
[--ldap-host=<ldap_host>] [--ldap-port=<ldap_port>]
[--redis-url=<redis_url>]
Execute the Huntress Log4Shell-Tester HTTP and LDAP servers.
-c, --config=<config_file>
Path to YAML configuration file (overrides commandline
options).
-h, --help Show this help message and exit.
--hostname=<hostname>
The publicly routable IP address or resolvable hostname of
the server (default: 127.0.0.1).
--http-host=<http_host>
IP address on which to listen for HTTP connections (default:
127.0.0.1)
--http-port=<http_port>
Port to listen for HTTP connections (default: 8000)
--ldap-host=<ldap_host>
IP address on which to listen for LDAP connections (default:
0.0.0.0)
--ldap-port=<ldap_port>
Port to listen for LDAP connections (default: 1389)
--redis-url=<redis_url>
Connection string for the Redis cache server (default: redis:
//localhost:6379)
-V, --version Print version information and exit.
# Example invocation listening on 127.0.0.1 for HTTP (default).
# This is recommended if running publicly so you can setup
# a proxy like nginx to handle SSL publicly.
$ java -jar target/log4shell-jar-with-dependencies.jar \
--hostname my-log4shell-tester.something.com \
--http-host 127.0.0.1 \
--http-port 8000 \
--ldap-host 0.0.0.0 \
--ldap-port 1389 \
--redis-url "redis://my-redis-url.something.com:6379"
# Example invocation allowing HTTP inbound externally
$ java -jar target/log4shell-jar-with-dependencies.jar \
--hostname my-log4shell-tester.something.com \
--http-host 0.0.0.0 \
--http-port 8000 \
--ldap-host 0.0.0.0 \
--ldap-port 1389 \
--redis-url "redis://:password@my-redis-url.something.com:6379"
# Example invocation with a configuration file (recommended to better store
# redis secrets).
$ java -jar target/log4shell-jar-with-dependencies.jar \
--config /path/to/log4shell/config.yaml
The configuration file is a YAML document that provides the same options as the
command line arguments, but in snake_case
instead of kabab-case
. An example
configuration file with the default values looks like:
⚠️ Any configurations specified in the configuration file will override command-line arguments.
# These represent the default values
http_host: 127.0.0.1
http_port: 8000
ldap_host: 0.0.0.0
ldap_port: 1389
redis_url: redis://localhost:6379
hostname: 127.0.0.1