68 GB Stolen From a Philippine Government Agency’s Overseas-Employment Databases, Exposed by the Operator’s Own Open Directory
68 GB Stolen From a Philippine Government Agency’s Overseas-Employment Databases, Exposed by the Operator’s Own Open Directory
Published on

Disclosure note: Hunt.io notified the relevant national CERT prior to publication. No personal records or credentials from the affected systems appear in this report.
An operator copied 68.837 GiB of a Philippine government agency's database backups, logged the transfer for themselves, and then left that log open on the internet. We captured the directory while it was still serving.
The copy finished in under 24 minutes on 6 September 2026, 27 SQL Server backups whose names match the agency's overseas-employment and migrant-worker systems. Beside the log sat the operator's toolkit, a rebranded GodPotato build, a PowerShell stager, two payloads and a full Impacket environment.
The access log shows that tooling pulled the same evening, which establishes distribution from this server and nothing past it. How the operator got in, and whether any payload ran, are not in the capture.
Key Findings
We reverse-engineered the payload, traced the operator's logs, and pivoted the certificates to the agency itself. The key takeaways:
A staging host at UpCloud Ltd (AS202053) left the operator's working folder open through an unauthenticated HTTP directory on port 80, including the operator's own transfer and access logs
Completed 68.837 GiB copy of 27 SQL Server backups, transferred in 23m 46s at a tool-reported 20.238 MiB/s that does not reconcile with the volume and duration
Backup filenames matching the case-management systems of a Philippine overseas-employment and migrant-worker administration, including POEA and OFW variants
A rebranded GodPotato .NET build staged as Wrqsnx.dll and Wrqsnx_portal.dll, with the RPC pipe, namespace and assembly metadata renamed and internal identifiers left untouched
Two builds from two different compilers, the second compiled 6m 43s before it was retrieved
An eight-line PowerShell stager that rebuilds the payload in memory from base64 fragments, so no DLL touches disk
A full Impacket environment with no signs of modification, including LDAP and MSSQL relay checks and a tool targeting Windows Server 2025 domain controllers
No initial access vector, no command-and-control channel and no confirmed payload execution appear in the recovered data
The exposed staging server
Each point above traces back to a file the operator left in the open. We start with the server that served them.
The host 213.163.205[.]35:80 ran a Python HTTP server on port 80 with directory listing enabled, and it served the operator's working folder to anyone who asked. No defender found the exposure: the directory was captured while it was open. The access log records 543 requests from 76 distinct addresses across a 16-hour, 9-minute window on 6 and 7 September 2026.
Figure 01: The capture in Hunt.io: the staging directory, served from 213.163.205[.]35:80 at UpCloud Ltd (AS202053), Singapore.The operator's environment is identifiable from the recovered files, not from the host itself. The Impacket environment records its own path in its activation script: /tmp/imp. That places the toolkit in a temporary directory on the staging server, and it fits an operator working from a rented Linux host rather than a maintained workstation.
Most of the traffic against the directory was scanner noise with no link to the operation. The six addresses assessed below were selected for their retrieval of operational files; the remaining 70 requested only directory listings or common exploit paths. A WordPress and PHP RCE sweeper sent 49 requests and received 404 or 501 on every one.
A handful of addresses did more than scan, and they downloaded files. Their roles are assessed separately from their activity in the indicators section, because taking a file from an open directory establishes neither that the requester is the operator nor that it is a victim.
What the host exposed was the operator's working folder, not a finished deployment: more than a hundred files, including a payload builder and its source tree, two compiled payloads, a PowerShell stager, a complete Impacket environment, a small Python upload receiver, and the operator's own logs.
Figure 02: The staging directory was captured: the payloads, the stager, the transfer logs and the Impacket environment, all in the open.The upload receiver is a small Python service that binds port 8888 and writes request bodies to disk. Its companion log is zero bytes, but the handler contains no logging call, so the empty log is not evidence of disuse, and no received file was recovered. Whether the endpoint was ever used cannot be determined from this capture.
The logs are the most consequential files in the directory, and they are treated in their own section below.
Wrqsnx: a rebranded GodPotato
The payload is the most detailed piece in the directory, so we start there.
The payload is GodPotato, a publicly available .NET tool. It turns the rights of a service account into full SYSTEM control through DCOM and RPC, and it needs no Windows vulnerability to do it. The operator rebuilt it under the name Wrqsnx and renamed the namespace, the context classes, the pipe path and the assembly metadata, while leaving the source file names and some internal field names unchanged. That gap is a fingerprint: the tool is public, and the copy is lightly edited.
Microsoft's platform detects the payload as Trojan:MSIL/GodPotato.FF!MTB. That corroborates the lineage independently of our code reading. Everything below is read from the recovered files; none of it was observed running.
Rebuilding the payload in memory
The stager runs the payload without ever writing a DLL to disk. It is eight lines of PowerShell. It collects the base64 fragments named p_*.b64 from C:\Users\Public in filename order, joins them, strips whitespace, decodes the result in memory, loads it as a .NET assembly and calls its Main method.
The design has two weak points the operator accepted. The join depends on fixed-width fragment names, and the script never checks this. And the completion marker, POTATO_FIRED, only shows that the stager reached its last line: failures inside the payload are caught and swallowed, so the marker says nothing about SYSTEM.
Figure 03: portalload.ps1 as served and no DLL touches disk.Nothing in the stager validates the fragments, so whatever the files contain is what gets loaded.
Finding the target in memory
The payload takes over one decision inside Windows RPC. Hardcoding the location of that decision would work on a single Windows build, so the payload finds it at runtime instead. It copies the combase.dll module image into memory and searches for a short byte pattern: the size of the structure it wants followed by a known interface identifier.
From the first match, it follows the structure's own records to the dispatch table and learns how many arguments the routine it wants to replace takes, between four and fourteen. That count changes between Windows versions, and the payload reads it instead of assuming it.
Figure 04: Finding combase.dll at runtime and building the 20-byte search pattern.The second figure carries the walk on from the match to the pointer the payload replaces.
Figure 05: Walking RPC_SERVER_INTERFACE and MIDL_SERVER_INFO to reach the dispatch table pointer.The walk reads the layout Windows ships, so the same code reaches the routine on any build.
Taking over the RPC lookup
When Windows needs to reach an interface, one routine answers a single question: which transport does it use? The payload takes that routine over. It makes the dispatch table writable, replaces the first entry, the transport chooser, with a pointer to its own function, and stores the original pointer to put back later.
One thing is never put back. The memory page was made writable and stays writable after the process exits. No code is injected, and the change is four bytes wide, so it escapes tools that scan for injected code. It is the clearest trace the tool leaves on a host.
Figure 06: HookRPC makes the page writable; Restore rewrites the pointer but not the page protection.The two functions sit beside each other in the source, and the page permission is the only thing they disagree on.
Pulling in a SYSTEM connection
For the technique to work, a SYSTEM service has to connect to the payload. The payload creates the named pipe \.\pipe\Wrqsnx\pipe\epmapper with a descriptor that grants Everyone full control. That looks careless but is required, because a named pipe created normally would refuse the SYSTEM-context connection the technique depends on.
Figure 07: The pipe is created with Everyone Full Control, a condition of the attack.The payload then builds a genuine-looking COM object reference for a local object, rewrites its destination to point at the same machine with NTLM authentication, and hands it to CoUnmarshalInterface. combase asks the hooked lookup how to reach the interface, receives the pipe instead of a network address, and the DCOM resolver inside RPCSS, which runs as SYSTEM, opens the pipe. That is where the SYSTEM client comes from.
Figure 08: The hooked routine answers combase with the pipe endpoint instead of a network address.The answer the resolver receives is a pipe on the local machine, which is the connection the payload wants.
Stealing a SYSTEM token
With a SYSTEM client attached, the pipe thread impersonates the connected client, reads the system-wide handle table through NtQuerySystemInformation, and duplicates a token that matches three conditions: the local system SID S-1-5-18, an impersonation level of at least Impersonation, and System integrity or higher.
No memory corruption is involved at any point, and no vulnerability is exploited. Every call uses a permission the process already holds. The escalation works because a SYSTEM token is reachable in the table and the caller has the right to duplicate it.
Figure 09: Reading the system handle table with NtQuerySystemInformation.The search walks the table entry by entry, and the three conditions are the whole of the check.
Running the command
The payload runs one command as SYSTEM. It reads a base64 command from C:\Users\Public\ptcmd.txt, decodes it, runs it as cmd.exe /c under the stolen token, and pipes the output back to its own console. It prints the stolen identity with the result.
The child process is created without a window. That hides the console and nothing else: the creation event, the command line and the parent-child link are all recorded. The command file is not in the capture, so what ran as SYSTEM is not known.
Figure 10: The stolen identity is printed, ptcmd.txt is read and decoded, the command runs as SYSTEM, and SHELL_DONE is written.The output between the two markers belongs to the command, printed under the stolen identity.
Cleanup
The payload restores the original function pointer, connects to its own pipe and writes a single byte to release the waiting thread, then exits. Everything is reversed except the page protection from the third stage.
Two builds, one program
Two payloads were recovered. They are the same program from two different compilers, and the differences are the evidence. One build comes from Mono's mcs compiler and the other from Microsoft's Roslyn, based on three signals that agree: the compiler-generated class names, the image base, and the way field initialisers are placed.
The two builds differ in exactly one place, a stray dollar sign in an error message that never executes. The second build was compiled at 22:48:01 on 6 September and retrieved at 22:54:44, under seven minutes later. A fresh hash against hash-based blocking is the plausible reason, but no log states it.
The source tree and the served archive are byte-identical copies of the same eleven files, and the tree does not build. It calls a helper class named Sunday that ships in no file in the archive, and its project file declares an older .NET version than the binaries it produced. The tree matches the second build, not the first.
Figure 11: The gp_build source tree: Program.cs, SharpToken.cs and the GodPotato project files.The tree is the operator's build directory, and it is the last of the files left in the open.
The staged toolkit
The payload and its build tree were not the only tooling left in the open. The directory held a full Impacket environment, the standard toolkit for working with Windows networks from Linux. We swept all 69 Python scripts for hardcoded addresses, embedded data and added code, and found nothing. We did not diff them against upstream line by line, so a careful single-line edit could pass this check.
Two scripts check whether LDAP or MSSQL relay is viable against a target, and one filters domain controllers for Windows Server 2025. Those read as per-target checks rather than a spray.
The rest is the standard Active Directory attack surface, from secretsdump to five remote-execution methods. No tool in the set was observed in use, and the capture holds no command history, no tool output and no execution telemetry.
The exfiltration
The operator's own logs carry more weight than the payloads, because the operator wrote them for private use, not for an audience. The transfer log records a completed copy of 68.837 GiB across 27 files in 23 minutes 46 seconds.
2026/09/06 01:26:50 INFO : POEA_EServices.bak: Multi-thread Copied (new)
Transferred: 68.837 GiB / 68.837 GiB, 100%, 20.238 MiB/s, ETA 0s
Transferred: 27 / 27, 100%
Elapsed time: 23m46.3s
Copy
Its counterpart records a failed attempt fourteen hours later against a source path of /data/chunk that no longer existed. That indicates the collection was assembled separately from the transfer and subsequently cleared.
The log does not name the source host or the destination remote. The volume and the displayed rate also do not reconcile: 68.837 GiB over 23 minutes 46 seconds averages approximately 49.4 MiB/s, while the summary line reads 20.238 MiB/s. Rclone's summary speed is a rolling average at completion, not total bytes divided by elapsed time, which accounts for the gap. We report both as logged.
The ordering of the transfer against the payload matters more than either figure. The transfer completed at 01:26:50 on 6 September and the first payload was fetched at 21:41:33 the same day, which the logs place approximately twenty hours later. So the payload was not the mechanism of the theft, and whatever access the operator held when the backups were copied was already sufficient.
That is as far as the operator's own files take us. The rest comes from what our platform already recorded about the host.
Infrastructure Analysis
The staging directory was served over port 80 from 213.163.205[.]35, a Linux host at UpCloud Ltd (AS202053) in Singapore. The Impacket virtual environment path, /tmp/imp, is recorded in the environment's own activation script. A separate Python service on the host binds port 8888 and accepts push uploads, though no received file was recovered and its use is not established. The transfer destination does not appear in the indicators, because the log does not name it. The staging address does appear: it is the same address published in the Hunt.io AttackCapture report covering this capture, so a defender who needs it for blocking has two sources for it.
Figure 12: The staging host, flagged for the malicious open directory on 7 September 2026.An automated capability check was run against the first payload as a cross-check and reported virtualisation and sandbox evasion, which we do not consider supported: the match derives from two token-enumeration names in a bundled third-party library, and no environment detection exists anywhere in the payload or that library. The same check reported no process injection and no event-triggered execution, which agrees with our own reading.
Our AttackCapture platform indexed the staging directory on 7 September 2026, and the same platform keeps the scan telemetry, the certificates and the directory listings behind it. We queried our tables for every address in the log, so each statement below rests on a record and can be reproduced with the query printed beside it.
The staging host
Our record for 213.163.205[.]35 gives the operator's platform: UpCloud Ltd (AS202053), Singapore, in the range 213.163.192[.]0/20, behind the PTR 213-163-205-35.sg-sin1.upcloud.host. The platform carries one warning on the address and nothing else: a potential malicious open directory, dated 7 September 2026.
Figure 13: The staging host listening on port 80, running a SimpleHTTP/0.6 Python/3.13.5 under the title Directory listing forThe open ports confirm the capture's own story and add one detail. Port 80 answered with SimpleHTTP/0.6 Python/3.13.5 under the title Directory listing for /, which is Python's built-in server, started by hand. Port 887 carried a self-signed *.aapanel.com certificate valid to November 2035, and 887 is aaPanel's default port, so the VPS was run through that panel. The same port 80 had answered as WebSockify Python/3.11.2 in September 2025, a browser terminal bridge of the kind these panels install, so the host was set up as a managed VPS well before the intrusion. The SSH banner is OpenSSH_10.0p2 Debian-7+deb13u4, a current Debian release, seen up to 8 September 2026.
Our crawler indexed the directory at 13:47 UTC on 7 September. Its index holds 141 entries, 112 files and 29 directories, matching the capture package. A second pass that evening, from 20:02 to 01:05, recorded the names of files it did not download and reached deeper into the Impacket environment than the capture does, including the site-packages versions.
Both queries below return that record, the first the host's HTTP history and the second the filenames our crawler indexed from the open directory.
SELECT * FROM ip.events.http.history WHERE ip = '213.163.205.35'
SELECT * FROM open_directory_filenames WHERE hostname LIKE 'http://213.163.205.35%'
Copy
Neither our malware tracking nor the C2 feed holds a record for this host, and no address in its /24 is flagged either. The staging server never probed our sensors.
The requesting addresses, by role
The staging host is one address in the log. The other five are the ones that reached in and pulled files.
Our bulk enrich feature helps view the six addresses and puts provider, country, VPN flags and the capture hit in one place. The roles below are read from the access log against the certificate and scanner evidence.
Figure 14: The six addresses in one view: provider, country, VPN flag and the AttackCapture hit on the staging host.The table below sets out what each address did in the log and how that activity is read.
| Address | Network | In the access log | Assessment |
|---|---|---|---|
| 213.163.205[.]35 | UpCloud Ltd (AS202053), Singapore | served the directory | staging and delivery host |
| 121.58.231[.]55 | Converge ICT (AS17639), Mandaluyong, PH | loader twice, both payloads, 21:38:42 to 22:54:44 | agency portal host, certificate match |
| 121.58.231[.]35 | Converge ICT (AS17639), Mandaluyong, PH | source archive eleven attempts, 21:56:03 to 22:30:41 | agency portal host, certificate match |
| 156.59.127[.]203 | Zenlayer (AS21859) | source archive eleven times, second payload | SSL VPN appliance, no role established |
| 172.105.82[.]111 | Linode, now Akamai (AS63949), Frankfurt | walked the tree over nine hours and took the tooling | mass scanner |
| 158.178.237[.]116 | Oracle (AS31898), Singapore | swept the directory in sixteen seconds | CVE scanner |
Both queries below back the table, the first returning the current enrichment for all six addresses at once and the second checking each against our honeypot records.
SELECT * FROM ip.current WHERE ip IN ('213.163.205.35','121.58.231.35','121.58.231.55','156.59.127.203','158.178.237.116','172.105.82.111')
SELECT * FROM ip.events.honeypot WHERE ip IN ('213.163.205.35','121.58.231.35','121.58.231.55','156.59.127.203','158.178.237.116','172.105.82.111')
Copy
The agency side of the request log
The address that took the loader and both payloads carries one domain in the platform's records, and it is the agency's: apps.dmw.gov[.]ph, answering 403 to the scanner. The address that pulled the source archive eleven times carries the agency's other portal name, legalassistance.dmw.gov[.]ph, sitting behind a FatPipe MPVPN login page. Neither host carries a risk flag on the platform.
Figure 15: 121.58.231[.]55: Converge ICT (AS17639), Mandaluyong City, with no risk flag on the platform.The domain record on that address is what the rest of this section turns on.
Figure 16: The domain on 121.58.231[.]55: apps.dmw.gov[.]ph, answering 403 to the scanner.The second address that downloaded from the directory sits with the same provider, in the same city.
Figure 17: 121.58.231[.]35: the same provider and city, also without a risk flag.Its own domain record names the agency's legal assistance portal, behind an appliance login.
Figure 18: The single domain we record on 121.58.231[.]35: legalassistance.dmw.gov[.]ph, behind a FatPipe MPVPN login.Both are ordinary Windows servers, answering as Microsoft-HTTPAPI/2.0 on ports 80 and 443 with SMB on 445 and WinRM on 5985 and 47001. The second address also presents a self-signed certificate named PORTAL.dmw.gov[.]ph on port 3389 and on port 8888, renewed on a six-month cycle.
The stronger evidence is the certificate itself. Both addresses present a valid GlobalSign wildcard for *.dmw.gov[.]ph issued to the Philippine Overseas Employment Administration, the agency the backup filenames describe. The pivot starts from the certificate hash.
We query our certificate inventory for those hashes, the three renewals of the agency wildcard, and return every address and port presenting them.
SELECT ip, port, certificate_hash, subject.common_name, timestamp FROM certificates.inventory
WHERE certificate_hash IN ('05E2DAF00FD6D1F91E5AC32B156BAE290BB43D4FA0C1521981D804582C6444D4','FA2FAC83EBC5DBDFEAFE8E6950275FE3BE0D4BE87DF37AF0CC66671C318287AC','59309CCA70A714CA7E6A2353D583D29B0EC02E408A413B86E85A621926C3B038')
Copy
The same search run from the common name returns eleven addresses presenting the wildcard, most of them in 121.58.231[.]0/24, among them .37, .41, .46, .60 and .61. That is a portal farm rather than one machine, and it is the reason a single address in the log should not be read as the whole of the agency's exposure.
Figure 19: The certificate pivot across the platform: eleven addresses present the agency wildcard.The history also shows the portal moving. The wildcard sat on 121.58.231[.]35 from June 2023 to July 2024, on 121.58.231[.]43 from July to September 2025, and on 121.58.231[.]55 from 15 September 2025 to the present.
Figure 20: The pivots for 121.58.231[.]55: the certificate common name first, then fingerprints shared with hundreds of thousands of hosts.The same two fingerprints appear on the archive address, from the years the portal ran there.
Figure 21: The same certificate and fingerprint pivots for 121.58.231[.]35, with the wildcard at the top of the list.The agency domain dmw.gov[.]ph itself resolves 145 subdomains, among them onlineservices, accreditation, agency, agencyportal, aims and ams, the same service families the transfer log names.
Figure 22: The agency domain legalassistance.dmw.gov[.]ph resolves 145 subdomains, among them the service families the backup filenames describe.This closes the question the request log left open. The certificate establishes what these addresses are, the agency's own portal hosts, not what they did with the files. The capture shows delivery to them and nothing about what ran on them afterwards.
The addresses with no assessed role
156.59.127[.]203 retrieved the source archive eleven times and checked the second payload within a minute of the rebuild. Our platform places it at Zenlayer (AS21859) and carries one warning on the address: a possible, unverified Mullvad VPN.
Figure 23: 156.59.127[.]203: Zenlayer (AS21859) with one VPN warning, flagged as a possible unverified Mullvad exit.The scan telemetry reads differently. The SSH banner is SSH-2.0-ArrayOS, the operating system of Array Networks SSL VPN appliances, with a second service on port 8008, and we last observed the host in 2022. An appliance of that kind is a plausible relay for someone else's traffic, which would fit a host that reads the same file eleven times. We record the discrepancy and do not resolve it.
Our code search over its own captures makes the log lines searchable, and the two archive retrievals sit next to each other in the index.
Figure 24: The access log as we index it: 121.58.231[.]35 and 156.59.127[.]203 pulling the source archive minutes apart.172.105.82[.]111 walked the directory for nine hours and took the toolkit, and it does that everywhere. Our honeypot network recorded 1,069 probes from it between January 2023 and September 2025, against paths such as /index.htm, /cgi and /apply.cgi, which are router and IoT exploitation patterns, with browser user agents in the requests. The tree walk is what it does to everything it finds.
158.178.237[.]116 is the same kind of host with a different purpose. It swept the directory in sixteen seconds, read the operator's logs and left.
Figure 25: 158.178.237[.]116: Oracle Corporation (AS31898), Singapore.The signal view for the same address shows what it does with that reach.
Figure 26: The signal profile for 158.178.237[.]116: HTTP crawler, TLS client and the ZMap scanner.Our sensors recorded 41 probes from it between 4 September and 12 October 2026, as an HTTP crawler, a TLS client and a ZMap mass-scan client, and one request for /config/secrets.json carrying the user agent WebSiphon/next-0.1. The same address appears in other captures' web-scan logs asking for /.env.development.
Figure 27: The same address in a third-party web scan log, one row among many scanner hits.It collects exposed secrets at scale. The sixteen-second sweep is its normal behaviour rather than interest in this operation.
That settles who touched the directory. The next question is whether this operator's tooling turns up anywhere else in our captures.
Where the toolkit does and does not appear
A loose search for the staged file names returns source archives under similar names on other hosts, including gp_src.tar on 154.89.151[.]143:443 and gp_src.tgz on 124.198.132[.]250:8000.
The query is below. Two of its terms are specific to this operator, but %gp_src% matches any GodPotato source archive, which is what pulls in the unrelated hosts above.
SELECT
*
FROM
open_directory_filenames
WHERE
file_name LIKE '%Wrqsnx%'
OR file_name LIKE '%portalload%'
OR file_name LIKE '%gp_src%'
Copy
Output example:
Figure 28: The loose search: source archives under similar names on other hosts, including gp_src.tar and gp_src.tgz.The tighter search answers the question that matters. Run across the platform's whole capture index for the names this operator used, it returns twenty entries, and every one of them is on the staging host.
SELECT ip, hostname, file_name, timestamp FROM attackcapture.files
WHERE file_name LIKE '%Wrqsnx%' OR file_name LIKE '%portalload%'
OR file_name LIKE '%rclone-chunk%' OR file_name LIKE '%rclone-drive%'
OR file_name LIKE '%gp_src.tgz%' OR file_name LIKE '%gp_build%'
The query returns twenty entries, and the figure below is the whole of that result.
Copy
Figure 29: The exact search: twenty entries across the whole capture index, all on the staging host.GodPotato itself is a different matter. Ten other open directories across the platform expose GodPotato source or builds, on 130.94.11[.]60, 154.89.151[.]143, 177.3.42[.]39, 38.60.252[.]110, 45.32.9[.]123, 63.141.229[.]228, 63.141.229[.]229, 63.141.229[.]230, 124.198.132[.]250 and 149.88.73[.]163, between August and October 2026. Each packages it differently, as gp-src.zip, gp_src.cs, gp_src.tar or a plain GodPotato-main tree, and none carries the Wrqsnx rename or a loader. Leaving this tool in an open directory is a habit several operators share. This operator's copy is not on the shelf with them.
The tooling and the requesters account for the operator's side. Whose data they took is the other half.
Victims
The transfer log records 27 SQL Server backups whose filenames correspond to the case-management systems of a Philippine overseas-employment and migrant-worker administration. The names include POEA_EServices, POEA_HelpDesk, POEAHelpDeskDB, OFW and OfwDB, together with accreditation, repatriation, eContracts, Cashier and LandBank variants. The mapping is best read as a filename-based contextual assessment rather than as a confirmed organisational identification.
We have not examined any of the backups, and several of the mappings rest on shared naming rather than on documentation: BMonline, BMDB and BMContracts match the Balik-Manggagawa Online Processing System and OWMSDB matches the OFW Welfare Monitoring System, while the remaining entries such as RepatriationDB, AgencyDB and AdjudicationDB suggest their systems by name alone. No organisational identifier, victim hostname or credential is present in the capture, and the contents of the backups are not established.
The systems named in the backups belong to the agency that administers the Philippines' overseas-employment program. The Philippine Statistics Authority estimated 2.16 million overseas Filipino workers in 2023. That figure is the population those systems cover, not a count of the records in these backups, which we have not examined.
On the evening of 6 September an address in the requesting network retrieved the loader and both payloads across 76 minutes, and a second address in the same /24 retrieved the source archive repeatedly over the same window. The log establishes delivery and nothing further. It does not establish that either executed anything, and it does not establish those addresses as victim systems rather than as operators or other requesters.
Attribution
We do not attribute this activity to a tracked actor, and the details that could be mistaken for attribution signals are recorded here without supporting an inference. The AssemblyInfo.cs in the distributed source carries Chinese-language Visual Studio template comments, and the bundled SharpToken library carries Chinese-language source comments, the latter belonging to a third-party project rather than necessarily to this operator. The tar metadata names a Linux account, cicada.
The hypothesis considered and not supported is that these place the operator in a particular country, because a localised development environment indicates the language of the toolchain rather than the location or affiliation of the person using it, and the SharpToken comments may not be this operator's at all. The account handle requires corroboration we do not have, and the capture is not sufficient to confirm attribution or to identify a state nexus.
The technique does not require a vulnerability. A service account holding SeImpersonate sits one reachable handle from SYSTEM on a default Windows host, and the payload reads that condition rather than creating it, which is the part of this operation most likely to recur in others.
Indicators of compromise
Network
| Indicator | Role in this case |
|---|---|
| 213.163.205[.]35 | Staging host, unauthenticated directory on port 80, UpCloud Ltd (AS202053), Singapore. Also published in the Hunt.io AttackCapture report |
| 172.105.82[.]111 | Walked the exposed tree over about nine hours and collected the tooling, including both payloads; role not established |
| 156.59.127[.]203 | Retrieved the source archive eleven times and checked the second payload; role not established |
| 121.58.231[.]x | An address in this /24 retrieved the loader and both payloads across 76 minutes; a second retrieved the source archive repeatedly; role not established, address masked |
| 158.178.237[.]116 | Swept the directory in sixteen seconds, probing for secrets files, and collected the files present; role not established |
| 80/tcp | Unauthenticated Python HTTP server serving the staging directory |
| 8888/tcp | Python upload receiver, writes request bodies to /tmp/uploaded.dll |
File hashes
| SHA-256 | File |
|---|---|
| 4188295ae1f7f8a99d15e90eb037eef3eb03f6acd4422bf877c6e3304e70fcb9 | Wrqsnx.dll, rebranded GodPotato payload, first build |
| 0405d4f79a3cc97fa492f1957cde0d51bc569f5432792f1b8f72077aa3fb2434 | Wrqsnx_portal.dll, second build |
| fcbfc74ddffad4789120c618bdf166c6c8aaca286fb2d184f7fa0ed8b8f26c59 | portalload.ps1, stager |
| cde477ef57ef6f100dcb0242f055113690fdeade8204e0986a3ad257be1fb81e | upload.py, upload receiver |
| 9d3f2f6031ec3b487ae12dd6f9311dd89b4a6bd23af252212bcc1f5507784f39 | gp_src.tgz, incomplete source archive |
| ee15c2a54f1bb483f70bf7777ae08d39c8abbbf7f5b1f2139de0ff76ec3e241e | http80.log, staging server access log |
| e7e6bfc3a2d6c3eb0ed6e1f4ade99ca761d517886412da99a2cf4a0626bce5e3 | rclone.log, transfer record |
Host artifacts and strings
| Artifact | Note |
|---|---|
| C:\Users\Public\ptcmd.txt | Base64 command channel read by the payload; capability only, not observed on a host |
| C:\Users\Public\p_*.b64 | Base64 payload fragments reassembled by the stager |
| \.\pipe\Wrqsnx\pipe\epmapper | Named pipe created with Everyone Full Control; specific to this rename |
| [+] SHELL_DONE | Operator's completion marker on the payload's stdout |
| POTATO_FIRED | Stager completion marker; specific to this toolkit |
| 18f70770-8e64-11cf-9af1-0020af6e72f4 | ORCB interface GUID; inherited from public GodPotato and matches any build of the tool |
| ncacn_ip_tcp debugger trap | Inherited from public GodPotato; matches any build of the tool |
MITRE ATT&CK Mapping
Status is carried on every row. Observed denotes activity present in the recovered logs, binaries or artifacts; inferred denotes activity supported by converging indicators and not directly established; capability only denotes a tool or function present in the recovered material whose execution is not demonstrated.
| ID | Technique | Tactic | Status | Evidence |
|---|---|---|---|---|
| T1583.003 | Acquire Infrastructure: Virtual Private Server | Resource Development | Inferred | Staging host serving the working directory |
| T1588.005 | Obtain Capabilities: Exploits | Resource Development | Observed | Public GodPotato source present in the recovered tree |
| T1608.001 | Stage Capabilities: Upload Malware | Resource Development | Observed | Payload and loader served from the operator's HTTP root |
| T1059.001 | PowerShell | Execution | Observed | portalload.ps1 is the delivered stager |
| T1059.003 | Windows Command Shell | Execution | Capability only | cmd.exe /c invoked through the token utility |
| T1620 | Reflective Code Loading | Execution | Capability only | In-memory assembly load from base64 chunks |
| T1068 | Exploitation for Privilege Escalation | Privilege Escalation | Capability only | DCOM unmarshal trigger against the dispatch table |
| T1134.001 | Token Impersonation | Privilege Escalation | Capability only | Named-pipe impersonation, then SYSTEM token duplication |
| T1036 | Masquerading | Defense Evasion | Observed | GodPotato renamed end to end |
| T1027 | Obfuscated Files or Information | Defense Evasion | Capability only | Payload split into base64 chunks |
| T1140 | Deobfuscate/Decode Files or Information | Defense Evasion | Capability only | Chunks concatenated and decoded before loading |
| T1213 | Data from Information Repositories | Collection | Observed | 27 database backups staged and transferred |
| T1567 | Exfiltration Over Web Service | Exfiltration | Unknown | Transfer completed; external destination and channel not established |
| T1003 | OS Credential Dumping | Credential Access | Capability only | secretsdump, dpapi and keylistattack present |
| T1087 | Account Discovery | Discovery | Capability only | GetADUsers, GetADComputers and ldapdomaindump present, not observed in use |
| T1021 | Remote Services | Lateral Movement | Capability only | Five remote-execution methods present |
| - | Initial Access | Not established | Unknown | No vector in this capture |
| - | Command and Control | Not established | Unknown | Neither payload beacons |
| - | Persistence | Not established | Unknown | No persistence mechanism in the recovered payload |
Conclusion
What the recovered material establishes is a completed theft, a delivery server and tooling rebuilt in place. What it does not establish is how the operator entered the agency network, what command ran under SYSTEM, or where the 68.837 GiB was sent, and the operation ended because the working directory was public rather than because anyone detected it.
The exploit is public and unchanged, and the operator's work comprises the renaming, the stager and one rebuild. The payload is careful where correctness matters and careless where evidence accumulates: the impersonation-level checks are correct and defensive, the named-pipe error handling is correct, and the token selection resolves its object type at runtime rather than hardcoding an index, while a variable is declared and discarded and a system DLL page remains writable after the process exits.
The staging directory in this post was captured and indexed by AttackCapture before the operator took it down. If you want to see what's sitting in the open across your own exposed infrastructure, book a demo.
Disclosure note: Hunt.io notified the relevant national CERT prior to publication. No personal records or credentials from the affected systems appear in this report.
An operator copied 68.837 GiB of a Philippine government agency's database backups, logged the transfer for themselves, and then left that log open on the internet. We captured the directory while it was still serving.
The copy finished in under 24 minutes on 6 September 2026, 27 SQL Server backups whose names match the agency's overseas-employment and migrant-worker systems. Beside the log sat the operator's toolkit, a rebranded GodPotato build, a PowerShell stager, two payloads and a full Impacket environment.
The access log shows that tooling pulled the same evening, which establishes distribution from this server and nothing past it. How the operator got in, and whether any payload ran, are not in the capture.
Key Findings
We reverse-engineered the payload, traced the operator's logs, and pivoted the certificates to the agency itself. The key takeaways:
A staging host at UpCloud Ltd (AS202053) left the operator's working folder open through an unauthenticated HTTP directory on port 80, including the operator's own transfer and access logs
Completed 68.837 GiB copy of 27 SQL Server backups, transferred in 23m 46s at a tool-reported 20.238 MiB/s that does not reconcile with the volume and duration
Backup filenames matching the case-management systems of a Philippine overseas-employment and migrant-worker administration, including POEA and OFW variants
A rebranded GodPotato .NET build staged as Wrqsnx.dll and Wrqsnx_portal.dll, with the RPC pipe, namespace and assembly metadata renamed and internal identifiers left untouched
Two builds from two different compilers, the second compiled 6m 43s before it was retrieved
An eight-line PowerShell stager that rebuilds the payload in memory from base64 fragments, so no DLL touches disk
A full Impacket environment with no signs of modification, including LDAP and MSSQL relay checks and a tool targeting Windows Server 2025 domain controllers
No initial access vector, no command-and-control channel and no confirmed payload execution appear in the recovered data
The exposed staging server
Each point above traces back to a file the operator left in the open. We start with the server that served them.
The host 213.163.205[.]35:80 ran a Python HTTP server on port 80 with directory listing enabled, and it served the operator's working folder to anyone who asked. No defender found the exposure: the directory was captured while it was open. The access log records 543 requests from 76 distinct addresses across a 16-hour, 9-minute window on 6 and 7 September 2026.
Figure 01: The capture in Hunt.io: the staging directory, served from 213.163.205[.]35:80 at UpCloud Ltd (AS202053), Singapore.The operator's environment is identifiable from the recovered files, not from the host itself. The Impacket environment records its own path in its activation script: /tmp/imp. That places the toolkit in a temporary directory on the staging server, and it fits an operator working from a rented Linux host rather than a maintained workstation.
Most of the traffic against the directory was scanner noise with no link to the operation. The six addresses assessed below were selected for their retrieval of operational files; the remaining 70 requested only directory listings or common exploit paths. A WordPress and PHP RCE sweeper sent 49 requests and received 404 or 501 on every one.
A handful of addresses did more than scan, and they downloaded files. Their roles are assessed separately from their activity in the indicators section, because taking a file from an open directory establishes neither that the requester is the operator nor that it is a victim.
What the host exposed was the operator's working folder, not a finished deployment: more than a hundred files, including a payload builder and its source tree, two compiled payloads, a PowerShell stager, a complete Impacket environment, a small Python upload receiver, and the operator's own logs.
Figure 02: The staging directory was captured: the payloads, the stager, the transfer logs and the Impacket environment, all in the open.The upload receiver is a small Python service that binds port 8888 and writes request bodies to disk. Its companion log is zero bytes, but the handler contains no logging call, so the empty log is not evidence of disuse, and no received file was recovered. Whether the endpoint was ever used cannot be determined from this capture.
The logs are the most consequential files in the directory, and they are treated in their own section below.
Wrqsnx: a rebranded GodPotato
The payload is the most detailed piece in the directory, so we start there.
The payload is GodPotato, a publicly available .NET tool. It turns the rights of a service account into full SYSTEM control through DCOM and RPC, and it needs no Windows vulnerability to do it. The operator rebuilt it under the name Wrqsnx and renamed the namespace, the context classes, the pipe path and the assembly metadata, while leaving the source file names and some internal field names unchanged. That gap is a fingerprint: the tool is public, and the copy is lightly edited.
Microsoft's platform detects the payload as Trojan:MSIL/GodPotato.FF!MTB. That corroborates the lineage independently of our code reading. Everything below is read from the recovered files; none of it was observed running.
Rebuilding the payload in memory
The stager runs the payload without ever writing a DLL to disk. It is eight lines of PowerShell. It collects the base64 fragments named p_*.b64 from C:\Users\Public in filename order, joins them, strips whitespace, decodes the result in memory, loads it as a .NET assembly and calls its Main method.
The design has two weak points the operator accepted. The join depends on fixed-width fragment names, and the script never checks this. And the completion marker, POTATO_FIRED, only shows that the stager reached its last line: failures inside the payload are caught and swallowed, so the marker says nothing about SYSTEM.
Figure 03: portalload.ps1 as served and no DLL touches disk.Nothing in the stager validates the fragments, so whatever the files contain is what gets loaded.
Finding the target in memory
The payload takes over one decision inside Windows RPC. Hardcoding the location of that decision would work on a single Windows build, so the payload finds it at runtime instead. It copies the combase.dll module image into memory and searches for a short byte pattern: the size of the structure it wants followed by a known interface identifier.
From the first match, it follows the structure's own records to the dispatch table and learns how many arguments the routine it wants to replace takes, between four and fourteen. That count changes between Windows versions, and the payload reads it instead of assuming it.
Figure 04: Finding combase.dll at runtime and building the 20-byte search pattern.The second figure carries the walk on from the match to the pointer the payload replaces.
Figure 05: Walking RPC_SERVER_INTERFACE and MIDL_SERVER_INFO to reach the dispatch table pointer.The walk reads the layout Windows ships, so the same code reaches the routine on any build.
Taking over the RPC lookup
When Windows needs to reach an interface, one routine answers a single question: which transport does it use? The payload takes that routine over. It makes the dispatch table writable, replaces the first entry, the transport chooser, with a pointer to its own function, and stores the original pointer to put back later.
One thing is never put back. The memory page was made writable and stays writable after the process exits. No code is injected, and the change is four bytes wide, so it escapes tools that scan for injected code. It is the clearest trace the tool leaves on a host.
Figure 06: HookRPC makes the page writable; Restore rewrites the pointer but not the page protection.The two functions sit beside each other in the source, and the page permission is the only thing they disagree on.
Pulling in a SYSTEM connection
For the technique to work, a SYSTEM service has to connect to the payload. The payload creates the named pipe \.\pipe\Wrqsnx\pipe\epmapper with a descriptor that grants Everyone full control. That looks careless but is required, because a named pipe created normally would refuse the SYSTEM-context connection the technique depends on.
Figure 07: The pipe is created with Everyone Full Control, a condition of the attack.The payload then builds a genuine-looking COM object reference for a local object, rewrites its destination to point at the same machine with NTLM authentication, and hands it to CoUnmarshalInterface. combase asks the hooked lookup how to reach the interface, receives the pipe instead of a network address, and the DCOM resolver inside RPCSS, which runs as SYSTEM, opens the pipe. That is where the SYSTEM client comes from.
Figure 08: The hooked routine answers combase with the pipe endpoint instead of a network address.The answer the resolver receives is a pipe on the local machine, which is the connection the payload wants.
Stealing a SYSTEM token
With a SYSTEM client attached, the pipe thread impersonates the connected client, reads the system-wide handle table through NtQuerySystemInformation, and duplicates a token that matches three conditions: the local system SID S-1-5-18, an impersonation level of at least Impersonation, and System integrity or higher.
No memory corruption is involved at any point, and no vulnerability is exploited. Every call uses a permission the process already holds. The escalation works because a SYSTEM token is reachable in the table and the caller has the right to duplicate it.
Figure 09: Reading the system handle table with NtQuerySystemInformation.The search walks the table entry by entry, and the three conditions are the whole of the check.
Running the command
The payload runs one command as SYSTEM. It reads a base64 command from C:\Users\Public\ptcmd.txt, decodes it, runs it as cmd.exe /c under the stolen token, and pipes the output back to its own console. It prints the stolen identity with the result.
The child process is created without a window. That hides the console and nothing else: the creation event, the command line and the parent-child link are all recorded. The command file is not in the capture, so what ran as SYSTEM is not known.
Figure 10: The stolen identity is printed, ptcmd.txt is read and decoded, the command runs as SYSTEM, and SHELL_DONE is written.The output between the two markers belongs to the command, printed under the stolen identity.
Cleanup
The payload restores the original function pointer, connects to its own pipe and writes a single byte to release the waiting thread, then exits. Everything is reversed except the page protection from the third stage.
Two builds, one program
Two payloads were recovered. They are the same program from two different compilers, and the differences are the evidence. One build comes from Mono's mcs compiler and the other from Microsoft's Roslyn, based on three signals that agree: the compiler-generated class names, the image base, and the way field initialisers are placed.
The two builds differ in exactly one place, a stray dollar sign in an error message that never executes. The second build was compiled at 22:48:01 on 6 September and retrieved at 22:54:44, under seven minutes later. A fresh hash against hash-based blocking is the plausible reason, but no log states it.
The source tree and the served archive are byte-identical copies of the same eleven files, and the tree does not build. It calls a helper class named Sunday that ships in no file in the archive, and its project file declares an older .NET version than the binaries it produced. The tree matches the second build, not the first.
Figure 11: The gp_build source tree: Program.cs, SharpToken.cs and the GodPotato project files.The tree is the operator's build directory, and it is the last of the files left in the open.
The staged toolkit
The payload and its build tree were not the only tooling left in the open. The directory held a full Impacket environment, the standard toolkit for working with Windows networks from Linux. We swept all 69 Python scripts for hardcoded addresses, embedded data and added code, and found nothing. We did not diff them against upstream line by line, so a careful single-line edit could pass this check.
Two scripts check whether LDAP or MSSQL relay is viable against a target, and one filters domain controllers for Windows Server 2025. Those read as per-target checks rather than a spray.
The rest is the standard Active Directory attack surface, from secretsdump to five remote-execution methods. No tool in the set was observed in use, and the capture holds no command history, no tool output and no execution telemetry.
The exfiltration
The operator's own logs carry more weight than the payloads, because the operator wrote them for private use, not for an audience. The transfer log records a completed copy of 68.837 GiB across 27 files in 23 minutes 46 seconds.
2026/09/06 01:26:50 INFO : POEA_EServices.bak: Multi-thread Copied (new)
Transferred: 68.837 GiB / 68.837 GiB, 100%, 20.238 MiB/s, ETA 0s
Transferred: 27 / 27, 100%
Elapsed time: 23m46.3s
Copy
Its counterpart records a failed attempt fourteen hours later against a source path of /data/chunk that no longer existed. That indicates the collection was assembled separately from the transfer and subsequently cleared.
The log does not name the source host or the destination remote. The volume and the displayed rate also do not reconcile: 68.837 GiB over 23 minutes 46 seconds averages approximately 49.4 MiB/s, while the summary line reads 20.238 MiB/s. Rclone's summary speed is a rolling average at completion, not total bytes divided by elapsed time, which accounts for the gap. We report both as logged.
The ordering of the transfer against the payload matters more than either figure. The transfer completed at 01:26:50 on 6 September and the first payload was fetched at 21:41:33 the same day, which the logs place approximately twenty hours later. So the payload was not the mechanism of the theft, and whatever access the operator held when the backups were copied was already sufficient.
That is as far as the operator's own files take us. The rest comes from what our platform already recorded about the host.
Infrastructure Analysis
The staging directory was served over port 80 from 213.163.205[.]35, a Linux host at UpCloud Ltd (AS202053) in Singapore. The Impacket virtual environment path, /tmp/imp, is recorded in the environment's own activation script. A separate Python service on the host binds port 8888 and accepts push uploads, though no received file was recovered and its use is not established. The transfer destination does not appear in the indicators, because the log does not name it. The staging address does appear: it is the same address published in the Hunt.io AttackCapture report covering this capture, so a defender who needs it for blocking has two sources for it.
Figure 12: The staging host, flagged for the malicious open directory on 7 September 2026.An automated capability check was run against the first payload as a cross-check and reported virtualisation and sandbox evasion, which we do not consider supported: the match derives from two token-enumeration names in a bundled third-party library, and no environment detection exists anywhere in the payload or that library. The same check reported no process injection and no event-triggered execution, which agrees with our own reading.
Our AttackCapture platform indexed the staging directory on 7 September 2026, and the same platform keeps the scan telemetry, the certificates and the directory listings behind it. We queried our tables for every address in the log, so each statement below rests on a record and can be reproduced with the query printed beside it.
The staging host
Our record for 213.163.205[.]35 gives the operator's platform: UpCloud Ltd (AS202053), Singapore, in the range 213.163.192[.]0/20, behind the PTR 213-163-205-35.sg-sin1.upcloud.host. The platform carries one warning on the address and nothing else: a potential malicious open directory, dated 7 September 2026.
Figure 13: The staging host listening on port 80, running a SimpleHTTP/0.6 Python/3.13.5 under the title Directory listing forThe open ports confirm the capture's own story and add one detail. Port 80 answered with SimpleHTTP/0.6 Python/3.13.5 under the title Directory listing for /, which is Python's built-in server, started by hand. Port 887 carried a self-signed *.aapanel.com certificate valid to November 2035, and 887 is aaPanel's default port, so the VPS was run through that panel. The same port 80 had answered as WebSockify Python/3.11.2 in September 2025, a browser terminal bridge of the kind these panels install, so the host was set up as a managed VPS well before the intrusion. The SSH banner is OpenSSH_10.0p2 Debian-7+deb13u4, a current Debian release, seen up to 8 September 2026.
Our crawler indexed the directory at 13:47 UTC on 7 September. Its index holds 141 entries, 112 files and 29 directories, matching the capture package. A second pass that evening, from 20:02 to 01:05, recorded the names of files it did not download and reached deeper into the Impacket environment than the capture does, including the site-packages versions.
Both queries below return that record, the first the host's HTTP history and the second the filenames our crawler indexed from the open directory.
SELECT * FROM ip.events.http.history WHERE ip = '213.163.205.35'
SELECT * FROM open_directory_filenames WHERE hostname LIKE 'http://213.163.205.35%'
Copy
Neither our malware tracking nor the C2 feed holds a record for this host, and no address in its /24 is flagged either. The staging server never probed our sensors.
The requesting addresses, by role
The staging host is one address in the log. The other five are the ones that reached in and pulled files.
Our bulk enrich feature helps view the six addresses and puts provider, country, VPN flags and the capture hit in one place. The roles below are read from the access log against the certificate and scanner evidence.
Figure 14: The six addresses in one view: provider, country, VPN flag and the AttackCapture hit on the staging host.The table below sets out what each address did in the log and how that activity is read.
| Address | Network | In the access log | Assessment |
|---|---|---|---|
| 213.163.205[.]35 | UpCloud Ltd (AS202053), Singapore | served the directory | staging and delivery host |
| 121.58.231[.]55 | Converge ICT (AS17639), Mandaluyong, PH | loader twice, both payloads, 21:38:42 to 22:54:44 | agency portal host, certificate match |
| 121.58.231[.]35 | Converge ICT (AS17639), Mandaluyong, PH | source archive eleven attempts, 21:56:03 to 22:30:41 | agency portal host, certificate match |
| 156.59.127[.]203 | Zenlayer (AS21859) | source archive eleven times, second payload | SSL VPN appliance, no role established |
| 172.105.82[.]111 | Linode, now Akamai (AS63949), Frankfurt | walked the tree over nine hours and took the tooling | mass scanner |
| 158.178.237[.]116 | Oracle (AS31898), Singapore | swept the directory in sixteen seconds | CVE scanner |
Both queries below back the table, the first returning the current enrichment for all six addresses at once and the second checking each against our honeypot records.
SELECT * FROM ip.current WHERE ip IN ('213.163.205.35','121.58.231.35','121.58.231.55','156.59.127.203','158.178.237.116','172.105.82.111')
SELECT * FROM ip.events.honeypot WHERE ip IN ('213.163.205.35','121.58.231.35','121.58.231.55','156.59.127.203','158.178.237.116','172.105.82.111')
Copy
The agency side of the request log
The address that took the loader and both payloads carries one domain in the platform's records, and it is the agency's: apps.dmw.gov[.]ph, answering 403 to the scanner. The address that pulled the source archive eleven times carries the agency's other portal name, legalassistance.dmw.gov[.]ph, sitting behind a FatPipe MPVPN login page. Neither host carries a risk flag on the platform.
Figure 15: 121.58.231[.]55: Converge ICT (AS17639), Mandaluyong City, with no risk flag on the platform.The domain record on that address is what the rest of this section turns on.
Figure 16: The domain on 121.58.231[.]55: apps.dmw.gov[.]ph, answering 403 to the scanner.The second address that downloaded from the directory sits with the same provider, in the same city.
Figure 17: 121.58.231[.]35: the same provider and city, also without a risk flag.Its own domain record names the agency's legal assistance portal, behind an appliance login.
Figure 18: The single domain we record on 121.58.231[.]35: legalassistance.dmw.gov[.]ph, behind a FatPipe MPVPN login.Both are ordinary Windows servers, answering as Microsoft-HTTPAPI/2.0 on ports 80 and 443 with SMB on 445 and WinRM on 5985 and 47001. The second address also presents a self-signed certificate named PORTAL.dmw.gov[.]ph on port 3389 and on port 8888, renewed on a six-month cycle.
The stronger evidence is the certificate itself. Both addresses present a valid GlobalSign wildcard for *.dmw.gov[.]ph issued to the Philippine Overseas Employment Administration, the agency the backup filenames describe. The pivot starts from the certificate hash.
We query our certificate inventory for those hashes, the three renewals of the agency wildcard, and return every address and port presenting them.
SELECT ip, port, certificate_hash, subject.common_name, timestamp FROM certificates.inventory
WHERE certificate_hash IN ('05E2DAF00FD6D1F91E5AC32B156BAE290BB43D4FA0C1521981D804582C6444D4','FA2FAC83EBC5DBDFEAFE8E6950275FE3BE0D4BE87DF37AF0CC66671C318287AC','59309CCA70A714CA7E6A2353D583D29B0EC02E408A413B86E85A621926C3B038')
Copy
The same search run from the common name returns eleven addresses presenting the wildcard, most of them in 121.58.231[.]0/24, among them .37, .41, .46, .60 and .61. That is a portal farm rather than one machine, and it is the reason a single address in the log should not be read as the whole of the agency's exposure.
Figure 19: The certificate pivot across the platform: eleven addresses present the agency wildcard.The history also shows the portal moving. The wildcard sat on 121.58.231[.]35 from June 2023 to July 2024, on 121.58.231[.]43 from July to September 2025, and on 121.58.231[.]55 from 15 September 2025 to the present.
Figure 20: The pivots for 121.58.231[.]55: the certificate common name first, then fingerprints shared with hundreds of thousands of hosts.The same two fingerprints appear on the archive address, from the years the portal ran there.
Figure 21: The same certificate and fingerprint pivots for 121.58.231[.]35, with the wildcard at the top of the list.The agency domain dmw.gov[.]ph itself resolves 145 subdomains, among them onlineservices, accreditation, agency, agencyportal, aims and ams, the same service families the transfer log names.
Figure 22: The agency domain legalassistance.dmw.gov[.]ph resolves 145 subdomains, among them the service families the backup filenames describe.This closes the question the request log left open. The certificate establishes what these addresses are, the agency's own portal hosts, not what they did with the files. The capture shows delivery to them and nothing about what ran on them afterwards.
The addresses with no assessed role
156.59.127[.]203 retrieved the source archive eleven times and checked the second payload within a minute of the rebuild. Our platform places it at Zenlayer (AS21859) and carries one warning on the address: a possible, unverified Mullvad VPN.
Figure 23: 156.59.127[.]203: Zenlayer (AS21859) with one VPN warning, flagged as a possible unverified Mullvad exit.The scan telemetry reads differently. The SSH banner is SSH-2.0-ArrayOS, the operating system of Array Networks SSL VPN appliances, with a second service on port 8008, and we last observed the host in 2022. An appliance of that kind is a plausible relay for someone else's traffic, which would fit a host that reads the same file eleven times. We record the discrepancy and do not resolve it.
Our code search over its own captures makes the log lines searchable, and the two archive retrievals sit next to each other in the index.
Figure 24: The access log as we index it: 121.58.231[.]35 and 156.59.127[.]203 pulling the source archive minutes apart.172.105.82[.]111 walked the directory for nine hours and took the toolkit, and it does that everywhere. Our honeypot network recorded 1,069 probes from it between January 2023 and September 2025, against paths such as /index.htm, /cgi and /apply.cgi, which are router and IoT exploitation patterns, with browser user agents in the requests. The tree walk is what it does to everything it finds.
158.178.237[.]116 is the same kind of host with a different purpose. It swept the directory in sixteen seconds, read the operator's logs and left.
Figure 25: 158.178.237[.]116: Oracle Corporation (AS31898), Singapore.The signal view for the same address shows what it does with that reach.
Figure 26: The signal profile for 158.178.237[.]116: HTTP crawler, TLS client and the ZMap scanner.Our sensors recorded 41 probes from it between 4 September and 12 October 2026, as an HTTP crawler, a TLS client and a ZMap mass-scan client, and one request for /config/secrets.json carrying the user agent WebSiphon/next-0.1. The same address appears in other captures' web-scan logs asking for /.env.development.
Figure 27: The same address in a third-party web scan log, one row among many scanner hits.It collects exposed secrets at scale. The sixteen-second sweep is its normal behaviour rather than interest in this operation.
That settles who touched the directory. The next question is whether this operator's tooling turns up anywhere else in our captures.
Where the toolkit does and does not appear
A loose search for the staged file names returns source archives under similar names on other hosts, including gp_src.tar on 154.89.151[.]143:443 and gp_src.tgz on 124.198.132[.]250:8000.
The query is below. Two of its terms are specific to this operator, but %gp_src% matches any GodPotato source archive, which is what pulls in the unrelated hosts above.
SELECT
*
FROM
open_directory_filenames
WHERE
file_name LIKE '%Wrqsnx%'
OR file_name LIKE '%portalload%'
OR file_name LIKE '%gp_src%'
Copy
Output example:
Figure 28: The loose search: source archives under similar names on other hosts, including gp_src.tar and gp_src.tgz.The tighter search answers the question that matters. Run across the platform's whole capture index for the names this operator used, it returns twenty entries, and every one of them is on the staging host.
SELECT ip, hostname, file_name, timestamp FROM attackcapture.files
WHERE file_name LIKE '%Wrqsnx%' OR file_name LIKE '%portalload%'
OR file_name LIKE '%rclone-chunk%' OR file_name LIKE '%rclone-drive%'
OR file_name LIKE '%gp_src.tgz%' OR file_name LIKE '%gp_build%'
The query returns twenty entries, and the figure below is the whole of that result.
Copy
Figure 29: The exact search: twenty entries across the whole capture index, all on the staging host.GodPotato itself is a different matter. Ten other open directories across the platform expose GodPotato source or builds, on 130.94.11[.]60, 154.89.151[.]143, 177.3.42[.]39, 38.60.252[.]110, 45.32.9[.]123, 63.141.229[.]228, 63.141.229[.]229, 63.141.229[.]230, 124.198.132[.]250 and 149.88.73[.]163, between August and October 2026. Each packages it differently, as gp-src.zip, gp_src.cs, gp_src.tar or a plain GodPotato-main tree, and none carries the Wrqsnx rename or a loader. Leaving this tool in an open directory is a habit several operators share. This operator's copy is not on the shelf with them.
The tooling and the requesters account for the operator's side. Whose data they took is the other half.
Victims
The transfer log records 27 SQL Server backups whose filenames correspond to the case-management systems of a Philippine overseas-employment and migrant-worker administration. The names include POEA_EServices, POEA_HelpDesk, POEAHelpDeskDB, OFW and OfwDB, together with accreditation, repatriation, eContracts, Cashier and LandBank variants. The mapping is best read as a filename-based contextual assessment rather than as a confirmed organisational identification.
We have not examined any of the backups, and several of the mappings rest on shared naming rather than on documentation: BMonline, BMDB and BMContracts match the Balik-Manggagawa Online Processing System and OWMSDB matches the OFW Welfare Monitoring System, while the remaining entries such as RepatriationDB, AgencyDB and AdjudicationDB suggest their systems by name alone. No organisational identifier, victim hostname or credential is present in the capture, and the contents of the backups are not established.
The systems named in the backups belong to the agency that administers the Philippines' overseas-employment program. The Philippine Statistics Authority estimated 2.16 million overseas Filipino workers in 2023. That figure is the population those systems cover, not a count of the records in these backups, which we have not examined.
On the evening of 6 September an address in the requesting network retrieved the loader and both payloads across 76 minutes, and a second address in the same /24 retrieved the source archive repeatedly over the same window. The log establishes delivery and nothing further. It does not establish that either executed anything, and it does not establish those addresses as victim systems rather than as operators or other requesters.
Attribution
We do not attribute this activity to a tracked actor, and the details that could be mistaken for attribution signals are recorded here without supporting an inference. The AssemblyInfo.cs in the distributed source carries Chinese-language Visual Studio template comments, and the bundled SharpToken library carries Chinese-language source comments, the latter belonging to a third-party project rather than necessarily to this operator. The tar metadata names a Linux account, cicada.
The hypothesis considered and not supported is that these place the operator in a particular country, because a localised development environment indicates the language of the toolchain rather than the location or affiliation of the person using it, and the SharpToken comments may not be this operator's at all. The account handle requires corroboration we do not have, and the capture is not sufficient to confirm attribution or to identify a state nexus.
The technique does not require a vulnerability. A service account holding SeImpersonate sits one reachable handle from SYSTEM on a default Windows host, and the payload reads that condition rather than creating it, which is the part of this operation most likely to recur in others.
Indicators of compromise
Network
| Indicator | Role in this case |
|---|---|
| 213.163.205[.]35 | Staging host, unauthenticated directory on port 80, UpCloud Ltd (AS202053), Singapore. Also published in the Hunt.io AttackCapture report |
| 172.105.82[.]111 | Walked the exposed tree over about nine hours and collected the tooling, including both payloads; role not established |
| 156.59.127[.]203 | Retrieved the source archive eleven times and checked the second payload; role not established |
| 121.58.231[.]x | An address in this /24 retrieved the loader and both payloads across 76 minutes; a second retrieved the source archive repeatedly; role not established, address masked |
| 158.178.237[.]116 | Swept the directory in sixteen seconds, probing for secrets files, and collected the files present; role not established |
| 80/tcp | Unauthenticated Python HTTP server serving the staging directory |
| 8888/tcp | Python upload receiver, writes request bodies to /tmp/uploaded.dll |
File hashes
| SHA-256 | File |
|---|---|
| 4188295ae1f7f8a99d15e90eb037eef3eb03f6acd4422bf877c6e3304e70fcb9 | Wrqsnx.dll, rebranded GodPotato payload, first build |
| 0405d4f79a3cc97fa492f1957cde0d51bc569f5432792f1b8f72077aa3fb2434 | Wrqsnx_portal.dll, second build |
| fcbfc74ddffad4789120c618bdf166c6c8aaca286fb2d184f7fa0ed8b8f26c59 | portalload.ps1, stager |
| cde477ef57ef6f100dcb0242f055113690fdeade8204e0986a3ad257be1fb81e | upload.py, upload receiver |
| 9d3f2f6031ec3b487ae12dd6f9311dd89b4a6bd23af252212bcc1f5507784f39 | gp_src.tgz, incomplete source archive |
| ee15c2a54f1bb483f70bf7777ae08d39c8abbbf7f5b1f2139de0ff76ec3e241e | http80.log, staging server access log |
| e7e6bfc3a2d6c3eb0ed6e1f4ade99ca761d517886412da99a2cf4a0626bce5e3 | rclone.log, transfer record |
Host artifacts and strings
| Artifact | Note |
|---|---|
| C:\Users\Public\ptcmd.txt | Base64 command channel read by the payload; capability only, not observed on a host |
| C:\Users\Public\p_*.b64 | Base64 payload fragments reassembled by the stager |
| \.\pipe\Wrqsnx\pipe\epmapper | Named pipe created with Everyone Full Control; specific to this rename |
| [+] SHELL_DONE | Operator's completion marker on the payload's stdout |
| POTATO_FIRED | Stager completion marker; specific to this toolkit |
| 18f70770-8e64-11cf-9af1-0020af6e72f4 | ORCB interface GUID; inherited from public GodPotato and matches any build of the tool |
| ncacn_ip_tcp debugger trap | Inherited from public GodPotato; matches any build of the tool |
MITRE ATT&CK Mapping
Status is carried on every row. Observed denotes activity present in the recovered logs, binaries or artifacts; inferred denotes activity supported by converging indicators and not directly established; capability only denotes a tool or function present in the recovered material whose execution is not demonstrated.
| ID | Technique | Tactic | Status | Evidence |
|---|---|---|---|---|
| T1583.003 | Acquire Infrastructure: Virtual Private Server | Resource Development | Inferred | Staging host serving the working directory |
| T1588.005 | Obtain Capabilities: Exploits | Resource Development | Observed | Public GodPotato source present in the recovered tree |
| T1608.001 | Stage Capabilities: Upload Malware | Resource Development | Observed | Payload and loader served from the operator's HTTP root |
| T1059.001 | PowerShell | Execution | Observed | portalload.ps1 is the delivered stager |
| T1059.003 | Windows Command Shell | Execution | Capability only | cmd.exe /c invoked through the token utility |
| T1620 | Reflective Code Loading | Execution | Capability only | In-memory assembly load from base64 chunks |
| T1068 | Exploitation for Privilege Escalation | Privilege Escalation | Capability only | DCOM unmarshal trigger against the dispatch table |
| T1134.001 | Token Impersonation | Privilege Escalation | Capability only | Named-pipe impersonation, then SYSTEM token duplication |
| T1036 | Masquerading | Defense Evasion | Observed | GodPotato renamed end to end |
| T1027 | Obfuscated Files or Information | Defense Evasion | Capability only | Payload split into base64 chunks |
| T1140 | Deobfuscate/Decode Files or Information | Defense Evasion | Capability only | Chunks concatenated and decoded before loading |
| T1213 | Data from Information Repositories | Collection | Observed | 27 database backups staged and transferred |
| T1567 | Exfiltration Over Web Service | Exfiltration | Unknown | Transfer completed; external destination and channel not established |
| T1003 | OS Credential Dumping | Credential Access | Capability only | secretsdump, dpapi and keylistattack present |
| T1087 | Account Discovery | Discovery | Capability only | GetADUsers, GetADComputers and ldapdomaindump present, not observed in use |
| T1021 | Remote Services | Lateral Movement | Capability only | Five remote-execution methods present |
| - | Initial Access | Not established | Unknown | No vector in this capture |
| - | Command and Control | Not established | Unknown | Neither payload beacons |
| - | Persistence | Not established | Unknown | No persistence mechanism in the recovered payload |
Conclusion
What the recovered material establishes is a completed theft, a delivery server and tooling rebuilt in place. What it does not establish is how the operator entered the agency network, what command ran under SYSTEM, or where the 68.837 GiB was sent, and the operation ended because the working directory was public rather than because anyone detected it.
The exploit is public and unchanged, and the operator's work comprises the renaming, the stager and one rebuild. The payload is careful where correctness matters and careless where evidence accumulates: the impersonation-level checks are correct and defensive, the named-pipe error handling is correct, and the token selection resolves its object type at runtime rather than hardcoding an index, while a variable is declared and discarded and a system DLL page remains writable after the process exits.
The staging directory in this post was captured and indexed by AttackCapture before the operator took it down. If you want to see what's sitting in the open across your own exposed infrastructure, book a demo.
Related Posts
Related Posts
Related Posts


