Skip to content

Latest commit

 

History

History
147 lines (124 loc) · 9.65 KB

detection.md

File metadata and controls

147 lines (124 loc) · 9.65 KB

PHP detection research

Research date: 2026-10-22.

The PHP manual explains that a server can suppress PHP identification and process arbitrary file extensions through PHP. A remote checker therefore cannot determine the runtime of every site. Absence of a header, cookie or extension is not proof that PHP is absent.

WhatWeb's PHP detector uses several independent channels, including HTTP headers, diagnostics and file extensions. WhatCMS also matches patterns in software artifacts, and its per-page detection model applies here: a PHP application on one path does not establish the runtime on every other path. The php2shell rules are written independently. Neither WhatWeb's code nor its signature catalogue is imported, and no runtime dependency is added.

Cloudflare documents cf-mitigated: challenge as a challenge indicator even when the response is HTML. Treating that HTML as the application page would lose the distinction between blocked inspection and a successful inspection without PHP hints. A GET of 99musik.se returned HTTP 200 with a One moment, please... title, script execution and a wsidchk marker. Their combination is recognised as a JavaScript challenge; the title alone is insufficient.

A GET of flowr.dk on 2026-10-23 returned HTTP 403 with a page reading Your request was blocked and logged by Sansec Shield and linking to Sansec's guide. The same request with a browser or curl User-Agent returned HTTP 200, so Shield refused the checker's User-Agent, which names php2shell; the guide says only that Shield blocks attack probes. The text and the guide link together identify the page. The checker keeps its User-Agent and does not try to pass the block.

Four header and cookie hints come from the applications' own code. WordPress sends X-Redirect-By: WordPress on its redirects (source). Drupal core sends X-Drupal-Dynamic-Cache (source) and X-Drupal-Cache (source). phpBB names its session cookies phpbb3_ in 3.3 (source) and phpbb_ in 4.0 (source), each followed by five random characters and _sid, _u or _k. Shopware 6 names its session session- (source) and Shopware 5 session- followed by the shop ID (source).

The checker SHOULD combine independent hints and retain their source URLs. Generator and application versions MUST NOT become PHP versions. A PHP extension or application asset SHOULD be reported as an indicator rather than proof of a live PHP handler. A failed request to an arbitrary .php path MUST NOT create a PHP-extension hint merely because it returned 404.

Discovery is limited to two additional GETs, on the final origin, from PHP links and form actions in the start page. Requests contain no query string, forward no cookies, and do not follow redirects or recurse. A shared three-second timeout keeps discovery within the caller's overall budget. The same network policy applies throughout. Successful discovered endpoints can join the attested session-request candidates; passive checks perform only GETs. An intercepted start page stops discovery and session requests.

The small attribute scanner handles quoted and unquoted attributes, HTML entities and attribute order, and skips comments and raw-text elements. It is deliberately conservative and is no browser or full HTML5 parser, so malformed HTML, or a body cut off at the size cap, can reduce coverage.

A sourced framework catalogue supplements these generic signals. fingerprints.md lists all twenty framework families, the per-signal sources and confidence, and the distinction between declared identity, default-cookie hints and component evidence. Roundcube application rules are maintained separately from the twenty framework families. applications.md lists fifty further researched applications and distinguishes production artifacts from conditional diagnostic coverage.

Unknown challenge products, hidden warnings, static exports and stripped headers still limit what the check can see. method.md defines the resulting verdicts and the owner's local verification step.

Sites hosted at all-inkl.com were unreachable from the service on 2026-10-23: threeman.info and depeche-mode-world.de timed out at the TCP connection from the service's address while answering elsewhere. A second checking address was dropped the same way after a few minutes of checks. The provider's firewall, not the site, refuses the checker; the check cannot pass it and reports the timeout. Port 443 of depeche-mode-world.de also served the provider's kasserver.com certificate, which the HTTP retry for an assumed HTTPS covers.

Layers in front of the site

A layer is named only from a header its vendor documents. Load balancers that pass the origin's headers through unchanged are not named, nor are vendors whose response headers are not publicly documented, such as Imperva. Fastly runs on Varnish and sends X-Varnish too, so Varnish is named only without Fastly. A Via header with no recognised vendor names a proxy.

Layer Signal Source
Cloudflare header CF-Ray Source
Amazon CloudFront header X-Amz-Cf-Id; Via naming (CloudFront) Source
Fastly X-Served-By entry cache-{datacenter}{nodeid}-{datacenter} Source
Akamai Server: AkamaiGHost; header Akamai-GRN Source, Source
Azure Front Door header X-Azure-Ref Source
Sucuri header X-Sucuri-ID; Server: Sucuri/ Source
Varnish header X-Varnish Source
Any proxy header Via RFC 9110, section 7.6.3

Other platforms

When no answer shows PHP, the documented defaults of other platforms name what the answers point to. Each signal is the platform's own default; a renamed cookie or a disabled header goes unnoticed. X-Powered-By: ASP.NET is not used, because IIS adds it to every response, PHP pages included.

Platform Signal Source
Java servlets cookie JSESSIONID Jakarta Servlet 6.0
Play Framework cookies PLAY_SESSION, PLAY_FLASH Source
ASP.NET cookie ASP.NET_SessionId Source
Express cookie connect.sid; X-Powered-By: Express Source, Source
Next.js X-Powered-By: Next.js Source
Django cookie csrftoken Source

Verification

make test, make build and make test-lab passed on 2026-10-22. Regression tests cover discovery limits, origin restrictions, redirect refusal, query and action filtering, timeout preservation, passive-mode behavior, attested discovered paths, generator parsing, redirect cookies, diagnostic hints, challenge handling, the verdict matrix and the API response.

GET-only checks of the public examples on that date returned:

Site Result Observations
99musik.se inspection_blocked HTTP 200 JavaScript bot challenge
huvudstacentrum.se inconclusive WordPress assets and REST API, Elementor generator, WP Engine header; no PHP version
flowr.dk (2026-10-23) inspection_blocked HTTP 403 Sansec Shield block page, passed through Sucuri
cartographie.pevelecarembault.fr (2026-10-23) no_php_signal OpenID login redirects, JSESSIONID and renamed Play cookies; Java
depeche-mode-world.de (2026-10-23) unreachable Provider certificate on 443; plain HTTP answered until the provider dropped the checking address

No session requests were sent to these public examples during verification.