DLL Sideloading via version.dll in WinSCP: Search Order Exploitation, Rust Proxy and Payload Interception

WinSCP loads version.dll from its own directory because Windows searches for DLLs in a specific order starting with the application folder. Researchers demonstrated how to identify this library through the import table, Known DLLs exclusion, and Procmon monitoring to observe the loader attempting the AppDir path before falling back to SysWOW64. The same technique was recently used in campaigns targeting FileZilla via a fake domain and CPUID supply-chain compromises involving cryptbase.dll. A Rust-based proxy DLL forwards 14 exports via linker-level redirection while implementing three hijacked functions that trigger a MessageBox payload immediately upon WinSCP startup. The PoC was built for 32-bit WinSCP on Windows 11 using cargo and a generated .def file that adapts to x86 or x64 targets. This attack remains effective because version.dll is not listed in KnownDLLs and is directly imported by WinSCP, guaranteeing early execution before the main application window appears.

HabrTranslated from Russian

Read at source

WinSCP loads version.dll from its own folder because Windows follows a deterministic DLL search order that begins with the application directory (AppDir). Researchers published a detailed analysis showing how to detect this vector through static import table review, Known DLLs filtering, and dynamic tracing with Procmon.

The technique mirrors a recent campaign that distributed a trojanized FileZilla build through the fake domain filezilla-project.live, again abusing version.dll. The same actors later compromised the CPUID supply chain (CPU-Z and HWMonitor) using cryptbase.dll.

DLL Search Order and Known DLLs

Windows checks AppDir first, then System32/SysWOW64, and finally PATH. Known DLLs registered under HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs are loaded exclusively from the system directory, bypassing AppDir entirely. version.dll is absent from this list, leaving it vulnerable to sideloading when placed next to WinSCP.exe.

Static analysis with PE-Bear and the lief Python library revealed that WinSCP.exe directly imports only three functions from version.dll: GetFileVersionInfoSizeW, GetFileVersionInfoW, and VerQueryValueW. This small surface makes proxy implementation straightforward.

Proof-of-Concept Implementation

The Rust cdylib proxy exports all 17 functions of the original library. Fourteen are forwarded at link time via a generated proxy.def file that points to C:\Windows\SysWOW64\version.dll for x86 builds. The three hijacked functions are implemented in Rust and trigger a MessageBoxW payload from a separate thread upon first invocation.

Because WinSCP calls these functions during early initialization, the payload executes before the main application window appears. The real system DLL is loaded lazily only when the forwarded functions are first called, preserving compatibility.

The build script (build.rs) dynamically creates the .def file based on CARGO_CFG_TARGET_ARCH, ensuring correct paths for both 32-bit and 64-bit targets. Release builds enable LTO, symbol stripping, and panic=abort for minimal footprint.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Vulnerabilities & Exploits

Telegram for Android Patches Voice Call Vulnerability Enabling Code Execution
Yandex Patches Millions of Stations After eMudhra Certificate Keys Compromised
Cisco ASA and FTD Face DoS Vulnerability in SSL VPN Already Exploited in the Wild