오늘은 Toddler's Bottle의 cmd1을 풀어보려한다💪
바로 SSH로 접속해보자!
서버에 접속하면 위와 같이 cmd1 바이너리 파일과 cmd1.c, flag 파일이 보인다.
cmd1 파일을 실행해보자.
??? 실행시키자마자 Segmentation fault 라는 오류를 뱉고 프로그램이 종료된다.
그럼 바로 소스코드를 살펴보자.
#include <stdio.h>
#include <string.h>
int filter(char* cmd){
int r=0;
r += strstr(cmd, "flag")!=0;
printf("flag : %d\n", r);
r += strstr(cmd, "sh")!=0;
printf("sh : %d\n", r);
r += strstr(cmd, "tmp")!=0;
printf("tmp : %d\n", r);
return r;
}
int main(int argc, char* argv[], char** envp){
putenv("PATH=/thankyouverymuch");
if(filter(argv[1])) return 0;
system( argv[1] );
return 0;
}
코드는 간결하다!
main함수부터 살펴보자.
int main(int argc, char* argv[], char** envp){
putenv("PATH=/thankyouverymuch");
// 기존 변수를 변경하거나 새 변수를 작성하여 환경 변수의 값을 설정
// PATH 환경 변수 =/thankyouverymuch 설정
if(filter(argv[1])) return 0;
system( argv[1] );
return 0;
}
putenv 함수는 기존 변수를 변경하거나, 새 변수를 작성하여 환경 변수의 값을 설정하는 함수이다.
즉, 위와 같이 PATH 환경변수의 값을 /thankyouverymuch로 바꿔버리는 것이다.
여기서 잠깐🤚 환경변수에 대해 짚고 넘어가보자.
환경변수는 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는, 동적인 값들의 모임 이라고 쓰여있다.
우리는 그 중 PATH 환경변수에 대해 알아야하는데, PATH 환경변수는 디렉터리 경로의 목록으로 사용자가 전체 경로를 지정하지 않고, 명령을 입력하면, 환경변수에 등록된 디렉터리의 경로에서 해당 명령을 찾아서 실행을 도와준다.
예를 들면, 우리가 파일 및 디렉터리의 목록들을 확인하기 위해 사용하는 ls명령어는 실제로 /bin 디렉터리에 존재하는 실행 파일이다. /bin 디렉터리가 PATH 환경변수에 등록되어, 사용자의 입장에선 ls만 입력하지만, 실제로는 /bin/ls가 실행되는 것이다.
실제로 /bin/ls -al과 ls -al이 같은 결과를 보여주는 것을 확인할 수 있다.
다시 문제로 돌아오자.
그러면 cmd1의 코드에서 putenv 부분이 실행되면, 우리는 기존처럼 ls만 입력하여 파일 및 디렉터리 목록을 확인할 수 없다.
/bin부터 입력해줘야 ls를 실행할 수 있는 것이다!
아래에서 보면, argv[1]으로 입력받은 것을 system 함수를 통해 실행시키는 것을 확인할 수 있다.
그러면 cat ./flag를 argv[1]의 인자로 주어 실행시키면 Flag를 확인할 수 있을 것 같지만, 실제로는 putenv 부분에서 PATH 환경변수의 값을 없애버리므로, "/bin/cat ./flag"를 입력하여야 확인할 수 있는 것이다...
그러나, ./cmd1 "/bin/cat ./flag"를 실행시키면 아무런 반응이 없다.
이번에는 Filter 함수로 넘어가보자. Filter 함수의 코드는 아래와 같다.
int filter(char* cmd){
int r=0;
r += strstr(cmd, "flag")!=0;
printf("flag : %d\n", r);
r += strstr(cmd, "sh")!=0;
printf("sh : %d\n", r);
r += strstr(cmd, "tmp")!=0;
printf("tmp : %d\n", r);
return r;
}
우선 strstr 함수부터 알아보자.
strstr 함수의 원형 : char strstr(const char string1, const char *string2);
해당 함수는 string1에서 string2가 표시는 부분을 찾는 함수로, string2를 찾으면 시작 위치에 대한 포인터를 리턴하는 함수이다.. 만약에 찾지못하면 strstr 함수는 NULL을 리턴한다.
즉, 다시 말해서 "flag", "sh", "tmp" 라는 문자열을 명령어에 포함시키면 안되는 것이다 !!!
간단하게 "/bin/cat ./*"을 바이너리 실행 시 넘겨보자~
🚩 Flag 획득
※ 참고
👉 https://www.ibm.com/docs/ko/i/7.3?topic=functions-putenv-changeadd-environment-variables
👉 https://ko.wikipedia.org/wiki/%ED%99%98%EA%B2%BD_%EB%B3%80%EC%88%98
👉 https://www.ibm.com/docs/ko/i/7.3?topic=functions-strstr-locate-substring