122 lines
3.4 KiB
C
Executable File
122 lines
3.4 KiB
C
Executable File
// SPDX-License-Identifier: MIT
|
|
/**
|
|
* eBPF Port Knocking Program
|
|
* Cross-platform: Linux and Windows
|
|
*
|
|
* This program monitors incoming TCP connection attempts and tracks sequences
|
|
* of ports. When the correct sequence (7000, 8000, 9000 by default) is
|
|
* detected, it allows access to port 31337.
|
|
* Some includes and other files are missing because this is not the full PoC.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
#define SEQUENCE_LEN 3
|
|
#define TARGET_PORT 31337
|
|
|
|
#ifdef _WIN32
|
|
#include "bpf_helpers.h"
|
|
#include "xdp_hooks.h"
|
|
typedef xdp_md_t xdp_md_ctx_t;
|
|
typedef xdp_action_t xdp_return_t;
|
|
#define XDP_RETURN_PASS XDP_PASS
|
|
#define XDP_RETURN_DROP XDP_DROP
|
|
#else
|
|
#include <linux/types.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/tcp.h>
|
|
#include <linux/bpf.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
typedef struct xdp_md xdp_md_ctx_t;
|
|
typedef int xdp_return_t;
|
|
#define XDP_RETURN_PASS XDP_PASS
|
|
#define XDP_RETURN_DROP XDP_DROP
|
|
#endif
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
|
__type(key, uint32_t);
|
|
__type(value, uint32_t);
|
|
__uint(max_entries, 1024);
|
|
} knock_tracker SEC(".maps");
|
|
|
|
#ifndef _WIN32
|
|
char _license[] SEC("license") = "GPL";
|
|
#endif
|
|
|
|
SEC("xdp")
|
|
xdp_return_t port_knock_xdp(xdp_md_ctx_t* ctx) {
|
|
#ifdef _WIN32
|
|
void* data = ctx->data;
|
|
void* data_end = ctx->data_end;
|
|
#else
|
|
void* data = (void*)(long)ctx->data;
|
|
void* data_end = (void*)(long)ctx->data_end;
|
|
#endif
|
|
|
|
if ((unsigned char*)data + 54 > (unsigned char*)data_end)
|
|
return XDP_RETURN_PASS;
|
|
|
|
unsigned char* pkt = (unsigned char*)data;
|
|
|
|
if (pkt[12] != 0x08 || pkt[13] != 0x00)
|
|
return XDP_RETURN_PASS;
|
|
|
|
if (pkt[23] != 6)
|
|
return XDP_RETURN_PASS;
|
|
|
|
uint32_t src_ip = pkt[26] | (pkt[27] << 8) | (pkt[28] << 16) | (pkt[29] << 24);
|
|
|
|
if ((pkt[47] & 0x02) != 0x02)
|
|
return XDP_RETURN_PASS;
|
|
|
|
uint16_t dport = (pkt[36] << 8) | pkt[37];
|
|
|
|
bpf_printk("Packet: src_ip=%d, dport=%d", src_ip, dport);
|
|
|
|
if (dport == TARGET_PORT) {
|
|
uint32_t* val = bpf_map_lookup_elem(&knock_tracker, &src_ip);
|
|
uint32_t state = val ? *val : 0;
|
|
|
|
bpf_printk("Target port check: state=%d", state);
|
|
|
|
if (state == 3) {
|
|
bpf_printk("ALLOWED: IP authorized");
|
|
return XDP_RETURN_PASS;
|
|
} else {
|
|
bpf_printk("DENIED: IP not authorized");
|
|
return XDP_RETURN_DROP;
|
|
}
|
|
}
|
|
|
|
if (dport == 7000 || dport == 8000 || dport == 9000) {
|
|
uint32_t* val = bpf_map_lookup_elem(&knock_tracker, &src_ip);
|
|
uint32_t state = val ? *val : 0;
|
|
|
|
bpf_printk("Knock port: dport=%d, current_state=%d", dport, state);
|
|
|
|
/* Only advance if we're moving forward in the sequence */
|
|
if ((state == 0 && dport == 7000) ||
|
|
(state == 1 && dport == 8000) ||
|
|
(state == 2 && dport == 9000)) {
|
|
|
|
if (state == 2) {
|
|
/* Complete sequence */
|
|
uint32_t new_state = 3;
|
|
bpf_map_update_elem(&knock_tracker, &src_ip, &new_state, 0);
|
|
bpf_printk("Sequence COMPLETE! IP authorized");
|
|
} else {
|
|
/* Advance to next stage */
|
|
uint32_t new_state = state + 1;
|
|
bpf_map_update_elem(&knock_tracker, &src_ip, &new_state, 0);
|
|
bpf_printk("Advanced to stage %d", new_state);
|
|
}
|
|
}
|
|
/* Don't update state on retries - just pass */
|
|
}
|
|
|
|
return XDP_RETURN_PASS;
|
|
}
|