这个题目一看就知道这位同学是网络安全相关专业。
很多粉丝以为彭老师知识搞驱动的,
但是其实作为一个拥有多篇网络协议专利的老鸟,
网络知识还是比较擅长的!
应用层套接字、组网、网卡驱动都有所涉猎,
目前还缺Linux内核协议栈这块没深入研究,后期会补上。
题目要求是扫描所有TCP半连接的端口,需要实现的功能如下:
解决这个问题必须掌握以下几个知识点:
整体来说对网络知识的基本功要求还是很高的。
关于TCP/IP协议栈这些基础知识点的本文就不列举了。
下面主要强化下这个题目涉及的TCP的知识点。
序列号:
在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题
确认应答号:
指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决不丢包的问题
控制位:
ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1
RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接
SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定
FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位置为 1 的 TCP 段
与本题目相关的是最主要字段是控制位,控制位的操作最主要体现在3次握手和4次握手。
开始客户端和服务器都处于CLOSED状态,然后服务端开始监听某个端口,进入LISTEN状态:
四次挥手过程:
更详细 tcp知识点可以参考下面文章:
《28 张图,一次性说清楚 TCP》
TCP半连接及全连接状态,在服务器的性能分析中,起着重要的作用,它通常是反应服务端的处理能力
客户端发送SYN包,服务端收到后回复SYN+ACK后,服务端进入SYN_RCVD状态,这个时候的socket会放到半连接队列。
当服务端收到客户端的ACK后,socket会从半连接队列移出到全连接队列。当调用accpet函数的时候,会从全连接队列的头部返回可用socket给用户进程。
全连接队列中存放的是已完成TCP三次握手的过程,等待被处理的连接,在客户端及服务端的状态均为 ESTABLISHED
要想学好网络,抓包工具是必须掌握的。
下图是一口君通过抓包工具抓取的一个完整的 tcp 3次握手 + HTTP GET请求 + 4次握手 的完整通信数据包。
如何抓包,可以参考下面文章:
《一文包你学会网络数据抓包》
B站也有详细的教学视频:
《教你如何抓取网络中的数据包!黑客必备技能》
https://www.bilibili.com/video/BV1xr4y1T7cT/?vd_source=07570058a62e0e8a6cf489efac35cfec
关于socket API内容,大家可以的参考下面这篇文章
《socket到底是什么?》
libpcap是一个网络数据包捕获函数库,功能非常强大,Linux下著名的tcpdump就是以它为基础的。
libpcap主要由两部分组成:网络分接头(network tap)和数据过滤器(packet filter)。
网络分接头从网络设备驱动程序中收集数据进行拷贝,过滤器决定是否接收该数据包。
libpcap利用BSD packet filter(BPF)算法对网卡接收到的链路层数据包进行过滤。
libpcap的包捕获机制就是在数据链路层加一个旁路处理。当一个数据包到达网络接口时,libpcap首先利用已经创建的套接字从链路层驱动程序中获得该数据包的拷贝,再通过Tap函数将数据包发给BPF过滤器。
BPF过滤器根据用户已经定义好的过滤规则对数据包进行逐一匹配,匹配成功则放入内核缓冲区,并传递给用户缓冲区,匹配失败则直接丢弃。
如果没有设置过滤规则,所有数据包都将放入内核缓冲区,并传递给用户层缓冲区。
sudo apt-get install libpcap-dev
这种适合有网络的朋友
如何无法安装尝试更新下源:
sudo apt-get update
http://www.tcpdump.org/#latest-release
然后解压
tar zxvf libpcap-1.10.3.tar.gz
cd libpcap-1.10.3
./configure
sudo make
sudo make install
struct pcap_pkthdr {
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* 抓到的数据包实际长度 */
bpf_u_int32 len; /*数据包的长度 */
};
关于libcap的详细讲解,后续会出文章,
本文只讲几个重要的函数。
//这个函数会返回指定接口的pcap_t类型指针,后面的所有操作都要使用这个指针。
pcap_t * pcap_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)
device:网络接口字符串,可以直接使用硬编码,比如eth0。
snaplen:对于每个数据包,从开头要抓多少个字节,我们可以设置这个值来只抓每个数据包的头部,而不关心具体的内容。典型的以太网帧长度是1518字节,但其他的某些协议的数据包会更长一点,但任何一个协议的一个数据包长度都必然小于65535个字节。
promisc:指定是否打开混杂模式(Promiscuous Mode),0表示非混杂模式,任何其他值表示混合模式。如果要打开混杂模式,那么网卡必须也要打开混杂模式,可以使用如下的命令打开eth0混杂模式:ifconfig eth0
to_ms:抓包时长单位为毫秒,0标示一直等待。
errbuf: 输出参数,打开网络接口失败原因。
pcap_t * pcap_open_offline (const char *fname, char *errbuf)
fname :文件名称。
errbuf :打开失败的错误信息。
int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
p: 打开的pcap_t类型指针。
cnt:一共抓多少个包,如果为负数就一直循环。
callback:回调函数指针
user:传递给回调函数的参数。
void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
userarg:是pcap_loop的最后一个参数,当收到足够数量的包后pcap_loop会调用callback回调函数,同时将pcap_loop()的user参数传递给它
pkthdr: 抓到的报文头信息。
packet:收到的包的数据。
int pcap_compile(pcap_t * p, struct bpf_program * fp, char * str, int optimize, bpf_u_int32 netmask)
//fp:这是一个传出参数,存放编译后的bpf
//str:过滤表达式
//optimize:是否需要优化过滤表达式
//metmask:简单设置为0即可
int pcap_setfilter(pcap_t * p, struct bpf_program * fp)
//参数fp就是pcap_compile()的第二个参数,存放编译后的bpf
void pcap_close(pcap_t * p)
//该函数用于关闭pcap_open_live()获取的pcap_t的网络接口对象并释放相关资源。
pcap_dumper_t * pcap_dump_open (pcap_t *p, const char *fname)
//p:是我们已经打开的网络设备,从这个设备接收数据包。
// fname:是我们要写入的文件名,随便起。
//return: 如果出错,会返回NULL。可以借此检查这个文件有没有打开。
void pcap_dump (u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
user:就是文件描述符dumpfp,只不过要做一下类型转换。
由于这个函数一般在pcap_loop()的函数指针所指向的packet_handler中使用,所以packet_handler中的user就是这里的user。
h:就是pkt_header
pcap_dump_close(pcap_dumper_t * t);
一些过滤表达式的例子如下:
src host 192.168.1.177
dst port 80
not tcp
tcp[13] == 0x02 and (dst port 22 or dst port 23)
icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo
ether dst 00:e0:09:c1:0e:82
只接收ip的ttl=5的数据包(ip首部开始的第8个字节)
ip[8] == 5
本例只抓取ip地址为本地IP的数据包,然后程序再对数据包协议头进行解析:
host 192.168.0.113
atach、cap进程运行在ubuntu中,要攻击的目的终端可以使网络中任意设备,只需要能ping通即可。
本例在windows上测试,采用桥接模式将ubuntu的网口和windows的网口桥接起来。
atach进程主要功能:
cap进程主要功能:
windows ip:192.168.0.116
ubuntu ip:192.168.0.113
peng@ubuntu:~/work/test/pcap$ ls
atach header.c libpcap-1.10.3.tar.gz cap.c
cap libpcap-1.10.3 atach.c protocol.h
其中atach是上攻击方,用于向指定ip发送sync包
cap 用于检测所有网卡收到的sync+ack数据包
程序运行在ubuntu中。
在windows上启动网络调试助手,
建立几个Tcp Server,端口号分别为55、56、57
peng@ubuntu:~/work/test/pcap$ sudo ./cap 192.168.0.116
found device: eth0
netaddr:0000a8c0
try to open device eth0
filter:host 192.168.0.116
需要新开启一个终端。
peng@ubuntu:~/work/test/pcap$ ./atach 192.168.0.116
右边log可见,列举出了所有可以访问的端口,包括55、56、57。
注意:
那个单词atach故意少了一个t,否则编译不过去:
大家可以试试你们的编译器,刑不刑!
代码已经同步到gitee,地址如下:
https://gitee.com/yikoulinux/pcap.git
更多嵌入式、Linux、网络知识,后台留言加一口君好友!