pwnable.kr input

2018-12-23  本文已影响0人  chenmuxin

思路

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;
}

首先介绍一个函数int execve(const char *filename, char *const argv[],char *const envp[])作用是启动新的进程,而进程的文件有filename指定,传入的参数为argv,并且有环境变量envp,这个函数将在下面中用到,同时需要注意argv和envp都需要以NULL结尾

第一关

    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"); 
#include<stdio.h>
int main()
{
    /*1*/
    char *argv[101]={0};
    for(int i=1;i<100;i++)
        argv[i]="a";
    argv[0]="/home/input2/input";
    argv['A']="\x00";
    argv['B']="\x20\x0a\x0d";
    
}

第二关

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");

pipe是为了在两个进程之间通信设置的,单方向的通信,一方面读,一方面写。以下是pipe的定义http://man7.org/linux/man-pages/man2/pipe.2.html

pipe通道是为两个进程通信服务的,但此时只有一个进程,因此我们要fork一个子进程,实现子进程和父进程的通信,以下是fork的原理
https://blog.csdn.net/jason314/article/details/5640969

I/O重定向指的是将已创建的文件描述符指向其他文件,以下是具体原理
http://www.cnblogs.com/weidagang2046/p/io-redirection.html

以下是一个很好的利用pipe通道实现I/O重定向的说明
http://unixwiz.net/techtips/remap-pipe-fds.html

    /*2*/
    int pipe_stdin[2] = {-1, -1};
    int pipe_stderr[2] = {-1, -1};
    pid_t pid_child;
    if ( pipe(pipe_stdin) < 0 || pipe(pipe_stderr) < 0 )
    {
        perror("Cannot create the pipe.");
    }

    #define STDIN_READ   pipe_stdin[0]
    #define STDIN_WRITE  pipe_stdin[1]
    #define STDERR_READ  pipe_stderr[0]
    #define STDERR_WRITE pipe_stderr[1]

    if ( ( pid_child = fork() ) < 0 )   // do not forget the ()!
    {
        perror("Cannot create fork child.");
    }
    if(pid_child == 0)  //in child
    {
        close(STDIN_READ);
        close(STDERR_READ);//关闭输入
        write(STDIN_WRITE,"\x00\x0a\x00\xff",4);
        write(STDERR_WRITE,"\x00\x0a\x02\xff",4);
    }
    else    //in father
    {
        close(STDERR_WRITE);
        close(STDIN_WRITE);//关闭输出
        dup2(STDIN_READ,0);
        dup2(STDERR_READ,2);
    }
    printf("link\n");
   
}

第三关

 // env
    if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
    printf("Stage 3 clear!\n");

char *getenv(const char *name)是查找程序环境列表中参数name的值

char *envp[2] = {"\xde\xad\xbe\xef=\xca\xfe\xba\xbe", NULL};//第三关用到的环境变量
execve("/home/input2/input", argv, envp);

第四关

    // 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"); 
/*4*/
    FILE *fp=fopen("\x0a","wb");
    if(!fp)
    {
        perror("Can not open file.");

    }
    printf("Open file success.\n");
    fwrite("\x00\x00\x00\x00",4,1,fp);
    fclose(fp);
}

第五关

 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;
}
argv['C'] = "9999"; 
sleep(2); // wait the server start
    int sockfd;
    char buf[10] = {0}; // buf to be sent
    int len;            // len of avail buf
    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;  
    servaddr.sin_port = htons(9999);  // port in argv['C'] 
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //local
    if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )  
    {  
        perror("socket error.");  
        exit(1);  
    }  
    if ( connect(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0 )
    {
        perror("connect error.");
        exit(1);
        }
    printf("socket connect.\n");
    strcpy(buf, "\xde\xad\xbe\xef");
    len = strlen(buf);
    send(sockfd, buf, len, 0);
    close(sockfd);  

    return 0;

总结

tips:在这道题提交的时候需要将自己的文件用scp上传到/tmp或者在服务器的tmp文件夹中新建文件夹,用vim写,使用“gcc 文件 -o 输出文件名称”来编译,同时还需要软连接,“ln -s /home/input2/flag flag”

#include<stdio.h>//fopen perror
#include <stdlib.h>
#include <unistd.h>//pipe execve
#include <string.h>//strcmp  
#include <sys/types.h>//bind
#include <sys/socket.h>// linux socket
#include <netinet/in.h>   
#include <netdb.h>   
#include <arpa/inet.h>  

int main()
{
    /*1*/
    char *argv[101]={0};
    for(int i=1;i<100;i++)
        argv[i]="a";
    argv[0]="/home/input2/input";
    argv['A']="\x00";
    argv['B']="\x20\x0a\x0d";
    argv['C'] = "9999"; 
    argv[100] = NULL;


    char *envp[2] = {"\xde\xad\xbe\xef=\xca\xfe\xba\xbe", NULL};//第三关用到的环境变量

    /*2*/
    int pipe_stdin[2] = {-1, -1};
    int pipe_stderr[2] = {-1, -1};
    pid_t pid_child;
    if ( pipe(pipe_stdin) < 0 || pipe(pipe_stderr) < 0 )
    {
        perror("Cannot create the pipe.");
    }

    #define STDIN_READ   pipe_stdin[0]
    #define STDIN_WRITE  pipe_stdin[1]
    #define STDERR_READ  pipe_stderr[0]
    #define STDERR_WRITE pipe_stderr[1]

    if ( ( pid_child = fork() ) < 0 )   // do not forget the ()!
    {
        perror("Cannot create fork child.");
    }
    if(pid_child == 0)  //in child
    {
        close(STDIN_READ);
        close(STDERR_READ);//关闭输入
        write(STDIN_WRITE,"\x00\x0a\x00\xff",4);
        write(STDERR_WRITE,"\x00\x0a\x02\xff",4);
    }
    else    //in father
    {
        close(STDERR_WRITE);
        close(STDIN_WRITE);
        dup2(STDIN_READ,0);
        dup2(STDERR_READ,2);
        execve("/home/input2/input", argv, envp);  
    }
    printf("link\n");

    /*4*/
    FILE *fp=fopen("\x0a","wb");
    if(!fp)
    {
        perror("Can not open file.");

    }
    printf("Open file success.\n");
    fwrite("\x00\x00\x00\x00",4,1,fp);
    fclose(fp);

    /*5*/
    sleep(2); // wait the server start
    int sockfd;
    char buf[10] = {0}; // buf to be sent
    int len;            // len of avail buf
    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;  
    servaddr.sin_port = htons(9999);  // port in argv['C'] 
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //local
    if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )  
    {  
        perror("socket error.");  
        exit(1);  
    }  
    if ( connect(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0 )
    {
        perror("connect error.");
        exit(1);
        }
    printf("socket connect.\n");
    strcpy(buf, "\xde\xad\xbe\xef");
    len = strlen(buf);
    send(sockfd, buf, len, 0);
    close(sockfd);  

    return 0;
}
success.png
上一篇 下一篇

猜你喜欢

热点阅读