前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go编写工具教程第二课 高并发主机发现

Go编写工具教程第二课 高并发主机发现

原创
作者头像
WgpSec
修改2021-02-04 18:05:52
1.3K1
修改2021-02-04 18:05:52
举报
文章被收录于专栏:狼组安全团队狼组安全团队

声明

本文作者:TheNorth

本文字数:2000

阅读时长:20分钟

附件/链接:点击查看原文下载

声明:请勿用作违法用途,否则后果自负

本文属于WgpSec原创奖励计划,未经许可禁止转载

前言

    这是Go编写工具教程第二课:高并发主机发现,本文持续连载在【狼组安全平台】plat.wgpsec.org

一、

什么是主机发现?

以我的理解,就是我们主动与目标主机建立通信,如果目标主机给了我们反馈,我们就认为该主机是存活的,否则就是死亡的。

二、

主机发现方式

基于ARP协议主机发现

ARP协议是一种实现将IP地址转换成主机的MAC地址的一种网络协议。

优点:扫描速度快、可靠

缺点:不可路由

基于ICMP协议的主机发现

优点:可路由

缺点:扫描速度慢,会被防火墙拦截

基于TCP、UDP协议的主机发现

优点:可路由,扫描主机的时候可以获取端口是否开放,很少被防火墙过滤

缺点:扫描速度慢

三、

实现一个高并发的主机发现工具

基于上面的方式,由于我们主要想既可以判断局域网的主机是否存活,又可以判断互联网上的主机是否存活,因此,我们决定采用ICMP协议来实现主机发现,由于ping是基于ICMP协议实现的,而且无论是windows还是Linux系统中,都自带ping程序,所以我们实现一个利用ping程序实现的一个高并发主机发现工具。

关于Go的一些基础知识,师傅们可以参考我的上篇文章

GO编写一个高并发端口扫描工具

实现一个非并发的主机发现工具

hostscan.go

代码语言:javascript
复制
package IcmpScan

import (
	"io/ioutil"
	"log"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
)

func ScanHost(ip string, count int) bool {
	var cmd = &exec.Cmd{}
    //判断当前系统是什么系统,不同的系统ping的使用稍有不同
	switch runtime.GOOS {
	case "windows":
        //go中使用exec.Command执行系统命令,每一个参数都各占一个位置
		cmd = exec.Command("ping", "-n", strconv.Itoa(count), ip)
	default:
		cmd = exec.Command("ping", "-c", strconv.Itoa(count), ip)
	}
	output, err := cmd.StdoutPipe()
	defer output.Close()
	cmd.Start()
	if err != nil {
		log.Fatal(err)
	} else {
		result, err := ioutil.ReadAll(output)
		if err != nil {
			log.Fatal(err)
		}
        //通过返回的内容中是否存在TTL字段来判断主机是否在线
		if strings.Contains(string(result), "TTL") || strings.Contains(string(result), "ttl") {
			return true
		} else {
			return false
		}
	}
	return false
}

main.go

代码语言:javascript
复制
package main

import (
	"AstaGo/Tools/IcmpScan"
	"fmt"
	"time"
)

func main() {
	hosts := [...]string{
		"127.0.0.1", "110.242.68.4", "192.168.10.3"}
	start := time.Now()
	for _, host := range hosts {
		res := IcmpScan.ScanHost(host, 4)
		if res == true {
			fmt.Println("开放的主机", host)
		}
	}
	end := time.Since(start)
	fmt.Println("花费的时间", end)
}

高并发的主机发现工具

hostscan.go

代码语言:javascript
复制
package IcmpScan

import (
	"io/ioutil"
	"log"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"sync"
)

func ScanHost(ip string, count int) bool {
	var cmd = &exec.Cmd{}
	switch runtime.GOOS {
	case "windows":
		cmd = exec.Command("ping", "-n", strconv.Itoa(count), ip)
	default:
		cmd = exec.Command("ping", "-c", strconv.Itoa(count), ip)
	}
	output, err := cmd.StdoutPipe()
	defer output.Close()
	cmd.Start()
	if err != nil {
		log.Fatal(err)
	} else {
		result, err := ioutil.ReadAll(output)
		if err != nil {
			log.Fatal(err)
		}
		if strings.Contains(string(result), "TTL") || strings.Contains(string(result), "ttl") {
			return true
		} else {
			return false
		}
	}
	return false
}
//hostsChan存放要扫描的主机,resChan存放扫描的结果,exitChan存储每一个goroutine完成的状态,wg用来同步各个goroutiine
func ScanHostTasks(hostsChan chan string, resChan chan string, exitChan chan bool, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		host, ok := <-hostsChan
		if !ok {
			break
		} else {
			res := ScanHost(host, 4)
			if res {
				resChan <- host
			}
		}
	}
	exitChan <- true
}

main.go

代码语言:javascript
复制
func main() {
	hosts := [...]string{
		"127.0.0.1", "110.242.68.4", "192.168.10.3"}

	tasksChan := make(chan string, len(hosts))
	resChan := make(chan string, len(hosts))
	exitChan := make(chan bool, 4)
	var wg sync.WaitGroup
	for _, host := range hosts {
		tasksChan <- host
	}
	close(tasksChan)
	start := time.Now()
	for i := 0; i < 4; i++ {
		wg.Add(1)
		go IcmpScan.ScanHostTasks(tasksChan, resChan, exitChan, &wg)
	}
	wg.Wait()
	for i := 0; i < 4; i++ {
		<-exitChan
	}
	close(resChan)
	end := time.Since(start)
	for {
		openhost, ok := <-resChan
		if !ok {
			break
		}
		fmt.Println("开放的主机", openhost)
	}
	fmt.Println("花费的时间", end)
}

四、

优化主机发现工具

使用flag包

main.go

代码语言:javascript
复制
package main

import (
	"AstaGo/Tools/IcmpScan"
	"flag"
	"fmt"
	"strings"
	"sync"
	"time"
)

func main() {
	//hosts := [...]string{
	//	"127.0.0.1", "110.242.68.4", "192.168.10.3"}

	var hostslist string
	var gonum int
	flag.StringVar(&hostslist, "i", "", "输入要扫描的地址,默认为空")
	flag.IntVar(&gonum, "g", 1, "需要开启的goroutine的数量")
	flag.Parse()
	if len(hostslist) == 0 {
		fmt.Println("请输入要扫描的主机")
	} else {
		hosts := strings.Split(hostslist, ",")
		tasksChan := make(chan string, len(hosts))
		resChan := make(chan string, len(hosts))
		exitChan := make(chan bool, 4)
		var wg sync.WaitGroup
		for _, host := range hosts {
			tasksChan <- host
		}
		close(tasksChan)
		start := time.Now()
		for i := 0; i < gonum; i++ {
			wg.Add(1)
			go IcmpScan.ScanHostTasks(tasksChan, resChan, exitChan, &wg)
		}
		wg.Wait()
		for i := 0; i < gonum; i++ {
			<-exitChan
		}
		close(resChan)
		end := time.Since(start)
		for {
			openhost, ok := <-resChan
			if !ok {
				break
			}
			fmt.Println("开放的主机", openhost)
		}
		fmt.Println("花费的时间", end)
	}
}

后记

        使用系统自带的ping工具实现主机发现,但是扫描花费的时间还是比较长,但是有两个地方可以修改,一个是选择发包的的数量,目前设置的是4,如果只发一个包会提高效率,但是准确率可能会下降,虽然ping是基于ICMP协议实现的,下一步打算直接使用ICMP协议发现主机,看看效率能不能提高。

师傅们存在的问题或者建议可以留言,到 https://github.com/wgpsec/AstaGo提issue 。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基于ARP协议主机发现
  • 基于ICMP协议的主机发现
  • 基于TCP、UDP协议的主机发现
  • 实现一个非并发的主机发现工具
  • 高并发的主机发现工具
相关产品与服务
网站渗透测试
网站渗透测试(Website Penetration Test,WPT)是完全模拟黑客可能使用的攻击技术和漏洞发现技术,对目标系统的安全做深入的探测,发现系统最脆弱的环节。渗透测试和黑客入侵最大区别在于渗透测试是经过客户授权,采用可控制、非破坏性质的方法和手段发现目标和网络设备中存在弱点,帮助管理者知道自己网络所面临的问题,同时提供安全加固意见帮助客户提升系统的安全性。腾讯云网站渗透测试由腾讯安全实验室安全专家进行,我们提供黑盒、白盒、灰盒多种测试方案,更全面更深入的发现客户的潜在风险。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档