#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> int main(int argc, char* argv[], char* envp[]){ printf("Welcome to pwnable.kr\n"); printf("Let's see if you know how to give input to program\n"); printf("Just give me correct inputs then you will get the flag :)\n"); // argv if(argc != 100) return 0; if(strcmp(argv['A'],"\x00")) return 0; if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0; printf("Stage 1 clear!\n"); // stdio char buf[4]; read(0, buf, 4); if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0; read(2, buf, 4); if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0; printf("Stage 2 clear!\n"); // env if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0; printf("Stage 3 clear!\n"); // file FILE* fp = fopen("\x0a", "r"); if(!fp) return 0; if( fread(buf, 4, 1, fp)!=1 ) return 0; if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0; fclose(fp); printf("Stage 4 clear!\n"); // network int sd, cd; struct sockaddr_in saddr, caddr; sd = socket(AF_INET, SOCK_STREAM, 0); if(sd == -1){ printf("socket error, tell admin\n"); return 0; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_port = htons( atoi(argv['C']) ); if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){ printf("bind error, use another port\n"); return 1; } listen(sd, 1); int c = sizeof(struct sockaddr_in); cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c); if(cd < 0){ printf("accept error, tell admin\n"); return 0; } if( recv(cd, buf, 4, 0) != 4 ) return 0; if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0; printf("Stage 5 clear!\n"); // here's your flag system("/bin/cat flag"); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define STDIN 0 #define STDERR 2 int main(){ int pipes_si[2]; int pipes_se[2]; if((pipe(pipes_si)==-1)) { printf("error in pipes_si\n"); exit(1); } if((pipe(pipes_se)==-1)) { printf("error in pipes_se\n"); exit(1); } if(fork()){ dup2(pipes_si[0], STDIN); close(pipes_si[0]); close(pipes_si[1]); dup2(pipes_se[0], STDERR); close(pipes_se[0]); close(pipes_se[1]); char *i_argv[101] = {[0 ... 99] = "A"}; i_argv[65] = "\x00"; i_argv[66] = "\x20\x0a\x0d"; char *i_env[] = { "\xde\xad\xbe\xef=\xca\xfe\xba\xbe" }; FILE* fp = fopen("\x0a", "a"); if(!fp) printf("fp error\n"); if( fwrite("\x00\x00\x00\x00", 4, 1, fp)!=1) printf("fwrite error\n"); fclose(fp); execve("/home/input/input", i_argv, i_env); } else{ write(pipes_si[1], "\x00\x0a\x00\xff", 4); write(pipes_se[1], "\x00\x0a\x02\xff", 4); sleep(2); int client; struct sockaddr_in c_addr; client = socket(AF_INET, SOCK_STREAM, 0); if(client == -1){ printf("socket error, tell admin\n"); return 0; } c_addr.sin_family = AF_INET; c_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); c_addr.sin_port = htons( 25005 ); if( -1 == connect(client, (struct sockaddr*)&c_addr, sizeof(c_addr))) { printf("connection fail\n"); exit(1); } write(client, "\xde\xad\xbe\xef", 4); sleep(3); close(client); } }
Introduction:
본 문제는 input이라는 프로그램과 커뮤니케이션 하며, 프로그램에서 요구하는 정보를 전달해 주는 문제. input이 요구하는 정답을 하나씩 넣어주면 스테이지가 하나씩 클리어 되고, 모든 스테이지가 클리어 되면 마지막에 flag를 출력함
How to solve:
사실 어떻게 푼다는 것을 설명하는 것은 조금 어려울 것 같고, 그냥 프로그램이 요구하는 결과들을 하나씩 넣어주면 풀리게 된다. 시스템의 /tmp에 개인용 폴더를 만들고, 여기에서 익스플로잇을 작성해 돌렸다.
문제를 풀며 한 가지 고민을 하게 만들었던 것이 있는데, 2번 째 스크립트의 20번 줄에 배열을 100칸만 선언하면 이상하게 부모프로세스에서 자식프로세스에서 실행된 input이라는 프로그램에 값을 넣어줘도 아무런 출력을 하지 않았다는 것이다. 이에 대한 것은 사실 아직도 잘 모르겠다.. (쨋든 101칸 이상을 선언하면 정상적으로 출력이 된다..)
이렇게 해서 stage 5 clear까지 화면에 출력되게 한 후 flag의 내용을 봐야하는데, 이를 위해 flag를 익스플로잇을 작성했던 개인용 폴더로 옮겨와야 한다. 하지만 권한 문제로 flag파일 본체를 개인 폴더로 옮겨올 수는 없으므로, 그림 1과 같이 심볼릭 링크를 이용하였다.
<그림 1> 익스플로잇을 작성하던 폴더에 flag파일의 심볼릭 링크를 만듬
<그림 2> 문제 해결
References:
1) 여러 시스템 함수들 - http://forum.falinux.com/zbxe/index.php?_filter=search&mid=C_LIB&search_target=title&search_keyword=recv&document_srl=441107
2) 어떤 분이 올려주신 답안 - http://rk700.github.io/writeup/2014/11/16/input/
'Pwnable.kr' 카테고리의 다른 글
[3pt]collision (0) | 2015.08.07 |
---|---|
[1pt]mistake (0) | 2015.08.06 |
[1pt]cmd1 (0) | 2015.08.06 |
[1pt]fd (0) | 2015.08.06 |
[5pt]bof (0) | 2015.08.06 |