Huntress CTF 2024 - writeups
Writeups for all web(6/6) and scripting(2/2) challenges. + misc/time-will-tell
team: joyuriz points: 3105 rank: 257/3444
Web
Y2J (50 pts)
A web application where we can convert Yaml to JSON. I learned the server uses python and by checking headers and looked for vulnerabilities regarding Yaml especially in Python YAML.
Searched and found CVE-2020-14343 https://nvd.nist.gov/vuln/detail/CVE-2020-14343 that allowed code execution in PyYAML library.
This writeup https://hackmd.io/@harrier/uiuctf20 explains and builds upon the payload. I used this payload to get the flag.
|
|
Plantopia (131 pts)
We given a web application with credentials to the login page. Logging in we can observe that session
and auth
cookies are set as well as other cookies.
|
|
We can also see there is API documentation but some looks like its for admin.
Accessing these endpoints require us to use an Authorization
header using the auth
cookie set during our login. We can set Authorization: dGVzdHVzZXIuMC4xNzMwNTgzODIw
to access the API. which is just base64 encoded from testuser.0.1730583820
Since most of these functionality require admin privileges. I played around and just changed the value from testuser
to admin
and from 0
to 1
. and I successfully accessed the /api/admin/logs
From there its just playing around with the admin functionalities. We can see that we can change the commands in the /api/plants/1/edit
|
|
Then we can trigger it via /api/admin/sendmail
then view the output in /api/admin/logs
HelpfulDesk (231 pts)
Not going deep into this one. This is duplicate from NahamconCTF https://www.google.com/search?q=nahamconctf+helpfuldesk+writeup
There is a /Setup/SetupWizard
path if you download and view the source code where you can change the admin credentials and from there we can get the flag.
PillowFight (338pts)
“PillowFight uses advanced AI/MLRegressionLearning* to combine two images of your choosing”
Trying out the web application feature we can upload 2 images and combine into /static/combined.png
. We can also see that this is Powered by Python Pillow v8.4.0!
as seen from the footer.
Searching around, I learned it might be vulnerable to https://nvd.nist.gov/vuln/detail/CVE-2022-22817 “PIL.ImageMath.eval in Pillow before 9.0.0 allows evaluation of arbitrary expressions, such as ones that use the Python exec method. A lambda expression could also be used.”
We can see that we can also add custom commands from the API documentation
This looks like we can pass our own eval
command, so I tried working with python code injection payloads and ended up using a standard os command payload to get the flag and write to the /static
directory.
|
|
MOVEable (376 pts)
We can see in the web application a standard login form, no registration. Aside from that we have the source code.
What I observed first in the source code is the executeScript
under /login
route.
|
|
executeScript
allows multiple statements
https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executescript and will not be able to return any rows so the user will not be able to login regardless if there exists a valid user from the database.
Under /download/<filename>/<sessionid>
we can see that it just checks if the session exists from the database and we will be able to download the file.
|
|
We can also see in the code that when fetching the file it deserializes it using pickle.
So with this information, I solved by doing the following:
- Adding a valid session to the
activesessions
table. - Adding a pickle RCE payload to the
files
table.
Adding a valid session to the DB
Since we know that the executeScript
allows multiple statements. We can add an INSERT
after the initial SELECT
statement. However we still have to bypass the input sanitation inplaced as the inputs are passed in the DBClean
function.
|
|
To bypass we can just fill in with comments and backslash \
:
|
|
We can supply an arbitrary username and add our payload in the password like so.
|
|
Note: We can verify if the session is inserted by going to /download/flag.txt/1337
. and the error is not “No active sessions found”
Exploiting using Pickle RCE
I was stuck trying to exfiltrate using boolean based to determine if the database is the same as provided. Once confirmed, I thought that reading a mangled flag.txt is the challenge or trying to read from a different table. Then I noticed that it is using pickle library for files which can be vulnerable to deserialization attacks .
Create generic Pickle RCE payload. There are online guides out there but this is generally what it looks like.
|
|
To add this file on the database, we can just use the previous entry point in the password like in the previous payload inserting into files
.
|
|
Setup a listener nc -nvlp <port>
To trigger this pickle RCE we just have to navigate to /download/pickle.rce/1337
. this depends on the inserted values on the database. Check the listener and well get the shell and find the flag under root.
Zippy (392 pts)
The web applications main functionality is the upload and extraction of ZIP files contents.
We can upload zip files in the /Upload
and browse directories and filenames under /Browse
.
Additionally we can observe the backend is asp.net Razor pages when we check the /Logs
I searched for File upload attacks regarding zip files and found the zip slip vulnerability and found a guide online https://infosecwriteups.com/zip-slip-vulnerability-064d46ca42e5
I used this vulnerability to change the code of the Browse.cshtml
Razor page that allowed me to view the contents of files in the server.
- Create (Generate using ChatGPT) a
Browse.cshtml
that expectsfile
query parameter that outputs the file passed as argument.
|
|
- Create malicious
browse.zip
that will replace the application/app/Pages/Browse.cshtml
|
|
-
Upload the malicious zip file.
-
Visit the
/Browse
endpoint and notice the page is replaced with our malicious cshtml file. We can get the flag via?file=flag.txt
Scripting
base64by32 (50 pts)
We are given a text file in base64, if we decode the output is still base64. Create a script that can decode it in base64 until it encountered an error
|
|
Echo Chamber (50 pts)
We are given pcap file. If we open it in wireshark and observe the request/responses we can see some repetitive bytes at the end of the packets.
First packet shows a repetitive 89
bytes at the end. Succeeding packets shows 89 50 4E
indicating that there might be a PNG file being sent.
quick reference for magic numbers: https://gist.github.com/leommoore/f9e57ba2aa4bf197ebc5
The packets on last bytes when combined will look like this forming the flag.
To solve we this, we can create a python script parsing the last few bytes and write it to a PNG
file. I utilized https://github.com/KimiNewt/pyshark
|
|
Misc
Time will tell (241 pts)
This is a challenge about trying to guess a randomly generated 8 hexadecimal characters. The important code here is in the check_guess function where it does a do_heavy_compute()
if the character from our guess matches with the solution.
|
|
I have read some writeups regarding timing attacks and relying on the delay on responses. Seeing the source code makes it more understandable how these type of attacks work.
For more context the do_heavy_compute()
function is just set on a time.sleep(0.1)
for this challenge.
Constructing the solution. First we can start a connection using pwntools and print the first few lines. and send a basic guess.
|
|
Since we have a 90 second window to guess, we can run a brute-force by looping through every hex character and observe the response delay using this flow.
So if the observed response increased from the previous ones we find the first character. We append the character to the current guess and continue the loop
Continue this until we find the correct password
We can add this logic to the initial script to brute-force. The brute-force logic would look something like this:
|
|
Note that for max_time varies on the average connection response. during my tries it looks like the incorrect response would take
0.29
seconds and0.39
seconds if it is correct. so i set themax_time
to0.35
initially. It is also important to increasemax_time
as it would increase the delay the more correct characters we have.
When we run the script and we can see it started guessing initial character as 3
as the response time increased to 0.38+secs
After a while we can see the script works and we find the correct password 38aacb77
and get the flag.