Support

Site Restoration

#43259 Lenspect is finding malware in your kickstart.zip file, specifically HackTool/PHP.DirSniffer.a

Posted in ‘Site restoration’
This is a public ticket

Everybody will be able to see its contents. Do not include usernames, passwords or any other sensitive information.

Environment Information

PHP version
n/a
CMS Type
Joomla!
CMS Version
n/a
Backup Tool Version
n/a
Kickstart version
n/a

Latest post by moira on Friday, 07 August 2026 11:33 CDT

bigal0228
I ran Lenspect on my system and it returned the following: kickstart-pro-9.1.0.zip 125.47 KB Found: 1 Malicious HackTool/PHP.DirSniffer.a I'm just informing you that this was what was returned from my most recent scan after downloading it from your website.

Blue Ridge Visions Design Group of Spruce Pine, NC

moira

Thank you for letting us know. That is a false positive; there is no malware in Kickstart.

The specific signature you were given, HackTool/PHP.DirSniffer.a, is a pattern match for “a PHP file that lists the contents of a directory”. Kickstart does exactly that, and it has to: when you load it in your browser it lists the folder it is sitting in so it can show you the backup archives available for extraction. That is the entire point of the tool. The scanner sees opendir() and readdir() in a standalone PHP file and reports it, without any way of knowing whether that code is a restoration utility or something unwanted.

The rest of what a scanner sees is equally mundane. Kickstart 9.1 is a single, long, plain-text PHP file — our source tree concatenated into one file at build time, so the tool can be dropped into a folder and run without an installer. There is no packaging, no compression, and no encoding wrapped around it. Every line is readable in a text editor, which means you or your host can inspect the whole thing directly rather than taking our word for it. The one long unreadable-looking string in it is a small PNG icon embedded in the stylesheet as a data: URI, so the tool has its logo without needing a second file.

This is worth understanding in general, not just for our software: no malware scanner can determine what code actually does. Determining the behaviour of an arbitrary program by inspection is not a hard problem, it is a provably unsolvable one. What these products do instead is match filenames, byte patterns, and the names of PHP functions such as opendir, base64_decode, unpack, and eval. Those functions are used by legitimate software constantly — every archiver, installer, backup tool, and template engine you have ever run uses some of them. A scanner flagging them is reporting “this file contains code that could, in some other program, be used for something bad”. That is not the same statement as “this file is malicious”, even though the red “1 Malicious” banner is presented as if it were.

You do not have to take our word for any of this. Because kickstart.php is plain, readable PHP, you can have an AI coding assistant read the actual file and tell you what it does — including whether it finds anything genuinely malicious. Tools that work for this are the ones that run on your machine and can open the file directly: Claude Code, OpenAI Codex, Google Antigravity, Google Gemini CLI, Cursor, Qwen Code, and similar. Ask it something like “read kickstart.php and tell me exactly what it does, and whether any of it is intentionally malicious.”

One important caveat: this must be a coding assistant with real access to the file, not a chatbot such as ChatGPT, Claude on the web, or Copilot Chat. A chatbot cannot read the whole file, will silently work from a fragment of it, and is quite capable of producing a confident answer in either direction that has no relationship to what the code actually contains. That is the same failure mode as the scanner, just with better prose.

So: nothing to worry about, nothing to clean, nothing to remove. If you would like to be certain the download was not tampered with in transit, download it again from our site and confirm the file is byte-for-byte identical to the one you have. If your scanner offers a way to report false positives to its vendor we would appreciate you doing so — it is the only thing that actually gets these signatures corrected.

Technical information

Kickstart Professional 9.1.0 is a single, self-contained, plain-text PHP file distributed inside a ZIP. It contains no obfuscation and no encoded payloads. The constructs that trigger scanner heuristics are used for:

  • opendir() / readdir() — listing the folder Kickstart is placed in, to find the backup archives available for extraction, and enumerating extracted files.
  • unpack() / base64_decode() — reading the binary headers and compressed data blocks inside JPA, JPS, and ZIP backup archives.
  • base64_encode() — computing request signatures in the bundled S3 client, used by the optional “import from S3” feature.
  • A long base64 data: URI in the stylesheet — the Kickstart logo, embedded so the single-file distribution needs no separate image.
  • File writing functions — writing the extracted files to disk, which is what an extraction tool does.

The complete source is available under the GNU General Public License, so the code is open to inspection by anyone, including your scanner’s vendor.


Appendix: what an actual code audit of Kickstart looks like

Rather than just tell you that a tool which understands code reaches a different conclusion than a signature matcher, here is us doing it. We ran Claude Code (Sonnet 5, medium thinking effort) over kickstart.php, using roughly the prompt a reasonably suspicious person in your position would write. We are including both the prompt and the full response so you can see the level of detail these tools reach — and so you can run the same thing yourself and compare.

Two things to be upfront about. First, we ran this against a current 9.2.0 development build rather than the exact 9.1.0 file you downloaded, because that is what was on the machine at the time; the two are architecturally the same, but if you want certainty about your copy, run it against your copy. Second, we deliberately did not tell it that we are the authors, and we asked it to assume we might be lying.

The prompt we used:

A malware scanner flagged the file kickstart.php as HackTool/PHP.DirSniffer.a. I downloaded it from a vendor’s website and I want to know whether that verdict is correct before I run it.

Read the actual file and tell me exactly what it does, and whether any part of it is intentionally malicious.

Treat this as an adversarial audit, not a code review. I do not want reassurance, I want evidence. Specifically:

  1. What is this program for? What does it actually do when run?
  2. Does it contain a backdoor, webshell, or any remote code execution path an attacker could reach? Check how it handles input from the request, whether it evaluates or includes anything derived from user input, and whether any authentication gate can be bypassed.
  3. Does it exfiltrate anything? Look for network calls and check where data goes and whether any destination is attacker-controlled or hardcoded to a third party.
  4. Is anything obfuscated, encoded, or packed in a way that hides its behaviour? If you find encoded blobs, decode them and say what they contain.
  5. Why would a scanner produce a DirSniffer verdict on this file? Point at the specific code responsible and say whether that code is legitimate for this program’s stated purpose or not.

The file is large (~670KB, tens of thousands of lines). Do not answer from the first few hundred lines or from the file’s own comments and branding — a malicious file would lie about itself. Grep for the dangerous constructs directly (eval, assert, system, exec, shell_exec, passthru, popen, proc_open, create_function, preg_replace with /e, call_user_func, variable functions, variable variables, unserialize, extract, include/require with variables, base64_decode, gzinflate, curl, fsockopen, file_get_contents on remote URLs, mail) and inspect every hit in context before drawing a conclusion.

Give me a clear verdict: is this file safe to run, is it malicious, or is it something in between? If in between, be specific about what the residual risk is and what an attacker would need in order to exploit it. Do not soften your findings, and do not assume the vendor is trustworthy just because the file says who wrote it.

The response, in full:

Verdict: Not malicious. Legitimate, unmodified Akeeba Kickstart source (older single-file architecture). The DirSniffer hit is a heuristic false positive on directory-enumeration code that is core to the program’s stated job.

I read the file directly and grepped every dangerous construct on your list, then inspected each hit in context (not the header comments). File: kickstart.php, 23,885 lines / 674 KB.

1. What it is / does. This is Akeeba Kickstart — an AJAX-driven web tool that extracts a split/encrypted Akeeba Backup archive (JPA/JPS/ZIP) sitting next to it on the server and, optionally, restores files via direct write, FTP, or SFTP. It’s meant to be uploaded once, run once, then deleted.

2. Backdoor / webshell / RCE.

  • No raw eval/assert/system/exec/shell_exec/passthru/popen/proc_open/create_function on the PHP side. The only eval(/exec( hits are in embedded client-side JavaScript (JSON parsing fallback, a regex .exec()), not PHP.
  • No preg_replace(...,'/e'), no dynamic $var(...) function calls, no dynamic include/require on a variable path anywhere.
  • All request input funnels through a single getQueryParam() wrapper around $_REQUEST — no direct $_GET/$_POST/$_REQUEST sink into anything dangerous.
  • unserialize() (AKFactory::unserialize) does deserialize attacker-reachable data — a factory parameter round-tripped between AJAX steps — but it’s called with ['allowed_classes' => self::getAllowedClasses()], and getAllowedClasses() restricts instantiable classes to stdClass plus only classes physically declared in this same file. The code even contains an explicit comment acknowledging the data is untrusted and explaining why the class whitelist exists. This is hardening, not a vulnerability.
  • Authentication: kickstart_application_web() blocks every AJAX task except display/logout with a 401 if a password is configured (ksMustAskForPassword()). If no password is configured, the tool is open to anyone who can reach the URL — but that’s Kickstart’s documented-by-design bootstrap state (it runs before the site exists yet), not a hidden bypass.
  • One notable capability worth flagging as residual risk, not as malice: importKickstartFeatures() opens the script’s own directory, lists every file, and include_onces any file matching the naming pattern <selfname>.SOMETHING.php. This is Kickstart’s documented plugin mechanism (e.g. kickstart.transfer.php). It only loads files that are already present on disk — it doesn’t fetch or write them from the request — so it doesn’t grant RCE by itself. But if an attacker separately gains file-write on the server, dropping a matching filename next to kickstart.php would get it auto-executed. That’s a real amplifier, not a backdoor in this file.

3. Exfiltration. Two curl_init() sites and three file_get_contents() sites, all inspected:

  • One curl call is inside the bundled Amazon-S3-compatible client — talks to whatever S3 endpoint/bucket the site owner configures for cloud restore. Not attacker-hardcoded.
  • The other curl call is Kickstart’s “import backup from URL” feature — downloads from a URL the operator supplies in the setup wizard, in chunks, to a local file. Not hardcoded, not automatic.
  • file_get_contents() calls are all local: reading kickstart.json.php config, probing a local defines.php for Joomla path detection, reading a local .htaccess. No remote fetch.
  • Grepped every http:///https:// literal in the file: all resolve to AWS/Google Cloud Storage API documentation, akeeba.com documentation links, and third-party library attribution comments. No third-party telemetry/exfil endpoint.
  • No mail() calls anywhere.

4. Obfuscation / encoding. base64_decode() appears exactly once, feeding the class-whitelisted unserialize() above (session-state round-trip, not payload hiding). gzinflate() appears twice, both inside the archive-extraction engine decompressing ZIP/JPS file entries during restore — standard archive handling, not a decode-then-eval obfuscation gadget (I checked; nothing decoded is ever passed to eval, include, or a dynamic call). No packed/minified blobs, no suspicious long encoded strings outside of those two legitimate contexts.

5. Why DirSniffer. The heuristic is almost certainly triggered by the combination of: (a) opendir()/readdir() loops that enumerate the script’s own directory to locate split archive parts and clean up leftover Kickstart files after restore, (b) the FTP/SFTP directory-browser AJAX handlers getListing()/getSftpListing() used by the setup wizard to let the operator pick a destination path, and (c) the filename-pattern-driven include_once feature loader described above. All of this is directory enumeration by design — it’s a restoration tool that has to find its own archive parts and browse remote filesystems to configure FTP/SFTP — which is exactly the shape a generic “scans directories, conditionally includes files” signature is built to catch, and exactly the shape a file-manager webshell also has. Static heuristics can’t tell the difference; that’s the false positive.

Bottom line: every “dangerous” primitive I found traces to well-scoped, legitimate archive-extraction/restoration functionality, with the deserialization path explicitly hardened against object-injection. I found no hardcoded exfil destination, no eval-of-decoded-blob pattern, and no way for an unauthenticated remote request to execute arbitrary code through this file alone. The one thing to keep in mind operationally (independent of the malware-scanner question) is standard Kickstart hygiene: don’t leave it on the server after restoring, and don’t leave the destination directory writable by other untrusted processes, since the feature-file loader will execute anything matching its naming convention that shows up there.

One correction from us, which is instructive in itself. In its opening line it calls this the “older single-file architecture” and elsewhere implies the single-file design was superseded. That is backwards: the single-file build is the current design. Older 9.0.x releases used PHAR packaging, which we discontinued in 9.1.0. It reached that conclusion because it had access to an out-of-date copy of our source tree on the same machine and gave it more weight than it should have.

We are pointing this out for two reasons. It is a genuine error and we would rather flag it than let you find it. More importantly, it is the honest version of the argument we are making: these tools are far better than a signature matcher at telling you what code does, and they are still not oracles. The difference is that when one of them is wrong, it shows you its reasoning and the specific lines it looked at, so you can check. A scanner that prints “1 Malicious” and a signature name gives you nothing to check at all.

Note also that its two operational cautions — delete Kickstart after you are done, and don’t leave the directory writable by untrusted processes — are advice we have given for years, and are good practice regardless of this ticket.

Moira Fari

Support Specialist

🇬🇧English: native 🕐 My time zone is Asia / Nicosia
Kindly note that my replies are fully vetted by our developers.

Support Information

Working hours: We are open Monday to Friday, 9am to 7pm Cyprus timezone (EET / EEST). Support is provided by the same developers writing the software, all of which live in Europe. You can still file tickets outside of our working hours, but we cannot respond to them until we're back at the office.

Support policy: We would like to kindly inform you that when using our support you have already agreed to the Support Policy which is part of our Terms of Service. Thank you for your understanding and for helping us help you!