Because She Was a Princess She Had a Pegasus.
Knapsy (blog) released Pegasus - to be honest I was supposed to beta test it, but I kinda didn’t get a chance to. However, it allowed me to experience the VM at the same time as everyone else.
People generally work alone on VM’s, so to mix it up a bit, I decided to team up with barrebas (blog) and own the VM as a collaboration :)
So, here’s a quick walkthrough on how to root Pegasus, written by both barrebas and myself.
Getting a Foot(hoof?)hold
An NMAP scan shows that the VM only has a few ports open that are of interest - 22 and 8088
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
8088, when visited with a browser, shows a lovely picture of a Pegasus. A quick look at the source doesn’t reveal anything, and there’s nothing hidden in the image file.
Time to brute force some directories/files. Experience has shown me that vulnerable VM creators are sneaky gits, so I opted to use a large dictionary here, just to see what it came up with. Because of this large dictionary, I had to use dirbuster instead of dirb, because dirb takes ages to parse large dictionary files. Prepare for some horrible UI screenshots…
I’m only interested in the files that returned HTTP 200, as these actually exist, so submit.php and codereview.php
codereview.php POSTS to submit.php, so for the moment I can ignore submit.php and focus on codereview.php
Mike is a code reviewer, and a trainee… therefore is pretty inexperienced. After a bit of time throwing various languages at the application, I found out that if you provide C sourcecode, it gets compiled and executed. Nice ! Lets bash some shellcode in there - specifically a bind shell and submit it.
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 28 29 30 31 32 33 |
|
A quick NMAP scan confirms port 4444 has been opened.
1 2 3 4 5 6 7 8 9 10 11 |
|
A quick connection to the port via Netcat and a bit of Python allow us to get a TTY enabled shell.
1 2 3 4 5 6 7 |
|
Now over to barrebas for the next step ! fancy screen wipe animation
So as user “mike”, I started poking around in the setuid binary “my_first”. It seemed to be some sort of C program with several functions:
1 2 3 4 5 6 7 8 |
|
The mail in /var/mail/mike mentions a git repo with the source code. We started attacking the binary without looking at the code, because the vulnerability jumped up quickly. The third option was not implemented and the reverse string operation seemed to be secure. I then went for the calculator, entering:
1 2 3 4 5 |
|
That seemed promising. I entered:
1 2 3 4 5 |
|
And we have our format string vulnerability! The basic idea now was to abuse it and overwrite a got pointer. I chose printf as the target and I wanted to overwrite it with the address of system. ASLR was enabled on pegasus, but because it is a 32 bit box, we can easily “fix” this with ulimit -s unlimited
. This enlarges the stack and fixes the address of libc:
1 2 3 4 5 |
|
Finding the address of system within gdb was trivial. The got pointer address can be found using objdump:
1 2 3 4 |
|
So it’s at 0x8049bfc. Now we needed to find the start of the format string on the stack. Recrudesce quickly identified it as argument number 8:
1 2 3 4 5 |
|
So I got working on an exploit. I quickly came up with this python script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
The format string first writes some dummy bytes and then overwrites the first part of the got pointer. It takes the 8th argument off the stack and uses %hn to write a half-nibble to that address. The value is the number of bytes that have been written.
Then, it takes the 12th argument, which is the pointer to the second half of the got entry. It writes some dummy bytes and then the outputs the number of bytes written to the got address. Effectively, after running the exploit, the memory location at 0x8049bfc now contains 0x40069060. This is the address of system in libc after running the ulimit trick.
So if we run this exploit, the next time printf() will be called by the binary, it will call system() instead!
1 2 3 4 5 6 7 |
|
OK, we have system() being called! So to fully exploit it and grant us a shell, we make a symlink to /bin/dash and call it “Selection:”. Finally we need to set the PATH environment variable so that the shell searches in the current directory and finds our symlink. The exploit is pushed to the binary via stdin and the cat command then catches the shell that is being spawned (otherwise it closes immediately).
1 2 3 4 5 6 7 8 9 |
|
So we now have a shell as john! I wanted to spawn another shell (using python) to get a pty, but it wouldn’t let me:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
This is probably because our little trainee “mike” is not a real person and is using up all our pty’s! No problem, we thought, let’s upload our ssh keys… only that failed, because our gid is set to mike and not john. Hmmm.. I wrote a small C wrapper to try and set gid and uid to 1000 (john) but it wouldn’t let me set gid.
1 2 3 4 5 6 7 8 9 10 |
|
But this did have the nice side-effect of allowing us a to spawn a pty shell!
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Nice! Now we can see that john is allowed to start the nfs daemon… Interesting, because /etc/exports lists the following entry:
1
|
|
no_root_squash… we can mount it remotely and have our own uid! NFS will not set it to nobody:nobody…
Over to recrudesce for the last bit of pwning pegasus!
Before I continue, lets hear it for barrebas and his exploit dev skills.
So, NFS huh ? What can I do with that ? thinks… well, I can mount it remotely and drop a file as root on my Kali box, suid the binary and execute it on Pegasus as john.
1 2 3 4 5 6 |
|
OK, so a quick side note here - my Kali box is 64 bit… if it were 32 bit I could just copy /bin/sh to /mnt/nfs and suid it. So, in this case, I have to use a C wrapper to execute a shell instead.
The code for the C wrapper is pretty straight forward
1 2 3 4 |
|
This is then compiled as a 32 bit binary, dropped into /mnt/nfs on my Kali box, and chmodded to 4777
1 2 |
|
Which, when executed as user john, drops me to a root shell
1 2 3 4 5 6 7 8 9 10 |
|
Allowing the grail of grails… the ability to cat /root/flag
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 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|