1번 문제 fd 를 풀어보았다.
fd 는 File Descriptor 를 의미한다.
문제를 풀어보면 알 수 있듯이 File Descriptor 를 모르면 풀 수 없는 문제이다.
문제에서도 "What is a file descriptor?"라는 힌트를 주고 있다.
ssh 로 fd@pwnable.kr 에 접속해보자.
파일을 살펴봤더니 flag 파일을 확인할 수 있으면 문제가 해결될 것 같다.
하지만 현재 권한이 없기 때문에 직접 볼 수는 없고,
fd 파일에 setUID 가 걸려있으므로 fd 파일을 이용하면 flag 를 출력할 수 있을 것 같다.
우선 fd.c 파일의 소스코드를 확인해보자.
main 함수의 매개변수로 들어가 있는 argc 는 명령 인자의 개수를 의미하고
argv는 인자의 벡터를 의미하는데, 인자로 들어가는 문자열이라고 간단히 생각하면 된다.
envp는 시스템 환경 변수인데, 여기서는 크게 고려하지 않아도 되니 넘어가자.
코드를 해석해보자.
우선 명령 인자로 2개 미만이 들어오면 밑의 코드가 실행되지 않고 return 된다.
명령 인자를 2개 이상 넣어주면 fd 변수에 argv[1] 값을 정수로 변환한 뒤 0x1234 만큼 빼고 초기화한다.
이후, read 함수의 첫 번째 인자로 넣어 buf[]에 32byte만큼 읽어오고 있다.
"LETMEWIN" 문자열과 buf 를 비교하여 같으면 flag 를 출력하는 구조이다.
이 문제를 풀기 위해선 문제의 힌트에서 나온 것처럼 file descriptor 에 대해 알고 있어야 한다.
리눅스는 모든 것이 파일로 관리되는데, 프로세스에 접근하고 관리하기 위해 번호를 부여한다.
기본적으로 0,1,2 file descriptor 가 존재하고,
각각 0 : 표준 입력, 1 : 표준 출력, 2 : 표준 에러를 의미한다.
file descriptor 0 이 표준 입력 stdin 을 의미하고
read 함수는 첫 번째 인자로 받은 파일 디스크립터 값의 파일을 읽어온다.
read 함수의 첫 번째 인자인 변수 fd 에 표준 입력 file descriptor 0을 넣어주면
사용자가 입력하는 내용이 buf 에 저장되게 된다.
fd 변수에 0이 저장되게 하면 문자열을 입력할 수 있는 상태가 되는 것이다.
argv[1] 로 입력한 값에서 0x1234 만큼을 빼서 fd 변수에 저장하고 있기 때문에,
4660 (0x1234) 을 입력하면 된다.
표준 입력 상태에서 "LETMEWIN"을 입력했더니
flag 가 출력되는 걸 볼 수 있다.