Featured image of post 使用 Go 对TCP数据进行抓包分析

使用 Go 对TCP数据进行抓包分析

场景需求

在一个系统中,内部网络开放了Socks5代理(代理软件是V2ray),采用了账号密码的方式进行授权;在这个过程中需要对使用代理的客户端进行日志监控,主要包括来源IP、登录账号以及活动时间。

谷歌了一圈,发现Golang已经有一个很强大的Gopacket包,能对设备网卡进行直接抓包,解包等操作,而正好解决上面我的需求;但该包的功能并不仅限于此,比如拦截修改貌似也能做到,只是这里暂不需要所以没有深入。

Ps:其实要实现这个需求,也可以选择硬刚v2ray的源代码,加上需要实现的功能,然后重新编译运行也行;但是初学Golang,看了V2ray的源码 还有很多疑惑的地方,所以本文这种“笨方法”只能说是一种权宜之策吧。

抓包分析

在socks5的认证过程中,客户端会将账号密码明文形式发送给服务端,而我们要做的就是抓下这个数据包;在服务端配置的所有账号密码中,账号密码必然会带有meg这个关键词,开放的端口是6688,传输的数据长度必然小于128个字节。

所以过滤器规则便是:抓取所有TCP中,目的端口是6688,数据长度小于128字节,抓取之后取出TCP的承载数据并且含有关键词meg,精准命中。

socks 认证.png

** Ps:在写本文回忆的时候,突然发现此方法依然存在一些问题,比如如果有人恶意伪造数据包呢?直接拉低整个监控日志的有效性,看来选择直接修改V2ray才能避免此类情况。 **

源码Demo

 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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

package main

import (
	"bytes"
	"fmt"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"log"
	"time"
)

func main() {
	port := "6688"
	device := "eth0"

	log.Println("开始监控数据:" + device)

	handle, err := pcap.OpenLive(device, 1024, false, 30*time.Second)
	if err != nil {
		log.Fatal(err)

		return
	}

	defer handle.Close()

	// 过滤规则,指定TCP协议,指定端口
	var filter = fmt.Sprintf("tcp and port %s and len <= 128", port)

	err = handle.SetBPFFilter(filter)
	if err != nil {

		log.Fatal(err)
	}

	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	for packet := range packetSource.Packets() {
		// 过滤需要抓包的数据关键词,ASCII
		meg := []byte{109, 101, 103}
		data := packet.Data()
		if !bytes.Contains(data, qimeng) {

			continue
		}

		// 解析TCP数据
		ipLayer := packet.Layer(layers.LayerTypeIPv4)
		tcpLayer := packet.Layer(layers.LayerTypeTCP)
		if tcpLayer == nil {

			continue
		}

		// IP层
		ip, _ := ipLayer.(*layers.IPv4)

		// TCP层
		tcp, _ := tcpLayer.(*layers.TCP)

		// TCP负载数据
		tcpData := tcpLayer.LayerPayload()

		// 来源IP
		srcIp := ip.SrcIP.String()

		// 来源端口
		srcPort := tcp.SrcPort.String()

		// 解析来自 SOCKS5 客户端的账号密码数据
		userLen := tcpData[1]
		username := string(tcpData[2 : 2+userLen])
		passLen := userLen + 2 + 1
		password := string(tcpData[passLen:])

		log.Printf("账号:%s(%s) 上线成功,来源地址:%s:%s", username, password, srcIp, srcPort)
	}
}

参考文章

  1. https://colobu.com/2019/06/01/packet-capture-injection-and-analysis-gopacket/
  2. https://juejin.cn/post/6844903923518537741
本文采用 CC BY 4.0 协议,转载请署名并注明出处。
最后更新于 2021-07-21 16:12:53
使用 Hugo 构建
主题 StackJimmy 设计