처음배우는 입장에서 문제가 어렵다고해서 (많이 들어보기도 하고)
그냥 한번 들어가볼까 하는 생각으로 한번 들어가보았다.
일단 홈페이지에서 확인 했던데로 Putty를 사용했고 ID는 fd가 될것이고 PW는 guest가 될 것이다.
ls로 안에 있는 어떤 파일들이 있는가 확인을 해 보았다.
총 3가지의 파일이 보이는데 여기서 flag가 보여서 바로 실행해보았다.
Permission denied 즉 권한이 없다고 한다.
다른것들은 뭐가 있는지 확인 해 보자
fd.c를 확인해보았다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32]; //32 buffer
int main(int argc, char* argv[], char* envp[]){
if(argc<2){ //인자가 2개보다 작을때
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234; //argv[1] - 0x1234를 fd에 넣음
int len = 0;
len = read(fd, buf, 32); // buffer 읽어오기
if(!strcmp("LETMEWIN\n", buf)){ //LETMEWIN이랑 비교해서 같을때
printf("good job :)\n");
system("/bin/cat flag"); // 쉘이 실행됨
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
여기서 봐야 할 것은 read 함수인데 read 함수의 원형을 살펴보면 아래와 같다.
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
여기서 보면 read 함수는
파일 디스크립터, 데이터를 저장할 버퍼의 크기 , 최대 길이 순으로 사용이 되는것을 볼 수 있다.
File Descripter란?
프로세스가 파일에 접근할 때 사용되는 인덱스. 윈도우 관점에서의 핸들
파일을 open할 때, 파일 디스크립터는 0을 포함한 양의 정수를 배당받는다.
그 중, 0 과 1,2 는 기본으로 할당되는 FD이다.
각각 표준 입력, 표준 출력, 표준 에러를 의미한다.
0 = 표준 입력(키보드)
1 = 표준 출력(모니터)
2 = 표준 에러(모니터)
그렇다면 fd.c 의 코드에서 보면 아래와 같은 코드가 있는데...
int len = 0;
len = read(fd, buf, 32); // buffer 읽어오기
read라는 함수를 이용해서 fd에 들어가는 값을 읽어오는것 같다.
그렇다면 fd는 0이 되어야 우리가 입력한 문자열을 읽어올 수 있다는 말이 된다.
다음 코드를 보면 아래와 같은데
len = read(fd, buf, 32); // buffer 읽어오기
if(!strcmp("LETMEWIN\n", buf)){ //LETMEWIN이랑 비교해서 같을때
printf("good job :)\n");
system("/bin/cat flag"); // 쉘이 실행됨
exit(0);
}
buf가 LETMEWIN이라는 문자열이 되면 조건문 안의 코드를 실행하게 된다.
그러면 자동적으로 bash 쉘이 사용이 될것이고 flag를 얻을 수 있을것이다.
아래의 부분을 자세히 보면
char로 선언한 배열이라서 숫자를 입력을 한다고 하더라도
결국엔 문자열로 들어가게 되는데 atoi 함수를 사용해서 문자열을 정수형으로 변환해주고 있다.
따라서 argv[1] - 0x1234의 결과 값이 fd에 들어가게 된다.
int fd = atoi( argv[1] ) - 0x1234; //argv[1] - 0x1234를 fd에 넣음
int len = 0;
len = read(fd, buf, 32); // buffer 읽어오기
if(!strcmp("LETMEWIN\n", buf)){ //LETMEWIN이랑 비교해서 같을때
printf("good job :)\n");
system("/bin/cat flag"); // 쉘이 실행됨
exit(0);
}
이전에 봤었던 파일 디스크립터를 참고해보면
우리가 입력을 했던 값을 읽어올려면 fd가 0이되어야 할 것이다.
일단 buf에 LETMEWIN이라는 문자열을 입력해서 flag를 실행을 해야하기 때문에
fd를 0으로 만들어서 우리가 입력할 LETMEWIN을 입력 할 수 있도록 만들것이다.
0x1234를 10진수로 변환하면 4660이 된다.
그러면 우리는 이 fd를 실행시키고 뒤에 인자를 4660을 입력해주면 될것같다.
일단 실행권한이 있는지 확인을 해보자
다행이도 fd는 실행권한을 가지고 있다.
나머지 fd.c와 flag는 실행권한이 없어서 실행을 시킬 수 없다.
여기서 fd를 실행시키면서 인자를 같이 보내주면 될 것 같다.
4660을 인자로 보내주었더니 fd가 0이되면서 입력을 기다린다.
그래서 코드에서 봤듯이 LETMEWIN이라는 문자열과 일치하면 쉘을 실행시키는 코드였기 때문에 쉘이 실행되어 flag를 얻을 수 있었다.