Introduction
Protostar exploits are a cool bunch of ctf type exercises that focus on Linux binary exploits that progressively get harder. A ISO containing the OS and challenges can be downloaded.
The website with all information and downloads is at https://exploit-exercises.com/protostar/
Challenge
Test run
net0 is a network daemon that listens on port 2999. The iso image automatically starts the daemon for you. If we list the running processes you should see it.
user@protostar:~$ ps ax |grep net0 1740 ? Ss 0:00 /opt/protostar/bin/net0 5225 pts/2 S+ 0:00 grep net0 user@protostar:~$ sudo netstat -nap|grep net0 sudo: unable to resolve host protostar tcp 0 0 0.0.0.0:2999 0.0.0.0:* LISTEN 1740/net0 user@protostar:~$ nc -vvv localhost 2999 DNS fwd/rev mismatch: localhost.localdomain != localhost.qualcomm.com localhost.localdomain [127.0.0.1] 2999 (?) open Please send '590895857' as a little endian 32bit int AAAA I'm sorry, you sent 1094795585 instead sent 5, rcvd 92
Exploit
We need to connect to the network daemon, read the random number sent to us and send back the integer value’s equivalent hex representation in little endian order. Success will be indicated with the message ‘Thank you sir/madam’.
#include "../common/common.c" #define NAME "net0" #define UID 999 #define GID 999 #define PORT 2999 void run() { unsigned int i; unsigned int wanted; wanted = random(); printf("Please send '%d' as a little endian 32bit int\n", wanted); if(fread(&i, sizeof(i), 1, stdin) == NULL) { errx(1, ":(\n"); } if(i == wanted) { printf("Thank you sir/madam\n"); } else { printf("I'm sorry, you sent %d instead\n", i); } } int main(int argc, char **argv, char **envp) { int fd; char *username; /* Run the process as a daemon */ background_process(NAME, UID, GID); /* Wait for socket activity and return */ fd = serve_forever(PORT); /* Set the client socket to STDIN, STDOUT, and STDERR */ set_io(fd); /* Don't do this :>; */ srandom(time(NULL)); run(); }
I found that scripting my challenge helped me have greater control over reading the challenge integer value and converting to little endian ready for sending back to the server as raw bytes.
Here is my script https://github.com/muttiopenbts/protostar/blob/master/protostar-net0.py
""" This code is for protostar net0 challange. Will connect to net0 network daemon, read the decimal value send from server, convert to hex, then send back in little endian. """ import socket # for sockets import sys # for exit import re import struct try: #create an AF_INET, STREAM socket (TCP) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error, msg: print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1] sys.exit() print 'Socket Created' host = sys.argv[1] port = sys.argv[2] try: remote_ip = socket.gethostbyname( host ) except socket.gaierror: #could not resolve print 'Hostname could not be resolved. Exiting' sys.exit() print 'Ip address of ' + host + ' is ' + remote_ip #Connect to remote server s.connect((remote_ip, int(port))) print 'Socket Connected to ' + host + ' on ip ' + remote_ip try: #Now receive data recv = s.recv(4096) print recv m = re.search('\'(.+?)\'', recv) #search for decimal value between single quotes if m: found = m.group(1) #Set the whole string hexval = hex(int(found)) hexval = hexval[2:]#remove leading '0x' characters rev_bytes = struct.pack('<L',int(found))#Convert big endian to little print "challenge, %s send back hex %s in little endian %s" %(found,hexval,rev_bytes.encode('hex')) s.sendall(rev_bytes) recv = s.recv(4096) print recv except socket.error: #Send failed print 'Send failed' sys.exit() print 'Done.'
Testing the script
user@protostar:~$ python protostar-net0.py localhost 2999 Socket Created Ip address of localhost is 127.0.0.1 Socket Connected to localhost on ip 127.0.0.1 Please send '157677536' as a little endian 32bit int challenge, 157677536 send back hex 965f7e0 in little endian e0f76509 Thank you sir/madam Done.
The script reads and extracts the string representing the challenge decimal value ‘157677536’, converts this to hexadecimal ‘0x965f7e0’ but because the program has this stored in little endian format we have to reverse the 8 bit chunks ‘0xe0 0xf7 0x65 0x09’ of the value and send them back to the server to have a successful match.
Thank you