当前位置:网站首页>Golang端口扫描设计
Golang端口扫描设计
2022-07-26 13:13:00 【凌木LSJ】
1 TCP全连接实现
TCP全连接端口扫描器是最基础的扫描器,它的原理是调用Socket的connect函数连接到目标IP的特定端口上,如果连接成功说明端口是开放的,如果连接失败,说明端口没有开放。
1)连接访问实现
Go语言的net包提供的Dial与DialTimeout函数,对传统的socket函数进行了封装,无论想创建什么协议的连接,都只需要调用这两个函数即可。这两个函数的区别是DialTimeout增加了超时时间。
func Connect(ip string, port int) (string, int, error) {
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", ip, port), 2*time.Second)
defer func() {
if conn != nil {
_ = conn.Close()
}
}()
return ip, port, err
}2)IP处理
iprange库会将Nmap风格的IP解析为AddressRange对象,然后调用AddressRange的Expand方法会返回一个[]net.IP,支持的格式如下。
- 10.0.0.1
- 10.0.0.0/24
- 10.0.0.∗
- 10.0.0.1-10
- 10.0.0.1,10.0.0.5-10,192.168.1.∗,192.168.10.0/24
func GetIpList(ips string) ([]net.IP, error) {
addressList, err := iprange.ParseList(ips)
if err != nil {
return nil, err
}
list := addressList.Expand()
return list, err
}3)port处理
多端口的处理需要支持“,”与“-”分割的端口列表,可以使用strings包的Split函数先分割以“,”连接的ipList,然后再分割以“-”连接的ipList,最后返回一个[]int切片
func GetPorts(selection string) ([]int, error) {
ports := []int{}
if selection == "" {
return ports, nil
}
ranges := strings.Split(selection, ",")
for _, r := range ranges {
r = strings.TrimSpace(r)
if strings.Contains(r, "-") {
parts := strings.Split(r, "-")
if len(parts) != 2 {
return nil, fmt.Errorf("Invalid port selection segment: '%s'", r)
}
p1, err := strconv.Atoi(parts[0])
if err != nil {
return nil, fmt.Errorf("Invalid port number: '%s'", parts[0])
}
p2, err := strconv.Atoi(parts[1])
if err != nil {
return nil, fmt.Errorf("Invalid port number: '%s'", parts[1])
}
if p1 > p2 {
return nil, fmt.Errorf("Invalid port range: %d-%d", p1, p2)
}
for i := p1; i <= p2; i++ {
ports = append(ports, i)
}
} else {
if port, err := strconv.Atoi(r); err != nil {
return nil, fmt.Errorf("Invalid port number: '%s'", r)
} else {
ports = append(ports, port)
}
}
}
return ports, nil
}4)main函数调用
func main() {
if len(os.Args) == 3 {
ipList := os.Args[1]
portList := os.Args[2]
ips, err := util.GetIpList(ipList)
ports, err := util.GetPorts(portList)
_ = err
for _,ip := range ips {
for _,port := range ports{
_,err := scanner.Connect(ip.String(),port)
if err != nil{
continue
}
fmt.Printf("IP %v , Port %v is open \n",ip,port)
}
}
} else {
fmt.Printf("%v iplist port\n", os.Args[0])
}
}2 TCP半连接实现
TCP半连接端口扫描器只会向目标端口发送一个SYN包,如果服务器的端口是开放的,会返回SYN/ACK包,如果端口不开放,则会返回RST/ACK包。
将执行全连接扫描的Connect(ip string, port int)函数修改为半连接扫描的函数:
func SynScan(dstIp string, dstPort int) (string, int, error) {
srcIp, srcPort, err := localIPPort(net.ParseIP(dstIp))
dstAddrs, err := net.LookupIP(dstIp)
if err != nil {
return dstIp, 0, err
}
dstip := dstAddrs[0].To4()
var dstport layers.TCPPort
dstport = layers.TCPPort(dstPort)
srcport := layers.TCPPort(srcPort)
// 构建IP报头
ip := &layers.IPv4{
SrcIP: srcIp,
DstIP: dstip,
Protocol: layers.IPProtocolTCP,
}
// 构建TCP报头
tcp := &layers.TCP{
SrcPort: srcport,
DstPort: dstport,
SYN: true,
}
//计算校验和
err = tcp.SetNetworkLayerForChecksum(ip)
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
//填充buf
if err := gopacket.SerializeLayers(buf, opts, tcp); err != nil {
return dstIp, 0, err
}
//创建本地监听TCP的conn
conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
return dstIp, 0, err
}
defer conn.Close()
//向目标地址发送TCP SYN报文
if _, err := conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}); err != nil {
return dstIp, 0, err
}
if err := conn.SetDeadline(time.Now().Add(4 * time.Second)); err != nil {
return dstIp, 0, err
}
//不断从conn连接中读取数据
for {
b := make([]byte, 4096)
n, addr, err := conn.ReadFrom(b)
if err != nil {
return dstIp, 0, err
} else if addr.String() == dstip.String() {
// Decode a packet
packet := gopacket.NewPacket(b[:n], layers.LayerTypeTCP, gopacket.Default)
// Get the TCP layer from this packet
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.TCP)
if tcp.DstPort == srcport {
if tcp.SYN && tcp.ACK {
// log.Printf("%v:%d is OPEN\n", dstIp, dstport)
return dstIp, dstPort, err
} else {
return dstIp, 0, err
}
}
}
}
}
}
3 合并两种检测方式
1)使用github.com/urfave/cli包来处理命令行参数
var Scan = cli.Command{
Name: "scan",
Usage: "start to scan port",
Description: "start to scan port",
Action: util.Scan,
Flags: []cli.Flag{
stringFlag("iplist, i", "", "ip list"),
stringFlag("port, p", "", "port list"),
stringFlag("mode, m", "", "scan mode"),
intFlag("timeout, t", 3, "timeout"),
intFlag("concurrency, c", 1000, "concurrency"),
},
}
func stringFlag(name, value, usage string) cli.StringFlag {
return cli.StringFlag{
Name: name,
Value: value,
Usage: usage,
}
}
func boolFlag(name, usage string) cli.BoolFlag {
return cli.BoolFlag{
Name: name,
Usage: usage,
}
}
func intFlag(name string, value int, usage string) cli.IntFlag {
return cli.IntFlag{
Name: name,
Value: value,
Usage: usage,
}
}
2)获取命令行参数并进行相应的处理
func Scan(ctx *cli.Context) error {
if ctx.IsSet("iplist") {
vars.Host = ctx.String("iplist")
}
if ctx.IsSet("port") {
vars.Port = ctx.String("port")
}
if ctx.IsSet("mode") {
vars.Mode = ctx.String("mode")
}
if ctx.IsSet("timeout") {
vars.Timeout = ctx.Int("timeout")
}
if ctx.IsSet("concurrency") {
vars.ThreadNum = ctx.Int("concurrency")
}
if strings.ToLower(vars.Mode) == "syn" {
CheckRoot()
}
ips, err := GetIpList(vars.Host)
ports, err := GetPorts(vars.Port)
tasks, n := scanner.GenerateTask(ips, ports)
_ = n
scanner.RunTask(tasks)
scanner.PrintResult()
return err
}3)根据不同的模式启动不同的扫描方式
func Scan(taskChan chan map[string]int, wg *sync.WaitGroup) {
// 每个协程都从channel中读取数据后开始扫描并入库
for task := range taskChan {
for ip, port := range task {
if strings.ToLower(vars.Mode) == "syn" {
err := SaveResult(SynScan(ip, port))
_ = err
} else {
err := SaveResult(Connect(ip, port))
_ = err
}
wg.Done()
}
}
}摘自:《白帽子安全开发实战》
边栏推荐
- StreamNative 团队文化:一家“透明”的公司
- Flutter dart generates a list of random numbers that are not repeated in n intervals
- Kubernetes---- installing and deploying NFS servers
- Leetcode 217. there are duplicate elements
- B+树索引使用(8)排序使用及其注意事项(二十)
- Kubelet CRI container runtime
- 【上位机教程】CANopen通信下一体化步进电机与台达PLC(AS228T)的应用
- Why do you want to make "secret comments"?
- B+树索引使用(6)最左原则 --mysql从入门到精通(十八)
- Bitwise and how to write SQL
猜你喜欢

基于ASP.NET的某高校学院档案管理系统

1-6月中国ADAS供应商占比9% 又一家零部件巨头全面布局智驾新赛道

【花雕动手做】有趣好玩的音乐可视化系列小项目(13)---有机棒立柱灯

历史上的今天:IBM 获得了第一项专利;Verizon 收购雅虎;亚马逊发布 Fire Phone...

Today's sleep quality record 75 points

From January to June, China's ADAS suppliers accounted for 9%, and another parts giant comprehensively laid out the new smart drive track

我们被一个 kong 的性能 bug 折腾了一个通宵

1312_适用7z命令进行压缩与解压
![[typescript] typescript common types (Part 2)](/img/6b/2ac07f16af044bdfb719753ae241cc.png)
[typescript] typescript common types (Part 2)

Slam 02. overall framework
随机推荐
【花雕动手做】有趣好玩的音乐可视化系列小项目(12)---米管快速节奏灯
基于ASP.NET的某高校学院档案管理系统
Today in history: IBM obtained the first patent; Verizon acquires Yahoo; Amazon releases fire phone
[flower carving hands-on] fun music visualization series small project (12) -- meter tube fast rhythm light
mqtt send receive
C#把Type当做泛型T,来作为方法的泛型进行使用
父组件访问子组件的方法或参数 (子组件暴漏出方法defineExpose)
B+树索引使用(7)匹配列前缀,匹配值范围(十九)
pomerium
pomerium
Use float to realize left, middle and right layout, and the middle content is adaptive
Reflection, an implementation of automatic repeated call interface
维度灾难 维数灾难 暂记
Can MySQL customize variable parameter storage functions?
Streamnational team culture: a "transparent" company
B+树挑选索引(1)---mysql从入门到精通(二十二)
MySQL可以自定义变参存储函数吗?
华为年内二度招聘“天才少年”;540万Twitter账号信息泄露,卖价3万美元;谷歌解雇了相信AI有意识的工程师|极客头条...
Use positioning to realize left, middle and right layout, and the middle content is adaptive
Extra (5) - MySQL execution plan (51)