Inside an Exposed Qilin Affiliate Server

Exposed Qilin Affiliate Server

Files recovered from a compromised server trace a Qilin intrusion from Exchange mailbox collection to backup destruction, wiper deployment, and the first reported executions of the ransomware.

Executive summary

In July 2026, we discovered a mirror of a public directory listing at 43.204.2.142:8888. The mirror contains 55,080 files totaling approximately 3.8 GB and appears to reproduce the root account’s home directory on a Linux server. It includes offensive tooling, command histories, SSH material, command-and-control (C2) documentation, staged victim data, a Qilin encryptor, and reports generated by the affiliate’s deployment framework.

The server was not simply an anonymous C2 host. Artifacts in .bash_history, .ssh/, and the application environment identify it as an AWS-hosted server belonging to another legitimate organization, which we refer to as VICTIM-B. By June 2026, a Qilin affiliate had obtained root access and was using the host to conduct operations against a European manufacturer, which we call VICTIM-A.

The VICTIM-A files capture the final stages of the intrusion:

  • Five Exchange Web Services (EWS) scripts impersonated selected executives, searched their mailboxes, and retrieved messages and attachments through a SOCKS proxy.
  • veeam_kill.py targeted Veeam services, backup repositories, Volume Shadow Copies, the Windows backup catalog, and Veeam’s configuration database.
  • deadman.py prepared a time-triggered wiper for 37 named systems. It could install the trigger as a permanent WMI event subscription or deploy it across the domain with Group Policy.
  • deploy_locker.py copied a victim-specific Qilin encryptor to 37 systems in a defined order.
  • Reports generated on June 5 list 29 staged hosts, eight execution attempts, and three systems where the tool reported encryption impact.

We attribute the encryptor and deployment package to Qilin with high confidence. We also assess with high confidence that VICTIM-B’s server was compromised and used to support the operation. The available files do not identify the affiliate, reveal how VICTIM-A was initially compromised, or show the final state of every targeted system.

Figure 1: Exposed root-directory index from VICTIM-B, showing offensive tooling, staged data, C2 components, and Qilin deployment artifacts.

Analysis scope

This analysis is based on a static examination of the directory mirror; no payload was executed. Where possible, we compared source code, file hashes, SQLite entries, shell history, and embedded timestamps.

Unless otherwise noted, all artifact paths in this article refer to the mirrored root directory. The sanitized excerpts in the figures retain the relevant control flow and strings but replace victim-specific values.

We have redacted the names of the victim organizations, domains, accounts, login credentials, internal addresses, personal data, and negotiation details. We have retained the public IP address because it is useful for retrospective hunting. However, it belonged to compromised infrastructure and should not be treated as the actor’s infrastructure. Cloud addresses can also be cleaned up or reassigned.

We use the term “affiliate” to refer to the operator of this deployment environment. The files do not reveal the identity of this person, their relationship to the Qilin developers, or their role in the development of the Encryptor.

A Compromised Server as a Staging System

This analysis is based on static examination of the directory mirror; no payload was executed. We compared source code, file hashes, SQLite records, shell history, and embedded timestamps where possible.

Unless otherwise stated, artifact paths in this article are relative to the mirrored root directory. Sanitized figure excerpts preserve the relevant control flow and strings while replacing victim-specific values.

Victim names, domains, accounts, credentials, internal addresses, personal data, and negotiation details have been redacted. We retain the public IP because it is useful for historical hunting, but it belonged to compromised infrastructure and should not be treated as actor-owned. Cloud addresses can also be remediated or reassigned.

We use affiliate for the operator of this deployment environment. The files do not establish that person’s identity, relationship with Qilin’s developers, or role in developing the encryptor.

A compromised server became the staging host

The IP address 43.204.2.142 belonged to VICTIM-B, not necessarily to the Qilin affiliate. The files describe an EC2 instance in AWS region ap-south-1; activity under the root account shows the operator inspecting both the cloud environment and the industrial application hosted on the server.

ArtifactWhat it showed
.ssh/id_rsa.pubAn RSA-4096 key carrying the comment root@BELIIOT, modified June 2, 2026 at 18:21:11 UTC
.ssh/authorized_keysThe original AWS ubuntu key and four additional authorized keys
.bash_historyQueries to 169.254.169.254, inspection of /home/ubuntu/.bash_history, S3 enumeration, and SQL queries against industrial application tables such as systemconfigurationinfo, plantlevelconfigurationinfo, and deviceconfig
.mysql_historyCommands that purged logs and disabled database logging; authorship and intent are unclear
.viminfoEarlier edits to SSH and Tomcat configuration files; these may reflect administration or persistence

The distinction in the final two rows matters. Disabling SQL logging can be malicious, but it can also happen during emergency database maintenance. An edit to sshd_config is not malicious on its own either. The picture becomes clearer in June 2026, when new root-access material, a callback service, victim credentials, offensive tooling, and C2 configuration converge on the same host.

Taken together, these artifacts establish that an intruder controlled VICTIM-B’s server as root and used it as a staging and C2 host. Earlier compromise is possible, but the 2024 and 2025 records cannot be separated reliably from legitimate administration. Authentication logs, CloudTrail, Systems Manager records, and VPC Flow Logs would be needed to determine the initial access path and date., authentication logs, CloudTrail, Systems Manager records, and VPC Flow Logs would be required.

Figure 2: Root shell history showing EC2 metadata queries, S3 enumeration, user-history inspection, and industrial-application database reconnaissance.

Identifying the Qilin encryptor

The directory contains plenty of Qilin-themed material, but the attribution does not rest on filenames or folder names. It rests on the encryptor itself.

winbuild/pain.exe is a 4,921,344-byte PE32 console executable with the following SHA-256 hash:

e1b041fee6bf591a96d135e101577214cfce0bb145c5ba1ba1064103d5d5d2c0

Static strings and the embedded configuration provide four independent links to Qilin:

1.  The ransom note names Qilin and contains Qilin’s public blog addresses.

2.  The binary exposes Qilin’s password-gated command-line interface, including –password, –spread, and –spread-vcenter.

3.  The configuration contains a victim-specific company identifier, ransom note, file extension, service kill list, and credentials used for lateral movement. Those values are withheld.

4.  Embedded PowerShell uses VMware PowerCLI and SSH to change ESXi access, transfer a Linux payload, and execute it on hypervisor hosts.

MITRE’s Qilin software entry documents Windows, Linux, and ESXi variants, Rust and Go implementations, password-gated execution, and lateral-movement functionality. Those characteristics, together with the ransom note and victim configuration, support a high-confidence Qilin attribution.

The embedded password_hash validates the value passed to –password before the encryptor runs. It is not an encryption key and cannot be used to decrypt affected files.

Reconstructed VICTIM-A timeline

The table below separates what the artifacts date from what they imply. All times are UTC.

Date and timeEvidenceWhat it indicates
May 21-30Ten date-stamped Veeam configuration backup files exist in exfil/Confirms that daily backup artifacts were collected; does not establish that collection occurred once per day
May 30Payroll, ERP, endpoint-management, HR, directory, and Exchange enumeration artifacts have clustered modification timestampsData was staged on the compromised server; the transfer path and original acquisition time are not preserved
June 2 03:02:04.sysmon_listener.py and sysmonitor.service share this modification timeThe TCP callback service was staged or updated
June 2 06:55:47First callback, converted from the listener’s server-local timestampA source associated with VICTIM-A reached TCP/4444
June 3 06:12-15:54Five EWS scripts were created to scan executive mailboxesTargeted mailbox collection tooling was developed or modified
June 4 04:20-04:55veeam_kill.py, deadman.py, deploy_locker.py, and pain.exe have modification timestamps within a 35-minute windowThe affiliate staged backup destruction, wiper, and ransomware tooling together
June 5 04:14:45First deployment report: 36 hosts in scope, 35 SMB-reachable, 29 staged, zero executedThe framework reported that the encryptor had been copied to 29 hosts but had not yet been launched
June 5 05:09:28Second report: eight execution attempts and three reported impact checksThe framework reported that ransomware execution had begun
June 5 05:19-16:26Four verification reports show 26, 26, 34, and 33 hosts unreachableAvailability deteriorated, but the reports do not establish that ransomware caused every failure
June 9 12:00Default arm deadline in deadman.py usage textA planned wiper deadline; not evidence that WMI subscriptions were installed or triggered
June 22 21:50:55Last callback-file mtime in the acquired listener setThe last preserved callback, not necessarily the end of access

The 30-line Python listener provides a narrow but useful record of continued access. It binds 0.0.0.0:4444, logs the source address and local time, and discards the received data. The mirror contains 4,273 callback files holding 4,798 connection records from one VICTIM-A address. These artifacts establish repeated TCP connectivity; they do not identify the connecting process or show that commands ran.

Figure 3: Source of .sysmon_listener.py, a TCP/4444 listener that logs connections and discards received data.

The filename is misleading: .sysmon_listener.py has no relation to Sysinternals’ Sysmon. The available artifacts do not explain why the operator chose it.

Figure 4: Callback artifacts generated by the listener, recording 4,798 TCP connections across 4,273 files.

Targeted Exchange collection

The VICTIM-A artifacts then shift into targeted mailbox collection. Five Python scripts implement mailbox discovery, message search, and attachment retrieval by sending raw SOAP requests to EWS. Each uses the same hardcoded SOCKS5 proxy at 127.0.0.1:11080, the same redacted domain account, and disabled TLS certificate verification. The ExchangeImpersonation header selects the mailbox for each request:

<t:ExchangeImpersonation>
  <t:ConnectingSID>
    <t:SmtpAddress>[REDACTED-MAILBOX]</t:SmtpAddress>
  </t:ConnectingSID>
</t:ExchangeImpersonation>

Figure 5: EWS keyword scanner using SOCKS5 proxying, Exchange impersonation, and server-side FindItem searches.

Microsoft documents that Exchange impersonation allows a service account to act as another user and, in the affected Exchange versions, requires the ApplicationImpersonation role. Microsoft also notes that access is logged as the impersonated user, which can complicate an investigation. See Configure impersonation and Control access to EWS.

The collection was selective rather than indiscriminate:

ArtifactObserved behavior
ews_pull.pyRetrieves recent messages from selected executive mailboxes
ews_accounting.pyRetrieves recent accounting mailbox messages
ews_cfo_attach.py and ews_cfo_property_attach.pyDownloads attachments from specified CFO mailbox items
ews_cfo_keyword_scan.pyRuns server-side substring searches across Inbox and Sent Items
exfil/cfo_keyword_scan.txtRecords returned counts, including 177 for private bank, 129 for Luxembourg, and 76 each for trust and holding

The scanner defines 144 keyword entries, 141 of them unique, covering banking, legal and tax matters, property, family names, and corporate transactions. For each term, it sends a FindItem request with server-side Contains restrictions against the subject and body fields, then reads TotalItemsInView. This let the affiliate triage a mailbox by hit count before deciding what to retrieve.

The mailbox selection and search terms point to collection of financial and personal information that could support extortion. The scripts and saved output confirm the searches and their result counts, but not the download of every matching message or attachment.

Disabling recovery and preparing a wiper

The next group of scripts shifts from collection to impact preparation. Four Python programs reuse the same remote-execution pattern: authenticate over SMB/RPC, create a short-lived Windows service, run a command, retrieve a status file through ADMIN$, and delete the service. Depending on the program, service names begin with VKill, WinMnt, LDep, or AvChk.

av_check.py and av_check2.py

Before deploying the destructive tooling, the affiliate profiled endpoint defenses across a hardcoded host list. av_check.py executes a compound discovery command remotely; av_check2.py performs a quieter service-state check through MS-SCMR.a composite discovery command; av_check2.py checks the service status more discreetly via MS-SCMR.

Figure 6: av_check.py iterating the hardcoded target list, executing CHECK_CMD, and serializing parsed results to JSON.

For each target, av_check.py uses Impacket DCE/RPC over the svcctl named pipe, binds to the MS-SCMR interface, and creates an on-demand service named AvChk followed by the target’s last IP octet. The service runs the supplied command and is removed after execution.

Figure 7: scm_exec() using Impacket MS-SCMR calls to create, start, and remove a temporary AvChk* service.

The command checks the ESET services ekrn and ERAAgent, looks for listeners on TCP/2222, queries the Microsoft Defender services WinDefend and WdNisSvc, and reads Defender policy, exclusion, real-time protection, and tamper-protection state. Output is redirected to C:\Windows\Temp\avchk.txt for retrieval through ADMIN$.

Figure 8: Endpoint-security profiling command querying ESET, Microsoft Defender, TCP/2222, exclusions, and tamper-protection state.

av_check2.py avoids remote command execution. It calls OpenServiceW and QueryServiceStatus for service names in SVC_NAMES, marking ESET as present when ekrn or ERAAgent is running, Microsoft Defender when WinDefend is running, and Microsoft Defender for Endpoint when the Sense service is running.

Figure 9: av_check2.py querying ESET, Defender, and Sense service state through MS-SCMR without creating a remote service.

veeam_kill.py

The Veeam script is blunt. It targets one named backup server, which we have redacted here, and builds a command chain to:

  • stop ten Veeam services;
  • delete V:\Backup, V:\VeeamBackup, E:\Backup, and D:\Backup;
  • run vssadmin delete shadows /all /quiet and wbadmin delete catalog -quiet;
  • attempt to drop the VeeamBackup database through VEEAMSQL2016, VEEAMSQL, and local SQL instances; and
  • set the Veeam services to disabled.

Figure 10: veeam_kill.py command chain targeting Veeam services, repositories, shadow copies, the backup catalog, and configuration database.

These actions map to T1490 Inhibit System Recovery. Trying three SQL instance names allowed the script to operate without knowing the exact Veeam database configuration. We found no endpoint telemetry or authenticated completion log showing that the repository or database deletion succeeded.

deadman.py

Where veeam_kill.py targets recovery, deadman.py prepares a second destructive path: a time-triggered wiper orchestrator. It contains 37 hardcoded targets arranged in waves: 30 receive the full payload, while seven older systems receive a reduced variant. Its command-line modes let the affiliate install, verify, reschedule, or remove the trigger. A fifth mode deploys it through Group Policy.

Figure 11: deadman.py staging wiper components through ADMIN$ and invoking the installer via a transient WinMnt* service.

Figure 12: smb_connect() establishing an authenticated Impacket SMB session with hardcoded domain credentials.

For each target, do_arm() authenticates over SMB, writes the output of wipe_cmd() to ADMIN$\Temp\hcr.cmd, uploads hcr_arm.ps1, and invokes the installer through a temporary WinMnt* service.

The payload builder selects either a full or legacy destructive profile. Both variants remove ESET services, delete backup artifacts, and use powershell.exe or reg.exe to queue deletion of ntoskrnl.exe and the on-disk SAM and SYSTEM registry hives at boot. The full profile also targets the SOFTWARE and SECURITY hives, Boot Configuration Data, EFI files, and raw disk content.

Figure 13: wipe_cmd() generating full and legacy payloads targeting recovery artifacts, registry hives, boot files, EFI data, and raw disks.

The temporary service is only the delivery mechanism. The installer creates a permanent WMI event subscription in root\subscription:

WMI objectName and purpose
__EventFilterSCMHealthCheck evaluates Win32_LocalTime every 60 seconds
CommandLineEventConsumerSCMHealthRemediation executes cmd.exe /c C:\Windows\Temp\hcr.cmd
__FilterToConsumerBindingBinds the time-based filter to the command consumer

The subscription persists in the WMI repository after the installer exits and survives reboots. Because the WQL condition evaluates only the year, month, day, and hour, a deadline such as 12:30 becomes active at 12:00. It also relies on each host’s local clock and can execute repeatedly while the condition remains true.

When triggered, the full payload disables recovery controls, removes backup artifacts, schedules deletion of registry hives, ntoskrnl.exe, and BCD files, deletes EFI data, writes 4 MB of zeroes to the beginning of PhysicalDrive0 through PhysicalDrive7, and forces a reboot. Legacy targets omit the raw-disk overwrite loop, while the backup server receives additional Veeam teardown commands. The source implements these destructive actions, but it does not confirm that disk writes or deletions completed on any target.

The gpo mode provides a domain-wide deployment path through an enforced GPO named Windows Health Compliance. It places the payload and a startup script in SYSVOL, allowing domain members to create the same permanent WMI subscription during policy processing. This is abuse of normal Group Policy administration, not exploitation of a GPO vulnerability.

The artifacts establish that the affiliate prepared a wiper for deployment to individual hosts or across the domain. They do not show how many WMI subscriptions were installed, whether clients processed the GPO, or whether the June 9 deadline was reached on any system.

Qilin staging and execution

With recovery targeted and the wiper prepared, the affiliate moved to the locker. deploy_locker.py and deadman.py contain the same 37 targets. The deployer copies pain.exe to C:\Windows\Temp\svcmon.exe and launches it through temporary LDep* services. Comments in the target list place the backup server first, systems believed not to run ESET next, then other servers and hypervisors, followed by the security-management server and domain controllers. The ordering exposes the affiliate’s deployment plan; it does not establish that all 37 systems were reached.

Figure 14: deploy_locker.py orchestrating wave-based staging and execution of the Qilin encryptor.

Figure 15: run_wave() separating payload upload and execution while tracking per-host failures.

Figure 16: upload_locker() copying the encryptor through ADMIN$ to the target staging path.

Figure 17: Hardcoded payload paths renaming pain.exe to svcmon.exe in the target’s Windows temporary directory.

The deployment flow is split into two phases. run_wave() first attempts to stage the encryptor across the selected wave, then fires only on hosts where the upload succeeded. Per-host results are written under fired, fire_fail, and related status fields.

The deployment reports record execution

The reports provide the closest thing in the mirror to a live execution timeline. Two machine-generated records under seceng_reports/ capture the transition from staging to execution:

Generated UTCHostsSMB reachableStagedExecution attemptsReported impactSpread launcher
June 5 04:14:4536352900None
June 5 05:09:2836352983Redacted domain controller, wmi_spread_domain_scan, ok=True

The first report is a snapshot before execution: 29 hosts were staged, but none had been fired. Fifty-five minutes later, the framework recorded eight execution attempts and three positive impact checks. These are affiliate-generated results, not independent endpoint telemetry, but they are the clearest preserved evidence that the ransomware deployment moved from staging into execution.

Defensive implications

The affiliate generated several detectable events before launching the encryptor:

1.  One account performed EWS impersonation across high-value mailboxes through repeated FindItem calls.

2.  Remote service creation appeared under distinctive prefixes and launched cmd.exe from services.exe.

3.  Recovery controls, Veeam services, and security products were queried or modified before the encryptor was deployed.

4.  Permanent WMI objects and a new domain-linked GPO used plausible administrative names but unusual destructive payload paths.

5.  The Qilin executable was staged under the generic name svcmon.exe.

The exposed directory captures more than a collection of tools. It preserves an operational sequence: mailbox triage, security-product discovery, recovery inhibition, wiper preparation, and wave-based ransomware deployment. The remaining uncertainty is equally important—source code shows capability, and affiliate reports show claimed outcomes, but the acquired artifacts do not provide complete endpoint-level confirmation of impact.

Research hashes

ArtifactSHA-256
winbuild/pain.exee1b041fee6bf591a96d135e101577214cfce0bb145c5ba1ba1064103d5d5d2c0
deadman.py71fca801f0bd88a417d71aa0be5adc0a983127a063e7139345ae952571b453c6
veeam_kill.py2ec5fa31d1a590daf96e998941ad1dff4efc290ff42ee81a5425bb3d8c0069ed
deploy_locker.py4a933c387a9228056b9dc234e64210ce254c633eabaace2d63d4a7d6df75bfc8
av_check.py92de01b28a3cb8c7319667635c96cfd5dc1eee73e2b7a061afab375f2978ba8f
av_check2.pye7225880c730d190b872b60c7f109cdb56a5c7429f48736b9ef00130240d7a9e

Analysis based on a mirror acquired in July 2026. Static analysis only. All timestamps are normalized to UTC unless explicitly described as server-local.

Share post on:

XING
Twitter
LinkedIn

SECUINFRA Falcon Team • Autor

Digital Forensics & Incident Response experts

In addition to the activities that are the responsibility of customer orders, the Falcon team takes care of the operation, further development and research of various projects and topics in the DF/IR area.

> all articles
Cookie Consent with Real Cookie Banner