Fscan源码分析¶
fscan 发现域控的原理¶
代码实现¶
NetBIOS.go
senddata1 := []byte{102, 102, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 32, 67, 75, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, 0, 33, 0, 1}
realhost := fmt.Sprintf("%s:137", info.Host)
conn, err := net.DialTimeout("udp", realhost, time.Duration(common.Timeout)*time.Second)
当扫描到139
端口,向137
端口发送udp
数据以获取NetBios
,根据返回数据判别主机信息
func ParseNetBios(input []byte) (netbios NetBiosInfo, err error) {
if len(input) < 57 {
err = errNetBIOS
return
}
data := input[57:]
var num int
num, err = bytetoint(input[56:57][0])
if err != nil {
return
}
var msg string
for i := 0; i < num; i++ {
if len(data) < 18*i+16 {
break
}
name := string(data[18*i : 18*i+15])
flag_bit := data[18*i+15 : 18*i+16]
if GROUP_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
msg += fmt.Sprintf("%s: %s\n", GROUP_NAMES[string(flag_bit)], name)
} else if UNIQUE_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
msg += fmt.Sprintf("%s: %s\n", UNIQUE_NAMES[string(flag_bit)], name)
} else if string(flag_bit) == "\x00" || len(data) >= 18*i+18 {
name_flags := data[18*i+16 : 18*i+18][0]
if name_flags >= 128 {
msg += fmt.Sprintf("%s: %s\n", GROUP_NAMES[string(flag_bit)], name)
} else {
msg += fmt.Sprintf("%s: %s\n", UNIQUE_NAMES[string(flag_bit)], name)
}
} else {
msg += fmt.Sprintf("%s \n", name)
}
}
if len(msg) == 0 {
err = errNetBIOS
return
}
err = yaml.Unmarshal([]byte(msg), &netbios)
if netbios.DomainName != "" {
netbios.GroupName = netbios.DomainName
}
return
}
ParseNetBios
函数解析通过NBNS
收到的数据,从而根据规则判断主机身份
data := input[57:]
这一行将响应消息的前 57 个字节去掉,类似于协议头
num, err = bytetoint(input[56:57][0])
这行代码读取第 56 个字节,并将它转换为整数 num
。这个字节表示后续的 NetBIOS 名称记录数量。
函数接下来进入一个循环,每次循环处理一个 NetBIOS 名称记录。对于每个名称记录,函数提取 18 字节的数据:15 字节的名称和 1 字节的标志位。名称(name
)是记录的 NetBIOS 名称。标志位(flag_bit
)用于确定该名称是独特的名称还是组名称。根据标志位来决定如何处理每个名称。如果它匹配 UNIQUE_NAMES
或 GROUP_NAMES
中的一个条目,则将对应的名称和类型添加到输出消息中
GROUP_NAMES = map[string]string{
"\x00": "DomainName",
"\x1C": "DomainControllers",
"\x1E": "Browser Service Elections",
}
如果标志位是\x1C
那么就判定为域控