HTB - Oouch
Zweilosec's write-up on the hard difficulty Linux machine Oouch from https://hackthebox.eu
Overview

This had difficulty Linux machine taught me a lot about the internal workings of a federated access control system, specifically an implementation of Oauth2. Persistence and the ability to take error messages and learn from them were necessary to progress through this machine.
Useful Skills and Tools
Enumeration
Nmap scan
First off, I started my enumeration with an nmap scan of 10.10.10.177. The options I regularly use are: -p-, which is a shortcut which tells nmap to scan all TCP ports, -sC is the equivalent to --script=default and runs a collection of nmap enumeration scripts against the target, -sV does a service scan, and -oN <name> which saves the output with a filename of <name>.
Anonymous FTP
When doing my initial reconnaissance, I prefer to test for anonymous access to remote access and file sharing services such as ftp, telnet, and SMB before tacking more time and resource intensive services. In this case since port 21 was open, my first step was to login to FTP as anonymous.
There was only one file, project.txt on the server, and I couldn't navigate anywhere else.
The contents of the file revealed that Flask and Django were the two types of frameworks for the different services on some project. Doing a bit of quick reading revealed that Flask and Django are python-based frameworks for building web apps.
Next I checked SSH, but it did not allow me to connect without a private key (I did note that there is no password required though).
Website on port 5000
The next open port on my list was 5000. This is a non-standard port and could have been anything, but Nmap reported that there was an Nginx server hosting an HTTP server there, so I fired up my browser to check it out. Navigating to http://10.10.10.177:5000 led to a pretty bare-bones login page.

Initial Foothold
First, I tested a few common default logins such as 'admin:admin' but that didn't get me anywhere. From there I went to the Register page, created an account, logged in, and started looking around the site.

There was not much to do on most of the internal pages, though there was an interesting "send a message to the administrator" type input box on the /contact page.

Attempting to check for XSS on the contact page using javascript:alert(document.cookie) resulted in: "Hacking Attempt Detected" and a one minute IP ban (see screenshot below). Sending the word 'JavaScript' was fine...but sending just the word 'alert' also triggered this message...I decided there must be some sort of filter, WAF, or IPS.

Next I used Gobuster to search for more accessible directories and found an /oauth page. http://10.10.10.177:5000/oauth led to a "hidden" page with the following links:

In order to connect your account:
http://consumer.oouch.htb:5000/oauth/connectOnce your account is connected, login here:
http://consumer.oouch.htb:5000/oauth/login
Website on port 8000
After clicking the /connect link, I was redirected to http://authorization.oouch.htb:8000/login/. I added each of the newly found domains to my /etc/hosts file so I could proceed.
I didn't have any credentials that worked for the authorization site, so I began poking around to see if there was a way to register. The register link was at the root at http://authorization.oouch.htb:8000/.
The Oauth2 server

I found these sites to be useful while doing research on the Oauth2 protocol:
After creating an account and logging in, I was greeted with two API links /oauth/get_user and /oauth/token.

The two links didn't seem to do anything yet (according to my research I needed a higher privilege authorization token). I needed a way to get this token from a higher privilege user, and the only thing I could think of that I had found related to a site admin was the /contact page on the port 5000 site. Since the /oauth page had a method labeled "connect", I figured the path forward must involve using oauth2 to link my account to the admin account.
After a lot of trial and error and lots of reading of the Oath2 documentation I figured out how to pause the authorization process to connect two accounts in the middle just before the final step. This makes it so the account is in a state where you have an authorization to connect token that is supposed to be sent to the authorized service to connect to. Since this token is sent in the URL, it is trivial to send it as a link to other people in order to link my account to one of my choice.
In order to exploit this, I first went back to original account on http://consumer.oouch.htb:5000/ to use the /connect link on the /oauth page to authorize my two accounts to connect (the one on the consumer page on port 5000 and the Oauth2 internal account on port 8000).

Using Burp to intercept all browser requests, I allowed each of the requests to pass until got to the button to authorize the connect. I then clicked the button, allowed the POST to the server in Burp,
...then intercepted the GET request that contained the authorization link, and dropped the request in Burp so it wouldn't authorize the two accounts to be linked. I needed to start the authorization process in order to get that link I could use to get any other account to connect to mine.
Road to User
Server-side Request Forgery (SSRF)
Next, I needed to get the admin to link his account to mine in order to escalate my privileges. I went back to the http://consumer.oouch.htb:5000/contact page, and sent the admin the link with my authorization token request link, which was already activated through the POST message earlier. All I needed was for the admin to click the link to connect our accounts. This was an example of an attack called Server-side Request Forgery (SSRF).

I sent the following link to the admin, and hoped that there was some way that they would click it: http://consumer.oouch.htb:5000/oauth/connect/token?code=4GCuHQ0LTjKkezQmz2jlolgHxfLXbc (copied from the url bar after Burp dropped the GET earlier).

After getting a message thanking me for my feedback to the admin, I used the link http://consumer.oouch.htb:5000/oauth/login from the /oauth page to authorize the account connection.

The /profile page now showed was logged in as the user qtc with my oauth2 account linked to it.
Finding the developer creds
I noticed on the /documents page I now had the following items listed:
Hello qtc! You have currently following documents stored:
dev_access.txt develop:supermegasecureklarabubu123! -> Allows application registration.
o_auth_notes.txt /api/get_user -> user data. oauth/authorize -> Now also supports GET method.
todo.txt Chris mentioned all users could obtain my ssh key. Must be a joke...
I now had some credentials for a develop user but I wasn't sure where to use them, other than they were good for registering an application.
I turned to gobuster once again to search for more directories, and found /oauth/applications/register/ which gave me an HTTP basic authentication login prompt where I used the develop creds from the /documents page.

After logging in I was given a page where I could register a new application. I went back and did some more research on registering web applications and found information for both Django and Flask.
https://django-registration.readthedocs.io/en/3.1/quickstart.html - Programming information about registering Django apps
https://flask-oauthlib.readthedocs.io/en/latest/oauth2.html - how to register a new Flask application
You can apparently set the authorization link to redirect wherever you want. By setting the redirect URL to be my local machine, I could then listen for a connection with netcat and see if it returned any interesting information.
I forgot the port on my redirect URL while filling out the request the first time. Luckily there was an edit button!

Side note: After creating an app and clicking "Go Back" it prompts for basic authentication with the text “Oouch Admin Only” at URL http://authorization.oouch.htb:8000/oauth/applications/. The develop creds did not work here.

My web app registration request looked like this in Burp:
After allowing the POST request with my credentials I was redirected to a GET request to the register page.
I then sent an authorization request to the server to connect to the app I 'created', which I hoped would redirect to my netcat listener:
I got a connection on my listener!
The connection only sent an error message, but it was enough to see that it worked how I wanted and gave me a clue as to what I needed to send to get a proper response.
After seeing that I could get a connection from the server, I once again tried sending my request in a link to the admin on the http://consumer.oouch.htb:5000/contact page to see if we could use SSRF again to get any further info.
And I got a reply!
I now had a session cookie from the admin. Since I was already logged in as qtc on the consumer portal, I used this cookie to see if I could to log into http://authorization.oouch.htb:8000/ as qtc

It worked! Now that I had a higher privilege oauth2 account, I decided it was time to try out those endpoint links to get an authorization token from /oauth/token to access the API /oauth/get_user I saw earlier.
Next I did some more oauth2 research, in particular on authenticating to APIs:
I found out that the grant type must be
client_credentialshttps://www.oauth.com/oauth2-servers/access-tokens/client-credentials/
and the request must also include
client_idandclient_secret.
My first attempts failed:
I kept getting "invalid_grant_type" and "invalid_client" errors, until I did some more reading and found out that the the request cannot have newlines in it! https://stackoverflow.com/questions/29360349/getting-error-unsupported-grant-type-when-trying-to-get-a-jwt-by-calling-an
My next attempt went better:
Finding user creds
I got the access token! I then tried to use the token to get info from the /oauth/get_user API, but got back nothing useful. After playing around with it, I thought back to the the note on qtc's /documents page that mentioned easy user access to the SSH key and substituted get_user with get_ssh.
I got an SSH key for the user qtc! Annoyingly, it was on a single line and had a lot of \n characters in it that had to be fixed.
The next step was to use SSH to login to the machine. The command ssh -i <private_key_file> lets you use a private key to login.
User.txt
I got the user.txt! There was also a hidden file named .note.txt that mentioned using DBus and iptables to implement an IPS.
Path to Power (Gaining Administrator Access)
Enumeration as user - qtc
qtcWhile enumerating I found a configuration file named htb.oouch.Block.conf in the Dbus configuration files. I figured this must be related to that hidden note I found about an IPS using Dbus.
So the user www-data can send and receive on dbus using htb.oouch.Block, but I wasn't sure how to use this right then.
In the output from the command ip a I noticed that there were Docker containers running in the 172.17.0.1/16 range. I wondered if qtc was able to connect to one.
The answer was yes! It took a few tries to find an IP I could connect to (172.18.0.5), though.
After connecting through SSH with the same OpenSSH key for user qtc, I began enumerating the docker container. The /code folder in the root looked interesting...
There were lots of interesting looking files in this directory.
The file requirements.txt gave a listing of the dependencies and versions of the software needed to run the websites, so perhaps there was something I could use to find an exploit.
The MySQL creds in config.py file looked interesting...though I'm not sure if it was another route to root or a rabbit hole. I forgot about it until after I had gotten root and never used them.
The uwsgi service was running on the oouchbox, and I also found the wsgi.ini file in the Docker container. Apparently it runs in the context of the www-data user, which we saw earlier in the htb.oouch.Block.conf. I checked to see if there were any exploits for this service and found: https://github.com/wofeiwo/webcgi-exploits/blob/master/python/uwsgi_exp.py
I then tried to run the exploit to try to get a reverse shell:
The uwsgi service runs from the docker container so I couldn't figure out how to get this exploit to connect to my Kali machine easily. I used SCP to copy the exploit into the container (along with a version of nc since it wasn't installed.)
uwsgi.socket was in /tmp so I had my --uwsgi argument taken care of, but then encountered an error while running the exploit:
Fortunately commenting out the lines that referenced the bytes module solved the problem and the code ran. I still wasn't able to get a shell back to my box from the docker container, so tried sending it to the oouch box instead.
...it worked, and, I got a connection on my netcat listener I set up back on qtc@oouch.
Now that I was logged in as www-data, I needed to see if that dbus configuration file I found earlier could come in handy. It mentioned interacting with dbus and the htb.oouch.block app. The code below was from routes.py found in the /code/oouch directory of the docker container and showed the information needed to craft my message to DBus. (I also think this was the filter that was blocking my early XSS attempts on the /contact page).
I found some examples of how to craft the exploit message on GitHub at https://gist.github.com/ukBaz/d7cd0c4b9e7078c89980a3db2bbad98b. There was also a related POC that exploits a kernel module (which I didn't do for this challenge) at https://www.exploit-db.com/exploits/36820.
The example exploit command and reply were as follows:
My test code and the services reply:
The reply string "Carried out :D" made it look like I was on the right track, even though I didn't see any echo. I figured that the standard-out was not being sent back to my terminal and that was why I wasn't able to see my test work.
I then tried substituting the echo whoami command for a reverse shell:
I still couldn't reach my home box from the container...but I thought that maybe I could send this shell to qtc@oouch again.
Getting a root shell
My final working exploit:
I'm in! The service spawned a reverse shell connection back to my waiting netcat listener on the oouch machine.
Root.txt
Thanks to qtc for a very fun and very challenging box!
If you like this content and would like to see more, please consider buying me a coffee!
Last updated
Was this helpful?