[Pwnable.kr Prob] cmd1

코코·2023년 2월 23일
0

Pwnable.kr

목록 보기
8/10

오늘은 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 -alls -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을 리턴한다.


다시 filter 함수로 돌아가보면, 우리가 입력했던 argv[1]의 인자를 char *cmd라는 변수에 담고, 해당 변수에서 "flag", "sh", "tmp" 등의 문자열이 탐지되는 순간 바로 0이 아니게 되고, main의 f문에서 return 0;가 실행되어 프로그램이 종료되는 것이다.

즉, 다시 말해서 "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

profile
화이팅!

0개의 댓글