Search code examples
cpipeoutputexecv

How change execlp to execv and run other commands then just 'ls'


At the moment im running an HTML webserver that can run commands given to it through a text box and a submit button but i need to convert the execlp to execv and im not understanding the array portion of the execv. I tried to just make it execv(command, command); but it gives me a passing argument of incompatible pointer type issue. Also for some reason my execution will only run one word commands like ls and wont accept any flags either and im not quite sure why that is. Execution and parsing section of code below, can provide full code if needed.

Exection.c

char *parse(char *command){
    char * newCommand = (char *) malloc(sizeof(char)*50);
    int tgt = 0;
     newCommand = strstr(command, "/run?command=");
    newCommand = strtok(newCommand, " ");
    newCommand = newCommand + 13;
     for(int src = 0; src< strlen(newCommand); src++){
        if(newCommand[src] == '+')
        {
            newCommand[src] = ' ';
        }
        else if(newCommand[src] == '%')
        {
            newCommand[src] = ' ';
        }
        else if(newCommand[src] == '7')
        {
            newCommand[src] = ' ';
        }
        else if(newCommand[src] == 'C')
        {
            newCommand[src] = '|';
        }


    }

     return newCommand;
}

char * execution(char *command){

  int piper[2];
    size_t len = 0;
    pipe(piper);
  char* output =  malloc(1000 * sizeof(char));
    memset(output, '\0', 1000* sizeof(char));
    pid_t pid = fork();
    if(pid != 0)// parent
        {
            wait(NULL);
            close(piper[1]);
      int n = sizeof(output);

            struct pollfd * poll_fd = malloc(sizeof(struct pollfd));
             poll_fd->fd = piper[0];
             poll_fd->events = POLLIN;

            if(poll(poll_fd, 1, 0) == 1){ // pipe data check
            read(piper[0], output, 1000);
            }

        }
        else{

            close(1);
            dup(piper[1]);
            execlp(command, command, NULL);
        exit(1);
        }
                return output;
}

int main (void){
    int sockfd;
    int new_fd; 
    struct addrinfo hints;
    struct addrinfo *serverinfo; 
    struct addrinfo *p;
    struct sockaddr_storage client_addr;
    socklen_t addrsize;
    struct sigaction sa;
    int yes = 1;
    char s[INET6_ADDRSTRLEN];
    int status;

    memset(&hints, 0, sizeof hints); //makes struct empty 
    hints.ai_family = AF_UNSPEC; //IPv4 or v6 
    hints.ai_socktype = SOCK_STREAM; //TCP type need 
    hints.ai_flags = AI_PASSIVE; //Fill in IP for us 


    //if can't get address info print error 
    if((status = getaddrinfo(NULL, PORT, &hints, &serverinfo)) != 0){
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        return 1;
    }


    for(p = serverinfo; p != NULL; p = p->ai_next){
        if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
            perror("server: socket");
            continue;
        }

        if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
            perror("setsockopt");
            exit(1);
        }

        if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    freeaddrinfo(serverinfo);

    if(p == NULL){
        fprintf(stderr, "server: failed to bind\n");
        exit(1);
    }

    if(listen(sockfd, BACKLOG) == -1){
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections....\n");

    while(1){
        addrsize = sizeof client_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &addrsize);
        if(new_fd == -1){
            perror("Did not accept");
            continue;
        }

        inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
        printf("server: got connection from %s\n", s);

        if(!fork()){
            close(sockfd);
            int bufsize = 1024;

            char *buffer = malloc(bufsize);
            recv(new_fd, buffer, bufsize, 0);
            send(new_fd, header, bufsize, 0);

            if(send(new_fd, execution(parse(buffer)), 1000, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);
    }

    return 0;


}

Solution

  • If you want the command to be interpreted by a shell you will need to pass it as the an argument, something like:

    const char *args[] = {"/bin/sh", "-c", command};
    execve("/bin/sh", args, NULL);
    

    Beware that web shells are largely considered malware or future CVEs.