1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | #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; } | cs |
Stage 1
// 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");
argument count 가 100이고 argv[A]는 "\x00", argv[B]는 "\x20\x0a\x0d" 조건이 만족되면 Stage 1 Clear
실행되는 input 포함해서 argc를 100개 조건을 맞추고 argv['A']에 \x00, argv['B']에 \x20\x0a\x0d, Stage 5에 필요한 Port번호인 argv['C']는 임의적인 포트번호로 저장한다.
1 2 3 4 | char *argv[101] = {"/home/input/input", [1 ... 99] = "A", NULL}; argv['A'] = "\x00"; argv['B'] = "\x20\x0a\x0d"; argv['C'] = "55555"; | cs |
Stage 2
// 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");
buf에 stdin으로 "\x00\x0a\x00\xff" 4byte가 존재하고 buf에 stderr로 "\x00\x0a\x02\xff" 4byte 존재하면 Stage 2 Clear
2개의 pipe를 생성해서 부모 프로세스에선 stdin="\x00\x0a\x00\xff\", stderr="\x00\x0a\x02\xff"를 쓰고
자식 프로세스에선 dup2()함수를 이용해서 Mapping 시키고 execve()함수로 input프로그램을 실행한다.
pipe를 이용해 stdin으로 "\x00\x0a\x00\xff", stderr에 "\x00\x0a\x02\xff"를 전달한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | int pipe2stdin[2] = {-1,-1}; int pipe2stderr[2] = {-1,-1}; pid_t childpid; if ( pipe(pipe2stdin) < 0 || pipe(pipe2stderr) < 0){ perror("Cannot create the pipe"); exit(1); } if ( ( childpid = fork() ) < 0 ){ perror("Cannot fork"); exit(1); } if ( childpid == 0 ){ /* Parent process */ close(pipe2stdin[0]); close(pipe2stderr[0]); // Close pipes for reading write(pipe2stdin[1],"\x00\x0a\x00\xff",4); write(pipe2stderr[1],"\x00\x0a\x02\xff",4); } else { /* Child process */ close(pipe2stdin[1]); close(pipe2stderr[1]); // Close pipes for writing dup2(pipe2stdin[0],0); dup2(pipe2stderr[0],2); // Map to stdin and stderr close(pipe2stdin[0]); close(pipe2stderr[1]); // Close write end (the fd has been copied before) | cs |
Stage 3
// env
if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
printf("Stage 3 clear!\n");
환경변수 "\xde\xad\xbe\xef" 값이 "\xca\xfe\xba\xbe"이 만족하면 Stage 3 Clear
1 2 | char *env[2] = {"\xde\xad\xbe\xef=\xca\xfe\xba\xbe", NULL}; execve("/home/input/input",argv,env); | cs |
Stage 4
// 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");
"\0a" 파일을 읽었을 때 buf에 "\x00\x00\x00\x00" 4byte가 존재 할경우 Stage 4 Clear
"\x0a"파일을 생성 후 "\x00\x00\x00\x00" 데이터를 파일에 write 한다.
1 2 3 | FILE* fp = fopen("\x0a","w"); fwrite("\x00\x00\x00\x00",4,1,fp); fclose(fp); | cs |
Stage 5
// 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");
Socket 통신을 이용하고 recv 받은 4byte가 "\xde\xad\xbe\xef"가 존재 해야함
통신 Port는 argv[C]로 전달 받기 때문에 Stage 1 에서 설정 해야한다.
saddr.sin_port = htons( atoi(argv['C']) );
Stage 5 는 서버 Socket 통신 설정이므로 클라이언트 --> 서버로 전송하는 코드를 작성하면 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | sleep(5); int sockfd; struct sockaddr_in server; sockfd = socket(AF_INET,SOCK_STREAM,0); if ( sockfd < 0){ perror("Cannot create the socket"); exit(1); } server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = htons(55555); if ( connect(sockfd, (struct sockaddr*) &server, sizeof(server)) < 0 ){ perror("Problem connecting"); exit(1); } printf("Connected\n"); char buf[4] = "\xde\xad\xbe\xef"; write(sockfd,buf,4); close(sockfd); return 0; | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #include <sys/wait.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> int main (){ //Stage 1 char *argv[101] = {"/home/input2/input", [1 ... 99] = "A", NULL}; argv['A'] = "\x00"; argv['B'] = "\x20\x0a\x0d"; argv['C'] = "55555"; //Stage 2 int pipe2stdin[2] = {-1,-1}; int pipe2stderr[2] = {-1,-1}; pid_t childpid; if ( pipe(pipe2stdin) < 0 || pipe(pipe2stderr) < 0){ perror("Cannot create the pipe"); exit(1); } //Stage 4 FILE* fp = fopen("\x0a","w"); fwrite("\x00\x00\x00\x00",4,1,fp); fclose(fp); if ( ( childpid = fork() ) < 0 ){ perror("Cannot fork"); exit(1); } if ( childpid == 0 ){ /* Parent process */ close(pipe2stdin[0]); close(pipe2stderr[0]); // Close pipes for reading write(pipe2stdin[1],"\x00\x0a\x00\xff",4); write(pipe2stderr[1],"\x00\x0a\x02\xff",4); } else { /* Child process */ close(pipe2stdin[1]); close(pipe2stderr[1]); // Close pipes for writing dup2(pipe2stdin[0],0); dup2(pipe2stderr[0],2); // Map to stdin and stderr close(pipe2stdin[0]); close(pipe2stderr[1]); // Close write end (the fd has been copied before) // Stage 3 char *env[2] = {"\xde\xad\xbe\xef=\xca\xfe\xba\xbe", NULL}; execve("/home/input2/input",argv,env); // Execute the program perror("Fail to execute the program"); exit(1); } // Stage 5 sleep(5); int sockfd; struct sockaddr_in server; sockfd = socket(AF_INET,SOCK_STREAM,0); if ( sockfd < 0){ perror("Cannot create the socket"); exit(1); } server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr("127.0.0.1"); server.sin_port = htons(55555); if ( connect(sockfd, (struct sockaddr*) &server, sizeof(server)) < 0 ){ perror("Problem connecting"); exit(1); } printf("Connected\n"); char buf[4] = "\xde\xad\xbe\xef"; write(sockfd,buf,4); close(sockfd); return 0; } | cs |
input2@ubuntu:/tmp/rrrr$ ln -s /home/input2/flag flag
input2@ubuntu:/tmp/rrrr$ ls -l
total 20
-rwxrwxr-x 1 input2 input2 13544 Dec 2 08:58 aa
-rw-rw-r-- 1 input2 input2 1919 Dec 2 08:58 aa.c
lrwxrwxrwx 1 input2 input2 17 Dec 2 09:01 flag -> /home/input2/flag
input2@ubuntu:/tmp/rrrr$ ./aa
Welcome to pwnable.kr
Let's see if you know how to give input to program
Just give me correct inputs then you will get the flag :)
Stage 1 clear!
Stage 2 clear!
Stage 3 clear!
Stage 4 clear!
Connected
Stage 5 clear!
Mommy! I learned how to pass various input in Linux :)
'WarGame > pwnable.kr' 카테고리의 다른 글
Shellshock (0) | 2016.12.11 |
---|---|
mistake (0) | 2016.12.11 |
random (0) | 2016.11.27 |
passcode (0) | 2016.11.27 |
flag (0) | 2016.11.27 |