house of orange의 핵심은
1. 먼저 top chunk의 크기를 본래 크기보다 속여서 크기가 크고 free된 청크를 만들어냅니다.
2. 그리고 가짜 _IO_FILE_PLUS와 _IO_wide_data 구조체를 만듭니다.
3. _IO_list_all을 가짜 구조체의 포인터가 있는 주소로 덮어씁니다.
4. 메모리 손상을 일으킵니다.
5. 그럼 _IO_flush_all_lockup()을 호출하게 됩니다. 그런데 이것은 3번에 의해 변경된 값을 참조하게 됩니다.
6. _IO_OVERFLOW()를 호출하게 되는데 이 주소값은 우리가 2번 과정으로 변조한 값이 됩니다. (ex : one_gadget으로 덮을시에 쉘)
처음 보시면 잘 이해가 안되실 수 있습니다. 고로 첫번째부터 차근 차근 알려드리겠습니다. 우선 top chunk의 크기를 속여야 하는데 그 이유는 크기가 크고 free된 청크를 얻기 위해서입니다. 이것을 위해서 단순히 크게 할당했다가 free()시키면 되지 않나?라고 생각하실 수 있는데 이렇게 하는 이유는 malloc()의 인자로 주는 크기가 제한된어있는 경우가 있기때문입니다.
이제 구체적인 원리를 설명해보겠습니다. 이 1번 과정에서 핵심은 top chunk의 크기를 작게 수정하여 예전의 탑청크를 free시킨다. 입니다. 그 이유는 sysmalloc()의 코드를 보면 알 수 있습니다.
2019/08/30 - [힙(heap)/glibc] - sysmalloc() 분석(코드 분석&&순서도)
여기서 상세한 코드 분석과 순서도를 보실 수 있습니다. 다만 다 보는 것이 좋지만 이 기법은 아래의 과정을 실행하기 때문에
이 부분만 보시고 와도 충분합니다.
첫번째 목표를 달성하기 위해 실행해야되는 부분은
1. 위의 순서도 부분입니다.
알아야 하는 지식은
1. malloc() = __libc_malloc()입니다.
2. __libc_malloc()안에서 _int_malloc()을 호출하게 됩니다. 근데 이 int_malloc()에서 top chunk를 분할해서 요청을 처리하기에 top chunk의 크기가 부족할 때 sysmalloc()이 호출이 됩니다. (즉 요구한 바이트 수 > top chunk의 크기)
위의 순서도에 있는 과정은 malloc() 외부에서 sbrk()나 brk()가 호출되어 데이터 영역이 넓어졌을 때 입니다. 즉 우리의 첫번째 목표는 저 과정에 도달하는 것(malloc외부에서 데이터 영역이 넓어졌다고 속이는 것)입니다.
우리는 이것을 위해 top chunk의 크기를 수정을 할 것인데 우선 정상적인 힙 구조를 보여드리겠습니다.
malloc(8)을 했을 때 정상적인 힙구조라면 이렇게 됩니다. 하지만 우리는 여기서 이 top chunk의 크기를 작게 조정할 것입니다. 조정을 하게 되면
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *p1_chunk = malloc(8) - 2 * 8;
// 2 * 8을 빼주는 이유는 malloc()이 반환하는 주소가 chunk의 fd부분이기 때문에 계산하기가 불편하기 때문입니다.
// 만약 32bit라면 2 * 4 만큼 빼주면 구할 수 있습니다.
size_t* top = p1_chunk + 32;
//gdb를 통해 본 첫번쨰 청크의 크기가 33이였으나 prev_inuse_bit를 제외하면 32가 됩니다.
//따라서 이런 방식으로 계산하면 top chunk의 주소를 구할 수 있습니다.
top[1] = 0xfe1;
/*
가장 중요한 부분인데 top chunk의 크기를 수정할 때 top chunk와 이전의 청크의 크기를 더했을 때
0x1000의 배수가 되어야합니다. 왜냐하면 처음 힙을 할당할 때 page 크기단위로 할당하고 주소를 정렬
하게 되는데 이 페이지 크기가 보통 0x1000 입니다. 만약 크기를 더했을 때 0x1000 의 배수가 되지 않는다면
다음 할당에 오류가 발생하게 됩니다
또한 prev_inuse_bit를 고려해주어야 합니다. 왜냐하면 top chunk는 다른 청크와 병합되는 것을
막기 위해 prev_inuse_bit를 항상 셋팅해주기 때문입니다.
*/
}
이 코드를 컴파일하고 gdb로 수정한 뒤의 코드까지 실행한 뒤 힙을 보게되면
이렇게 성공적으로 top chunk의 크기가 수정 된 것을 볼 수 있습니다. 이제 top chunk의 크기를 초과하는 크기로 malloc()를 호출하게 되면 위의 순서도의 과정이 수행되면서 sbrk()를 호출하게되면서 확장이 되고, 2개의 2 * SIZE_SZ 크기의 울타리 청크가 생겨날 것입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *p1_chunk = malloc(8) - 2 * 8;
size_t* top = p1_chunk + 32;
top[1] = 0xfe1;
malloc(0x1000); // 0x1000 > 0xfe0
}
우리가 예상한 결과가 맞는지 확인하기 위해서 컴파일 후 gdb로 보게 되면
이렇게 우리가 예상 한대로 힙이(0x645000으로) 확장되면서 0xfc0(4032)바이트라는 크기를 가진 free chunk가 완성이 되었습니다. 이로써 house of orange의 첫번째 단계를 무사히 끝마쳤습니다! (grin)
'힙(heap) > house_of_orange' 카테고리의 다른 글
house_of_orange (6) pwnable.tw - bookwriter (0) | 2019.09.10 |
---|---|
house_of_orange (5) 자동 구조체 생성기 모듈 만들기 (0) | 2019.09.09 |
house_of_orange (4) HITCON house of orange writeup (0) | 2019.09.06 |
house_of_orange (3) (0) | 2019.09.04 |
house_of_orange (2) (0) | 2019.09.03 |