#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)){ printf("good job :)\n"); system("/bin/cat flag"); exit(0); } printf("learn about Linux file IO\n"); return 0; }
풀이
if(argc<2){ printf("pass argv[1] a number\n"); return 0; }
매개변수에 넘기는 값이 하나라도 없으면, pass argv[1] a number 메시지를 출력한다.
일반적으로 매개변수 없이 바이너리만 실행했을 때 발생한다.
int fd = atoi( argv[1] ) - 0x1234; int len = 0; len = read(fd, buf, 32);
atoi는 10진수 정수 문자열을 정수값으로 변환한다.
read는 말그대로 파일을 읽을때 쓰는 함수다.
각각 매개변수에는 파일 디스크립터, 파일을 읽어들일 버퍼, 버퍼의 크기가 들어간다.
파일 디스크립터는 프로세스에서 특정 파일에 접근할 때 사용하는 추상적인 값으로, 기본으로 할당되는 값은 다음과 같다.
파일 디스크립터 | 목적 | POSIX 이름 | stdio 스트림 |
0 | 표준 입력 | STDIN_FILENO | stdin |
1 | 표준 출력 | STDOUT_FILENO | stdout |
2 | 표준 에러 | STDERR_FILENO | stderr |
if(!strcmp("LETMEWIN\n", buf)){ printf("good job :)\n"); system("/bin/cat flag"); exit(0); }
strcmp는 문자열을 비교하는 함수다.
서로 문자열이 같을 때 0을 반환하고 플래그를 출력한다.
- buf 변수에 LETMEWIN이 들어가기 위해서는 사용자의 입력이 필요하다.
- 파일 디스크립터가 표준 입력인 0이 되어야 하기 때문에, 매개변수에 0x1234의 10진수인 4660 문자열과 함께 fd를 실행한다.
- 그리고 LETMEWIN을 입력한다.
fd@pwnable:~$ ./fd 4660 LETMEWIN good job :) mommy! I think I know what a file descriptor is!!