我一直在尝试编写一个内核模块来通过netfilter读取传出的FTP数据包的用户名、密码和cmd。当我测试我的代码时,我发现ftp数据包的长度是正确的,但我得到的所有数据都是
0x00
当检查内核模块的输出时。
这是我的代码。我编写了一个
pkt_hex_dump
函数,根据此打印sk_buff数据:将所有数据包的字节转储到互联网层(包括互联网层)之上
/* Sample code to install a Netfilter hook function */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
MODULE_LICENSE("MIT");
MODULE_AUTHOR("1933");
MODULE_DESCRIPTION("An net sniff module for demonstration");
MODULE_VERSION("1.0");
/* Used to describe our Netfilter hooks */
static struct nf_hook_ops post_hook;
/* THESE values are used to keep the USERname and PASSword until
* they are queried. Only one USER/PASS pair will be held at one
* time
*/
static char *username = NULL;
static char *password = NULL;
static unsigned short src_port = 0;
static int have_pair = 0; /* Marks if we already have a pair */
/* dump packet's data */
void pkt_hex_dump(struct sk_buff *skb){
size_t len;
int rowsize = 16;
int i, l, linelen, remaining;
int li = 0;
uint8_t *data, ch;
struct iphdr *ip = (struct iphdr *)skb_network_header(skb);
printk("Packet hex dump:\n");
data = (uint8_t *) skb_network_header(skb);
len=ntohs(ip->tot_len);
remaining = len;
for (i = 0; i < len; i += rowsize) {
printk("%06d\t", li);
linelen = min(remaining, rowsize);
remaining -= rowsize;
for (l = 0; l < linelen; l++) {
ch = data[l];
printk(KERN_CONT "%02X ", (uint32_t) ch);
}
data += linelen;
li += 10;
printk(KERN_CONT "\n");
}
}
/* This is the hook function itself */
unsigned int watch_out(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *ip = NULL;
struct tcphdr *tcp = NULL;
unsigned char *data=NULL;
ip = (struct iphdr *)skb_network_header(skb);
if (ip->protocol != IPPROTO_TCP){
return NF_ACCEPT;
}
tcp = (struct tcphdr *)skb_transport_header(skb);
/* Now check to see if it's an FTP packet */
if (tcp->dest!= htons(21)){
return NF_ACCEPT;
}
pkt_hex_dump(skb);
/* Parse the FTP packet for relevant information if we don't already
* have a username and password pair. */
data = (unsigned char *)((unsigned char *)tcp + (tcp->doff * 4));
printk("hex : data[0-3] = 0x%02x%02x%02x%02x\n", data[0], data[1], data[2], data[3]);
printk("char: data[0-3] = %c%c%c%c\n", data[0], data[1], data[2], data[3]);
printk("--------------- findpkt_iwant ------------------\n");
return NF_ACCEPT;
}
/* Initialisation routine */
int init_module(){
/* Fill in our hook structure */
post_hook.hook = watch_out; /* Handler function */
post_hook.hooknum = NF_INET_POST_ROUTING;
post_hook.pf = AF_INET;
post_hook.priority = NF_IP_PRI_FIRST; /* Make our function first */
nf_register_net_hook(&init_net,&post_hook);
// Debug
printk("HELLO: this is hello module speaking\n");
return 0;
}
/* Cleanup routine */
void cleanup_module(){
printk("HELLO : Goodbye!\n");
nf_unregister_net_hook(&init_net,&post_hook);
}
obj-m+=NetKernal.o
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
这是我连接到 ftp 服务器并在局域网上输入用户名和密码时的 整个 demsg 输出。
这是添加过滤规则后的整个wireshark数据包:
tcp.dstport == 21
。互联网层字节以pcapng中的偏移量0xe
开始。
这些ftp数据包有什么奇怪的。以第四个数据包为例。
/**/
是我为了更好理解而添加的注释)[ 4964.195893] Packet hex dump:
[ 4964.195904] 000000 45 10 00 42 D9 86 40 00 40 06 DD BC C0 A8 01 07 /* dump start from Internet layer */
[ 4964.195953] 000010 C0 A8 01 0B 93 E4 00 15 A5 63 17 A8 92 28 25 E3
[ 4964.195982] 000020 80 18 01 F6 83 97 00 00 01 01 08 0A C0 EC BD AB
[ 4964.196011] 000030 00 08 A7 2F 00 00 00 00 00 00 00 00 00 00 00 00 /* ftp content:0x00 */
[ 4964.196038] 000040 00 00
[ 4964.196045] hex : data[0-3] = 0x00000000
[ 4964.196049] char: data[0-3] =
[ 4964.196052] --------------- findpkt_iwant ------------------
No. Time Source Source Port Destination Destination Port Protocol Length Info
132 14.635575358 192.168.1.7 37860 192.168.1.11 21 FTP 80 Request: USER ftpuser
Frame 132: 80 bytes on wire (640 bits), 80 bytes captured (640 bits) on interface wlp3s0, id 0
Ethernet II, Src: 58:a0:23:05:3b:2e, Dst: 1c:c1:de:65:e5:d4
Internet Protocol Version 4, Src: 192.168.1.7, Dst: 192.168.1.11
Transmission Control Protocol, Src Port: 37860, Dst Port: 21, Seq: 1, Ack: 28, Len: 14
File Transfer Protocol (FTP)
[Current working directory: ]
0000 1c c1 de 65 e5 d4 58 a0 23 05 3b 2e 08 00 45 10 ...e..X.#.;...E. /* # Internet layer starts from the offset 0x0e */
0010 00 42 d9 86 40 00 40 06 dd bc c0 a8 01 07 c0 a8 .B..@.@.........
0020 01 0b 93 e4 00 15 a5 63 17 a8 92 28 25 e3 80 18 .......c...(%...
0030 01 f6 ab 01 00 00 01 01 08 0a c0 ec bd ab 00 08 ................
0040 a7 2f 55 53 45 52 20 66 74 70 75 73 65 72 0d 0a ./USER ftpuser..
可以看到,ftp数据包的内容是
0x00
,但是整个数据包的长度是正确的(在互联网层之上)。并且所有其他ftp数据包都有同样的问题。看来 sk_buff 没有获取 ftp 数据。
由于wireshark可以获取正确的数据包,我不认为这是防火墙的问题。
0x00
而数据包的长度却是正确的?任何帮助将不胜感激。
嗯,我想你遇到了和我一样的情况,你无法过滤/记录任何类型的 TCP 有效负载,我使用的是带有内核 5.18.x 的 arch Linux,我必须使用 netfilter TCP 数据包有效负载过滤支持重新编译内核为了让它工作,另一个有趣的事实是我也不能使用nftables的字符串匹配,因为它根本不起作用!,wireshark有一个不同的故事,我认为它使用一个单独的TAP或其他东西而不是 netfilter 来监视有效负载,此时我不太记得必须启用哪些内核选项才能使 netfilter TCP 有效负载跟踪器正常工作,但是给它一个搜索,它的全部我可以帮忙。
请记住(正如我的经验告诉我的那样),每当您遇到此类奇怪的问题时:获得意外的空结果,或者您发现它们无法修复的任何奇怪错误,或者根本没有任何意义,在大多数情况下必须与您的内核相关(又名内核配置):
例如: