作者:墨阳
免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责。

0x00 前言

上一篇实现了一个简单的子域名查询和ip反查工具,但是当我们的目标比较多时,一个一个查询体验并不友好,和网站查询没啥区别。这篇文章改造一下小工具。

0x01 实现

1、函数部分修改

首先设想一下输入,可以有两种输入方式,命令行手动输入,适用于目标比较少的。另一种是从文件读取,这里需要写一个读取文件的函数:

func ReadTarget(filename string) []string {var tasks []stringf,_ := os.Open(filename)defer f.Close()buff := bufio.NewReader(f)for i := 1 ; ; i++ {//按行读取,结果为[]byte类型target,_,err := buff.ReadLine()if err != nil && err != io.EOF{panic(err)}else if err == io.EOF {        //判断读取到最后则退出break}tasks = append(tasks,string(target))}return tasks
}

如果目标很多,单线程就会很慢,可以设计成并发模式,Start()函数用于开启协程:

func Start(tasks []string)  {wg := &sync.WaitGroup{}//定义一个通道taskChan := make(chan string,len(tasks))//开启五个协程for i:=1; i<=5; i++{go Run(taskChan,wg)}//将目标遍历出来添加到通道中for _,target := range tasks {wg.Add(1)taskChan <- target}close(taskChan)wg.Wait()
}

Run()函数,开始走程序的流程:


func Run(taskChan chan string,wg *sync.WaitGroup)  {for target := range taskChan{GetInfo(Request(strings.TrimSpace(target)))        //strings.TrimSpace()去除首尾空格wg.Done()}
}

因为多目标的原因,在保存结果的时候需要保存到对应的target中,所以我们在Request()函数中增加一个返回值target,并传递到GetInfo()中,其他不变。

func Request(target string) ([]byte,string) {start := time.Now()client := &http.Client{Timeout: 5*time.Second}url := "https://www.dnsgrep.cn/api/query?q="+target+"&token=[申请的token值]"resp,err := client.Get(url)if err != nil {fmt.Println("请求链接失败!",err)return nil,target}else if resp.Status != "200 OK" {fmt.Println("请求链接失败,状态码不为200!")return nil,target}defer resp.Body.Close()text,err := ioutil.ReadAll(resp.Body)if err != nil {fmt.Println("读取响应失败!",err)return nil,target}end := time.Since(start)fmt.Printf("请求数据用时:%s\n",end)return text,target
}

同样因为多目标的原因,需要新定义一个结构体来存放查询目标和对应的返回信息:

vars包:

package varsimport "sync"type JsonData struct {Status    int       `json:"status"`Data      Info      `json:"data"`
}
type Info struct {Data    []map[string]string  `json:"data"`Count   intType    int
}type Result struct {Target     []stringResultData []Info        //定义为Info类型的切片
}var (V         Result        //V变为了Result类型,用于存放总的结果Target    stringFileName  string        //导入target的文件名ExcelName string        //输出excel文件的文件名Mu        sync.Mutex    //定义一个锁
)

修改一下GetInfo()函数,增加保存到最终结果功能:

func GetInfo(jsonData []byte,target string)  {if jsonData == nil {fmt.Println("获取数据失败!")return}//局部变量v,用于存放当前target的解析数据var v vars.JsonDataerr := json.Unmarshal(jsonData, &v)if err != nil {fmt.Println("数据解析失败!", err)return}//结构体在多线程读写的时候不是并发安全的,加锁vars.Mu.Lock()//将target和结果添加到全局变量V也就是Result类型的结构体的对应字段中vars.V.Target = append(vars.V.Target,target)vars.V.ResultData = append(vars.V.ResultData,v.Data)vars.Mu.Unlock()
}

同样输出的函数也需要修改:

func OutPut()  {//遍历结果,i用于关联target和信息,r为下标i对应的信息for i,r := range vars.V.ResultData{fmt.Printf("\n==============目标:%s共检索到%d条数据================\n\n",vars.V.Target[i],len(r.Data))tb,err := gotable.Create("domain","value","type","time")if err != nil{fmt.Println("创建表格失败!",err)os.Exit(0)}tb.AddRows(r.Data)tb.PrintTable()}
}

在用户指定输出的文件名后,需要检查一下这个文件是否已经存在:

func CheckFileExist(filename string) bool {_,err := os.Stat(filename)if os.IsNotExist(err) {return false}else {return true}
}

输出到文件:

func WriteExcel(filename string)  {f := excelize.NewFile()//根据target名称创建工作表for _,r := range vars.V.Target{f.NewSheet(r)}//写入数据var sheetName stringfor i,obj := range vars.V.ResultData{sheetName = vars.V.Target[i]            //根据下标i来对应上target和数据,用于指定工作表//指定单元格,设置第一行的值f.SetCellValue(sheetName, "A1", "Domain")f.SetCellValue(sheetName, "B1", "Value")f.SetCellValue(sheetName, "C1", "Type")f.SetCellValue(sheetName, "D1", "Time")//指定工作表、单元格输出数据for i,r := range obj.Data{num := strconv.Itoa(i+2)f.SetCellValue(sheetName, "A"+num, r["domain"])f.SetCellValue(sheetName, "B"+num, r["value"])f.SetCellValue(sheetName, "C"+num, r["type"])f.SetCellValue(sheetName, "D"+num, r["time"])}}//设置工作簿默认工作表,即打开时显示的表f.SetActiveSheet(1)//根据指定路径保存文件if err := f.SaveAs(filename); err != nil {fmt.Println("写入文件失败:",err)return}fmt.Printf("写入文件:%s成功!\n",filename)
}

2、util包完整代码

package utilimport ("bufio""dnsgrep/vars""encoding/json""fmt""github.com/liushuochen/gotable""github.com/xuri/excelize/v2""io""io/ioutil""net/http""os""strconv""strings""sync""time"
)func ReadTarget(filename string) []string {var tasks []stringf,_ := os.Open(filename)defer f.Close()buff := bufio.NewReader(f)for i := 1 ; ; i++ {target,_,err := buff.ReadLine()if err != nil && err != io.EOF{panic(err)}else if err == io.EOF {break}tasks = append(tasks,string(target))}return tasks
}func Start(tasks []string)  {wg := &sync.WaitGroup{}taskChan := make(chan string,50)for i:=1; i<5; i++{go Run(taskChan,wg)}for _,target := range tasks {wg.Add(1)taskChan <- target}close(taskChan)wg.Wait()
}func Run(taskChan chan string,wg *sync.WaitGroup)  {for target := range taskChan{GetInfo(Request(strings.TrimSpace(target)))wg.Done()}
}func Request(target string) ([]byte,string) {start := time.Now()client := &http.Client{Timeout: 5*time.Second}url := "https://www.dnsgrep.cn/api/query?q="+target+"&token=[申请的token]"resp,err := client.Get(url)if err != nil {fmt.Println("请求链接失败!",err)return nil,target}else if resp.Status != "200 OK" {fmt.Println("请求链接失败,状态码不为200!")return nil,target}defer resp.Body.Close()text,err := ioutil.ReadAll(resp.Body)if err != nil {fmt.Println("读取响应失败!",err)return nil,target}end := time.Since(start)fmt.Printf("请求数据用时:%s\n",end)return text,target
}func GetInfo(jsonData []byte,target string)  {if jsonData == nil {fmt.Println("获取数据失败!")return}var v vars.JsonDataerr := json.Unmarshal(jsonData, &v)if err != nil {fmt.Println("数据解析失败!", err)return}vars.Mu.Lock()vars.V.Target = append(vars.V.Target,target)vars.V.ResultData = append(vars.V.ResultData,v.Data)vars.Mu.Unlock()
}func OutPut()  {for i,r := range vars.V.ResultData{fmt.Printf("\n==============目标:%s共检索到%d条数据================\n\n",vars.V.Target[i],len(r.Data))tb,err := gotable.Create("domain","value","type","time")if err != nil{fmt.Println("创建表格失败!",err)os.Exit(0)}tb.AddRows(r.Data)tb.PrintTable()}}func CheckFileExist(filename string) bool {_,err := os.Stat(filename)if os.IsNotExist(err) {return false}else {return true}
}func WriteExcel(filename string)  {f := excelize.NewFile()//根据target名称创建工作表for _,r := range vars.V.Target{f.NewSheet(r)}//写入数据var sheetName stringfor i,obj := range vars.V.ResultData{sheetName = vars.V.Target[i]//指定单元格,设置第一行的值f.SetCellValue(sheetName, "A1", "Domain")f.SetCellValue(sheetName, "B1", "Value")f.SetCellValue(sheetName, "C1", "Type")f.SetCellValue(sheetName, "D1", "Time")//指定工作表、单元格输出数据for i,r := range obj.Data{num := strconv.Itoa(i+2)f.SetCellValue(sheetName, "A"+num, r["domain"])f.SetCellValue(sheetName, "B"+num, r["value"])f.SetCellValue(sheetName, "C"+num, r["type"])f.SetCellValue(sheetName, "D"+num, r["time"])}}//设置工作簿默认工作表,即打开时显示的表f.SetActiveSheet(1)// 根据指定路径保存文件if err := f.SaveAs(filename); err != nil {fmt.Println("写入文件失败:",err)return}fmt.Printf("写入文件:%s成功!\n",filename)
}

3、主函数部分

主函数部分也需要添加参数和进行逻辑的调整:

package mainimport ("dnsgrep/util""dnsgrep/vars""fmt""github.com/urfave/cli""os""strings""time"
)func main()  {start := time.Now()app := &cli.App{Name: "名字",Author: "作者",Version: "版本信息",Usage: "简介",Flags: []cli.Flag{&cli.StringFlag{Name: "t",Value: "",Usage: "target,命令格式:-t `baidu.com,127.0.0.1`",Destination: &vars.Target,},&cli.StringFlag{Name: "r",Value: "",Usage: "从文件导入目标,目标文件内一行一个,命令格式:-r `xx.txt`",Destination: &vars.FileName,},&cli.StringFlag{Name: "f",Value: "",Usage: "输出表格名称,命令格式:-f `result.xlsx`",Destination: &vars.ExcelName,},},Action: func(c *cli.Context) {if !c.IsSet("t") && !c.IsSet("r") {fmt.Println("请输入查询目标,-h查看参数!")os.Exit(0)}},}app.Run(os.Args)//检查输出文件是否已经存在if vars.ExcelName != ""{if util.CheckFileExist(vars.ExcelName){fmt.Println("保存的文件名已存在,请重新输入!")os.Exit(0)}}//根据输入的target生成最终target切片if vars.Target != "" || vars.FileName != "" {var tasks []stringswitch  {//命令行输入和文件输入同时存在case vars.Target != "" && vars.FileName != "":tasks = strings.Split(vars.Target,",")            //根据逗号分割字符串,返回切片tasks = append(tasks,util.ReadTarget(vars.FileName)...)        //将切片添加到切片中,需要加...来表明这是个切片//只有命令行case vars.Target != "":tasks = strings.Split(vars.Target,",")//只有文件case vars.FileName != "":tasks = util.ReadTarget(vars.FileName)}fmt.Println("开始查询,待查询数:",len(tasks))util.Start(tasks)util.OutPut()}else {os.Exit(0)}//判断一下是否需要输出到文件if vars.ExcelName != ""{util.WriteExcel(vars.ExcelName)}end := time.Since(start)fmt.Printf("共用时:%s",end)
}

0x03 运行结果

运行一下,看看是不是我们想要的结果



0x04 总结

多任务并发模式的查询脚本就写好了,接下来的修改方向就是可以根据自己需要多添加写网站,这样收集的信息会全一些。初学可能有些地方不完美,望各位大佬不要吐槽我哈哈。
项目地址:https://github.com/MoYang233/subdomain-demo/tree/main/subdomain-demo2

0x05 了解更多安全知识

欢迎关注我们的安全公众号,学习更多安全知识!!!
欢迎关注我们的安全公众号,学习更多安全知识!!!
欢迎关注我们的安全公众号,学习更多安全知识!!!

GO工具开发|基于网站API的子域名与IP反查工具(二)相关推荐

  1. GO工具开发|基于网站API的子域名与IP反查工具(一)

    作者: 墨阳 免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责. 0x00 前言 最近开始学习GO语言,希望可以摆脱脚本小子的苦恼,在需要的时候可以根据需要写一些小工具.在做信息 ...

  2. p76 - Python 开发-内外网收集 Socket子域名DNS

    数据来源 本文仅用于信息安全学习,请遵守相关法律法规,严禁用于非法途径.若观众因此作出任何危害网络安全的行为,后果自负,与本人无关. Python 开发相关知识点: 1.开发基础环境配置说明      ...

  3. 第76天:Python开发-内外网收集Socket子域名DNS

    Python开发-内外网收集Socket&子域名&DNS 判断对方是否使用cdn 通过python执行系统命令nslookup返回的结果来进行判断 def cdn(url):#执行系统 ...

  4. 网站存活,ip反查,权重备案查询(方法)

    常用漏洞库: 佩奇漏洞文库: https://www.yuque.com/peiqiwiki/peiqi-poc-wiki http://wiki.peiqi.tech/ 白阁漏洞文库: https: ...

  5. IP反查网站,ip反查接口,旁站查询接口大全,通过IP查域名汇总,域名历史解析记录查询,IP地址查对应机房名称、地址,查IP地址的AS号码...

    IP反查网站,ip反查接口,旁站查询接口大全,通过IP查域名汇总: http://bgp.he.net/,IP地址查对应机房:IP地址在 bgp.he.net 直接能查到IP所属机房或运营商的AS号. ...

  6. IP反查网站/IP反查接口 域名汇总

    IP反查网站,ip反查接口,旁站查询接口大全,通过IP查域名汇总,域名历史解析记录查询,IP地址查对应机房名称.地址,查IP地址的AS号码. IP反查网站,ip反查接口,旁站查询接口大全,通过IP查域 ...

  7. [linux驱动开发] 基于gpiod API的platform总线多个led驱动开发

    gpiod API对platform-led进行驱动开发 修改设备树源码 如何在驱动中获取设备树节点信息 计算设备子节点数量 给私有属性分配内存 对子节点进行遍历 gpiod的获取 根据设备树字节给的 ...

  8. 第76天-Python 开发-内外网收集 Socket子域名

    思维导图 知识点 应急响应补充知识点 挖矿靶机分析 PDF 外加其他 应急响应资源包 提取码:xiao Python 开发相关知识点 1.开发基础环境配置说明 Windows10+Pycharm 2. ...

  9. python安全开发——内外网收集 Socket子域名DNS

    前言: 做渗透测试,第一步就是进行信息收集,对于具体的环境下,需要不同的测试需求,通过自己编写的脚本进行测试会有事半功倍的效果,本文主要介绍了在信息收集的时候,我们可能使用到的库函数. 本人水平有限, ...

最新文章

  1. 互联网企业安全高级指南3.7.1 攻防驱动修改
  2. 让我再撸一次HashMap
  3. 【星辰傀儡线·命运环·卷二 尘埃】 5 困惑
  4. XOOM MZ606 刷机
  5. 返回一个整数数组中最大子数组的和
  6. Lync 2013就地升级到Skype for Business 2015-01
  7. centos6.x 安装elasticsearch6.x步骤
  8. 【ruoyi若依】引入activiti 模块
  9. CSS3伪元素、伪类选择器
  10. [Deepin - Pycharm] PyQT5安装配置
  11. clickhouse 获取几天前的日期
  12. Python类私有方法的陷阱
  13. 在vmware中创建共享磁盘
  14. GitHub 标星 10,000+,Apache 顶级项目 ShardingSphere 的开源之路
  15. 鼠标移开事件(onmouseout)
  16. 3_kicad 5 0_PCB计算器(稳压器,布线宽度,电气间距,传输线路,RF衰减器,颜色代码,电路板类别)...
  17. C++ 查看openCV版本
  18. shuttle的DSA2LV板子逆向工程完成,Uboot和linux有源码了
  19. maftools: 可视化maf文件的神器
  20. 知名人寿保险品牌SCRM成功案例-全员营销方案赋能 提升客户管理能力

热门文章

  1. 用计算机术语赞美老师,【用一句话赞美各个学科】_赞美各学科老师的对联
  2. 61、智能指针类模板
  3. THz:通信系统的研究现状与应用展望
  4. 碎片化学习Java(十六)Java for得出年份生肖
  5. C语言概述:什么是C语言?
  6. 分治算法——快速幂(平方求幂)
  7. ffmpeg把透明背景图片合成透明背景视频
  8. 【ECM技术】ECM(Enhanced Compression Model)帧间技术总结
  9. 基于IGX Web SCADA平台构建 - 污水处理厂监控系统
  10. 开源规模化算法生产平台YMIR的保姆级上手教程