본문 바로가기

보안

[시스템해킹] Return to Library

Return to Library: 라이브러리 함수로 NX를 우회하고 셸을 획득하는 공격 기법

 

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

#include <stdio.h>
#include <stdlib.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; 보호 기법 확인

 

 

- NX로 인해 buf에 셸 코드를 주입하고 실행할 수 없음

- "/bin/sh"의 주소, system 함수의 PLT 주소를 알고 있음

- x86-64의 함수 호출 규약(6개의 인자를 rdi, rsi, rdx, rcx, r8, r9에 순서대로 저장)에 따라 rdi=<"/bin/sh"의 주소> 인 상태에서 system 함수를 호출해야 함

 

리턴 가젯(Return gadget): ret 명령어로 끝나는 어셈블리 코드 조각

- 리턴 가젯은 반환 주소를 덮는 공격의 유연성을 높여서 익스플로잇에 필요한 조건을 만족할 수 있도록 함

 

1. ("pop rdi; ret") 주소 

2. "/bin/sh" 주소 - 전역 상수가 저장되는 text 영역의 주소는 바뀌지 않음

3. system plt 주소

 

익스플로잇
  • pop rdi: rsp가 가리키는 값을 rdi에 넣고, rsp값 8 증가
  • ret; pop rip, jmp rip = 스택 최상단 값을 rip 값에 넣고, 그 값이 가리키는 곳으로 jmp

main 함수의 ret 실행 전/후

- main 함수의 ret 실행 시 rip는 return addr(pop rdi; ret 가젯의 주소를 넣어줄 거임)를 가리키고, rsp 값은 8 증가 

- 그럼 현재 프로그램의 실행 흐름은 pop rdi; ret 가젯임

- pop rdi; rsp 값을 rdi에 넣고, rsp값 8 증가시키므로 rdi에 "/bin/sh"의 주소 저장

- ret; rsp 값인 system함수의 주소를 rip에 넣고, jmp

- 현재 프로그램의 실행 흐름은 system 함수가 되었고, 첫 번째 인자가 저장되는 rdi에 "/bin/sh"의 주소가 저장되어 있으므로 쉘 획득

 

드림핵 워게임