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 != 100return 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, 41, 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, 40!= 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 != 100return 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, 41, 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, 40!= 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

+ Recent posts