gopacket 抓包实战基础 介绍 库地址:https://gitHub.com/google/gopacket
几个耳熟能详的抓包工具:
wireshark:依赖npcap
tcpdump:依赖libpcap
gopacket 是libpcap 和npcap的go封装, 是一个基于go语言实现的网络数据包解析库
1 2 3 4 5 6 7 yum install -y libpcap libpcap-devel go get gitHub.com/google/gopacket
指定eth0网卡 抓包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package mainimport ( "fmt" "log" "time" "github.com/google/gopacket" "github.com/google/gopacket/pcap" ) func main () { handler, err := pcap.OpenLive("eth0" , 1024 , false , time.Second*5 ) if err != nil { log.Fatalln(err) } defer handler.Close() source := gopacket.NewPacketSource(handler, handler.LinkType()) for packet := range source.Packets() { if tcpLayer := packet.TransportLayer(); tcpLayer != nil { fmt.Println(tcpLayer) } } }
执行这个程序,大概会输出这样的数据:
抓取指定http的包 准备一个程序:
1 2 3 4 5 6 7 8 9 10 11 12 package mainimport "net/http" func main () { http.HandleFunc("/" , func (writer http.ResponseWriter, request *http.Request) { writer.Write([]byte ("hello world" )) }) http.ListenAndServe(":8080" , nil ) }
运行这个程序
修改抓包的代码,获取tcp层的数据,并且只抓取8080端口的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package mainimport ( "fmt" "log" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" ) func main () { handler, err := pcap.OpenLive("eth0" , 1024 , false , time.Second*5 ) if err != nil { log.Fatalln(err) } defer handler.Close() source := gopacket.NewPacketSource(handler, handler.LinkType()) for packet := range source.Packets() { if layer4 := packet.TransportLayer(); layer4 != nil { if tcpLayer, ok := layer4.(*layers.TCP); ok && tcpLayer.DstPort == 8080 { fmt.Println(string (tcpLayer.Payload)) } } } }
直接执行
访问http程序,此时抓包数据如下:只抓取了请求的数据
如果使用GET请求中 传输body数据,从下图中很清楚的知道,body信息是明文的
借助gopacket理解三次握手 简单回顾一下tcp三次握手
客户端在向服务端发送数据 建立连接之前,需要建立三次握手,客户端发送SYN包,服务端应答发送ACK包。
准备tcp程序
tcp服务端代码 tcpserver.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package mainimport ( "fmt" "log" "net" ) func main () { l, err := net.Listen("tcp" , "0.0.0.0:8080" ) if err != nil { log.Fatalln(err) } for { conn, err := l.Accept() if err != nil { log.Fatalln(err) } fmt.Printf("Receive message %s -> %s\n" , conn.RemoteAddr(), conn.LocalAddr()) go handler(conn) } } func handler (conn net.Conn) { for { buf := make ([]byte , 1024 ) num, err := conn.Read(buf) if err != nil { fmt.Println(err) break } fmt.Printf("Receive data:%v\n" , string (buf[:num])) num, err = conn.Write([]byte ("ok" )) if err != nil { fmt.Println(err) break } } }
相应的客户端 tcpclient.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package mainimport ( "log" "net" "time" ) func main () { conn, err := net.Dial("tcp" , "147.112.58.137:8080" ) if err != nil { log.Fatalln(err) } for { _, err := conn.Write([]byte ("hello" )) if err != nil { log.Fatalln(err) } time.Sleep(time.Second * 2 ) } }
抓包的程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package mainimport ( "fmt" "log" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" ) func main () { handler, err := pcap.OpenLive("eth0" , 1024 , false , time.Second*5 ) if err != nil { log.Fatalln(err) } defer handler.Close() source := gopacket.NewPacketSource(handler, handler.LinkType()) for packet := range source.Packets() { if layer4 := packet.TransportLayer(); layer4 != nil { if tcpLayer, ok := layer4.(*layers.TCP); ok { if tcpLayer.DstPort == 8080 || tcpLayer.SrcPort == 8080 { fmt.Printf("%d-->%d, SYN=%v, ACK=%v, payload length=%v\n" , tcpLayer.SrcPort, tcpLayer.DstPort, tcpLayer.SYN, tcpLayer.ACK, len (tcpLayer.Payload)) } } } } }
依次启动服务端、抓包程序、客户端程序
通过抓包,我们也得知 客户端向服务端发送SYN,没有ACK包,服务端接收到之后,发送ACK包,且发送自己的SYN包。
三次握手 seq和ack的作用 seq和ack是啥(和SYN、ACK不是一回事):
序号(sequence number):seq序号,标识从TCP源端口向目的端口发送的字节流,发起方发送数据时对次进行标记。
确认号(acknowledgement number):ack序号,占32位,只有ACK标识位为1时,确认号字段才有效,ack=seq+1
两者用于确认数据是否准确,是否能正常通信。
大概的过程:
第一次握手:seq为x(x为任意值),无ack number
第二次握手:seq为y(y为任意值),ack number=接受包seq+1(即x+1)
第三次握手:seq等于上一个本机发送包seq+1(即x+1),ack number等于接受包seq+1(即y+1)
修改抓包的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package mainimport ( "fmt" "log" "time" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" ) func main () { handler, err := pcap.OpenLive("eth0" , 1024 , false , time.Second*5 ) if err != nil { log.Fatalln(err) } defer handler.Close() source := gopacket.NewPacketSource(handler, handler.LinkType()) for packet := range source.Packets() { if layer4 := packet.TransportLayer(); layer4 != nil { if tcpLayer, ok := layer4.(*layers.TCP); ok { if tcpLayer.DstPort == 8080 || tcpLayer.SrcPort == 8080 { fmt.Printf("%d-->%d, SYN=%v, ACK=%v, payload length=%v, seq=%v, ackNum=%v\n" , tcpLayer.SrcPort, tcpLayer.DstPort, tcpLayer.SYN, tcpLayer.ACK, len (tcpLayer.Payload), tcpLayer.Seq, tcpLayer.Ack, ) } } } } }
SYN攻击原理、简单模拟
SYN攻击:
攻击者发送大量的SYN包,源IP是伪造的,服务器回应(SYN+ACK)包,攻击者不回应ACK包
服务器不止带(SYN+ACK)是否发送成功,默认情况下5次 (tcp_syn_retries) cat /etc/sysctl.conf
使用工具 hping3
一款TCP/IP数据包编辑器/分析器,常用来做安全审计、防火墙测试等工作。支持TCP、UDP、ICMP和RAW-IP协议,具有跟踪路由模式,在覆盖通道之间发送文件的功能以及许多其他功能(如SYN攻击)
1 2 3 4 5 6 7 8 9 10 yum install hping3 -y hping3 -I eth0 -c 1 -a 192.168.10.60 172.31.107.15 --syn -p 8080 hping3 -I eth0 -c 1 172.31.107.15 --syn -p 8080