// Name: environ.c
// Compile: gcc -o environ environ.c
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
void sig_handle() {
exit(0);
}
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
signal(SIGALRM, sig_handle);
alarm(5);
}
void read_file() {
char file_buf[4096];
int fd = open("/etc/passwd", O_RDONLY);
read(fd, file_buf, sizeof(file_buf) - 1);
close(fd);
}
int main() {
char buf[1024];
long addr;
int idx;
init();
read_file();
printf("stdout: %p\n", stdout);
while (1) {
printf("> ");
scanf("%d", &idx);
switch (idx) {
case 1:
printf("Addr: ");
scanf("%ld", &addr);
printf("%s", (char *)addr);
break;
default:
break;
}
}
return 0;
}
이 문제는 로컬에서 푸는 문제이다.
모든 보호 기법이 걸려있다...
stdout 라이브러리 주소를 출력해주니 libc base 주소를 구할 수 있고 case 1:을 통해 임의 주소의 값을 읽을 수 있는 취약점이 존재한다.
익스플로잇 시나리오
1. __environ 주소 계산
[그림 1-2]는 stdout 라이브러리 주소를 이용해 libc base 주소와 전역 변수 __environ 주소를 얻어온다.
[그림 1-3] 주소 확인가능
2. 스택 주소 계산
__environ 주소를 알아냈다면, 임의 주소 읽기 취약점을 통해 스택 주소를 알아내고, "/etc/passwd" 파일의 내용이 저장된 스택 버퍼의 주소를 계산합니다. 해당 주소는 환경 변수와 상대적인 거리가 매번 같으므로, 디버깅을 통해 간격을 알아냅니다.
read_file+77에서 rsi 값이 파일 내용이 들어가는 스택 주소이다.
[그림 1-5] rsi 값을 [그림 1-6] 처럼 확인해보면 "/etc/passwd" 파일 내용이 들어가 있다.
노란색 주소 : 전역변수 __environ 위치
빨간색 주소: 스택 위치
빨간색 주소와 파일 내용("/etc/passwd")이 존재하는 스택 주소를 빼면 [그림 1-8]이 나온다.
앞서 말했드시 환경 변수와 거리가 상대적으로 같아 __environ 값에서 0x1538을 빼면 파일 내용 스택 주소가 나온다.
3. 파일 내용 읽기
[그림 2-1]은 최종 payload이다.
libc_env는 전역 변수 주소이고 값으로는 스택 주소를 가지고 있다. 따라서 임의 주소 읽기 취약점을 이용해 스택 주소(env)를 알아오고 그 값을 0x1538로 빼면 파일 내용이 존재하는 스택 주소가 된다.
익스를 하면 [그림 2-2] 처럼 "/etc/passwd" 파일 내용이 출력된다.
알게 된점
1. 프로세스에는 환경 변수 정보를 항상 가지고 있고 필요할 때마다 가져와서 사용한다.
2. 환경 변수에 대한 정보는 스택 영역에 존재한다.
3. __environ 라이브러리 주소를 알고 있고, 임의의 주소를 읽을 수 있는 취약점이 있다면 스택 주소를 알아낼 수 있다.
'Dreamhack - pwnable' 카테고리의 다른 글
Sigreturn-Oriented Progamming (0) | 2023.03.14 |
---|---|
rtld (0) | 2023.03.12 |
master_canary (1) | 2023.02.15 |
seccomp (0) | 2023.02.13 |
cmd_center (0) | 2023.02.03 |