用Go開發可以內網活躍主機嗅探器

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

文章關鍵詞

  • go/golang
  • gopacket
  • 抓包
  • pcap/libpcap
  • arp
  • nbns
  • mdns
  • manuf

程式


說明

本文對於Go語言本身的講解不會太多,想把更多的時間花在幾個網路通訊協定的講解上,希望本文對打算或正在用Go進行TCP/IP編程和抓包的朋友帶來協助。
github地址:https://github.com/timest/goscan

程式思路

  • 通過內網IP和子網路遮罩計算出內網IP範圍
  • 向內網廣播ARP Request
  • 監聽並抓取ARP Response包,記錄IP和Mac地址
  • 發活躍IP發送MDNS和NBNS包,並監聽和解析Hostname
  • 根據Mac地址計算出廠家資訊

通過內網IP和子網路遮罩計算出內網IP範圍

如果僅僅只是知道一個IP地址,是無法得知內網IP的網段,不能只是簡單的把本機IP的最後一個位元組改成1-255。需要通過子網路遮罩來計算得出內網的網段,這塊比較簡單,這裡不贅述了,有疑問的網上搜尋子網路遮罩擷取更多資料。值得一提的是IP地址的最後一個欄位是不能為0和255,前者是RFC規定,後者一般是廣播位址。

// 單網卡模式addrs, err := net.InterfaceAddrs()if err != nil {   log.Fatal("無法擷取本網資訊:", err)}for i, a := range addrs {   if ip, ok := a.(*net.IPNet); ok && !ip.IP.IsLoopback() {       if ip.IP.To4() != nil {           fmt.Println("IP:", ip.IP)           fmt.Println("子網路遮罩:", ip.Mask)           it, _ := net.InterfaceByIndex(i)           fmt.Println("Mac地址:", it.HardwareAddr)           break       }   }}

根據上面得到的IPNet,可以算出內網IP範圍:

type IP uint32// 根據IP和mask換算內網IP範圍func Table(ipNet *net.IPNet) []IP {    ip := ipNet.IP.To4()    log.Info("本機ip:", ip)    var min, max IP    var data []IP    for i := 0; i < 4; i++ {        b := IP(ip[i] & ipNet.Mask[i])        min += b << ((3 - uint(i)) * 8)    }    one, _ := ipNet.Mask.Size()    max = min | IP(math.Pow(2, float64(32 - one)) - 1)    log.Infof("內網IP範圍:%s --- %s", min, max)    // max 是廣播位址,忽略    // i & 0x000000ff  == 0 是尾段為0的IP,根據RFC的規定,忽略    for i := min; i < max; i++ {        if i & 0x000000ff == 0 {            continue        }        data = append(data, i)    }    return data}

向內網廣播ARP Request

ARP(Address Resolution Protocol),位址解析通訊協定,是根據IP地址擷取物理地址的一個TCP/IP協議。主機發送資訊時將包含目標IP地址的ARP請求廣播到網路上的所有主機,並接收返回訊息,以此確定目標的物理地址 ------百度百科

當我們要向乙太網路中另一台主機發送IP資料時,我們本地會根據目的主機的IP地址在ARP快取中查詢相應的乙太網路地址,ARP快取是主機維護的一個IP地址到相應乙太網路地址的映射表。如果查詢失敗,ARP會廣播一個詢問(op欄位為1)目的主機硬體地址的報文,等待目標主機的響應。
因為ARP快取有時效性,讀取到目標主機的硬體地址後,最好發送一個ICMP包驗證目標是否線上。當然也可以選擇不從快取裡讀取資料,而是直接並發發送arp包,等待線上主機回應ARP報文。


arp

gopacket有封裝好的ARP報文:

type ARP struct {    BaseLayer    AddrType          LinkType     // 硬體類型    Protocol          EthernetType // 協議類型    HwAddressSize     uint8        // 硬體地址長度    ProtAddressSize   uint8        // 協議地址長度    Operation         uint16       // 操作符(1代表request 2代表reply)    SourceHwAddress   []byte       // 寄件者硬體地址    SourceProtAddress []byte       // 寄件者IP地址    DstHwAddress      []byte       // 目標硬體地址(可以填寫00:00:00:00:00:00)    DstProtAddress    []byte       // 目標IP地址}

給出項目中具體的代碼:

// 發送arp包// ip 目標IP地址func sendArpPackage(ip IP) {    srcIp := net.ParseIP(ipNet.IP.String()).To4()    dstIp := net.ParseIP(ip.String()).To4()    if srcIp == nil || dstIp == nil {        log.Fatal("ip 解析出問題")    }    // 乙太網路首部    // EthernetType 0x0806  ARP    ether := &layers.Ethernet{        SrcMAC: localHaddr,        DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},        EthernetType: layers.EthernetTypeARP,    }        a := &layers.ARP{        AddrType: layers.LinkTypeEthernet,        Protocol: layers.EthernetTypeIPv4,        HwAddressSize: uint8(6),        ProtAddressSize: uint8(4),        Operation: uint16(1), // 0x0001 arp request 0x0002 arp response        SourceHwAddress: localHaddr,        SourceProtAddress: srcIp,        DstHwAddress: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},        DstProtAddress: dstIp,    }        buffer := gopacket.NewSerializeBuffer()    var opt gopacket.SerializeOptions    gopacket.SerializeLayers(buffer, opt, ether, a)    outgoingPacket := buffer.Bytes()        handle, err := pcap.OpenLive(iface, 2048, false, 30 * time.Second)    if err != nil {        log.Fatal("pcap開啟失敗:", err)    }    defer handle.Close()        err = handle.WritePacketData(outgoingPacket)    if err != nil {        log.Fatal("發送arp資料包失敗..")    }}

我們只需要將第一步得到的內網IP表,開啟一個goruntime遍曆發送arp報文就可以。

監聽並抓取ARP Response包,記錄IP和Mac地址

在上一步已經發送了arp請求,只需要開啟一個arp的監聽goruntime,所有有返回arp response包的,就是內網線上的host。

func listenARP(ctx context.Context) {    handle, err := pcap.OpenLive(iface, 1024, false, 10 * time.Second)    if err != nil {        log.Fatal("pcap開啟失敗:", err)    }    defer handle.Close()    handle.SetBPFFilter("arp")    ps := gopacket.NewPacketSource(handle, handle.LinkType())    for {        select {        case <-ctx.Done():            return        case p := <-ps.Packets():            arp := p.Layer(layers.LayerTypeARP).(*layers.ARP)            if arp.Operation == 2 {                mac := net.HardwareAddr(arp.SourceHwAddress)                pushData(ParseIP(arp.SourceProtAddress).String(), mac, "", manuf.Search(mac.String()))                go sendMdns(ParseIP(arp.SourceProtAddress), mac)                go sendNbns(ParseIP(arp.SourceProtAddress), mac)            }        }    }}

發活躍IP發送MDNS和NBNS包,並監聽和解析hostname

在上一步的過程中,我們在接受到一個arp的response後,就可以發起mdns和nbns包等待hostname的返回。

go sendMdns(ParseIP(arp.SourceProtAddress), mac)go sendNbns(ParseIP(arp.SourceProtAddress), mac)

mDNS:往對方的5353連接埠和01:00:5E:00:00:FB的mac地址發送UDP的mdns(Multicast DNS)包,如果目標系統支援,回返回host name。詳細協議介紹和報文格式可以查看維基百科的介紹。
NBNS:也是一個種常見的查看目標機器hostname的一種協議,和mDNS一樣,傳輸層也是UDP,連接埠是在137。
篇幅太長了,具體的代碼請看github上的nbns.go 和 mdns.go。

根據Mac地址計算出廠家資訊

我們可以通過目標主機的硬體地址,擷取到裝置的生產廠家資訊。這樣的話,即使遇到防禦比較好的系統,我們無法擷取到hostname,也能從廠家資訊裡擷取一定的資訊量,比如廠家資訊是oneplus或則Smartisan,就可以判斷是手機了
manuf檔案,檔案片段:

00:03:8F    Weinsche    Weinschel Corporation00:03:90    DigitalV    Digital Video Communications, Inc.00:03:91    Advanced    Advanced Digital Broadcast, Ltd.00:03:92    HyundaiT    Hyundai Teletek Co., Ltd.00:03:93    Apple   Apple, Inc.00:03:94    ConnectO    Connect One00:03:95    Californ    California Amplifier00:03:96    EzCast  EZ Cast Co., Ltd.00:03:97    Watchfro    Watchfront Limited

代碼不貼了,直接看代碼,100行不到的代碼,還是挺簡單的:manuf.go。測試結果99%的mac地址都能映射到相應的廠商資訊。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.