├── .DS_Store ├── README.md ├── img ├── 1.png ├── 2.png ├── 3.png └── 4.png ├── main.go ├── nmap.go └── test.xml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTF-MissFeng/NmapTools/6420ccaddb34a4e2cfb66a47d3ef19eb55f1e09e/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### NmapTools 2 | 3 | Go语言学习,第一个练手小工具,解析nmap扫描结果xml转换到xlsx、进行web服务探测、进行socket数据探测。 4 | 5 | ### 截图 6 | 7 | ![index](https://github.com/CTF-MissFeng/NmapTools/blob/master/img/1.png) 8 | 9 | 10 | ### 功能演示 11 | 12 | #### 一、xml转换到xlsx 13 | 14 | ```bash 15 | ./nmapTools -f test.xml -o test 16 | 2020/07/12 17:51:59 [+]解析成功,共计10001条IP及14063条端口数据 17 | 2020/07/12 17:51:59 [+]导出解析结果成功,请查看test.xlsx文件 18 | ``` 19 | 20 | ![index](https://github.com/CTF-MissFeng/NmapTools/blob/master/img/2.png) 21 | 22 | 23 | #### 二、Web服务探测 24 | 25 | ```bash 26 | ./nmapTools -f test.xml -w 27 | ...... 28 | 2020/07/12 18:03:21 [-]不是有效的web服务,errer:Get "https://202.173.15.148:80": http: server gave HTTP response to HTTPS client 29 | 2020/07/12 18:03:25 [-]不是有效的web服务,errer:Get "https://218.5.42.5:22": context deadline exceeded (Client.Timeout exceeded while awaiting headers) 30 | 2020/07/12 18:03:28 [-]不是有效的web服务,errer:Get "https://47.93.148.247:22": context deadline exceeded (Client.Timeout exceeded while awaiting headers) 31 | 2020/07/12 18:03:28 [+]http服务探测保存成功,请查看 test.xml_http探测结果.xlsx 32 | ``` 33 | 34 | ![index](https://github.com/CTF-MissFeng/NmapTools/blob/master/img/3.png) 35 | 36 | #### 三、Socket数据探测 37 | 38 | > 使用指定的命令进行Socket连接发送,能发现一些未授权访问服务漏洞,如dubbo、Hadoop等。 39 | 40 | ```bash 41 | ./nmapTools -f test.xml -s -c 100 42 | ...... 43 | 2020/07/12 10:12:05 [-] 27.148.193.123:80 获取数据失败 error:read tcp 192.168.0.102:56400->27.148.193.123:80: i/o timeout 44 | 2020/07/12 10:12:05 [-] 49.234.14.18:80 获取数据失败 error:read tcp 192.168.0.102:56401->49.234.14.18:80: i/o timeout 45 | 2020/07/12 10:12:05 [+]socket服务探测保存成功,请查看 test.xml_socket探测结果.xlsx 46 | ``` 47 | 48 | ![index](https://github.com/CTF-MissFeng/NmapTools/blob/master/img/4.png) -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTF-MissFeng/NmapTools/6420ccaddb34a4e2cfb66a47d3ef19eb55f1e09e/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTF-MissFeng/NmapTools/6420ccaddb34a4e2cfb66a47d3ef19eb55f1e09e/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTF-MissFeng/NmapTools/6420ccaddb34a4e2cfb66a47d3ef19eb55f1e09e/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CTF-MissFeng/NmapTools/6420ccaddb34a4e2cfb66a47d3ef19eb55f1e09e/img/4.png -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | "github.com/urfave/cli/v2" 8 | ) 9 | 10 | var nmaptool Nmap 11 | var TimeOut = 5 12 | 13 | func main() { 14 | app := &cli.App{ 15 | Name: "NmapTools", 16 | Version: "1.0", 17 | Usage: "解析导出nmap扫描结果、对扫描结果进行HTTP探测、socket端口数据获取、常规服务破解", 18 | UsageText: "NmapTools [参数选项] --file参数为必须", 19 | EnableBashCompletion: true, 20 | Copyright: "版权所有:MissFeng QQ:1767986993", 21 | UseShortOptionHandling: true, 22 | Flags: []cli.Flag{ 23 | &cli.StringFlag{ 24 | Name: "file", 25 | Aliases: []string{"f"}, 26 | Usage: "指定要解析的Nmap扫描结果xml文件路径", 27 | Required: true, 28 | }, 29 | &cli.StringFlag{ 30 | Name: "output", 31 | Aliases: []string{"o"}, 32 | Usage: "导出Nmap解析结果(xlsx文档)", 33 | }, 34 | &cli.BoolFlag{ 35 | Name: "web", 36 | Aliases: []string{"w"}, 37 | Usage: "解析nmap扫描结果,进行web服务探测", 38 | Value: true, 39 | }, 40 | &cli.IntFlag{ 41 | Name: "timeout", 42 | Aliases: []string{"t"}, 43 | Usage: "web服务探测超时时间", 44 | Value: 5, 45 | }, 46 | &cli.IntFlag{ 47 | Name: "Coroutine", 48 | Aliases: []string{"c"}, 49 | Usage: "协程并发数(web探测和socket探测)", 50 | Value: 20, 51 | }, 52 | &cli.BoolFlag{ 53 | Name: "socket", 54 | Aliases: []string{"s"}, 55 | Usage: "解析nmap扫描结果,进行Socket数据获取", 56 | Value: true, 57 | }, 58 | &cli.StringFlag{ 59 | Name: "command", 60 | Aliases: []string{"cmd"}, 61 | Usage: "Socket数据发送命令,以,号分割", 62 | Value: "\n,ls\n,help\n,envi\n,info\n,dir\n,id\n,?\n", 63 | }, 64 | &cli.IntFlag{ 65 | Name: "stimeout", 66 | Aliases: []string{"st"}, 67 | Usage: "socket数据探测超时时间", 68 | Value: 5, 69 | }, 70 | }, 71 | Action: func(c *cli.Context) error { 72 | if c.IsSet("file")&&c.IsSet("output"){ 73 | nmaptool.FileName = c.String("file") 74 | err := nmaptool.Parse() 75 | if err != nil { 76 | log.Fatal(err) 77 | } 78 | err = nmaptool.ToXlsx(c.String("output")) 79 | if err != nil { 80 | log.Fatal(err) 81 | }else { 82 | log.Printf("[+]导出解析结果成功,请查看%s文件", c.String("output")+".xlsx") 83 | } 84 | } else if c.IsSet("file")&&c.IsSet("web"){ 85 | TimeOut = c.Int("timeout") 86 | nmaptool.FileName = c.String("file") 87 | err := nmaptool.Parse() 88 | if err != nil { 89 | log.Fatal(err) 90 | } 91 | nmaptool.HttpProbe(c.Int("Coroutine")) 92 | } else if c.IsSet("file")&&c.IsSet("socket"){ 93 | nmaptool.FileName = c.String("file") 94 | err := nmaptool.Parse() 95 | if err != nil { 96 | log.Fatal(err) 97 | } 98 | nmaptool.SocketProbe(c.String("command"), c.Int("Coroutine"), c.Int("stimeout")) 99 | } 100 | return nil 101 | }, 102 | } 103 | 104 | err := app.Run(os.Args) 105 | if err != nil { 106 | log.Fatal(err) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /nmap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "encoding/xml" 6 | "errors" 7 | "fmt" 8 | "io/ioutil" 9 | "log" 10 | "net" 11 | "net/http" 12 | "strconv" 13 | "strings" 14 | "sync" 15 | "time" 16 | 17 | "github.com/360EntSecGroup-Skylar/excelize" 18 | "github.com/PuerkitoBio/goquery" 19 | "github.com/panjf2000/ants/v2" 20 | ) 21 | 22 | var wg sync.WaitGroup 23 | var tr = &http.Transport{ 24 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 25 | } 26 | var client = &http.Client{ 27 | Transport: tr, 28 | Timeout:time.Duration(int64(TimeOut))*time.Second, 29 | } 30 | 31 | type HttpInfoStruct struct { 32 | url string 33 | title string 34 | statuscode string 35 | } 36 | 37 | // 保存HTTP探测结果 38 | var HttpInfoStructs []HttpInfoStruct 39 | 40 | // 保存socket数据结果 41 | type SocketInfoStruct struct { 42 | Ip string 43 | Command string 44 | Command_Result string 45 | } 46 | 47 | var SocketInfoMap = make(map[string][]SocketInfoStruct, 10) 48 | 49 | var SocketTimeout = 3 50 | var Lock sync.Mutex 51 | // Timestamp represents time as a UNIX timestamp in seconds. 52 | type Timestamp time.Time 53 | 54 | // str2time converts a string containing a UNIX timestamp to to a time.Time. 55 | func (t *Timestamp) str2time(s string) error { 56 | ts, err := strconv.ParseInt(s, 10, 64) 57 | if err != nil { 58 | return err 59 | } 60 | *t = Timestamp(time.Unix(ts, 0)) 61 | return nil 62 | } 63 | 64 | // time2str formats the time.Time value as a UNIX timestamp string. 65 | // XXX these might also need to be changed to pointers. See str2time and UnmarshalXMLAttr. 66 | func (t Timestamp) time2str() string { 67 | return strconv.FormatInt(time.Time(t).Unix(), 10) 68 | } 69 | 70 | func (t Timestamp) MarshalJSON() ([]byte, error) { 71 | return []byte(t.time2str()), nil 72 | } 73 | 74 | func (t *Timestamp) UnmarshalJSON(b []byte) error { 75 | return t.str2time(string(b)) 76 | } 77 | 78 | func (t Timestamp) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { 79 | return xml.Attr{Name: name, Value: t.time2str()}, nil 80 | } 81 | 82 | func (t *Timestamp) UnmarshalXMLAttr(attr xml.Attr) (err error) { 83 | return t.str2time(attr.Value) 84 | } 85 | 86 | // NmapRun is contains all the data for a single nmap scan. 87 | type NmapRun struct { 88 | Scanner string `xml:"scanner,attr" json:"scanner"` 89 | Args string `xml:"args,attr" json:"args"` 90 | Start Timestamp `xml:"start,attr" json:"start"` 91 | StartStr string `xml:"startstr,attr" json:"startstr"` 92 | Version string `xml:"version,attr" json:"version"` 93 | ProfileName string `xml:"profile_name,attr" json:"profile_name"` 94 | XMLOutputVersion string `xml:"xmloutputversion,attr" json:"xmloutputversion"` 95 | ScanInfo ScanInfo `xml:"scaninfo" json:"scaninfo"` 96 | Verbose Verbose `xml:"verbose" json:"verbose"` 97 | Debugging Debugging `xml:"debugging" json:"debugging"` 98 | TaskBegin []Task `xml:"taskbegin" json:"taskbegin"` 99 | TaskProgress []TaskProgress `xml:"taskprogress" json:"taskprogress"` 100 | TaskEnd []Task `xml:"taskend" json:"taskend"` 101 | PreScripts []Script `xml:"prescript>script" json:"prescripts"` 102 | PostScripts []Script `xml:"postscript>script" json:"postscripts"` 103 | Hosts []Host `xml:"host" json:"hosts"` 104 | Targets []Target `xml:"target" json:"targets"` 105 | RunStats RunStats `xml:"runstats" json:"runstats"` 106 | } 107 | 108 | // ScanInfo contains informational regarding how the scan 109 | // was run. 110 | type ScanInfo struct { 111 | Type string `xml:"type,attr" json:"type"` 112 | Protocol string `xml:"protocol,attr" json:"protocol"` 113 | NumServices int `xml:"numservices,attr" json:"numservices"` 114 | Services string `xml:"services,attr" json:"services"` 115 | ScanFlags string `xml:"scanflags,attr" json:"scanflags"` 116 | } 117 | 118 | // Verbose contains the verbosity level for the Nmap scan. 119 | type Verbose struct { 120 | Level int `xml:"level,attr" json:"level"` 121 | } 122 | 123 | // Debugging contains the debugging level for the Nmap scan. 124 | type Debugging struct { 125 | Level int `xml:"level,attr" json:"level"` 126 | } 127 | 128 | // Task contains information about started and stopped Nmap tasks. 129 | type Task struct { 130 | Task string `xml:"task,attr" json:"task"` 131 | Time Timestamp `xml:"time,attr" json:"time"` 132 | ExtraInfo string `xml:"extrainfo,attr" json:"extrainfo"` 133 | } 134 | 135 | // TaskProgress contains information about the progression of a Task. 136 | type TaskProgress struct { 137 | Task string `xml:"task,attr" json:"task"` 138 | Time Timestamp `xml:"time,attr" json:"time"` 139 | Percent float32 `xml:"percent,attr" json:"percent"` 140 | Remaining int `xml:"remaining,attr" json:"remaining"` 141 | Etc Timestamp `xml:"etc,attr" json:"etc"` 142 | } 143 | 144 | // Target is found in the Nmap xml spec. I have no idea what it 145 | // actually is. 146 | type Target struct { 147 | Specification string `xml:"specification,attr" json:"specification"` 148 | Status string `xml:"status,attr" json:"status"` 149 | Reason string `xml:"reason,attr" json:"reason"` 150 | } 151 | 152 | // Host contains all information about a single host. 153 | type Host struct { 154 | StartTime Timestamp `xml:"starttime,attr" json:"starttime"` 155 | EndTime Timestamp `xml:"endtime,attr" json:"endtime"` 156 | Comment string `xml:"comment,attr" json:"comment"` 157 | Status Status `xml:"status" json:"status"` 158 | Addresses []Address `xml:"address" json:"addresses"` 159 | Hostnames []Hostname `xml:"hostnames>hostname" json:"hostnames"` 160 | Smurfs []Smurf `xml:"smurf" json:"smurfs"` 161 | Ports []Port `xml:"ports>port" json:"ports"` 162 | ExtraPorts []ExtraPorts `xml:"ports>extraports" json:"extraports"` 163 | Os Os `xml:"os" json:"os"` 164 | Distance Distance `xml:"distance" json:"distance"` 165 | Uptime Uptime `xml:"uptime" json:"uptime"` 166 | TcpSequence TcpSequence `xml:"tcpsequence" json:"tcpsequence"` 167 | IpIdSequence IpIdSequence `xml:"ipidsequence" json:"ipidsequence"` 168 | TcpTsSequence TcpTsSequence `xml:"tcptssequence" json:"tcptssequence"` 169 | HostScripts []Script `xml:"hostscript>script" json:"hostscripts"` 170 | Trace Trace `xml:"trace" json:"trace"` 171 | Times Times `xml:"times" json:"times"` 172 | } 173 | 174 | // Status is the host's status. Up, down, etc. 175 | type Status struct { 176 | State string `xml:"state,attr" json:"state"` 177 | Reason string `xml:"reason,attr" json:"reason"` 178 | ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"` 179 | } 180 | 181 | // Address contains a IPv4 or IPv6 address for a Host. 182 | type Address struct { 183 | Addr string `xml:"addr,attr" json:"addr"` 184 | AddrType string `xml:"addrtype,attr" json:"addrtype"` 185 | Vendor string `xml:"vendor,attr" json:"vendor"` 186 | } 187 | 188 | // Hostname is a single name for a Host. 189 | type Hostname struct { 190 | Name string `xml:"name,attr" json:"name"` 191 | Type string `xml:"type,attr" json:"type"` 192 | } 193 | 194 | // Smurf contains repsonses from a smurf attack. I think. 195 | // Smurf attacks, really? 196 | type Smurf struct { 197 | Responses string `xml:"responses,attr" json:"responses"` 198 | } 199 | 200 | // ExtraPorts contains the information about the closed|filtered ports. 201 | type ExtraPorts struct { 202 | State string `xml:"state,attr" json:"state"` 203 | Count int `xml:"count,attr" json:"count"` 204 | Reasons []Reason `xml:"extrareasons" json:"reasons"` 205 | } 206 | type Reason struct { 207 | Reason string `xml:"reason,attr" json:"reason"` 208 | Count int `xml:"count,attr" json:"count"` 209 | } 210 | 211 | // Port contains all the information about a scanned port. 212 | type Port struct { 213 | Protocol string `xml:"protocol,attr" json:"protocol"` 214 | PortId int `xml:"portid,attr" json:"id"` 215 | State State `xml:"state" json:"state"` 216 | Owner Owner `xml:"owner" json:"owner"` 217 | Service Service `xml:"service" json:"service"` 218 | Scripts []Script `xml:"script" json:"scripts"` 219 | } 220 | 221 | // State contains information about a given ports 222 | // status. State will be open, closed, etc. 223 | type State struct { 224 | State string `xml:"state,attr" json:"state"` 225 | Reason string `xml:"reason,attr" json:"reason"` 226 | ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"` 227 | ReasonIP string `xml:"reason_ip,attr" json:"reason_ip"` 228 | } 229 | 230 | // Owner contains the name of Port.Owner. 231 | type Owner struct { 232 | Name string `xml:"name,attr" json:"name"` 233 | } 234 | 235 | // Service contains detailed information about a Port's 236 | // service details. 237 | type Service struct { 238 | Name string `xml:"name,attr" json:"name"` 239 | Conf int `xml:"conf,attr" json:"conf"` 240 | Method string `xml:"method,attr" json:"method"` 241 | Version string `xml:"version,attr" json:"version"` 242 | Product string `xml:"product,attr" json:"product"` 243 | ExtraInfo string `xml:"extrainfo,attr" json:"extrainfo"` 244 | Tunnel string `xml:"tunnel,attr" json:"tunnel"` 245 | Proto string `xml:"proto,attr" json:"proto"` 246 | Rpcnum string `xml:"rpcnum,attr" json:"rpcnum"` 247 | Lowver string `xml:"lowver,attr" json:"lowver"` 248 | Highver string `xml:"hiver,attr" json:"hiver"` 249 | Hostname string `xml:"hostname,attr" json:"hostname"` 250 | OsType string `xml:"ostype,attr" json:"ostype"` 251 | DeviceType string `xml:"devicetype,attr" json:"devicetype"` 252 | ServiceFp string `xml:"servicefp,attr" json:"servicefp"` 253 | CPEs []CPE `xml:"cpe" json:"cpes"` 254 | } 255 | 256 | // CPE (Common Platform Enumeration) is a standardized way to name software 257 | // applications, operating systems, and hardware platforms. 258 | type CPE string 259 | 260 | // Script contains information from Nmap Scripting Engine. 261 | type Script struct { 262 | Id string `xml:"id,attr" json:"id"` 263 | Output string `xml:"output,attr" json:"output"` 264 | Tables []Table `xml:"table" json:"tables"` 265 | Elements []Element `xml:"elem" json:"elements"` 266 | } 267 | 268 | // Table contains the output of the script in a more parse-able form. 269 | // ToDo: This should be a map[string][]string 270 | type Table struct { 271 | Key string `xml:"key,attr" json:"key"` 272 | Elements []Element `xml:"elem" json:"elements"` 273 | Table []Table `xml:"table" json:"tables"` 274 | } 275 | 276 | // Element contains the output of the script, with detailed information 277 | type Element struct { 278 | Key string `xml:"key,attr" json:"key"` 279 | Value string `xml:",chardata" json:"value"` 280 | } 281 | 282 | // Os contains the fingerprinted operating system for a Host. 283 | type Os struct { 284 | PortsUsed []PortUsed `xml:"portused" json:"portsused"` 285 | OsMatches []OsMatch `xml:"osmatch" json:"osmatches"` 286 | OsFingerprints []OsFingerprint `xml:"osfingerprint" json:"osfingerprints"` 287 | } 288 | 289 | // PortsUsed is the port used to fingerprint a Os. 290 | type PortUsed struct { 291 | State string `xml:"state,attr" json:"state"` 292 | Proto string `xml:"proto,attr" json:"proto"` 293 | PortId int `xml:"portid,attr" json:"portid"` 294 | } 295 | 296 | // OsClass contains vendor information for an Os. 297 | type OsClass struct { 298 | Vendor string `xml:"vendor,attr" json:"vendor"` 299 | OsGen string `xml"osgen,attr"` 300 | Type string `xml:"type,attr" json:"type"` 301 | Accuracy string `xml:"accurancy,attr" json:"accurancy"` 302 | OsFamily string `xml:"osfamily,attr" json:"osfamily"` 303 | CPEs []CPE `xml:"cpe" json:"cpes"` 304 | } 305 | 306 | // OsMatch contains detailed information regarding a Os fingerprint. 307 | type OsMatch struct { 308 | Name string `xml:"name,attr" json:"name"` 309 | Accuracy string `xml:"accuracy,attr" json:"accuracy"` 310 | Line string `xml:"line,attr" json:"line"` 311 | OsClasses []OsClass `xml:"osclass" json:"osclasses"` 312 | } 313 | 314 | // OsFingerprint is the actual fingerprint string. 315 | type OsFingerprint struct { 316 | Fingerprint string `xml:"fingerprint,attr" json:"fingerprint"` 317 | } 318 | 319 | // Distance is the amount of hops to a particular host. 320 | type Distance struct { 321 | Value int `xml:"value,attr" json:"value"` 322 | } 323 | 324 | // Uptime is the amount of time the host has been up. 325 | type Uptime struct { 326 | Seconds int `xml:"seconds,attr" json:"seconds"` 327 | Lastboot string `xml:"lastboot,attr" json:"lastboot"` 328 | } 329 | 330 | // TcpSequence contains information regarding the detected tcp sequence. 331 | type TcpSequence struct { 332 | Index int `xml:"index,attr" json:"index"` 333 | Difficulty string `xml:"difficulty,attr" json:"difficulty"` 334 | Values string `xml:"vaules,attr" json:"vaules"` 335 | } 336 | 337 | // Sequence contains information regarding the detected X sequence. 338 | type Sequence struct { 339 | Class string `xml:"class,attr" json:"class"` 340 | Values string `xml:"values,attr" json:"values"` 341 | } 342 | type IpIdSequence Sequence 343 | type TcpTsSequence Sequence 344 | 345 | // Trace contains the hops to a Host. 346 | type Trace struct { 347 | Proto string `xml:"proto,attr" json:"proto"` 348 | Port int `xml:"port,attr" json:"port"` 349 | Hops []Hop `xml:"hop" json:"hops"` 350 | } 351 | 352 | // Hop is a ip hop to a Host. 353 | type Hop struct { 354 | TTL float32 `xml:"ttl,attr" json:"ttl"` 355 | RTT float32 `xml:"rtt,attr" json:"rtt"` 356 | IPAddr string `xml:"ipaddr,attr" json:"ipaddr"` 357 | Host string `xml:"host,attr" json:"host"` 358 | } 359 | 360 | // Times contains time statistics for an Nmap scan. 361 | type Times struct { 362 | SRTT string `xml:"srtt,attr" json:"srtt"` 363 | RTT string `xml:"rttvar,attr" json:"rttv"` 364 | To string `xml:"to,attr" json:"to"` 365 | } 366 | 367 | // RunStats contains statistics for a 368 | // finished Nmap scan. 369 | type RunStats struct { 370 | Finished Finished `xml:"finished" json:"finished"` 371 | Hosts HostStats `xml:"hosts" json:"hosts"` 372 | } 373 | 374 | // Finished contains detailed statistics regarding 375 | // a finished Nmap scan. 376 | type Finished struct { 377 | Time Timestamp `xml:"time,attr" json:"time"` 378 | TimeStr string `xml:"timestr,attr" json:"timestr"` 379 | Elapsed float32 `xml:"elapsed,attr" json:"elapsed"` 380 | Summary string `xml:"summary,attr" json:"summary"` 381 | Exit string `xml:"exit,attr" json:"exit"` 382 | ErrorMsg string `xml:"errormsg,attr" json:"errormsg"` 383 | } 384 | 385 | // HostStats contains the amount of up and down hosts and the total count. 386 | type HostStats struct { 387 | Up int `xml:"up,attr" json:"up"` 388 | Down int `xml:"down,attr" json:"down"` 389 | Total int `xml:"total,attr" json:"total"` 390 | } 391 | 392 | type Nmap struct { 393 | FileName string 394 | NmapRun 395 | } 396 | 397 | // 解析nmap扫描结果 398 | func (n *Nmap)Parse() (error) { 399 | file, err := ioutil.ReadFile(n.FileName) 400 | if err != nil { 401 | err = errors.New(fmt.Sprintf("[-]读取%s文件内容失败:%s", n.FileName, err)) 402 | return err 403 | } 404 | r := &NmapRun{} 405 | err = xml.Unmarshal(file, r) 406 | n.NmapRun = *r 407 | return err 408 | } 409 | 410 | // 导出解析结果到xlsx表格中 411 | func (n *Nmap)ToXlsx(output string)(error){ 412 | book := excelize.NewFile() 413 | book.SetSheetName("Sheet1", "nmap解析结果") // 设置工作表名 414 | book.SetCellValue("nmap解析结果", "A1", "IP地址") // 设置单元格的值 415 | book.SetCellValue("nmap解析结果", "B1", "端口") 416 | book.SetCellValue("nmap解析结果", "C1", "协议") 417 | book.SetCellValue("nmap解析结果", "D1", "服务") 418 | book.SetCellValue("nmap解析结果", "E1", "服务详情") 419 | book.SetCellValue("nmap解析结果", "F1", "版本") 420 | index := 2 421 | ipIndex := 1 422 | for _, v := range n.NmapRun.Hosts{ 423 | ipIndex++ 424 | for _, portSlice := range v.Ports { 425 | if portSlice.State.State != "open"{ // 过滤未开放的端口 426 | continue 427 | } 428 | book.SetCellValue("nmap解析结果", "A"+strconv.Itoa(index), v.Addresses[0].Addr) 429 | book.SetCellValue("nmap解析结果", "B"+strconv.Itoa(index), portSlice.PortId) 430 | book.SetCellValue("nmap解析结果", "C"+strconv.Itoa(index), portSlice.Protocol) 431 | book.SetCellValue("nmap解析结果", "D"+strconv.Itoa(index), portSlice.Service.Name) 432 | book.SetCellValue("nmap解析结果", "E"+strconv.Itoa(index), portSlice.Service.Product) 433 | book.SetCellValue("nmap解析结果", "F"+strconv.Itoa(index), portSlice.Service.Version) 434 | index++ 435 | } 436 | } 437 | book.SetActiveSheet(0) // 设置工作簿的默认工作表 438 | book.SetColWidth("nmap解析结果", "A", "A", 15) // 设置列宽度 439 | book.SetColWidth("nmap解析结果", "B", "B", 8) 440 | book.SetColWidth("nmap解析结果", "C", "D", 12) 441 | book.SetColWidth("nmap解析结果", "E", "F", 18) 442 | log.Printf("[+]解析成功,共计%d条IP及%d条端口数据", ipIndex, index-1) 443 | err := book.SaveAs(output + ".xlsx") 444 | return err 445 | } 446 | 447 | // 探测HTTP服务 448 | func getHttp(get_url string){ 449 | http_url := "http://" + get_url 450 | https_url := "https://" + get_url 451 | log.Printf("[+]开始Http服务探测 %s", http_url) 452 | defer wg.Done() 453 | resp, err := client.Get(http_url) 454 | var tmp_http HttpInfoStruct 455 | if err != nil { 456 | resp, err = client.Get(https_url) 457 | if err != nil { 458 | log.Printf("[-]不是有效的web服务,errer:%s",err) 459 | return 460 | } else { 461 | tmp_http.url = https_url 462 | } 463 | }else { 464 | tmp_http.url = http_url 465 | } 466 | tmp_http.statuscode = strconv.Itoa(resp.StatusCode) 467 | doc, err := goquery.NewDocumentFromReader(resp.Body) 468 | if err != nil { 469 | log.Printf("[-] %s 获取title失败,error:%s", tmp_http.url, err.Error()) 470 | HttpInfoStructs = append(HttpInfoStructs, tmp_http) 471 | log.Printf("[+] %s %s", tmp_http.url, tmp_http.statuscode) 472 | return 473 | } 474 | doc.Find("title").Each(func(i int, selection *goquery.Selection) { 475 | tmp_http.title = selection.Text() 476 | }) 477 | Lock.Lock() 478 | HttpInfoStructs = append(HttpInfoStructs, tmp_http) 479 | Lock.Unlock() 480 | log.Printf("[+] %s %s %s", tmp_http.url, tmp_http.statuscode, tmp_http.title) 481 | defer func(){ 482 | if resp != nil { 483 | resp.Body.Close() 484 | } 485 | }() 486 | } 487 | 488 | // HTTP探测主任务调度 489 | func(n *Nmap)HttpProbe(thread int){ 490 | url_chan := make(chan string, 50) 491 | go func() { // HTTP探测 生产者 492 | for _, v := range n.NmapRun.Hosts{ 493 | for _, portSlice := range v.Ports { 494 | if portSlice.State.State != "open"{ // 过滤未开放的端口 495 | continue 496 | } 497 | url_port := v.Addresses[0].Addr + ":" + strconv.Itoa(portSlice.PortId) 498 | url_chan <- url_port 499 | } 500 | } 501 | defer close(url_chan) 502 | }() 503 | chairPool, _ := ants.NewPoolWithFunc(thread, func(i interface{}) { 504 | getHttp(i.(string)) 505 | }) // 协程池 506 | defer chairPool.Release() 507 | func() { // HTTP探测 消费者 508 | for { 509 | i, ok := <-url_chan 510 | if !ok { 511 | break 512 | } 513 | wg.Add(1) 514 | chairPool.Invoke(i) 515 | } 516 | }() 517 | wg.Wait() 518 | err := httpToXlsx(n.FileName) 519 | if err != nil { 520 | log.Fatal("[-]保存http服务探测失败,error:",err.Error()) 521 | } 522 | log.Printf("[+]http服务探测保存成功,请查看 %s", n.FileName + "_http探测结果.xlsx") 523 | } 524 | 525 | // 导出http探测结果 526 | func httpToXlsx(filename string)(error){ 527 | book := excelize.NewFile() 528 | book.SetSheetName("Sheet1", "Http服务探测结果") // 设置工作表名 529 | book.SetCellValue("Http服务探测结果", "A1", "Url") // 设置单元格的值 530 | book.SetCellValue("Http服务探测结果", "B1", "Title") 531 | book.SetCellValue("Http服务探测结果", "C1", "StatusCode") 532 | Index := 1 533 | for _, tmp := range HttpInfoStructs{ 534 | Index++ 535 | book.SetCellValue("Http服务探测结果", "A"+strconv.Itoa(Index), tmp.url) 536 | book.SetCellValue("Http服务探测结果", "B"+strconv.Itoa(Index), tmp.title) 537 | book.SetCellValue("Http服务探测结果", "C"+strconv.Itoa(Index), tmp.statuscode) 538 | } 539 | book.SetActiveSheet(0) // 设置工作簿的默认工作表 540 | book.SetColWidth("Http服务探测结果", "A", "A", 40) // 设置列宽度 541 | book.SetColWidth("Http服务探测结果", "B", "B", 30) 542 | book.SetColWidth("Http服务探测结果", "C", "C", 15) 543 | err := book.SaveAs(filename + "_http探测结果.xlsx") 544 | return err 545 | } 546 | 547 | // socket数据获取 548 | func getSocket(ip_port string){ 549 | slice1 := strings.Split(ip_port,"|") 550 | if len(slice1)!=2{ 551 | log.Printf("[-]错误的socket命令:%s\n", ip_port) 552 | return 553 | } 554 | defer wg.Done() 555 | connTimeout := time.Duration(int64(SocketTimeout))*time.Second 556 | conn, err := net.DialTimeout("tcp", slice1[0], connTimeout) 557 | defer func() { 558 | if conn != nil { 559 | conn.Close() 560 | } 561 | }() 562 | if err != nil { 563 | log.Printf("[-] %s socket连接失败, error:%s\n", slice1[0], err.Error()) 564 | return 565 | } 566 | writeTimeout := 5*time.Second 567 | err = conn.SetWriteDeadline(time.Now().Add(writeTimeout)) 568 | if err != nil { 569 | log.Printf("[-] %s 写入超时设置失败:%s\n", slice1[0], err.Error()) 570 | return 571 | } 572 | _, err = conn.Write([]byte(slice1[1])) 573 | if err != nil { 574 | log.Printf("[-] %s 发送命令失败 %s\n", slice1[0], err.Error()) 575 | return 576 | } 577 | buf := [512]byte{} 578 | readTimeout := 5*time.Second 579 | err = conn.SetReadDeadline(time.Now().Add(readTimeout)) 580 | if err != nil { 581 | log.Printf("[-] %s 读取超时设置失败:%s\n", slice1[0], err.Error()) 582 | return 583 | } 584 | n, err := conn.Read(buf[:]) 585 | if err != nil { 586 | log.Printf("[-] %s 获取数据失败 error:%s\n", slice1[0], err.Error()) 587 | return 588 | } 589 | result := string(buf[:n]) 590 | //log.Printf("[-] %s 获取数据成功:%s\n", slice1[0], result) 591 | var tmp_socket SocketInfoStruct 592 | tmp_socket.Ip = slice1[0] 593 | tmp_socket.Command = slice1[1] 594 | tmp_socket.Command_Result = result 595 | Lock.Lock() 596 | tmp_old, ok := SocketInfoMap[slice1[0]] 597 | if !ok{ 598 | SocketInfoMap[slice1[0]] = []SocketInfoStruct{tmp_socket} 599 | } else { 600 | SocketInfoMap[slice1[0]] = append(tmp_old, tmp_socket) 601 | } 602 | Lock.Unlock() 603 | } 604 | 605 | // socket探测主任务调度 606 | func(n *Nmap)SocketProbe(command string, thread int, socket_timeout int){ 607 | SocketTimeout = socket_timeout 608 | ip_chan := make(chan string, 50) 609 | command_slice := strings.Split(command,",") 610 | if len(command_slice)<=1{ 611 | log.Fatal("[-]Socket数据探测Command命令错误,请以,号分割命令") 612 | } 613 | go func() { // socket探测 生产者 614 | for _, v := range n.NmapRun.Hosts{ 615 | for _, portSlice := range v.Ports { 616 | if portSlice.State.State != "open"{ // 过滤未开放的端口 617 | continue 618 | } 619 | for _, tmp_command := range command_slice{ 620 | url_port := v.Addresses[0].Addr + ":" + strconv.Itoa(portSlice.PortId) + "|" + tmp_command 621 | ip_chan <- url_port 622 | } 623 | 624 | } 625 | } 626 | defer close(ip_chan) 627 | }() 628 | chairPool, _ := ants.NewPoolWithFunc(thread, func(i interface{}) { 629 | getSocket(i.(string)) 630 | }) // 协程池 631 | defer chairPool.Release() 632 | func() { // Socket探测 消费者 633 | for { 634 | i, ok := <-ip_chan 635 | if !ok { 636 | break 637 | } 638 | wg.Add(1) 639 | chairPool.Invoke(i) 640 | } 641 | }() 642 | wg.Wait() 643 | err := scoketToXlsx(n.FileName) 644 | if err != nil { 645 | log.Fatal("[-]保存socket服务探测失败,error:",err.Error()) 646 | } 647 | log.Printf("[+]socket服务探测保存成功,请查看 %s", n.FileName + "_socket探测结果.xlsx") 648 | } 649 | 650 | // 导出socket探测结果 651 | func scoketToXlsx(filename string)(error){ 652 | book := excelize.NewFile() 653 | book.SetSheetName("Sheet1", "socket服务探测结果") // 设置工作表名 654 | book.SetCellValue("socket服务探测结果", "A1", "IP") // 设置单元格的值 655 | book.SetCellValue("socket服务探测结果", "B1", "Command") 656 | book.SetCellValue("socket服务探测结果", "C1", "Result") 657 | Index := 1 658 | for _, v := range SocketInfoMap{ 659 | for _, tmp := range v{ 660 | Index++ 661 | book.SetCellValue("socket服务探测结果", "A"+strconv.Itoa(Index), tmp.Ip) 662 | book.SetCellValue("socket服务探测结果", "B"+strconv.Itoa(Index), tmp.Command) 663 | book.SetCellValue("socket服务探测结果", "C"+strconv.Itoa(Index), tmp.Command_Result) 664 | } 665 | } 666 | book.SetActiveSheet(0) // 设置工作簿的默认工作表 667 | book.SetColWidth("socket服务探测结果", "A", "A", 20) // 设置列宽度 668 | book.SetColWidth("socket服务探测结果", "B", "B", 12) 669 | book.SetColWidth("socket服务探测结果", "C", "C", 40) 670 | err := book.SaveAs(filename + "_socket探测结果.xlsx") 671 | return err 672 | } --------------------------------------------------------------------------------