이번 문제는 파일 디스크립터에 대한 문제인 거 같습니다. 먼저 파일 디스크립터에 대해 살펴보면
파일 디스크립터란 특정한 파일에 접근하기 위한 추상적인 키입니다.
모든 프로세스가 갖추어야 하는 표준 POSIX 파일 서술자에는 3개가 있습니다.
0 | 표준 입력 (stdin) |
---|---|
1 | 표준 출력 (stdout) |
2 | 표준 오류 (stderr) |
이제 문제를 풀기위해 서버에 접속해서 ls -l 명령어를 입력해보면
fd@pwnable:~$ ls -l
total 16
-r-sr-x--- 1 fd_pwn fd 7322 Jun 11 2014 fd
-rw-r--r-- 1 root root 418 Jun 11 2014 fd.c
-r--r----- 1 fd_pwn root 50 Jun 11 2014 flag
flag 파일과 fd 파일이 있습니다.
fd.c 파일을 출력해보면
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){ // buf가 "LETMEWIN\n"이면
printf("good job :)\n"); // "good job :)\n" 출력
system("/bin/cat flag"); // "/bin/cat flag" 실행
exit(0); // 종료
}
printf("learn about Linux file IO\n");
return 0;
}
buf가 LETMEWIN\n이면 flag 파일을 출력해주는 프로그램입니다.
buf가 LETMEWIN\n이 되려면 buf에 값을 입력할 수 있어야 하기 때문에, read 함수에 대해 살펴보면
헤더 | unistd.h |
---|---|
형태 | ssize_t read(int fd, void *buf, size_t len); |
인수 | int fd : 파일 디스크립터 void *buf : 파일을 읽어 들일 버퍼 size_t len : 버퍼의 크기 |
반환 | 실패 → -1 성공 → 읽어들인 바이트 수 |
fd를 0으로 만들면 read() 함수를 이용해서 buf에 표준 입력을 할 수 있습니다.
먼저 fd를 0으로 만들려면
int fd = atoi( argv[1] ) - 0x1234;
0x1234 = 4660
argv[1]이 4660이면 fd가 0이 됩니다.
4660을 argv[1]의 인자로 fd를 실행시켜보면
fd@pwnable:~$ ./fd 4660
LETMEWIN
표준 입력을 받게 되고 LETMEWIN을 입력하면
good job :)
mommy! I think I know what a file descriptor is!!
플래그가 출력되었습니다.