【发布时间】:2022-08-03 13:34:05
【问题描述】:
Netfilter 内核模块未获取 FTP 数据包数据
问题
我一直在尝试编写一个内核模块来通过 netfilter 读取传出的 FTP 数据包的用户名、密码和 cmd。当我测试我的代码时,我发现 ftp 数据包的长度是正确的,但是我得到的所有数据都是0x00 检查内核模块的输出时。
代码
这是我的代码。我写了一个pkt_hex_dump 函数来将我所有的数据包的字节转储到 Internet 层(包括 Internet 层)之上,这符合 Printing sk_buff data:
/* 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);
}
环境
- Linux 5.13.0-37-通用 x86_64 GNU/Linux
- Ubuntu 20.04.4 LTS
- 生成文件:
obj-m+=NetKernal.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
内核模块的输出和 Wireshark 的捕获:
-
这是the whole demsg output,当我连接到 ftp 服务器并在局域网上输入我的用户名和密码时。
-
这是添加过滤规则后的整个wireshark packet:
tcp.dstport == 21。Internet 层字节以 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 ------------------
- 这是根据以下内容的wireshark捕获数据包:
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,但是整个数据包的长度是正确的(在Internet层之上)。所有其他的ftp数据包都有同样的问题。似乎 sk_buff 没有得到 ftp 数据。
由于wireshark可以得到正确的数据包,我不认为它是防火墙的问题。
我的问题是:
- 为什么所有 ftp 数据包的内容都是
0x00而数据包的长度是正确的? - 我的 ftp 数据在 struct sk_buff 中的什么位置或存储在其他位置?
- 是否有人遇到过同样的问题?
任何帮助将不胜感激。
标签: c linux-kernel network-programming kernel-module netfilter