Skip to content

Latest commit

 

History

History
executable file
·
92 lines (62 loc) · 4.87 KB

File metadata and controls

executable file
·
92 lines (62 loc) · 4.87 KB

Horsetrack

Overview

300 points

Category: Binary Exploitation

Tags : #heap #useafterfree #writewhatwhere #tcache #poisoning #safelinking

Description

I'm starting to write a game about horse racing, would you mind testing it out? Maybe you can find some of my easter eggs... Hopefully it's a heap of fun! vuln, libc.so.6, ld-linux-x86-64.so.2, nc saturn.picoctf.net <port>

Status

THIS WRITE UP IS NOT A COMPLETE SOLUTION but details what progress I did achieve during the event, prior to getting stuck.

I plan to revisit this challenge with the hopes to complete it after the event.

Approach

Checking the binary security :

$ checksec vuln
[*] 'picoCTF/horsetrack/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
    RUNPATH:  b'./'

Disassembled vuln binary in Ghidra and begun analysis, renaming functions and variables along the way to describe their function.

Program uses a datastructure dynamically allocated in main() to store horses within a series of stables. There is a maximum capacity of 18 horses. Each horse within the stable is represented by the following data structure:

stables = horse[18]

horse
{
    // name of the horse (64-bit pointer)
    char *name;                 // &horse + 0x0
    // race position
    int position;               // &horse + 0x8
    // 1 = stable occupied with horse via add_horse(), 0 = no horse in this stable removed via remove_horse()
    int stable_in_use;          // &horse + 0xc
}

Analysis of heap operations :

  • malloc() in main() to allocate space for aforementioned stables structure
  • malloc() in add_horse() to allocate horse name string buffer when adding a new horse
    • size of malloc() is under user control, however is range bounded properly (not exploitable)
  • free() in remove_horse() to release string buffer containing horse's name
    • string buffer pointer is not cleared after free and remains dangling (exploitable)!

To make use of the exploitable dangling pointer, a secret menu item was found in the disassembly, item 0 which allows for moving of a horses position giving them a headstart in a race (refer position element of horse structure), however this cheating is detected via a global flag. But thats not the important part of this function, this function allows up to 16 characters to be written to a selected horses name string buffer. Even more so, the stable_in_use flag is not checked and therefore this horse may have already been removed... hence a mechanism for "use after free"!

Attack mechanism :

  • add_horse() .. allocates buffer

  • remove_horse() .. frees buffer

  • move_horse() ... writes to top 16 bytes (conventiently 64-bit pointer size) of the freed buffer, overwritting allocator data structures (TCache free list, forward pointer in this case).

    ─────────────────────────────────── Tcachebins for thread 1 ─────────────────────────────────── Tcachebins[idx=0, size=0x20, count=2] ← Chunk(addr=0x4055d0, size=0x20, flags=PREV_INUSE) ← Chunk(addr=0x4055b0, size=0x20, flags=PREV_INUSE)

    gef➤ vmmap [ Legend: Code | Heap | Stack ] Start End Offset Perm Path 0x00000000400000 0x00000000401000 0x00000000000000 r-- /home/scottw/picoCTF/horsetrack/vuln 0x00000000401000 0x00000000402000 0x00000000001000 r-x /home/scottw/picoCTF/horsetrack/vuln 0x00000000402000 0x00000000403000 0x00000000002000 r-- /home/scottw/picoCTF/horsetrack/vuln 0x00000000403000 0x00000000404000 0x00000000002000 r-- /home/scottw/picoCTF/horsetrack/vuln 0x00000000404000 0x00000000405000 0x00000000003000 rw- /home/scottw/picoCTF/horsetrack/vuln 0x00000000405000 0x00000000426000 0x00000000000000 rw- [heap]

And this is where the wheels started falling of my challenge attempt. Typically in the past this kind of exploit I'd use a TCache Poisoning attack to have malloc() return an arbritary pointer to a target memory location. With the ambitious plan of overwritting the free GOT entry with system with a horse aptly named /bin/sh.

However vuln appears to utilise GLIBC 2.33, which I quickly learnt benefits from safe-linking of the entries within the TCache bins, mitigating the standard TCache Poisoning attack. I was quickly coming to the end of my knowledge and current experience.

With a non-PIE and only partial relocatable binary, attempts were made to use fixed heap addresses as obtained through gdb, but the end result was always :

malloc(): unaligned tcache chunk detected

There was no fooling the GLIBC TCache Poisoning mitigations for me.

Solution

Unsolved.