e_yejun
Jun_ : Pwn
e_yejun
전체 방문자
오늘
어제
  • 분류 전체보기 (240)
    • Profile (1)
    • Pwnable (54)
    • Reversing (14)
    • Network (7)
    • Forensic (10)
    • Embedded (4)
    • Android (2)
    • Web (18)
    • 알고리즘 (42)
    • 프로그래밍 (24)
    • 프로젝트 (6)
    • 1-day (7)
    • CTF (15)
    • 기타 (33)
    • 일기장 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • dvwa
  • Heap
  • x64
  • how2heap
  • wargame
  • 1-day
  • X86
  • rev-basic
  • BOF
  • dreamhack.io

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
e_yejun

Jun_ : Pwn

Pwnable

[how2heap] fastbin_dup_into_stack

2023. 8. 11. 00:27

https://github.com/shellphish/how2heap

환경 : ubuntu 16.04 (glibc 2.23)

fastbin_dup_into_stack.c

#include <stdio.h>
#include <stdlib.h>

int main()
{
	fprintf(stderr, "This file extends on fastbin_dup.c by tricking malloc into\n"
	       "returning a pointer to a controlled location (in this case, the stack).\n");

	unsigned long long stack_var;

	fprintf(stderr, "The address we want malloc() to return is %p.\n", 8+(char *)&stack_var);

	fprintf(stderr, "Allocating 3 buffers.\n");
	int *a = malloc(8);
	int *b = malloc(8);
	int *c = malloc(8);

	fprintf(stderr, "1st malloc(8): %p\n", a);
	fprintf(stderr, "2nd malloc(8): %p\n", b);
	fprintf(stderr, "3rd malloc(8): %p\n", c);

	fprintf(stderr, "Freeing the first one...\n");
	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);
	// free(a);

	fprintf(stderr, "So, instead, we'll free %p.\n", b);
	free(b);

	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 long *d = malloc(8);

	fprintf(stderr, "1st malloc(8): %p\n", d);
	fprintf(stderr, "2nd malloc(8): %p\n", malloc(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 malloc will think there is a free chunk there and agree to\n"
		"return a pointer to it.\n", a);
	stack_var = 0x20;

	fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a);
	*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));

	fprintf(stderr, "3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));
	fprintf(stderr, "4th malloc(8): %p\n", malloc(8));
}

이 코드에서는 앞선 fastbin_dup 를 이용하여 fastbin의 주소를 조작하고, 이를 통해 malloc을 통한 chunk 재 할당 시 스택 영역이 할당되는 것을 보여준다.

세 번의 malloc()을 진행하고, a - b - a chunk의 free를 하여 a의 double free bug가 발생한다. 따라서, fastbin에 같은 주소가 두개 들어간 상태가 된다. 여기까지는 앞선 fastbin_dup와 같다.

free(a) → free(b) → free(a) 가 진행된 상황부터 gdb로 분석해보자.

fastbin[0]을 보면, 0x60300(a chunk) → 0x603020(b chunk) → 0x60300(a chunk)를 확인할 수 있다.

fastbin[0] 크기인 0x20만큼의 chunk를 재 할당 시, 재사용을 위해 이 bin에서 fd값을 통해 chunk의 주소를 꺼내 할당하게 된다.

unsigned long long *d = malloc(8);
fprintf(stderr, "1st malloc(8): %p\n", d);

이후, 새로운 포인터 변수 d에 malloc(8)로 chunk를 할당한다. 따라서, 포인터 변수 d는 다음과 같은 주소를 가진다.

fprintf(stderr, "2nd malloc(8): %p\n", malloc(8));

두 번째로 재할당된 heap 주소도 위 같다.

fprintf(stderr, "Now the free list has [ %p ].\n", a);

현재 상태에서 heapinfo와 parseheap으로 할당된 chunk와 bin list를 확인해보면, bin list에 두개의 chunk가 무한 루프로 할당이 되고 있음을 알 수 있고, 그래서 Freed Chunk로 인식하여 status가 Freed 인 것이다.

우리의 malloc과 free의 순서대로 생각해보면, double free bug로 인해 다음 재할당시 0x603000의 주소의 chunk가 할당될 것이다. 하지만 이는 현재 포인터 변수 d에 의해 값을 조작할 수 있는 상태이다.

unsigned long long stack_var;
// 코드 생략
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 malloc will think there is a free chunk there and agree to\n"
	"return a pointer to it.\n", a);
stack_var = 0x20;

fprintf(stderr, "Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n", a);
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));

우리는 앞서 할당해놓은 stack 영역의 stack_var 변수를 fake chunk로 위장하여 할당을 할 것이다.

stack_var 영역에서 chunk의 크기인 0x20을 세팅해주고, d chunk의 크기만큼 빼서 해당 주소의 값을 포인터 변수 d에 넣어준다.

🧐
fd의 값에는 chunk의 주소가 들어가기 때문에, 설정해준 stack_var(0x20)는 size 필드가 되어야 한다. 따라서, -sizeof(d)를 통해 8byte 앞의 주소를 할당해준다.

그러면 위 사진과 같이 0x603000의 fd의 값이 스택 주소가 들어가게 된다.

해당 주소는 d chunk의 크기였던 0x8만큼이 빠진 0x7fffffffe2e8 주소가 할당되었고, +0x8엔 stack_var에 넣어줬던 값인 0x20인 것을 볼 수 있다.

fprintf(stderr, "3rd malloc(8): %p, putting the stack address on the free list\n", malloc(8));

이후 malloc(8)을 호출하면, fastbin[0]의 맨 위에 있는 주소인 0x603000의 해당하는 heap chunk를 할당한다.

이 상황에서 freed chunk list에 최상단 주소는 앞서 변조했던 스택 주소이며, malloc(8) 시 해당 주소를 할당해줄 것이다.

fprintf(stderr, "4th malloc(8): %p\n", malloc(8));

스택 영역이 할당되는지 확인하기 위해 malloc(8)을 호출하고, 반환되는 주소를 출력한다.

malloc(8)로 반환된 주소가 스택 영역임을 확인할 수 있다.


Uploaded by N2T

    'Pwnable' 카테고리의 다른 글
    • [how2heap] unsafe_unlink
    • [how2heap] fastbin_dup_consolidate
    • [how2heap] fastbin_dup
    • [how2heap] first_fit
    e_yejun
    e_yejun
    정리노트 •_•

    티스토리툴바