工具|Golang安全开发之NMAP格式IP解析库

  • A+
所属分类:安全工具


工具|Golang安全开发之NMAP格式IP解析库

点击上方蓝字关注我们

0x00 简介

在平时使用golang写一些小工具的时候,ip地址解析是必须要使用的功能之一。很多工具解析ip只是简单的生成C段、B段、A段的全部ip地址,并不支持cidr的方式来灵活的生成ip。比如我们要扫描10.1.1.1/22网段,这时候简单的生成C段B段就不顶事儿了。于是就有了自己实现一个可以将nmap格式的ip地址范围解析生成ip的golang类库的想法。

0x01 TODO

实现可以解析以下ip地址段,获取其包含的全部ip

  • 192.168.0.1

  • 192.168.0.1/24 

  • 192.168.0.1-22 

  • 192.168.0.* 

  • 192.168.0.1,192.168.2.1/24,192.168.3.1-100,192.168.4.*


0x02 实现解析cidr来生成ip

func DealCIDR(cidr string) ([]string, error) {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}
var ips []string
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); ip_tools(ip) {
ips = append(ips, ip.String())
}
return ips[1 : len(ips)-1], nil
}

func ip_tools(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}

1、DealCIDR函数接收一个cidr格式的IP地址范围,使用net库中的ParseCIDR()函数来获取当前cidr的ip地址和该ip地址对应的网络(例如:传入192.0.2.1/24 获得返回192.0.2.1地址和其对应的网络192.0.2.0/24)

2、使用一个for循环来循环遍历该网络地址中包含的所有ip,循环的初始值应该为该网络对应的子网掩码所包含的ip中的第一个,即为ip.Mask(ipnet.Mask)。其中ipnet.Mask为当前网络所对应的子网掩码,使用ip.Mask()即可获取当前网络对应的子网掩码所包含的ip中的第一个。

3、for循环的条件应该是当前网络是否包含当前的ip地址,即为ipnet.Contains(ip)

4、实现ip的自增就要再写一个函数ip_tools来实现。该函数需要传入一个net.IP来实现ip的自增或者自减。这里需要注意的是IP数据类型其实是一个内部为byte类型的切片,而byte类型的最大值为255,只要255再加1,byte就会变成0,所以可以利用这一点来实现ip地址的自增和移位。


0x03 实现解析「*」来批量获取C、B、A段全部ip

func DealAsterisk(s string) ([]string, error) {
i := strings.Count(s, "*")

switch i {
case 1:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/24")
case 2:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/16")
case 3:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/8")
}

return nil, errors.New("wrong Asterisk")
}

1、原理很简单,传入的string我们直接统计其个数,如果为1个则是C段的全部ip,如果为2个则是B段的全部ip,如果为3个则是A段的全部ip。2、然后调用我们上面写好的DealCIDR函数来直接进行处理即可。

3、如果格式错误则会报错


0x04 处理「-」,来获取范围内的ip

func DealHyphen(s string) ([]string, error) {
tmp := strings.Split(s, ".")
//TODO 异常处理
if len(tmp) == 4 {
iprange_tmp := strings.Split(tmp[3], "-")
var ips []string
tail, _ := strconv.Atoi(iprange_tmp[1])
for head, _ := strconv.Atoi(iprange_tmp[0]); head <= tail; head++ {
ips = append(ips, tmp[0]+"."+tmp[1]+"."+tmp[2]+"."+strconv.Itoa(head))
}
return ips, nil
} else {
return nil, errors.New("wrong Hyphen")
}
}

原理很简单,将传入的ip范围按点分割,获取到最后的数值之后再依次添加进slice


0x05 Handler函数

func Handler(s string) ([]string, []error) {

IPstrings := strings.Split(strings.Trim(s, ","), ",")
var ips []string
var err []error

for i := 0; i < len(IPstrings); i++ {
if strings.Contains(IPstrings[i], "*") {
//TODO 192.168.0.*
ips_tmp, err_tmp := DealAsterisk(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else if strings.Contains(IPstrings[i], "/") {
//TODO 192.168.0.1/24
ips_tmp, err_tmp := DealCIDR(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)

} else if strings.Contains(IPstrings[i], "-") {
//TODO 192.668.0.1-255
ips_tmp, err_tmp := DealHyphen(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else {
//TODO singel ip
ips = append(ips, IPstrings[i])
}
}
fmt.Println("hello")
return ips, err
}

将传入的字符串按逗号进行分割,然后判断其中的元素是否含有特定的字符,再调用相应的函数处理即可


0x06 完整代码

package nmapIPrange
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
)

func DealCIDR(cidr string) ([]string, error) {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}
var ips []string
//在循环里创建的所有函数变量共享相同的变量。
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); ip_tools(ip) {
ips = append(ips, ip.String())
}
return ips[1 : len(ips)-1], nil
}

func ip_tools(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}

func DealAsterisk(s string) ([]string, error) {
i := strings.Count(s, "*")

switch i {
case 1:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/24")
case 2:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/16")
case 3:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/8")
}

return nil, errors.New("wrong Asterisk")
}

func DealHyphen(s string) ([]string, error) {
tmp := strings.Split(s, ".")
//TODO 异常处理
if len(tmp) == 4 {
iprange_tmp := strings.Split(tmp[3], "-")
var ips []string
tail, _ := strconv.Atoi(iprange_tmp[1])
for head, _ := strconv.Atoi(iprange_tmp[0]); head <= tail; head++ {
ips = append(ips, tmp[0]+"."+tmp[1]+"."+tmp[2]+"."+strconv.Itoa(head))
}
return ips, nil
} else {
return nil, errors.New("wrong Hyphen")
}

}

func Handler(s string) ([]string, []error) {

IPstrings := strings.Split(strings.Trim(s, ","), ",")
var ips []string
var err []error

for i := 0; i < len(IPstrings); i++ {
if strings.Contains(IPstrings[i], "*") {
//TODO 192.168.0.*
ips_tmp, err_tmp := DealAsterisk(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else if strings.Contains(IPstrings[i], "/") {
//TODO 192.168.0.1/24
ips_tmp, err_tmp := DealCIDR(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)

} else if strings.Contains(IPstrings[i], "-") {
//TODO 192.668.0.1-255
ips_tmp, err_tmp := DealHyphen(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else {
//TODO singel ip
ips = append(ips, IPstrings[i])
}
}
fmt.Println("hello")
return ips, err
}

0x07 总结

运行效果:工具|Golang安全开发之NMAP格式IP解析库

项目地址:https://github.com/gooderbrother/nmap-IPrange时间原因有个别异常处理没做,大佬们有时间可以提个issue,记得start。


☆ END ☆
工具|Golang安全开发之NMAP格式IP解析库

灼剑(Tsojan)

安全团队



工具|Golang安全开发之NMAP格式IP解析库

    # 点个在看你最好看  #

本文始发于微信公众号(哈拉少安全小队):工具|Golang安全开发之NMAP格式IP解析库

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: