스택 버퍼 오버 플로우와 관련한 문제이다.
// 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]; // 40 바이트
init();
printf("Input: ");
scanf("%s", buf);
return 0;
}
코드를 읽어봤을 때 get_shell() 함수 실행으로 플로우를 바꾸어 쉘을 획득하면 될 것 같다.
취약점 분석
scanf에 %s 포맷스트링은 입력 길이에 대해서 제한하지 않고, space, tab, 개행문자 등이 들어올 때까지 계속 입력을 받는다.
%[n]s 로 n개의 문자만 받게끔 제한 걸어두어야 한다.
*strcpy, strcat, sprint 등 버퍼 다루면서 길이 입력 안하는 함수들은 대부분 위험함
-> strncpy, strncat, snprintf, fgets, memcpy 등의 함수 사용이 추천됨

scanf 쪽에서 데이터가 넘어가므로 실행해서 입력값을 줬다.
짧을때는 입력되는데, 좀 길게 주니까 세그멘테이션 오류가 발생한다.
세그멘테이션 오류는 메모리 보호 기법에 의해 발생한 오류이고 허가되지 않은 메모리 접근 방지하기 위해서 나타나는 오류다.
함께 뜨는 코어 덤프됨은 메모리가 놓아짐... 이라는 의미를 가진다.
-> 그러니까 메모리 침범으로 인한 비정상적인 작동이 감지됐다?
덤프를 확인하면 단서가 있을거같은데.. 이녀석 대체 어디있는것임!!!
생성됨이라고 하고 아무리 찾아다녀도 안보이길래 터미널에 ulimit -c unlimited 입력하고 다시 오류를 발생시켜줬다.
/var/lib/apport/coredump 위치에 덤프가 존재하는 것을 확인할 수 있었다.
coredump 파일은 gdb로 열 수 있다. 경로 입력할 때 띄어쓰기가 있다면 주의하자. '\ ' 로 띄어쓰기 표기 해줘야한다.

현재 스택 최상단에 저장된 것이 0x4141414141414141. 즉 'AAAAAAAA'
ret 명령어를 실행하려는데, ret을 만나면 CPU는 rsp값을 읽어서 어디로 점프해서 다음 코드를 실행해야할지를 rip에 저장한다.
원래 있어야 할 값이 덮어씌워졌기에 실행 가능한 메모리 주소가 아니라서 세그멘테이션 폴트가 발생한 것이다.
원하는 주소로 이동하도록 값 덮어 씌우려면 해당 버퍼가 스택 프레임의 어디에 위치하는지 알아야 한다.
disass 로 확인했을 때

rbp-0x30의 주소값을 rax에 담아서 rsi에 저장
rdi에 rip+0xab 주소값 저장

함수가 call 될때 rdi -> rsi 순으로 레지스터 읽으므로 scanf("%s", (rbp-0x30)); 이 될 것이다.
오버플로우 발생시킬 버퍼는 rbp-0x30에 존재할 것이라 추측할 수 있다.
스택 프레임 구조를 생각해보면 다음과 같을 것이다.

0X38만큼의 거리가 있으므로 이를 임의의 값으로 채우고 실행하고자 하는 코드의 주소 입력하면 실행 흐름 조작이 가능할 것으로 예상된다.
return Addr은 get_shell()로 바꾸면 될 것이다. gdb로 get_shell()의 주소가 0x4006aa 임을 확인할 수 있다.


페이로드는 이렇게 구성했다.
(python3 -c "import sys;sys.stdout.buffer.write(b'F'*0x30 + b'K'*0x8 + b'\xaa\x06\x40\x00\x00\x00\x00\x00')";cat)| ./rao
| 은 파이썬이 생성한 64바이트 바이너리 데이터를 ./rao의 표준 입력으로 집어넣는다 .
;cat은 ./rao에 연결된 입력 스트림이 닫히는걸 방지. 파일 인자가 없는 cat이 실행되었으므로 cat이 키보드로 입력하는 명령어를 기다린다.
./rao 내부에서 쉘이 열린 상태라서 cat에 주는 입력이 | 타고 넘어가서 접속 성공한 쉘의 명령어로 실행된다.
cat은 파일의 끝을 만날 때까지 무한 루프하기 때문에 페이로드 뒤에 붙여서 연결을 유지. pwntools의 interactive()같은 역할이다.


이제 서버로 접속해서 flag를 얻어보자

p64는 8바이트 리틀엔디언 방식의 바이트 문자열로 변환(패킹)해주는 pwntools의 기능이다.

'Write-up > DreamHack' 카테고리의 다른 글
| basic_exploitation_001 (0) | 2026.05.17 |
|---|---|
| basic_exploitation_000 (0) | 2026.05.17 |
| shell_basic (0) | 2026.05.13 |
| addtion-quiz, flag-shop (0) | 2026.05.12 |
| [DH] Exercise : GDB (0) | 2026.05.11 |