news 2026/3/29 0:48:17

NetBIOS实现主机探测(包含完整实现代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
NetBIOS实现主机探测(包含完整实现代码)

目录

前言

NetBIOS

什么是 NetBIOS?

NetBIOS 核心服务

NetBIOS 到底干什么用?

1. 名字解析(主要功能)

2. 服务发现

3. 会话管理

探测原理

存活判断的标准

代码设计思路

两阶段扫描架构

状态机设计

模块1: NetBIOS探测模块

模块2: 协议验证模块

代码分析

构造探测数据

建立连接并发送探测数据

接受并分析响应

源代码

其它


前言

判断存活的标准是服务开启+端口开启,下面进行详细讲解,这种探测方式不太常用。


NetBIOS

什么是 NetBIOS?

网络基本输入/输出系统

NetBIOS(Network Basic Input/Output System)是1983年由IBM开发的网络协议,为局域网应用程序提供统一的命令集。虽然现在逐渐被DNS取代,但在Windows网络中仍然广泛使用。

NetBIOS 核心服务

端口

协议

服务名称

功能

137/UDP

NetBIOS名称服务

NBNS

主机名解析、名称注册查询

138/UDP

NetBIOS数据报服务

NBDS

网络广播、消息传递

139/TCP

NetBIOS会话服务

NBSS

文件/打印机共享连接

NetBIOS 到底干什么用?

1.名字解析(主要功能)

你想联系"财务部电脑",但不知道它的IP地址 → 问NetBIOS:"财务部电脑的IP是多少?" → NetBIOS回答:"192.168.1.105"

2.服务发现

你想知道网络里有哪些电脑共享了打印机 → 问NetBIOS:"谁共享了打印机?" → NetBIOS回答:"技术部电脑、前台电脑"

3.会话管理

你要访问"技术部电脑"的共享文件夹 → NetBIOS帮你建立稳定连接

探测原理

基于NetBIOS名称服务协议

  • 协议: NetBIOS Name Service (NBNS)
  • 端口: UDP 137
  • 机制: 通过发送特定的NetBIOS状态查询包,根据响应判断主机存活状态

存活判断的标准

udp的137端口开启且netbios服务开启


代码设计思路

两阶段扫描架构

阶段1: 主机发现 (TCP端口扫描) → 阶段2: NetBIOS服务探测 (UDP 137端口)

设计理念:先找到存活主机,再针对性地探测服务,避免对不存在的主机进行无谓的UDP探测。

状态机设计

定义了清晰的三种状态:

  • alive: 收到有效的NetBIOS响应
  • filtered: 主机存活但NetBIOS无响应(端口被过滤)
  • dead: 主机不存活或NetBIOS服务关闭

模块1: NetBIOS探测模块

// 设计思路:UDP协议状态探测 输入: 存活主机IP 输出: NetBIOS状态结果 策略: 发送标准NetBIOS查询包,根据响应判断服务状态

模块2: 协议验证模块

// 设计思路:协议格式验证 输入: 原始网络数据 输出: 是否为有效NetBIOS响应 策略: 检查数据包长度和标志位(QR位)

代码分析

构造探测数据

func createNetBIOSQuery() []byte { return []byte{ 0x12, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4B, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21, 0x00, 0x01, } }

这是一个NetBIOS名称服务状态查询包

这个查询包的作用是:

  • 查询类型: NetBIOS节点状态查询 (NBSTAT)
  • 目标: 请求目标主机返回其NetBIOS名称表
  • 响应内容: 包括主机名、服务类型、MAC地址等

当这个包发送到目标的137端口时:

  • 如果主机存在且运行NetBIOS服务,会返回节点状态信息
  • 如果主机不存在或服务关闭,会超时或无响应
  • 响应包包含详细的NetBIOS名称表和MAC地址

建立连接并发送探测数据

func netbios_scan_survival(ipaddres []string) { // 阶段1: NetBIOS扫描(只对存活主机) fmt.Println("阶段1: NetBIOS扫描...") sem := make(chan struct{}, 50) for _, ip := range aliveHosts { wg.Add(1) go func(ip string) { defer wg.Done() sem <- struct{}{} defer func() { <-sem }() result := netbiosProbe(ip) mu.Lock() if result.Status != "dead" { results = append(results, result) } mu.Unlock() }(ip) } wg.Wait() ...... } // NetBIOS探测 - 只对已知存活的主机进行 func netbiosProbe(ip string) NetBIOSResult { result := NetBIOSResult{ IP: ip, Status: "dead", Port137: "关闭", } // UDP 137端口探测 conn, err := net.DialTimeout("udp", fmt.Sprintf("%s:%d", ip, 137), 3*time.Second) if err != nil { return result } defer conn.Close() conn.SetDeadline(time.Now().Add(3 * time.Second)) // 发送查询 query := createNetBIOSQuery() if _, err := conn.Write(query); err != nil { return result } ...... return result }

接受并分析响应

// NetBIOS探测 - 只对已知存活的主机进行 func netbiosProbe(ip string) NetBIOSResult { result := NetBIOSResult{ IP: ip, Status: "dead", Port137: "关闭", } ...... // 接收响应 buffer := make([]byte, 1024) n, err := conn.Read(buffer) if err != nil { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { // 已知存活的主机 + UDP超时 = open|filtered result.Status = "filtered" result.Port137 = "开放或被过滤" } return result } // 收到有效响应 if n > 0 && validateNetBIOSResponse(buffer[:n]) { result.Status = "alive" result.Port137 = "开放" } return result } // 验证 NetBIOS 响应 func validateNetBIOSResponse(data []byte) bool { if len(data) < 12 { return false } // 检查响应标志位 (第3字节的最高位) flags := binary.BigEndian.Uint16(data[2:4]) isResponse := (flags & 0x8000) != 0 // 检查答案数量 answerCount := binary.BigEndian.Uint16(data[6:8]) //之前的代码没有,新添加的 return isResponse && answerCount > 0 }

长度检查

if len(data) < 12 { return false }
  • 原因: NetBINS响应包头部至少12字节
  • 作用: 过滤掉太短的无意义数据包

提取标志位

flags := binary.BigEndian.Uint16(data[2:4])
  • 位置: 数据包的第3-4字节(0-based索引2:4)
  • 格式: 大端序16位无符号整数
  • 含义: 提取NetBIOS响应标志字段

源代码

直接给出完整源代码

https://github.com/yty0v0/ReconQuiver/blob/main/internal/discovery/netbios_host/netbios.go


其它

在我写完针对多协议端口扫描和主机探测的工具后,希望通过文章整理用到的知识点,非常欢迎各位大佬指正文章内容的错误和工具的问题。

这里附上工具链接 https://github.com/yty0v0/ReconQuiver

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/25 13:27:35

如何写出优秀的单元测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快写出优秀的单元测试需要考虑以下几个方面&#xff1a;1. 测试用例设计测试用例应该覆盖被测试代码的不同场景和边界情况&#xff0c;以尽可能发现潜在的问题。在设计…

作者头像 李华
网站建设 2026/3/25 12:08:38

LLM - 从 Prompt 到上下文工程:面向 Java 的生产级 AI Agent 设计范式

文章目录引言&#xff1a;从“会写代码”到“能托付工作”Agent 能力边界与安全前提Prompt 注入威胁的现实形态多层防注入策略&#xff1a;从模型到框架工具设计&#xff1a;从“能用”到“好用又安全”工具调用策略&#xff1a;循环而非流水线上下文工程&#xff1a;从 Prompt…

作者头像 李华
网站建设 2026/3/25 16:07:18

完结 风哥Oracle RAC+DG生产实战(4):Oracle21c RAC DataGuard搭建2+2

如何高效掌握《Oracle 21c RAC DataGuard 22架构实战指南》并生成技术文章想要快速且有效地消化这篇架构实战指南&#xff0c;并将其精髓转化为一篇属于自己的技术文章&#xff0c;可以遵循以下系统化的学习与写作路径。这不仅适用于本文&#xff0c;也是学习任何复杂技术文档的…

作者头像 李华
网站建设 2026/3/27 13:57:55

AudioGen文本到音频生成技术深度解析

AudioGen文本到音频生成技术深度解析 【免费下载链接】audiocraft Audiocraft is a library for audio processing and generation with deep learning. It features the state-of-the-art EnCodec audio compressor / tokenizer, along with MusicGen, a simple and controlla…

作者头像 李华
网站建设 2026/3/27 16:02:57

泛型的相关知识

定义类、接口、方法时&#xff0c;同时声明了一个或多个类型变量&#xff08;如&#xff1a;<E>&#xff09;&#xff0c;称为泛型类、泛型接口、泛型方法&#xff0c;他们统称为泛型。public class ArrayList<E> {//... }作用&#xff1a;泛型提供了在编译阶段约束…

作者头像 李华
网站建设 2026/3/28 9:55:17

微信小程序开发实战之 02-微信小程序页面制作

页面制作概述 WXML 概述 在制作微信小程序页面时&#xff0c;页面的结构可以用 WXML 来实现。 WXML 是微信团队为微信小程序开发而设计的一套语言&#xff0c;可以结合微信小程序中的各种组件构建页面结构。 WXML 与 HTML 的区别&#xff1a; HTML 和 WXML 使用的标签不同。HTM…

作者头像 李华