rustscan是一个网络扫描工具,它相比于nmap的最明显的一个优势是扫描端口速度快。
当然,rustscan命令也可以通过追加参数实现nmap的部分功能。
注:本文对rustscan的理解是基于rustscan2.0.0版本的
rustscan常用命令解析
rustscan调用方式:rustscan [FLAGS] [OPTIONS] [-- <command>...]
rustscan -a 10.121.110.36 -p 22,80,3306 -b 10000 -- -sV --version-light
参数解析:
- -a 指定扫描ip(多个ip用逗号隔开,支持扫描192.168.0.0/30格式、主机文件扫描-a 'hosts.txt',不支持192.168.0.0-192.168.0.255格式)
- -p 指定扫描端口(单个端口的集合,端口之间用逗号分隔)
- -r 指定扫描端口段(1-65535)
- --timeout 指定端口扫描超时时间ms,默认为1500ms
- --tries 端口扫描尝试次数
- -b 指并发发包数量(-b数值越大,则扫描速度越快,同时可能导致部分端口扫描不出来),默认为4500
- -- 之后的追加的参数都是调用的nmap的参数
- -sV --version-light 是nmap的参数,表示开启轻量级端口服务探测
rustscan本身重点在于端口探活这一类检测任务,若是需要指定主机探活及主机探活方式(TCP SYN Ping、ICMP Ping等)可以通过拼接nmap参数实现
正则提取rustscan结果
在使用rustscan2.0.0版本时,调用nmap的参数-oX nmap.xml将扫描结果输出到一个xml文件中,发现扫描多个ip(已知存活),结果文件nmap.xml中也只有一个ip的结果
于是写了一个正则表达式,用于提取有用的信息
Nmap scan report for ((?:(?:\\d+\\.){3}\\d+)|([0-9a-fA-F]+(?:(?:[0-9a-fA-F]+)|:){0,6}[0-9a-fA-F]))\nHost is up(?:.*\n+)+?PORT\\s+STATE.*\n(?:\\d+/(?:tcp|udp).*\n)+MAC\\sAddress
在以上正则表达式的基础上,可以通过go语言编程实现功能:执行rustscan命令扫描目标ip和目标端口,并且将结果简化输出。代码如下:
package main
import (
"bytes"
"flag"
"fmt"
"os/exec"
"regexp"
)
var ip = flag.String("i", "", "ip")
var port = flag.String("o", "", "port")
func main() {
flag.Parse()
cmd := exec.Command("rustscan", "-a", *ip, "-r", *port, "-b", "10000", "--", "-n", "-T4", "-sV")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
fmt.Println("cmdRun error:", err)
return
}
rustRes := out.String()
reg1, err := regexp.Compile("Nmap scan report for ((?:(?:\\d+\\.){3}\\d+)|([0-9a-fA-F]+(?:(?:[0-9a-fA-F]+)|:){0,6}[0-9a-fA-F]))\nHost is up(?:.*\n+)+?PORT\\s+STATE.*\n(?:\\d+/(?:tcp|udp).*\n)+MAC\\sAddress")
if err != nil {
fmt.Println("regexp error1:", err)
}
allInfo := reg1.FindAllStringSubmatch(rustRes, -1)
//fmt.Println(allInfo[0][0]) //所有结果
//fmt.Println("************************************", allInfo[0][1]) //ip
for _, al := range allInfo {
reg2, err := regexp.Compile("(\\d+)/(tcp|udp)\\s+open\\s+(.*)\\s+(?:syn-ack|reset|no-response)\\s+(?:ttl\\s+\\d+)?(.*)\n")
if err != nil {
fmt.Println("regexp error2:", err)
}
portServices := reg2.FindAllStringSubmatch(al[0], -1)
for _, ps := range portServices {
//fmt.Println("=====", ps[0]) //单个端口行
//fmt.Println("=====", ps[1]) //端口
//fmt.Println("=====", ps[2]) //protocol
//fmt.Println("=====", ps[3]) //service
//fmt.Println("=====", ps[4]) //service version, 前提是开启端口扫描服务
fmt.Println("the opening port of ip", al[1], "is ", ps[1], ps[2], ps[3])
}
}
}
代码中,第一次正则拿到了ip和该ip的所有端口,第二次正则拿到了第一次正则中每一个ip中的所有开放端口的信息(协议、服务、端口号)
在linux上编译后生成二进制文件anaRustscan,执行命令./anaRustscan -i 扫描目标 -o 端口范围,即可运行