카테고리 없음

[DreamHack] rop

0x6b6569 2023. 2. 28. 01:34

 

스택의 반환 주소를 덮는 공격은 스택 카나리, NX, ASLR의 도입으로 인해 점점 어려워졌다. 공격 기법은 셸코드 실행에서 라이브러리 실행으로, 그리고 다수의 리턴 가젯을 연결해서 사용하는  Return Oriented Progamming(ROP)로  발전하였습니다. 

 

사실 바이너리의 PLT에 system 함수를 많은 개발자가 공격 벡터로 사용할 수 있음을 알고 있으며, 여러 개발 도구들에서도 해당 함수의 사용을 지양하도록 경고하고 있습니다. 그래서 실제 바이너리에서 system 함수가 PLT에 포함될 가능성은 매우 적습니다.

 

현실적으로, ASLR이 걸린 환경에서 system 함수를 사용하려면 프로세스에서 libc가 매핑된 주소를 찾고, 그 주소로부터 system 함수의 오프셋을 이용하여 함수의 주소를 계산해야 합니다.

 

Return Oriented Programming

ROP는 리턴 가젯을 사용하여 복잡한 실행 흐름을 구현하는 기법

 

공격자는 이를 이용해서 문제 상황에 맞춰 return to library, return to dl-resolve, GOT overwrite 등의 페이로드를 구성할 수 있다. ROP 페이로드는 리턴 가젯으로 구성되는데, ret단위로 여러 코드가 연쇄적으로 실행되는 모습에서 ROP 체인이라고도 불립니다. 

 

/ Name: rop.c
// Compile: gcc -o rop rop.c -fno-PIE -no-pie
#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;
}

 

보호기법 확인 (실습 환경에는 ASLR이 적용되어 있음)

 

1. 카나리 우회

 

카나리는 0x30의 버퍼, 0x8의 더미, 0x1만큼의 \x00를 payload로 덮게되면 얻을 수 있습니다.

 

2. system 함수의 주소 계산

system 함수는 libc.so.6에 정의되어 있으며, 해당 라이브러리에는 이 바이너리가 호출하는 read, puts, printf도 정의되어 있습니다. 라이브러리 파일은 메모레 매핑될 때 전체가 매핑되므로, 다른 함수들과 함께 system 함수도 메모리 프로세스에 같이 적재됩니다. 

 

하지만, 바이너리가 system 함수를 호출하지 않아서 system 함수는 GOT에 등록되지 않았습니다. 그러나 read, puts, printf는 GOT에 등록되어 있습니다. main 함수에서 반환될 때는 이 함수들을 모두 호출한 이후이므로, 이들의 GOT를 읽을 수 있다면 libc.so.6가 매핑된 주소를 구할 수 있습니다.

 

libc에는 여러 버전이 있는데 같은 libc 안에서 두 데이터 사이의 거리는 항상 같습니다.

 

예를 들어, Ubuntu GLIBC 2.27-3ubuntu1.2에서 read 함수와 system 함수 사이의 거리는 항상 0xc0ca0입니다. 따라서 read함수의 주소를 알 때, system=read-0xc0ca0으로 system 함수의 주소를 구할 수 있습니다.

3. “/bin/sh”

이 바이너리는 데이터 영역에 "/bin/sh" 문자열이 없습니다. 따라서 이 문자열을 임의 버퍼에 직접 주입하여 참조하거나. 다른 파일에 포함된 것을 사용해야 합니다. 후자의 방법을 사용할 때 많이 사용되는 것이 libc.so.6에 포함된 "/bin/sh" 문자열입니다. 이 문자열의 주소도 system 함수 주소를 계산할 때처럼 libc 영역의 임의 주소를 구하고, 그 주소로부터 거리를 더라거나 빼서 계산할 수 있습니다.