You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Minimal header: drop shields, keep the two-line tagline
- Reframe origins: inspired by p0wny-shell's concept and Weevely's
transport/module ideas, not a 'fork'
- Weevely section: fix stale claims (3 themes -> 11 + poly + none,
modules list), drop the 'use X when' split, state full parity as the
project goal and point the gaps to TODO.md
- Standardize on the exact 275-name pool size everywhere
- Security notes: document the env-var bcrypt build, and the honest
caveats (rc4 = obfuscation, --seed determinism, --no-auth, hex fallback)
- CI/CD: condense, fix shell count (10), mention seed reproducibility check
- Legal disclaimer: standard authorized-use wording with jurisdictional refs
- TODO: add CLI client, SQL console, proxy/pivot as Weevely-parity gaps
**Polymorphic PHP webshell generator for authorized red team operations.**
12
7
*A unique shell on every run. No two deployments share the same signature.*
13
8
14
9
</div>
@@ -17,16 +12,16 @@
17
12
18
13
## What is p0wnyShellX
19
14
20
-
p0wnyShellX is a **polymorphic generator** for post-exploitation PHP webshells, forked and heavily extended from [p0wny-shell](https://github.com/flozz/p0wny-shell).
15
+
p0wnyShellX is a **polymorphic generator** for post-exploitation PHP webshells. The project started from the [p0wny-shell](https://github.com/flozz/p0wny-shell) concept — a single self-contained PHP file that gives you a full terminal in the browser, with nothing to install on the operator machine. That idea is excellent; its limitations showed quickly in real engagement conditions: every deployment is byte-for-byte identical, there is no authentication layer, and the routing endpoints are hardcoded — all of it trivially signatureable. The transport obfuscation and the compile-time optional modules were inspired by [Weevely](https://github.com/epinna/weevely3) (per-session obfuscated request encoding, features baked in only when requested), rethought for a browser-first workflow.
21
16
22
-
The original p0wny-shell and most derivatives ship a **static file** — every deployment is byte-for-byte identical, making YARA/AV/SIEM detection trivial. p0wnyShellX solves this: instead of a static webshell, you run a Python generator that produces a **unique PHP file every time**, with randomized function names, routing tokens, junk code, bcrypt-hashed credentials, CSS themes, and a configurable AJAX transport layer.
17
+
The result: instead of shipping a static webshell, you run a Python generator that produces a **unique PHP file on every run** — randomized function names, routing tokens, junk code, bcrypt-hashed credentials, CSS camouflage themes, and a configurable AJAX transport layer. What reaches the target is a file that has never existed before and will never exist again.
| Password in file | — | bcrypt hash only — plaintext never stored |
66
-
|Reproductible builds | Yes (static) | Via `--seed` flag |
63
+
|Reproducible builds | Yes (static) | Via `--seed` flag |
67
64
68
65
---
69
66
70
67
## Compared to Weevely
71
68
72
-
[Weevely](https://github.com/epinna/weevely3) is the reference CLI webshell for red teamers. The two tools solve different problems — they can complement each other.
69
+
[Weevely](https://github.com/epinna/weevely3) is the reference CLI webshell framework. p0wnyShellX borrows two of its ideas — obfuscated transport and features compiled in on demand — and drops the rest of its model: no Python client on the operator machine, no per-target agent protocol, just a browser tab.
|`disable_functions` bypass | Yes — mod_cgi + `.htaccess` (Apache only, requires `AllowOverride` + write access) | No — not planned as a priority; the technique requires Apache + mod_cgi + AllowOverride + web-writable directory, which are rarely all met in prod|
80
+
|`disable_functions` bypass | Yes — mod_cgi + `.htaccess` (Apache only, requires `AllowOverride` + write access) | No — not planned as a priority; the technique requires Apache + mod_cgi + AllowOverride + a web-writable directory, conditions rarely all met in production|
| Port scan | Yes | Yes — `portscan <ip[-range]> <ports>` via fsockopen from the target host |
87
-
| SQL console | Yes | No |
88
-
89
-
**Use Weevely when**: you need CLI automation, module ecosystem (SQL, reverse shell, scan), or obfuscated HTTP transport matters more than visual camouflage.
83
+
| Port scan / host discovery | Yes (`:net_scan`) | Yes — `portscan` and `pingsweep`, via fsockopen from the target host |
84
+
| SQL console | Yes (`:sql_console`) | Not yet — see TODO |
90
85
91
-
**Use p0wnyShellX when**: browser access is your only option, per-deploy unique signatures are the priority, or themed camouflage helps the shell survive visual inspection.
86
+
**Where Weevely still leads, and the plan to close it.** The remaining gaps are a non-interactive CLI client for scripting and automation (p0wnyShellX is browser-only by design today), a SQL console module, proxy/pivoting, and XOR+gzip+base64 transport. They are tracked in [TODO.md](TODO.md) — the stated goal of the project is full parity, so that "Weevely *or* a browser shell" stops being a choice you have to make.
92
87
93
88
---
94
89
95
90
## How the polymorphism works
96
91
97
92
### 1. Function name randomization
98
93
99
-
Every PHP and JS function is assigned a name drawn at random from a pool of 250+ plausible business names (`archiveReplicationLog`, `fetchComplianceStatus`, `validateSchemaCompatibility`…). A new mapping is generated on each run.
94
+
Every PHP and JS function is assigned a name drawn at random from a pool of 275 plausible business names (`archiveReplicationLog`, `fetchComplianceStatus`, `validateSchemaCompatibility`…). A new mapping is generated on each run.
100
95
101
96
```
102
97
# Run 1 # Run 2
@@ -233,7 +228,7 @@ A YARA rule targeting exec methods needs to commit to a specific set: "file cont
233
228
234
229
### 5. Dynamic junk code
235
230
236
-
Between 20 and 80 decoy PHP functions are generated per run, drawn from 20 body templates × 250+ name combinations, with randomized return values, loop counts, and string literals. They are scattered around the functional core to increase noise ratio.
231
+
Between 20 and 80 decoy PHP functions are generated per run, drawn from 20 body templates × 275 name combinations, with randomized return values, loop counts, and string literals. They are scattered around the functional core to increase noise ratio.
237
232
238
233
### 6. AJAX transport modes
239
234
@@ -492,36 +487,29 @@ Omit `--theme` to pick at random from the named themes below (`poly` and `none`
492
487
493
488
---
494
489
495
-
---
496
-
497
490
## CI/CD
498
491
499
-
Every push to a version tag (`v*.*.*`) triggers a GitHub Actions workflow that:
500
-
501
-
1. Installs Python 3.11 and PHP 8.3
502
-
2. Generates an example shell with default credentials
503
-
3. Runs `php -l` syntax validation
504
-
4. Verifies absence of static signatures
505
-
5. Publishes a GitHub Release with `p0wnyShellX.py` and the example shell as assets
492
+
On every push and PR, a GitHub Actions suite generates 10 shells across the option matrix (named themes, `poly`, `none`, junk levels, transport modes, optional modules) and asserts: `php -l` passes on all of them, no static signature survives, two consecutive runs never produce the same file while two runs with the same `--seed` produce byte-identical ones, mimic mode randomizes parameter names, rc4 mode injects `tEnc`/`tDec` with no plaintext parameter left, and the exec fallback chain stays intact.
506
493
507
-
On every push/PR, the CI also runs a polymorphism validation suite:
508
-
- Generates 9 shells (named themes, `--theme poly`, `--theme none`, junk levels, and transport modes)
509
-
- Checks PHP syntax on all
510
-
- Confirms no static signatures remain
511
-
- Confirms two consecutive runs produce different output
512
-
- Verifies mimic transport uses randomized param names
513
-
- Verifies rc4 transport injects `tEnc`/`tDec` and no plain param names
514
-
- Verifies exec fallback chain integrity on all non-transport shells
494
+
On a version tag (`v*.*.*`), a second workflow additionally publishes a GitHub Release with `p0wnyShellX.py` and a freshly generated example shell as assets.
515
495
516
496
---
517
497
518
498
## Security notes
519
499
520
-
- The bcrypt hash in the generated file is irreversible without brute-force
521
-
-`hash_equals` on username prevents timing oracle attacks
522
-
-`password_verify` is constant-time for the password comparison
- Wrong password triggers a random 400–700ms delay (anti-bruteforce)
500
+
**On the generated file**
501
+
502
+
- The password exists nowhere in plaintext. The bcrypt hash (cost=12) is computed at build time by the local PHP CLI; the password is handed to the PHP process through an environment variable, never as a command-line argument — it does not leak through `ps`.
503
+
- Username comparison goes through `hash_equals`, password through `password_verify`: both comparisons are constant-time, no timing oracle.
504
+
- Sessions are started with `cookie_httponly`, `use_strict_mode` and `cookie_samesite=Lax`.
505
+
- A failed login sleeps a random 400–700 ms before answering — enough to make online brute-force impractical without penalizing legitimate use.
506
+
507
+
**Caveats worth knowing before you deploy**
508
+
509
+
- The `rc4` transport is **obfuscation, not encryption**. The key and the shuffled alphabet are embedded in the file: anyone holding the shell can decode the traffic. It defeats regex-based WAF inspection, not an analyst.
510
+
-`--seed` makes a build fully deterministic — **including the bcrypt salt**. Ideal for CI and testing; never reuse a seeded build on a real target.
511
+
-`--no-auth` removes the login form, the session and the hash: anyone who reaches the URL gets a shell. Reserve it for throwaway lab use, and pair it with an unguessable filename.
512
+
- If PHP is absent from the operator machine at build time, the generator falls back to a reversible hex encoding of the password and prints a loud warning — do not deploy a shell built that way.
525
513
526
514
---
527
515
@@ -533,7 +521,11 @@ On every push/PR, the CI also runs a polymorphism validation suite:
533
521
534
522
## Legal disclaimer
535
523
536
-
This tool is intended for **authorized penetration testing, red team engagements, and security research only**. Use it only on systems you own or have explicit written permission to test. Unauthorized use against systems you do not own is illegal. The author assumes no liability for misuse.
524
+
This software is provided for **authorized penetration testing, red team engagements, and security research only**. You may use it exclusively on systems you own, or on systems for which you hold explicit, prior, written authorization from the owner.
525
+
526
+
Unauthorized access to — or interference with — computer systems is a criminal offense in most jurisdictions (among others: the Computer Fraud and Abuse Act in the United States, articles 323-1 et seq. of the French Penal Code, the Computer Misuse Act in the United Kingdom, and the equivalent provisions transposing EU Directive 2013/40/EU).
527
+
528
+
This tool is provided *as is*, without warranty of any kind, express or implied. The author assumes no liability for any damage, data loss, or legal consequence arising from the use or misuse of this software. By using it, you accept sole responsibility for your actions and for complying with all applicable laws and regulations.
537
529
538
530
---
539
531
@@ -542,10 +534,3 @@ This tool is intended for **authorized penetration testing, red team engagements
542
534
GNU Affero General Public License v3.0 — see [LICENSE](LICENSE).
Copy file name to clipboardExpand all lines: TODO.md
+6-1Lines changed: 6 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,13 @@
1
1
# TODO / Roadmap
2
2
3
-
## Planned
3
+
**Project goal: full Weevely parity** — one generator that covers both the browser-terminal and the CLI-framework use cases, so the two tools no longer have to be combined.
4
+
5
+
## Planned (Weevely parity gaps)
4
6
5
7
-[ ] Obfuscated HTTP protocol — XOR+gzip+base64 for request and response payloads (à la Weevely), making POST body opaque to WAF inspection
8
+
-[ ] Non-interactive CLI client — scripted, pipeable command execution against a deployed shell (automation, à la Weevely client); the browser stays the primary interface, the CLI is for tooling chains
9
+
-[ ] SQL console module — interactive SQL queries against databases reachable from the target (à la `:sql_console`)
10
+
-[ ] Proxy/pivot module — route operator traffic through the target host (à la `:net_proxy`)
0 commit comments