Vulnerabilities
Five Open Servers Revealed How a PeopleSoft Zero-Day Became an Extortion Operation
Before Oracle disclosed CVE-2026-35273, UNC6240 used exposed PeopleSoft environment-management paths to obtain code execution, install a disguised MeshCentral control plane, map application infrastructure, move through SSH, stage data, and leave an extortion trail that later surfaced in an open staging directory.

In this article
1 The operation became visible because five servers were left open
On June 9, 2026, five neighboring Internet addresses behaved like a room whose door had been left open. Each host exposed a Python SimpleHTTP directory on port 8888. The listings held customized remote-management agents, operational files, and a shell history that should have remained private. A campaign that had been visible to its targets only through web requests, new processes, and missing data suddenly exposed part of its own working memory.
The discovery did not reveal every victim or every command, but it changed the quality of the public evidence. File names could be matched to hashes. An embedded manager address could be read from staged agents. Commands could be placed in order. The same history appeared across all five systems, making it possible to distinguish setup steps from later reconnaissance, propagation, compression, and a final outbound connection associated with the ShinyHunters data-leak infrastructure.
That accidental disclosure keeps the entire story attached to artifacts. Oracle's advisory establishes an unauthenticated, network-reachable takeover flaw in PeopleSoft Updates Environment Management. Mandiant and GTIG supply the observed campaign around it. The open directories add operational texture. Fixed revisions of MeshCentral and OpenJDK explain two downstream mechanisms. Each source answers a different question, and they form one evidentiary chain only where a date, hash, path, process, or function supports the join.
1.1 Code and response map: Oracle closes the entry; responders remove the control chain left behind
1.2 A command history turned loose files into an ordered event
The staging range ran from 142.11.200.186 through 142.11.200.190. Consecutive addresses can look like a single block on a firewall report, yet each address remains an individual host with its own provider records, filesystem, and network history. Responders should retain the exact address and port attached to every download or session. Collapsing the range too early can hide which host served a binary, which one received an agent, and which one produced an outbound connection. The acquisition inventory should also record first and last observation, provider ownership, response headers, and local clock for every host. If one address lacks logs, evidence from a neighbor cannot be used to reconstruct that host's experience. Consecutive numbering shows deployment proximity; it does not turn five records into one machine.
The identical .bash_history across all five machines is powerful evidence with a limit. It supports a shared preparation process, copied image, synchronized home directory, or repeated deployment procedure. It does not prove that an operator typed every line independently on every server. The hash published by GTIG, 2ab684d93c1553fad87041b4dea97188a97e78589deee2a7bacff905564f3a35, gives later acquisitions a stable comparison point while the surrounding file metadata can show when and how a copy reached each host.
The history records MeshCentral version 1.1.59 being installed on May 27 at 22:14 UTC. Eleven minutes later, at 22:25, the environment received the npm acme-client package used to automate certificate provisioning for azurenetfiles.net. Those timestamps describe preparation of the management service and its TLS identity. They precede Oracle's alert by almost two weeks and give defenders a concrete start for provider, certificate-transparency, DNS, package, and process-log review.
On May 29 at 18:46 UTC, the history queried globally installed npm packages whose names began with authenticode. GTIG correctly left the purpose open: such a package could sign binaries or inspect their metadata, depending on what was installed. The command proves interest in the tool name, not a completed signature operation. A recovered package list, npm cache, shell output, code-signing event, or signed binary would be needed to move from inquiry to use. Binary verification should record signer, certificate chain, digest algorithm, signing time, and validation result, tied to the exact staged-file hash; a publisher name in a Windows properties dialog is not enough. If a package was installed and removed, npm locks, cached tarballs, audit logs, and filesystem journals can still identify the version and use window.
The directory held three configured Windows agents named meshagent32-azure-ops.exe, meshagent64-azure-ops.exe, and meshagent64-v2.exe. Their Azure-flavored names supplied camouflage, while static configuration pointed to wss://azurenetfiles.net:443/agent.ashx. A fourth Linux meshagent lacked the same embedded configuration, leading GTIG to assess that parameters could be supplied at deployment. The distinction matters when hunting: Windows endpoints can be found through both hash and manager string, while Linux review must include command-line and service configuration.
The same history later contained meshctrl.js commands, PeopleSoft configuration reads, construction of a victim-specific fanout script, checks for the extortion marker, archive compression, and an SSH connection toward 176.120.22.24. Some lines carried timestamps and others did not. Sequence remains useful, but an analyst should resist assigning minute-level precision to every action. Package logs, file times, provider flow records, and target telemetry have to supply the missing clocks.
Before the directory exposure, Google began notifying more than one hundred organizations whose public IP addresses correlated with potentially vulnerable PeopleSoft endpoints. That number describes a notification population built from exposure signals. It is not a victim count. A service can answer a probe yet be patched, shielded by an unseen control, unused, or already blocked by the owner. Conversely, a host can be compromised through a route that later disappears from an external scan. A notification register should keep separate counts for organizations, addresses, endpoints, replies, and completed validations. One organization can own many addresses, and one ingress can front several domains. A record moves into an intrusion state only when local logs, host effects, or data evidence support that state; an external probe cannot make the owner's finding on its own.
Sixty-eight percent of the notified organizations operated in higher education. The percentage belongs to the same exposed-and-notified set. It does not mean that sixty-eight percent of all universities ran the vulnerable service, or that the same share suffered intrusion. The concentration still matters: education environments often combine long-lived enterprise applications, decentralized administration, partner access, and high-value identity, research, financial, and student records. Those conditions make rapid ownership and exposure validation especially important.
Mandiant reported that several organizations blocked the activity or remediated successfully, while others experienced compromise and later saw stolen information published on the ShinyHunters leak site. Those outcomes must stay separate in incident records. A notification can close as exposed but unaffected, exploitation attempted, exploitation confirmed, remote control established, data accessed, data transferred, or data published. Skipping intermediate states turns a useful warning campaign into an inaccurate breach ledger.
The observed activity ran from May 27 through June 9. Oracle's initial security alert arrived on June 10. The exploitation therefore preceded public vendor disclosure and qualifies as zero-day use in this campaign. That chronology does not reveal when the vulnerability was first discovered by the actor, how long reconnaissance preceded the staging setup, or whether every observed request used an identical payload. It does establish that ordinary patch-lag explanations cannot account for the earliest compromises.
Public reporting about the open directories appeared on June 9 and enabled GTIG to triage the five hosts in detail. The same date also appears in the campaign record as the day stolen organization data was placed on the ShinyHunters data-leak site. Temporal proximity strengthens the operational connection, especially when combined with the staging history's final SSH destination. It still leaves room for clock offset, preparation before publication, and activity on infrastructure that was never exposed.
By the time the directories were noticed, the operation had already crossed several systems: Internet-facing PeopleSoft, the web tier, a remote-management server, managed agents, internal SSH targets, an archive staging area, and leak-site infrastructure. The rest of the story follows those handoffs in order. It begins with the maintenance component Oracle named, then moves through the files and legitimate administration features that converted a single exposed service into a wider extortion operation.
2 A maintenance service became the first room in the incident
PeopleSoft's Environment Management framework exists to help administrators discover and manage the systems that support an application estate. That role explains why the affected component can see consequential parts of the environment. It also explains why the service should not be treated like an ordinary employee-facing page. A maintenance path that reaches configuration, metadata, and application infrastructure carries a different exposure cost from the browser screens used for day-to-day transactions.
In the observed campaign, activity aligned with the Environment Management Hub application and with the PeopleSoft Integration Gateway HTTP listening connector. Mandiant tells defenders to look for external POST requests to /PSEMHUB/hub and /PSIGW/HttpListeningConnector. Those paths are valuable pivots, but the evidence begins one layer earlier: which public listener, proxy rule, virtual host, load balancer, or partner route allowed an untrusted request to reach them.
The first security decision is therefore architectural. A product version can be vulnerable while a specific instance is unreachable through the path required by the campaign. A reachable instance can remain dangerous even when a dashboard inventory incorrectly marks it “internal.” Patch state, deployment mode, application state, and every network route to the administrative paths have to be joined. None of those fields alone provides a complete exposure answer.
2.1 Oracle confirmed takeover conditions; the campaign supplied the path and time
Oracle's June 10 alert names CVE-2026-35273 in PeopleSoft Enterprise PeopleTools, component “Updates Environment Management.” Supported PeopleTools versions 8.61 and 8.62 are listed as affected. The risk matrix says the flaw is reachable over HTTP, requires no authentication or user interaction, has low attack complexity, and can produce complete confidentiality, integrity, and availability impact. Oracle's text form summarizes the result as takeover of PeopleSoft Enterprise PeopleTools.
The CVSS 3.1 vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, yielding a base score of 9.8. The score describes generic exploitation conditions for the affected product. It does not tell an owner whether PSEMHUB is enabled, whether a reverse proxy exposes it, whether the official fix is installed on every node, or whether exploitation already occurred. Those questions require deployment and incident evidence.
Oracle also warns that unsupported earlier releases were not tested for the vulnerability and are likely affected. That wording matters. It prevents a team from treating “not listed in the supported-version table” as “confirmed safe.” An older PeopleTools train needs an upgrade path to a supported release where vendor mitigations and fixes are available. Until then, exposure reduction and historical hunting have to assume risk without claiming Oracle tested a version it did not test.
The machine-readable CSAF record marks PeopleTools 8.61 and 8.62 as known affected products, assigns Oracle bug ID 39522949, repeats the takeover description and CVSS vector, and directs customers with valid support contracts to the vendor fix. It was published with final status on June 10. That status describes the advisory, not remediation on any local server.
Six days later, Oracle's June Critical Security Patch Update stated that its PeopleSoft PeopleTools and Enterprise Applications update included patches for this alert along with additional fixes. That sequence creates two vendor milestones: the out-of-band warning on June 10 and the broader June update on June 16. Change records should preserve which package was installed, on which node, at what time, and with what post-install verification. If an installation is retried after failure, retain each result instead of replacing the failed record with the final success. Recording only “June patches applied” is too vague for incident reconstruction.
Mandiant observed activity from May 27 through June 9 that was consistent with exploiting this vulnerability against PSEMHUB endpoints. That incident report supplies the pre-disclosure time and operational context that the vendor matrix does not attempt to provide. It does not publish a complete exploit payload or the proprietary PeopleSoft code change. Reproduction claims should therefore stop at what the public evidence establishes: unauthenticated RCE, endpoint alignment, observed post-exploitation, and Oracle's fix.
The second path, /PSIGW/HttpListeningConnector, deserves its own request review. Mandiant advises looking for loopback values such as 127.0.0.1, localhost, or ::1, as well as internal address ranges in request headers or parameters, because server-side request behavior can be used to reach services that external clients cannot contact directly. Preserve the full request under policy, trusted-proxy interpretation, response, and correlation ID; a normalized URI alone may omit the decisive target. Keep duplicate parameters, case differences, percent encoding, IPv6 forms, and proxy-added headers in an untouched copy, then create a normalized copy for search. The analyst must also separate the value supplied by the client from one rewritten by the gateway, or a proxy transformation can be mistaken for the source of the target address.
2.2 A reachable endpoint is a configuration fact, not a version label
Reachability often hides behind architecture. An edge scan may see a general PeopleSoft login while a path-based proxy silently forwards PSEMHUB. A “private” application can still be reached through a VPN pool, partner tunnel, cloud ingress, alternate hostname, or misrouted load balancer. Exposure validation should enumerate listeners and routing rules, then test the exact administrative paths from an approved external vantage. Asset inventory and DNS records are inputs, not proof.
Deployment mode changes the immediate mitigation. Mandiant relays Oracle's guidance to disable the Environment Management Hub service in multi-server configurations or remove the PSEMHUB application in single-server configurations. The distinction prevents an owner from applying a service-stop procedure to a topology where the application is packaged differently. Before acting, the PeopleSoft team should identify the PIA domain, managed servers, startup scripts, deployed applications, dependencies, and rollback plan.
If the service cannot be disabled immediately, the public guidance calls for blocking external access to /PSEMHUB/* and /PSIGW/HttpListeningConnector. Mandiant characterizes that restriction as non-breaking for standard end-user PIA sessions because the paths support administrative or system-to-system functions. Local integrations still need testing. A connector that is legitimately used should be limited to named source systems and authenticated routes, not left reachable from the Internet.
Request-body inspection by a web application firewall is not a durable substitute for path isolation. Mandiant warns that body-focused rules can be bypassed. A route-level deny, listener removal, service shutdown, or tightly scoped source allowlist reduces the number of requests that reach the vulnerable code at all. WAF logs remain useful evidence, especially when they capture rejected and allowed bodies, but their alert state should not be mistaken for removal of the exposed service. The change record should preserve rule ID, configuration revision, active nodes, action, matched sample, and whether the upstream still received the request; a rule with one name may be monitoring, blocking, or disabled on different devices. Because bodies can hold credentials and personal data, collection also needs access controls and a retention period so sensitive payloads do not spread through ordinary tickets.
Oracle's risk-matrix convention says an affected protocol entry for HTTP also includes its secure variants. HTTPS protects the request from passive observation in transit; it does not change whether the endpoint authenticates the caller or safely processes the content after TLS termination. Inventory queries that search only for plain HTTP listeners will therefore miss relevant HTTPS deployments. Reverse-proxy termination also means the application log and edge log may see different source and scheme values.
Removing the route answers only whether a new unauthenticated request can arrive. It does not answer what happened before the change. The web-tier filesystem, transaction metadata, process history, outbound connections, remote-management agents, and internal authentication attempts need preservation first whenever compromise is plausible. The next chapter moves from the exposed endpoint to those host effects, because a quiet perimeter after mitigation can coexist with a persistent process or file already inside.
3 The web tier could preserve the intrusion after the first request ended
An exploit request can occupy a fraction of a second and still leave a durable change behind. On a PeopleSoft web tier, that change may be a JSP placed inside a deployed application, a binary or script in a transaction directory, an unexpected subdirectory used for staging, or environment XML that a trusted Java process reads later. Each artifact extends the investigation beyond the edge log and can survive after the vulnerable route has been blocked.
Mandiant's guidance names concrete places to look: the deployed PSEMHUB.war tree, envmetadata/transactions, unexpected logs, persistantstorage, or scratchpad directories, and recently created or modified XML under envmetadata/data/environment. It also tells defenders to watch outbound SMB on TCP 445. These observations are more useful as separate host questions than as one generic “webshell hunt.”
The XML guidance is especially easy to misread. Public reporting describes a persistence opportunity in which crafted environment metadata can be processed through XMLDecoder when the application restarts. That is downstream of initial access. Oracle's public alert does not say that XMLDecoder is the root cause of CVE-2026-35273, and the fixed open-source record does not contain the proprietary PeopleSoft caller. The Java path therefore explains a downstream capability without substituting for the undisclosed vendor flaw.
3.1 A JSP, a transaction folder, and an outbound SMB attempt tell different stories
The web-application review starts at <PS_CFG_HOME>/webserv/<domain>/applications/peoplesoft/PSEMHUB.war/. A path alone cannot classify a JSP because vendors and customers can deploy legitimate pages. Build an approved baseline from the shipped application, applied patches, sanctioned customizations, and deployment records. Then identify files whose content, hash, owner, size, or timestamps diverge, including copies in staging directories that may later be expanded into the live tree.
For each unexpected JSP, preserve more than the file. Record creation and modification metadata, filesystem owner and permissions, alternate data streams where applicable, signer information for adjacent components, and SHA-256. Search WebLogic access and application logs for the first request to that path, then join the serving thread or process to child processes and outbound connections. A file that was written but never invoked represents a different exposure state from a page that launched commands. Review compiled caches, class loading, and deployment logs as well, because a generated class or a live application context can survive removal of the source JSP. If privacy policy prevents storage of request parameters, retain a controlled hash, length, and correlation identifier so the invocation can still be matched to endpoint effects.
Clustered deployments complicate the comparison. A load balancer may send the exploit request to one managed server while a shared deployment, synchronization step, or administrator action distributes the resulting file. Conversely, one node may retain a JSP that peers never received. Inventory every node, mounted share, deployment staging area, and backup used by the PIA domain. “The cluster is clean” needs per-node evidence, not a sample from the instance that answered the health check.
The envmetadata/transactions tree can retain inputs, intermediate objects, archives, scripts, or output tied to Environment Management work. Mandiant advises inspecting it for unauthorized directories, files, and binary drops. Before cleanup, capture the directory recursively with original paths, timestamps, permissions, extended attributes, hashes, and a volume or filesystem image when feasible. Opening or moving a file with ordinary administration tools can update metadata that would otherwise order the event. Time interpretation also needs filesystem and mount semantics: copying, extraction, snapshot restoration, or a cross-volume move can rewrite selected times. Directory entries, journals, application logs, and parent processes support ordering together; one mtime is one observation. When a time looks unusual, investigate the operation that produced it before labeling timestamp manipulation.
Outbound SMB tells another story. The exploit chain may coerce a PeopleSoft host to contact an external SMB listener and expose a Windows machine-account NetNTLM challenge response. A firewall record for TCP 445 proves a connection attempt or flow according to the sensor. It does not by itself prove that a challenge was captured, cracked, relayed, or used. Authentication logs, packet evidence, destination records, and follow-on account activity determine the next rung. Machine-account authentication times on domain controllers and target servers can test whether new use followed a challenge response. If the sensor saw only a SYN or a blocked session, the conclusion stops at an attempt. The incident record should say whether the sensor observed connection, handshake, authentication, or a successful session so each retelling preserves the same state.
3.2 XMLDecoder turns an object description into executable calls
Mandiant advises checking <docroot>/envmetadata/data/environment/ for recently created or modified XML that could execute through XMLDecoder after an application restart. The phrase “after restart” supplies a practical correlation point: a suspicious write may lie dormant until a trusted service initializes, reads the metadata, and produces a new process or file effect. Restart and deployment events therefore belong beside file creation, not in a separate availability log.
The Java API describes XMLDecoder as a complementary class to XMLEncoder that reads an XML archive used to create Java objects. That is broader than passive key-value parsing. At the pinned OpenJDK revision, readObject() calls parsingComplete(); if parsing has not finished, the decoder sends its input to DocumentHandler.parse(). The document's element vocabulary then determines what object operations are assembled.
DocumentHandler.startElement() receives each SAX element, resolves an ElementHandler for the tag name, creates that handler, supplies attributes, and begins the element. Tags supported by the decoder include constructs for values, objects, methods, properties, arrays, and new instances. This step is the transition from raw XML syntax to a typed operation graph. The effect still depends on which elements, classes, owners, and arguments the input can reach.
NewElementHandler shows how construction becomes concrete. Its class attribute is resolved through the document owner, argument values are gathered, and ConstructorFinder.findConstructor() selects a compatible constructor. The handler then calls newInstance(). In a benign archive, this recreates an intended Java object. With an untrusted expressive archive, the same machinery can instantiate types the application author never meant an external writer to choose.
Object and void handlers can assemble a java.beans.Expression or statement that names a target, method, and arguments. Evaluation eventually reaches Statement.invoke(). The fixed source selects a method or constructor from runtime types and calls MethodUtil.invoke() or Constructor.newInstance(). That is why a decoder input can carry behavior: XML elements are not merely copied into fields; they can describe calls executed inside the trusted Java process.
This open-source call path establishes a generic capability, not the complete PeopleSoft persistence path. The public record does not expose the exact product class that locates environment XML, the code that chooses the decoder, the service identity in every topology, or the incident's crafted XML. A local case can fill some of those gaps through stack traces, process monitoring, class-load evidence, file access, and restart correlation. It should label the remainder as unavailable instead of fabricating a proprietary call chain.
Analysis should occur on a preserved copy in an isolated environment. Do not feed an unknown archive to a production PeopleSoft service or a general XMLDecoder merely to “see what happens.” Static structure, hashes, class and method names, and controlled instrumentation can establish risk without replaying the actor's operation. The vendor fix and deployment mitigation remain primary; ad hoc element filtering or deletion of one XML file cannot account for another write path, a JSP, or an already installed remote agent.
4 MeshCentral turned one compromised server into a management plane
A web-tier shell is useful for entry, but it can be noisy and dependent on the vulnerable application remaining available. The staging evidence shows the actor preparing something more durable: a complete MeshCentral server and agents that could turn compromised systems into managed nodes. Once an agent trusted the actor's manager, routine remote-administration features supplied command execution, output collection, file handling, and a stable control channel without requiring every action to pass through PSEMHUB again.
MeshCentral is an open-source remote monitoring and management platform used legitimately to administer endpoints. Its presence is not an indicator by itself. In this campaign, classification comes from the combination of actor-controlled infrastructure, Azure-themed disguises, an embedded manager at azurenetfiles.net, installation on compromised systems, and command history tied to PeopleSoft reconnaissance and lateral activity. The same product under an approved manager and administrator is a different event.
The pinned source matters because “remote command” can otherwise become an imprecise phrase. Release 1.1.59 shows how the command-line client serialized a task, how the server checked node rights and connection state, how an authenticated agent received it, how the agent launched the platform shell, and how output could return. Those stages create several independent places to detect and preserve the same operator action.
4.1 Version 1.1.59 shows exactly how RunCommand reached a shell
In meshctrl.js, the runcommand case begins at line 1753 of the fixed revision. It derives runAsUser and reply options, then sends a JSON object with action runcommands, the selected node ID, command type, command text, response ID, and those options. The CLI does not execute the command on its own machine. It asks the MeshCentral server to route an authenticated management request. Preserve the full JSON, login session, server receipt time, and CLI origin when reviewing logs; command text alone is incomplete. The response ID pairs requests with replies, but it may not remain globally unique across every restart and tenant. User, domain, node, and a narrow time window still belong in the correlation.
The server enters case 'runcommands' in meshuser.js. It validates the node array, command type, and domain form, then calls GetNodeWithRights() for each target. This means the task is tied to a MeshCentral user and a known node record before agent delivery. Server logs and events can therefore carry a management identity even when the operating-system child process runs under the agent's service account.
For standard shell, PowerShell, or Bash commands, the server checks the MESHRIGHT_REMOTECOMMAND permission bit. It also maps the requested command type to the target platform: Windows agents accept command shell or PowerShell, while non-Windows agents use the Unix-like shell type. These checks are legitimate safety controls. They become part of the attack path because the actor controls an authorized administrator account on its own management server.
After validation, the server builds an agent message containing action: runcommands, type, commands, run-as choice, reply choice, and response identifier. It sends only when the target agent is connected, has agent information, and has authenticated == 2. The server then dispatches a runcommands event containing user, node, command, command type, and run-as fields. If retained, that event is a near-direct record of operator intent. Its presence shows that the server accepted and routed a task. A missing reply has several explanations: no reply was requested, the agent disconnected, endpoint execution failed, or reply history expired. Server event, agent session, and endpoint process together distinguish a task that was sent from one that ran.
Agent authentication is not decorative. In meshagent.js, processAgentSignature() verifies a signature bound to certificate and nonce material before the connection reaches its authenticated state. In normal administration, that prevents an arbitrary endpoint from impersonating a managed node. In this incident, a preconfigured agent and actor-owned manager establish a valid trust relationship for malicious purposes. Cryptographic success shows who the software trusted; it does not decide whether the manager was authorized by the organization.
The agent's agents/meshcore.js receives runcommands around line 1714. It refuses a second task while a command child is already active and interprets runAsUser as agent, user-or-agent, or user-only behavior. Those details affect telemetry. A command may run under the service identity or the interactive console user, and a failed user-only request may produce no child process. Server task events should be compared with both success and absence on the endpoint. Preserve parent process, access token, logon session, full arguments, and standard-input origin. PowerShell receives its command through standard input in this path, so the visible process command line may omit the operation. No observed child means only that the current sensor did not capture execution; it cannot erase the server task.
On Windows, command type one launches cmd.exe; type two launches powershell.exe with no profile and reads commands from standard input. On non-Windows systems, type three launches /bin/sh. The agent collects standard output and error, writes the requested text followed by an exit command, and can send the result back when reply is enabled. This exact path connects a management event to a platform shell and, potentially, to returned reconnaissance output.
5 The first commands were questions about how PeopleSoft was assembled
Once the agents were available, the command history did not begin with dramatic destructive actions. It began with questions: what host is this, which identity is running, where are the PeopleSoft mounts, which machines appear in the process-scheduler configuration, and what does WebLogic know about the rest of the domain? The answers converted one compromised endpoint into a map of systems that shared names, storage, credentials, and operational roles.
The commands were ordinary Unix tools. Their value came from the files and naming conventions they targeted. A general process list says little about an enterprise application. An address extracted from psappsrv.cfg, an NFS mount containing ps_config, or a WebLogic server entry can identify the next application node and the relationship it serves. Detection needs that context because blocking every grep, mount, or cat would be unusable.
The open history redacted victim-specific strings and credentials in the public report, which is appropriate. It still preserves enough structure to build defensive analytics: command family, source process, parent MeshAgent, target file, directory pattern, output path, and the later network destination. A local response can use its own unredacted logs to connect each read to subsequent SSH attempts without publishing account material.
5.1 Configuration files became a map of hosts, mounts, and application roles
The actor used simple identity checks such as hostname and id through meshctrl.js. Those commands establish the current machine name, user and group context, and whether the agent has the privileges expected for follow-on work. In endpoint telemetry, they are most useful when their parent is the unapproved MeshAgent and their execution follows a new agent connection. The same commands under an administrator's approved automation remain common.
Process-scheduler topology came from psappsrv.cfg. The history searched for Address= and HostName= entries under a PeopleSoft configuration home and limited the returned lines. This is targeted discovery: the actor did not have to scan every address blindly because the application already maintained a directory of its own peers. Preserve file-open events and any returned command output, then compare discovered addresses with the next connections from the same host. The line limit means the public history may omit nodes present in the file. Local review should examine the complete configuration and its incident-time version, marking which names actually appeared in returned output. When MeshCentral reply was enabled, that output may survive only in manager events and never enter endpoint shell history.
The mount review filtered for names including psoft, ps_config, and nfs. Mount output can reveal shared configuration homes, application binaries, batch areas, and data-transfer paths, along with the remote server that supplies them. A writable shared mount can also amplify impact across nodes. Responders should record mount source, options, owning process, recent writes, and server-side access logs before unmounting or rebuilding the client. For every shared path, identify the server export, client caching behavior, and snapshot policy because a file may be recoverable from any of them. When logs show several nodes reading one object, assess each reader separately; one shared write should not be mechanically counted as several drops.
The local /etc/hosts file supplied another list. The actor searched for a victim-specific naming pattern and later used matching hosts in the fanout script. Static host files are often overlooked because DNS telemetry receives more attention, but they may encode internal application aliases unavailable to an external resolver. File history, configuration-management records, and endpoint reads can show exactly which names were visible at the time of compromise.
WebLogic config.xml provided a complementary view of the application domain. It can identify managed servers, listen addresses, clusters, deployments, data sources, and other relationships depending on the environment. The public report says the actor inspected these files to map application servers; it does not publish every value recovered. A case team should treat the file as sensitive configuration and compare access by the MeshAgent child shell with normal administrative tooling.
Together, these sources form a graph. psappsrv.cfg contributes scheduler hosts, mount output contributes storage relationships, /etc/hosts contributes local aliases, and WebLogic configuration contributes application roles. The graph can be replayed against connection logs: if a host first appears in a configuration read and receives an SSH attempt minutes later, the link is stronger than two events that merely occur on the same day.
5.2 The fanout script converted that map into repeated SSH attempts
The operation moved from mapping to repeated access when the history created [victim_abbreviation]_fanout.sh under /tmp. GTIG published a redacted copy because the script itself explains the lateral pattern. It selected hosts, tried a fixed set of credentials, copied a marker to PeopleSoft locations, counted results, and searched for the copied file. The code was tailored to one environment through its host pattern and base path.
Targets came from /etc/hosts: the script filtered a redacted victim pattern or names matching csprd[0-9], removed comments, sorted unique values, and then iterated a hard-coded list of common administrative and application credentials. The public report redacts the credential values, but local authentication logs still reveal username, source, order, and result. Even without a successful login, the hosts-file read, generated script, shell history, and clustered SSH attempts leave a coherent trace.
The password path used sshpass, disabled strict host-key checking, and imposed a six-second connection timeout. If password attempts failed, the script tried key-based SSH using the current user. Those choices produce distinguishable artifacts: an sshpass process, rapid SSH connections, new known-host behavior suppressed by options, authentication failures followed by a success, and possible use of an existing private key. EDR and server authentication logs should be correlated from both ends. The source process exit code describes only the client's view; target-side sshd establishes username, method, successful session, and later commands. A six-second timeout also creates ambiguous failures: network delay, interrupted handshake, and password rejection can look alike in the script summary, so triage must return to native logs.
After a successful login, the script checked two web-service directories and the process-scheduler application directory, streamed README-IF-YOU-SEE-THIS-YOUVE-BEEN-HACKED.TXT into the target, and set local copies to 0644. It tracked success, failure, and skip-style states before finding all markers, with output potentially returning through MeshCentral. Endpoint and SSH logs still determine actual success, and a shared filesystem can make one write appear on several nodes, so marker count cannot be converted directly into successful sessions.
Incident scope should distinguish an attempted login from an authenticated session and a session from a completed write. Failed attempts require password and exposure review; successful authentication brings the account and target into the incident; a marker write establishes filesystem control at that path. Absence of the marker does not clear a host because the credential may have worked before a later command failed, the file may have been removed, or a different action may have followed. A useful scope table assigns one row to source host, target host, account, authentication method, session, and write path, with separate states for attempt, success, and observed effect. Ten failures under one account then cannot hide a success on the eleventh host, and files created by one shared mount write do not inflate the login count.
The fanout script did not reveal where the credential list originally came from. Some values may have been guessed, reused from common defaults, recovered earlier, or drawn from configuration. Response should avoid choosing one story without evidence. Rotate credentials that were attempted successfully or exposed to the compromised context, revoke and replace relevant SSH keys, inspect trust files and authorized keys, and review the same account across all discovered nodes. The map that enabled movement is also the map needed to contain it.
6 The marker announced control; the archive raised the harder question
The fanout script made control visible by copying an unmistakable text file into application directories. That is the theatrical part of an extortion operation, easy to screenshot and easy to count. The more consequential evidence sits nearby in the history: an exfil directory, a measured Zstandard compression pipeline, and an outbound SSH connection to an address hosting the public mirror of the ShinyHunters leak site.
Those records support data theft and extortion in the campaign, especially when combined with organization data published on June 9. They still do not answer every local impact question. A command line can identify an input directory and output archive without listing each file. A network session can show destination and bytes without revealing plaintext. A leak-site post can show a sample without proving that every object in a local archive was published. A local impact table should separate each dataset and record source system, owner, time period, record type, reachable permissions, observed reads, staged copies, archive membership, transfer evidence, and published sample. When one column lacks evidence, leave the gap with its sensor explanation; proof from another dataset cannot be copied across.
The response therefore has to climb through evidence states: selected, read, copied into staging, archived, transferred, received by external infrastructure, and published. Each state has a different source and consequence. The actor's marker confirms unauthorized write access; the archive and egress records support data-loss assessment; the leak publication changes notification and legal analysis. Combining them into one word—“exfiltrated”—would discard the distinctions needed by affected people.
6.1 Zstandard, SSH, and the leak-site mirror form an evidence sequence
The exposed history used du -sb to calculate the size of an exfil directory, passed that size to pv for progress measurement, and piped content through zstd with level three and multithreading into exfil.tar.zst. The command shows deliberate preparation of a named collection area and an output archive. It also supplies process names, arguments, working directory candidates, and an expected relationship between input size and output activity.
The command as published does not enumerate the contents of exfil. Local evidence should. Preserve the directory tree, archive, shell history, command output, file-access telemetry, and deletion records. If the archive remains, inspect a forensic copy with tools that list metadata without extracting into an unsafe location, and hash both container and members. If it was deleted, filesystem journals, snapshots, backups, EDR file events, and source-file read sequences may still reconstruct the selection. The first inspection should only list member names, sizes, times, permissions, and link targets. Resolve absolute paths, parent-directory traversal, device entries, and extreme expansion risk before extraction. Every derived manifest should name its tool, arguments, and parent archive hash so later reviewers do not mistake analysis output for original material.
The history ended with an outbound SSH connection from staging infrastructure to 176.120.22.24, which GTIG identifies as hosting the clearnet mirror of the ShinyHunters data-leak site. This is a strong operational link. Preserve source host, user, destination, key or password method, session start and end, bytes, commands where recorded, and server-side provider logs. The public record does not expose a packet capture proving which archive crossed that session. SSH can carry an interactive shell, a command, SCP, SFTP, or port forwarding; a connection record cannot select the channel. If server or network evidence exposes subsystem, channel type, direction, and byte counts, place those values beside archive creation time to narrow the transfer assessment.
On June 9, stolen organization data appeared on the ShinyHunters leak site. Publication proves that the actor possessed at least the material displayed or offered there. It does not establish completeness, freshness, or source for every listed file without comparison to local records. A responsible impact review matches names, hashes, record counts, timestamps, schemas, and samples under controlled handling, while avoiding unnecessary redistribution of stolen data. Collect only the minimum material needed for the finding, recording access approval, time, source, tool, and storage location. If a screenshot is sufficient, there is no reason to copy the entire dataset. The data owner must validate field meaning and authoritative records; filenames and actor-supplied numbers cannot decide impact for affected people.
6.2 ShinyHunters attribution is an assessment, while host effects stand on their own
UNC6240 is Mandiant's activity-cluster designation, and the report maps it to ShinyHunters. That naming links the PeopleSoft activity to an extortion actor tracked through other evidence available to the intelligence team. It does not turn every use of MeshCentral, every PSEMHUB probe, or every file named “README” into ShinyHunters activity. Local classification starts with the full observed combination.
The strongest public actor links in this event are operational. The staging history points to the IP hosting the public ShinyHunters leak-site mirror. Stolen organization data appeared on that site during the activity window. The fanout script placed an extortion marker, and the infrastructure carried customized agents tied to the PeopleSoft campaign. These lines reinforce one another without requiring a logo, chat transcript, or self-claimed identity to carry the conclusion alone.
The extortion model shapes response priorities. An actor seeking data and publication may move quickly from entry to collection, then use a loud marker after access is already established. Availability restoration alone will not settle impact. Teams need to preserve archive and egress evidence, protect affected accounts, determine what data was accessible, coordinate with recipients of stolen information, and monitor for later publication or direct pressure.
Attribution can change as infrastructure is reexamined, another actor claims the operation, or private evidence becomes public. Host facts should remain stable beneath that change: a specific request reached an exposed path; a file appeared; an agent connected; a command ran; an SSH login succeeded; an archive was created; data was posted. Keeping those statements independent lets intelligence updates improve the case without forcing responders to reopen basic containment decisions.
7 The case only joins cleanly when every clock keeps its source
The public reconstruction is persuasive because several records point in the same direction, but they do not share one clock. Oracle has advisory and patch release times. The open shell history carries some command timestamps and omits others. PeopleSoft access logs, WebLogic events, filesystem metadata, MeshCentral tasks, SSH authentication, archive creation, network flows, and leak publication each record time differently. A clean-looking timeline can become less accurate as analysts force them into one sequence. Preserve original time, timezone, and record format, then add a searchable normalized UTC value. A measured offset needs its method and validity period. When offset cannot be measured, record it as unknown; do not move an event to improve the diagram or overwrite the source clock.
Build the case as linked records before drawing the narrative line. Every record needs its source, original timestamp and timezone, measured clock offset, host or service identifier, actor identity where known, artifact hash, and collection method. The case key should be immutable, while relationships can be marked exact, strongly correlated, plausible, or unresolved. That structure lets the story improve without silently changing the original evidence.
The goal is not to eliminate uncertainty. It is to place uncertainty where the sensors actually stop. A proxy request ID can prove that an edge handled a request; a WebLogic thread can show application processing; a file event can show a write; a MeshCentral task can show a command; an endpoint process can show execution. When one identifier does not cross all systems, several narrower joins can still carry the event with an honest confidence level.
Data impact begins with capability but cannot end there. A compromised PeopleSoft service identity may have permission to read broad application data; that establishes potential exposure. File-open, database audit, batch-output access, or command results can show actual reads. The scope should start with permissions and narrow through observed access, never assume that everything reachable was collected or that unlogged access was impossible.
Configuration reads deserve their own category. psappsrv.cfg, WebLogic XML, host files, mounts, keys, and service settings may contain little regulated personal data yet materially enable lateral movement. Their exposure affects recovery because host names, accounts, integration endpoints, and trust paths can remain useful after the initial server is rebuilt. Treating them as “just configuration” can leave the new environment discoverable with old knowledge.
A preserved exfil directory is stronger evidence of selection than a broad permission set. The member tree can show which business areas and dates were gathered. File-access telemetry can distinguish a bulk copy from files that merely existed in the directory before the incident. Ownership, mtime, ctime, source path, and command context should be reviewed together, especially when the actor staged data under an existing administrator workspace.
An archive proves packaging when its contents and creation are verified. It does not prove a completed transfer. Egress flows, SSH server logs, destination provider records, and external possession move the assessment forward. If sensors record only a session with unknown bytes, say so. If bytes closely match the archive but content is encrypted, state the correlation and its limits. Precision builds credibility during notification.
Leak-site publication is strong for the material displayed or downloadable there. Compare it to local schemas and records under controlled conditions, documenting hashes and sample selection. Actor-stated record counts can be inflated, incomplete, or drawn from multiple systems. Local owners should reconcile affected rows and people using authoritative sources, while investigators preserve evidence of what the actor actually offered.
The final case ledger should carry unresolved items with an owner and consequence: missing proxy bodies, expired WebLogic logs, an offline node, deleted archive, unknown MeshCentral reply, unavailable provider records, uncertain credential source, or incomplete leak sample. “Unknown” is not a failure when the sensor never existed. It becomes useful when the record explains what decision remains affected and what evidence, if recovered, could change it. Add a review date, escalation condition, and closure reason to every item, with reminders before evidence retention expires. When all sources are exhausted, the investigative action may close while the underlying question remains indeterminate, keeping the gap visible to notification and risk decisions.
8 Recovery starts by removing the entrance and proving the route is gone
Recovery has four connected goals: stop new requests from reaching the vulnerable maintenance paths, remove every foothold created after entry, invalidate the credentials and trust relationships that enabled movement, and settle data impact with evidence. Completing only the patch leaves remote agents and stolen secrets in play. Deleting only the agent leaves the entry available. Restoring service before preserving artifacts can erase the record needed for notification.
The order is shaped by evidence volatility. Proxy buffers, process memory, agent sessions, open sockets, shell history, temporary archives, and provider logs can disappear quickly. Filesystem snapshots, configuration exports, and application logs come next. Containment then closes the exposed route and untrusted egress while preserving responder access. Official patching, cleanup, credential work, rebuild, and validation follow under named owners.
This is a PeopleSoft application incident, a remote-management incident, an identity incident, and potentially a data incident at the same time. The application team understands PIA topology and maintenance services; endpoint and Unix teams understand processes and SSH; network teams hold ingress and egress; identity teams own account recovery; legal and privacy teams own notification; vendors and providers may hold missing server evidence. A shared case record prevents one workstream from declaring victory while another still has an open route; the incident owner should also maintain a cross-team dependency table that names each containment prerequisite, evidence owner, and retest time.
8.1 Preserve first, close exposure next, then rebuild trust
- Preserve volatile evidence first: export edge, PIA, WebLogic, authentication, EDR, DNS, firewall, and flow records; snapshot the web tier,
PS_CFG_HOME, PSEMHUB, transaction and environment metadata, temporary directories, service configuration, and mounted storage; where safe and lawful, capture process and memory state before stopping Java or MeshAgent. - Isolate and restrict egress: remove affected hosts from untrusted networks while retaining controlled forensic access; block the exact staging addresses,
azurenetfiles.net, and/agent.ashx; restrict outbound SMB from PeopleSoft nodes and review unexpected SSH. - Close the entry by topology and install the fix: disable EMHub on multi-server deployments or remove PSEMHUB on single-server deployments, block both published administrative paths, then verify PeopleTools release, patch inventory, loaded version, startup state, listener, route, and external result on every node. Unsupported releases require an upgrade plan.
- Remove footholds after preservation: clear unexpected JSPs, transaction objects, environment XML, scripts, archives, markers, startup entries, and the entire unapproved MeshAgent footprint, including services, configuration, node trust, and installers. Separate legitimate MeshCentral deployments by manager identity.
- Rebuild identity trust: reset accounts that authenticated successfully or were exposed to the compromised context, replace affected SSH keys, inspect
authorized_keys, and rotate PeopleSoft, WebLogic, sessions, and tokens when access evidence supports it. Investigate machine-account NetNTLM exposure before changing computer trust. - Coordinate infrastructure and data response: ask providers to preserve the five staging hosts, manager domain, certificates, DNS, hosting accounts, and leak-site-associated IP using precise UTC windows and hashes before takedown; in parallel, identify the datasets, owners, and evidence states represented by archives and leak samples.
8.2 A closed incident should survive restart, a full work cycle, and per-node acceptance
A restart is part of validation because the reported XMLDecoder persistence path may wait for application initialization. Before restart, baseline relevant XML and startup configuration. During restart, record the Java process, files read, loaded modules, child processes, network connections, and new filesystem objects. Afterward, compare hashes and directory trees. A successful health check is necessary but cannot substitute for observing that no unauthorized behavior returned. Restart a cluster node by node in an approved order and record when each node actually begins serving traffic, so an idle spare is not the only observed system. If an anomaly appears, preserve the new effect and triggering input before isolation or rollback; repeated restarts can erase the evidence that just emerged.
Continue through a full operational cycle. PeopleSoft schedulers, integrations, maintenance jobs, backups, and batch processes may activate hours later under identities not used during the initial restart. Watch for renewed MeshAgent sessions, new JSP or XML writes, outbound SMB, unexpected SSH, archive creation, and connections to related infrastructure. The observation window should include the organization's real schedule, not an arbitrary hour after service restoration.
Repeat external exposure tests from an approved source against every address, hostname, proxy route, and protocol variant. The administrative paths should produce the intended deny or absence, while approved PIA functions and explicitly authorized system integrations remain healthy. Save request and response evidence. A dashboard showing “service stopped” is weaker than an outside test that confirms no alternate listener still forwards the path. Before testing, record resolver, DNS answer, proxy egress, and TLS certificate so caching or traffic distribution cannot silently send the request to an old node. Afterward, confirm on the server that the same request ID reached the intended listener. Preserve both denied cases and a successful authorized integration sample to show that remediation retained business function.
Complete the data assessment in parallel with technical recovery. Inventory preserved staging directories and archives, compare read events and transfer bytes, reconcile any leak sample, and identify affected record owners. Document what was reachable, what was accessed, what was packaged, what likely left, and what was published. Notifications should reflect the strongest supported state for each data set and acknowledge gaps that missing telemetry cannot resolve.
Define acceptance per node and per trust relationship. The official fix is installed or the component is removed; untrusted routes are closed; unauthorized files and agents are absent; startup state is approved; compromised accounts and keys are replaced; lateral targets are reviewed; provider preservation is complete; data decisions have owners; and monitoring survives restart. Each item needs query evidence, time, coverage, and sign-off, including exceptions for offline or retired systems. Have someone who did not make the original change sample the results, confirm queries can be rerun, verify evidence still opens, and ensure failed cases survived summarization. Set the closure date before critical logs expire, leaving time for that independent review.
The operation succeeded by moving through ordinary administrative relationships: a maintenance endpoint, a trusted Java process, a remote-management agent, application configuration, SSH, and compression. Recovery uses the same relationships in reverse. Close the maintenance door, prove the trusted reader has clean input, sever the unauthorized manager, invalidate the map's credentials, account for the archive, and make every conclusion reproducible. Only then do the five open staging servers become an ending, not merely the place the story was first seen.
Research record
9Evidence, objects, and sources
The material below preserves the identifiers and references used in this report.
9.1Searchable observables
Values copied from the cited material or recovered during this investigation, with the context needed to use them.
| Type | Value | Context | Action |
|---|---|---|---|
| Domain | azurenetfiles.net | Actor-controlled MeshCentral management domain masquerading as Azure-related infrastructure. | |
| SHA-256 | f02a924c9ff92a8780ce812511341182c6b509d45bc59f3f7b522e37225d24fc | Configured 64-bit Windows MeshCentral agent. | |
| SHA-256 | d83fdb9e53c5ff03c4cb0451ea1bebd79b53f29eadc1e2fa394c7af13a86ce2f | Second configured 64-bit Windows MeshCentral agent. | |
| SHA-256 | c7e9332731b06644fc73e0046a2a89eaa59b09f54250e9bd622467187351711f | Configured 32-bit Windows MeshCentral agent. | |
| Filename | README-IF-YOU-SEE-THIS-YOUVE-BEEN-HACKED.TXT | Defacement and extortion marker reported in the fanout activity. |
9.2Research objects
Products, actors, techniques, affected objects, and control points discussed in the report.
Oracle PeopleSoft PeopleTools Updates Environment Management unauthenticated remote code execution.
Embedded manager address in configured Windows agents.
Five sequential staging hosts exposed through Python SimpleHTTP on port 8888.
9.3Event chronology
- Management infrastructure installed
Command history recorded MeshCentral 1.1.59 at 22:14 UTC and acme-client at 22:25 UTC.
- Zero-day activity observed
Mandiant and GTIG connected PeopleSoft Environment Management exploitation to UNC6240 activity.
- Open staging directories surfaced
Five adjacent hosts exposed agents, histories, and operational material; stolen data also appeared on the ShinyHunters leak site.
- Oracle issued the security alert
Oracle disclosed CVE-2026-35273 as unauthenticated remote code execution affecting supported PeopleTools 8.61 and 8.62.
- Mandiant published campaign analysis
The report documented notifications, infrastructure, MeshCentral, reconnaissance, fanout, archives, and response guidance.
- Oracle released the June CSPU
Oracle stated that the PeopleSoft update included the alert fix and additional patches.
- SOSEC public-record reconstruction completed
SOSEC separated and connected vendor facts, campaign observations, pinned-source mechanics, defensive conclusions, and unresolved evidence.
9.4Sources and material
- Oracle Security Alert Advisory — CVE-2026-35273https://www.oracle.com/security-alerts/alert-cve-2026-35273.html
- Oracle text risk matrix — CVE-2026-35273https://www.oracle.com/security-alerts/cve-2026-35273verbose.html
- Oracle CSAF — CVE-2026-35273https://www.oracle.com/a/tech/docs/security-alerts/cve-2026-35273csaf.json
- Oracle Critical Security Patch Update — June 2026https://www.oracle.com/security-alerts/cspujun2026.html
- Mandiant / GTIG — ShinyHunters Targets Education Sector with Oracle PeopleSoft Exploithttps://cloud.google.com/blog/topics/threat-intelligence/shinyhunters-targets-education-sector-oracle-exploit
- Google Threat Intelligence — PeopleSoft campaign IOC collectionhttps://www.virustotal.com/gui/collection/50ac0ffbc9ecf4559949faa026a412c9bb57e81d3ae0714a4dcd25b4fec35105
- MeshCentral 1.1.59 release — revision d488472https://github.com/Ylianst/MeshCentral/releases/tag/1.1.59
- MeshCentral 1.1.59 meshctrl.js RunCommand serializationhttps://github.com/Ylianst/MeshCentral/blob/d48847236617a18680891d322f4a0014da434e7c/meshctrl.js#L1753
- MeshCentral 1.1.59 meshuser.js authorization and routinghttps://github.com/Ylianst/MeshCentral/blob/d48847236617a18680891d322f4a0014da434e7c/meshuser.js#L3050
- MeshCentral 1.1.59 meshcore.js shell executionhttps://github.com/Ylianst/MeshCentral/blob/d48847236617a18680891d322f4a0014da434e7c/agents/meshcore.js#L1714
- MeshCentral 1.1.59 meshagent.js signature verificationhttps://github.com/Ylianst/MeshCentral/blob/d48847236617a18680891d322f4a0014da434e7c/meshagent.js#L1136
- Oracle Java API — XMLDecoderhttps://docs.oracle.com/en/java/javase/25/docs/api/java.desktop/java/beans/XMLDecoder.html
- OpenJDK XMLDecoder.java at fixed revisionhttps://github.com/openjdk/jdk/blob/d3e5304c0f70aa03a52f5449cb38645a184b23dc/src/java.desktop/share/classes/java/beans/XMLDecoder.java#L188
- OpenJDK DocumentHandler.java at fixed revisionhttps://github.com/openjdk/jdk/blob/d3e5304c0f70aa03a52f5449cb38645a184b23dc/src/java.desktop/share/classes/com/sun/beans/decoder/DocumentHandler.java#L277
- OpenJDK NewElementHandler.java at fixed revisionhttps://github.com/openjdk/jdk/blob/d3e5304c0f70aa03a52f5449cb38645a184b23dc/src/java.desktop/share/classes/com/sun/beans/decoder/NewElementHandler.java#L80
- OpenJDK Statement.java reflective invocation pathhttps://github.com/openjdk/jdk/blob/d3e5304c0f70aa03a52f5449cb38645a184b23dc/src/java.desktop/share/classes/java/beans/Statement.java#L170