Oct 30 2026

In-Memory PHP Web Shell: ZIP Loader and Pastebin C2

Technical analysis of a PHP web shell using ZIP streams, Pastebin-hosted payloads, cookie-based C2 switching, and eval(). Includes IOCs, YARA, and defenses.
A technical analysis of a multi-stage PHP loader that combines compressed archive execution, password-protected access, remotely hosted payloads, and runtime code evaluation.

A PHP web shell does not need thousands of lines of malicious code to compromise a website. Sometimes, a small entry script is enough to activate a much larger payload concealed in a local archive or retrieved from an external service.

In this technical analysis, we examine a PHP web shell loader that combines several mechanisms:
  • PHP zip:// stream wrappers to execute compressed code without extracting a separate PHP file.
  • Bcrypt password verification to restrict access to selected operator functions.
  • A PDF-like output prefix that may be intended to mislead simple content inspection.
  • Cookie-controlled switching between remote payload locations.
  • Base64 decoding, Gzip decompression, XOR transformation, and PHP eval() to reconstruct and execute additional code.
The resulting architecture separates the visible entry point from much of the functionality it ultimately executes.

That separation is the central security problem. An investigator examining only the initial PHP file may not see the full web shell, while a scan of the website's public-facing content may not encounter the authenticated execution path at all.

TL;DR

The loader uses a small PHP entry point to execute code stored inside a local ZIP archive. The unpacked script contains password-gated functionality, a configurable remote payload source, and a decoding chain that ultimately passes reconstructed PHP code to eval().

Its default remote location is a Pastebin raw endpoint, but an operator can change that destination through an HTTP parameter and retain the selection in a browser cookie for ten hours.

The technique is memory-resident at the payload-execution stage, not completely fileless. The entry script and compressed archive remain important disk artifacts.

For defenders, the investigation must connect three layers: files on the server, HTTP requests to the loader, and outbound connections from the PHP runtime.
Analysis scope: This breakdown is based on the supplied technical report and code excerpts. The initial infection route, complete secondary payload, live C2 status, and effectiveness against specific security products have not been independently established.

Attack architecture: four stages of PHP execution

The attack is organized around a relatively small local loader that delegates functionality to other components.

Stage 1 — Local entry point

An HTTP-accessible PHP script loads code from a member inside a ZIP archive using PHP's zip:// stream wrapper.

Stage 2 — Unpacked controller

The archive member implements password checking, response manipulation, and operator-controlled configuration.

Stage 3 — Remote payload retrieval

The controller retrieves additional content from a default public paste-service URL or from an alternative URL selected through the ts_url cookie.

Stage 4 — Runtime decoding and execution

The downloaded content is decoded, decompressed, transformed, and evaluated as PHP code inside the running server process.

The execution flow is:

PHP entry → ZIP archive member → controller → remote payload → decoding → eval()

This architecture can complicate detection because the artifacts are distributed across local storage, network traffic, and transient runtime state.

Stage 1: Executing PHP directly from a ZIP archive

The first component uses a native PHP feature rather than a custom archive extractor.

PHP supports compressed stream wrappers, including the following syntax:

require('zip://archive.zip#member.php');

The zip:// path identifies an archive and a specific member inside that archive.

PHP reads the selected member through the wrapper and executes its contents in the current interpreter context.

The supplied sample uses string concatenation to construct the wrapper path:

(function($str) {
require($str);
})('zi'.'p:/'.'/d#k');

The fragments reconstruct a zip:// reference that points to archive d and member k.

The meaningful behavior is the same: PHP executes the selected member without requiring a separate, visibly extracted PHP file.

Why this matters

A basic file audit may prioritize recognizable .php files while overlooking archives with unusual names or extensions.

An archive can contain executable PHP logic even when the visible entry script appears almost empty.

This is not equivalent to saying the payload leaves no evidence on disk. The ZIP container itself is a persistent artifact, and its members can be examined without executing them.

For defenders, the key distinction is between the files that exist on disk and the code that PHP can execute through its stream abstraction.

We have previously examined related concealment mechanisms in Obfuscating PHP Backdoors Using Legitimate Code Wrappers. The same investigative principle applies here: a legitimate language feature becomes dangerous when used to conceal unauthorized execution.

Stage 2: PDF-like output and password-gated access

After the archive member is loaded, the supplied analysis identifies two mechanisms intended to control visibility and access.

PDF-like output masquerading

The loader uses the marker:

%PDF-0-1

This resembles the beginning of a PDF file but is not a standard PDF version header.

Its presence suggests an attempt to influence how a simple inspection tool or signature-based detector interprets the response.

However, merely printing this string does not turn an HTTP response into a valid PDF, nor does it establish that a WAF or another security product will ignore the content.

The actual effect depends on response headers, byte placement, the downstream parser, and the inspection technology involved.

The relevant hunting indicator is therefore not a generic PDF signature. It is this particular, unusual marker occurring in the context of suspicious PHP execution.

Bcrypt operator authentication

The controller also uses PHP's password_verify() function with an embedded Bcrypt hash.

The access parameter identified in the supplied sample is:

pd

A request containing a candidate password can be checked against the stored hash before selected web shell functionality becomes available.

This creates a useful barrier for the attacker.

An unauthenticated scanner may reach the PHP endpoint but receive no evidence of the functionality available to an authenticated operator.

In addition, the hash does not expose the original password in plaintext.

The excerpts demonstrate the existence of password verification but do not establish whether every configuration and payload-loading path is protected by the same check.

Defensive implication: A publicly reachable PHP endpoint that produces an unremarkable response is not necessarily benign. Authentication-dependent behavior may require server-side investigation and log correlation.

Stage 3: Dynamic C2 selection through HTTP cookies

The remote payload mechanism is one of the most interesting elements of this loader.

The supplied sample identifies the following default endpoint:

https://pastebin[.]com/raw/E5pYQG1x

The URL is deliberately defanged here.

The loader uses an ordinary HTTP request to retrieve remotely hosted content.

Using a legitimate paste service as a payload source creates an investigative challenge: the destination domain may have many legitimate users, while the content retrieved from a particular path can be controlled independently.

The presence of Pastebin traffic alone is not proof of compromise.

Operator-controlled endpoint switching

The malware also accepts a parameter named url.

The supplied logic shows that an alternative destination can be assigned and stored in a cookie:

setcookie("ts_url", $tnpp9, time() + 36000);

The expiration interval is 36,000 seconds, or ten hours.

On subsequent requests from the same browser or HTTP client, the loader can inspect the ts_url cookie and use the stored destination.

This permits the operator to change the remote payload source without modifying the local PHP entry script or archive.

A separate parameter, ts_reset, is described as resetting the selection to the default location.

Why cookie-controlled routing matters

The remote payload source is not necessarily a single fixed address.

A defender who blocks only the default Pastebin URL may still miss activity involving a previously configured alternative destination.

Likewise, the current contents of the default endpoint may not represent the payload that was retrieved during an earlier execution.

The cookie also has an important limitation: it stores state on the client side. It does not, by itself, establish persistence on the compromised server.

Server-side persistence is provided by the malicious entry point or another mechanism that keeps the code reachable.

In this design, the cookie preserves an operator's preferred payload location, while the local PHP entry point preserves the ability to execute the loader.

This distinction matters when reconstructing an incident timeline.

Stage 4: Reconstructing and executing the remote payload

After retrieving remote content, the loader uses multiple transformations to reconstruct executable PHP code.
The supplied analysis identifies four principal operations.

Operation

Purpose

base64_decode()

Converts encoded text back into binary or textual content

gzinflate()

Decompresses DEFLATE-compressed content

XOR transformation

Reconstructs data through a reversible byte-level operation

eval()

Executes the reconstructed PHP source as code


The malware also constructs sensitive function names from string fragments rather than always storing them as recognizable literals.

For example, fragments such as gz, in, f, la, and te can be assembled into gzinflate.

This introduces an additional obstacle for simple static signatures that search for complete function names.

The supplied excerpts do not provide every intermediate buffer or transformation routine, so the precise decoding sequence should be confirmed against a complete specimen before reproducing it in a laboratory.

The significance of eval()

The final execution step is especially consequential.

PHP's eval() evaluates a string as PHP code in the scope of the running script.

In this case, it allows the functionality delivered by the remote payload source to become executable without first saving a separate, decoded PHP script to the filesystem.

The consequences depend on the retrieved code and the PHP process's privileges.

Potential follow-on activity could include modifying website files, accessing application data, injecting content, or establishing additional access mechanisms. These are possible capabilities of unauthorized PHP execution, not confirmed actions of the unseen secondary payload in this sample.

The major investigative implication is that a small local loader can execute code that changes independently of the files originally found on the server.

Why this loader is difficult to investigate

The technique combines several visibility gaps that should be considered together.

A compressed local component. The entry script does not need to contain the complete malicious controller.

An authenticated control path. Some functionality may remain inaccessible without the correct operator password.

A changeable remote source. The content retrieved during one execution may differ from content available during a later investigation.

Obfuscated code reconstruction. Static patterns may not reveal the complete set of functions or payload strings.

Runtime execution. The final decoded payload may exist only transiently in the PHP process unless it is separately captured or logged.

None of these features independently guarantees security-product evasion.

Together, however, they illustrate why looking only for recognizable malicious files, checking one HTTP response, or blocking one destination can leave significant gaps.

A WAF primarily evaluates traffic according to its deployment and inspection capabilities. It does not necessarily expose every operation that a compromised server performs internally.

Likewise, an external malware scan cannot directly inspect every local archive member or transient PHP runtime object without additional host-level access.

These differences explain why application security, server-side malware analysis, network telemetry, and ongoing integrity monitoring are complementary controls rather than interchangeable ones.

MITRE ATT&CK mapping

The following mapping focuses on behavior supported by the supplied analysis.

ATT&CK ID

Technique

Application to this loader

T1505.003

Server Software Component: Web Shell

The PHP entry point provides a mechanism for continued unauthorized server access

T1059

Command and Scripting Interpreter

The PHP interpreter executes attacker-supplied code

T1027

Obfuscated Files or Information

Archive compression, encoded strings, and fragmented function names conceal code

T1140

Deobfuscate/Decode Files or Information

Base64, decompression, and XOR recover the payload before execution

T1071.001

Application Layer Protocol: Web Protocols

HTTP(S) is used to retrieve remote content

T1102

Web Service

A public paste service is used to host remotely retrievable content


The PDF-like marker could also support an analysis of file-type masquerading under T1036.008, but the full response behavior would need to be examined before asserting that mapping.

Similarly, T1190 — Exploit Public-Facing Application should not be treated as confirmed initial access. The supplied loader does not establish how the attacker originally gained the ability to place or execute the malicious files.

These distinctions are important. ATT&CK describes adversary techniques; a mapping should not imply that every stage of a compromise has been observed.

Indicators of compromise

The following indicators are extracted from the supplied technical report.

Network and HTTP indicators

Indicator

Value

Investigative relevance

Default remote endpoint

https://pastebin[.]com/raw/E5pYQG1x

Reported default payload source

Authentication parameter

pd

Candidate operator password

C2 override parameter

url

Remote payload-source reconfiguration

Reset parameter

ts_reset

Restores default routing

Routing cookie

ts_url

Stores a client-side payload-source preference

Additional reported parameters

ts, tj

Require verification against the complete sample


Host and code indicators

Bcrypt hash

$2y$10$pbZlRFVfrK.yepPrtIsHeOm7pEYOTlaCQ16Vhc1hYchl2iJM8AoKq

Unusual PDF-like output marker

%PDF-0-1

Suspicious execution patterns

  • zip:// references used within require() or include() calls.
  • String fragments constructing PHP stream-wrapper paths.
  • Unexplained executable archive members in website directories.
  • Use of password_verify() alongside suspicious HTTP operator parameters.
  • Remote payload fetching combined with runtime decoding and eval().
  • References to the ts_url and ts_reset values.
The specific endpoint, hash, and marker are useful sample-level indicators. General PHP functions such as base64_decode() or setcookie() are not malicious by themselves.

Indicator limitation: No confirmed file hashes, initial compromise timestamps, or secondary payload hashes are available from the supplied excerpts. The Pastebin endpoint has not been independently validated as currently active.

Detection engineering: finding both stages

This architecture requires more than one detection approach.

Inspect the PHP entry points

Review recently added or modified PHP scripts, including unusually small files that execute other resources.

Search for zip://, require, include, and suspicious string concatenation. Do not assume the literal text zip:// must appear in an obfuscated variant.

Pay particular attention to files outside the expected deployment manifest.

Inspect archives as executable content

Inventory ZIP and other archive files inside web roots, writable directories, and application paths.

Inspect archive members in a controlled environment without executing their contents.

A YARA rule applied only to the compressed ZIP bytes may miss strings that become visible after extraction.

Correlate HTTP access and outbound activity

Review access logs for unexpected parameters, unusual requests to small PHP files, and suspicious cookie values.

Where logging permits, correlate these requests with outbound HTTP or HTTPS connections initiated by the web server or PHP worker.

A request involving url or ts_reset deserves attention when associated with an unauthorized script. These parameter names alone are not sufficient evidence across arbitrary applications.

Hunt for the specific sample

We recommend two complementary YARA rules: one aimed at the local ZIP-stream entry script and another aimed at the unpacked controller.

The rules accompanying this analysis are starting points for threat hunting, not universal signatures for all PHP web shells.

They should be tested against representative clean application files and known malicious samples before operational deployment.

rule Quttera_PHP_ZipStream_Entry
{
    meta:
        description = "Hunts for PHP ZIP-stream entry loaders"
        author = "Quttera Security Team"
        confidence = "medium"

    strings:
        $require1 = "require(" ascii
        $require2 = "require " ascii
        $zip_literal = "zip://" ascii
        $zip_split = "zi'.'p:/" ascii

    condition:
        filesize < 256KB and
        (1 of ($require*)) and
        (1 of ($zip*))
}

rule Quttera_PHP_ZipStream_C2_Controller
{
    meta:
        description = "Hunts for the reported cookie-routed PHP controller"
        author = "Quttera Security Team"
        confidence = "medium"

    strings:
        $cookie = "ts_url" ascii
        $reset = "ts_reset" ascii
        $c2 = "pastebin.com/raw/" ascii nocase
        $pdf = "%PDF-0-1" ascii
        $auth = "password_verify(" ascii
        $eval = "eval(" ascii
        $hash = "$2y$10$pbZlRFVfrK.yepPrtIsHeOm7pEYOTlaCQ16Vhc1hYchl2iJM8AoKq" ascii

    condition:
        filesize < 2MB and
        (
            ($hash and $cookie) or
            (
                $cookie and
                (2 of ($reset, $c2, $pdf, $auth, $eval))
            )
        )
}

Remediation and PHP hardening

If this pattern is found on a production server, the response should focus on both removing unauthorized code and understanding how it arrived.

Preserve evidence before cleanup

Capture relevant PHP files, archives, access logs, application logs, and outbound network evidence.

Preserve timestamps and hashes where possible. Record suspicious cookies and request parameters without unnecessarily collecting unrelated user session data.

If the website is actively compromised, contain the affected application according to the organization's incident response process.

Remove unauthorized execution paths

Identify the PHP entry point, referenced archive, unauthorized modifications, and any additional backdoors.

Restore trusted application files and configurations from verified sources.

Do not assume deleting the entry script resolves the original access weakness.

Review administrator accounts, deployment credentials, application secrets, and hosting access for signs of compromise.

Apply network egress controls

Web server processes should not have unrestricted outbound access when the application does not require it.

Use an approved-destination policy where practical, with monitoring for exceptions.

Blocking a known malicious endpoint may help contain a specific incident, but the operator-controlled URL mechanism means a single-domain block is not a complete defense.

Harden executable file handling

Keep PHP, the CMS, extensions, and dependencies up to date.

Prevent untrusted users from placing executable files in web-accessible directories.

Separate application code from writable upload locations, limit filesystem permissions, and enforce deployment integrity.

Review whether archive features and PHP extensions are required in the production runtime.

Understand configuration limitations

allow_url_include = Off is a useful hardening setting, but it should not be considered a complete mitigation for local archive-wrapper execution.

Similarly, disable_functions can restrict selected PHP functions but does not disable the eval() language construct.

Blindly disabling every archive-related feature may also break legitimate application functionality.

Effective hardening requires testing the actual PHP configuration, runtime behavior, application dependencies, and filesystem permissions.

What continuous website protection should verify

This loader demonstrates a wider security issue: the code stored in a repository, the code present on disk, and the code actually executed by a production server may not be the same.

The website may continue responding normally while an unauthorized server-side component remains accessible to an operator.

A useful monitoring approach therefore connects several layers of evidence:

  • Changes to deployed website files and executable entry points.
  • Malicious or suspicious server-side code, where host-level monitoring is available.
  • Unexpected externally visible behavior.
  • Reputation and blacklist signals.
  • Alerts that support investigation over time.
At Quttera, we approach these risks through continuous website monitoring rather than treating one clean scan as permanent assurance.

ThreatSign Website Security combines ongoing external security checks with additional protection and server-side monitoring capabilities where configured.

For security platforms, hosting providers, and teams that need to integrate website security findings into automated workflows, the Quttera Security and Compliance API provides structured security evidence for integration and analysis.

Neither service should be represented as guaranteeing direct visibility into every transient PHP execution path. Host evidence, access controls, network telemetry, and incident response remain essential components of the security architecture.

Conclusion: The visible loader is only part of the threat

This PHP web shell loader illustrates how attackers can distribute malicious functionality across multiple execution layers.

The local entry point activates compressed code. The controller restricts access and allows the remote payload source to change. The PHP runtime reconstructs and evaluates the final code.

Removing the entry point may terminate that execution path, but a complete response must also address the archive, any additional unauthorized components, and the underlying compromise.

The broader lesson is not that PHP stream wrappers or compression are inherently malicious.

It is that an apparently small and familiar piece of application code can conceal an execution chain whose important behavior is neither obvious from the file extension nor permanently present as a decoded file.

For defenders, the question is not only what files are present on the website. It is what those files can cause the server to execute.

Technical references and related research
Build Web Integrity Intelligence Into Your Platform

Use Quttera’s Website Security and Risk Intelligence API to automate malware detection, blacklist intelligence, integrity analysis, compliance evidence, and machine-readable website assessment across digital assets.