Nmap作为一款强大的网络扫描工具,其拥有的功能是非常多的。Nmap的插件也极其强大,目前大部分的人都在使用python,perl等语言调用Nmap,然后等待扫面完毕在读取结果进而下一步操作,不过如果我们使用Nmap的插件进行整改,可以急速优化我们的扫描器。这篇文章与大家分享如何利用Nmap和NSE脚本(有关于Nmap下NSE脚本的介绍请参考文章末尾的参考链接)来将Nmap的扫描结果导入Mysq数据库并进一步利用golang语言用web界面的方式显示出来。这篇文章主要是教大家如何实现。具体的技术细节不作详细解释,大家可以参考文章末尾的链接。
首先简单说一下我所用的系统及软件:
Kali-Linux-2017.2-vm-amd64
Mysql 5.7.21-log(大家也可以用kali自带的mysql)
golang:go1.9.2 windows/amd64
Nmap以及其他所用到的已经在kali中集成,所以不需要安装。
由于nse脚本是基于lua的语法,所以我们还需要安装lua环境
安装lua下载lua安装包
curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
解压lua
tar zxf lua-5.3.0.tar.gz
编译安装
cd lua-5.3.0 && make linux test && make install
安装lua连接mysql相关组件
apt-get install lua-sql-*
插件编写
在kali中的nmap脚本目录(/usr/share/nmap/scripts)下创建mysql-output.nse脚本
cd /usr/share/nmap/scripts
touch mysql-output.nse
脚本内容:
-- 调入初始化模块
local luasql = require "luasql.mysql"
local nmap = require "nmap"
description = [[
This script stores the following nmap output into a mysql database: Hostname, IP, port number, protocol (tcp/udp), service and version
]]
---
-- you must have database
--
-- mysql -uroot -p123456 -e "CREATE DATABASE IF NOT EXISTS NmapScan default character set utf8 COLLATE utf8_general_ci";
--
-- @usage
-- nmap --script mysql-output <target>
--
-- @example
-- $ nmap -sS -A -F --script mysql-output 127.0.0.1
-- $ mysql -uroot -p123456 -e "select * from NmapScan.scanData";
--
-- +-----------+-----------+------+----------+-------+---------+---------------+
-- | hostname | ip | port | protocol | state | service | version |
-- +-----------+-----------+------+----------+-------+---------+---------------+
-- | localhost | 127.0.0.1 | 22 | tcp | open | ssh | OpenSSH6.6.1 |
-- | localhost | 127.0.0.1 | 25 | tcp | open | smtp | Postfix smtpd |
-- | localhost | 127.0.0.1 | 3306 | tcp | open | mysql | MySQL5.6.37 |
-- | localhost | 127.0.0.1 | 80 | tcp | open | http | nginx1.10.2 |
-- +-----------+-----------+------+----------+-------+---------+---------------+
--
--
---
author = "010sec"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"external", "safe"}
prerule = function () return true end
portrule = function () return true end
postrule = function () return true end
--
-- 调用MySQL
--
local env = luasql.mysql()
local conn = env:connect("NmapScan","root","123456","192.168.2.155","3306")
conn:execute"SET NAMES UTF8"
local cur,sql
--
-- 在执行之前检测如果表不存在则创建
--
function preaction()
local cur = conn:execute("CREATE TABLE IF NOT EXISTS scanData (hostname varchar(100), ip varchar(16), port integer(5), protocol varchar(3), state varchar(20), service varchar(100), version varchar(100))")
if (cur~=nil) then
print("Create tables success")
else
print("Crteat tables error")
end
end
--
-- 将端口信息存入数据库
--
function portaction (host, port)
local version = ""
if (port.version.product~=nil) then
version = port.version.product
end
if (port.version.version~=nil) then
version = version .. port.version.version
end
sql = string.format("INSERT INTO scanData VALUES ('%s', '%s', %d, '%s', '%s', '%s', '%s')" , conn:escape(host.name), conn:escape(host.ip), port.number, conn:escape(port.protocol), conn:escape(port.state), conn:escape(port.service), conn:escape(version))
cur = conn:execute(sql)
if (cur~=nil) then
print("Insert success")
else
print("Insert error")
end
end
--
-- 关闭MySQL环境
--
function postaction ()
conn:close()
env:close()
end
local ActionsTable = {
prerule = preaction,
portrule = portaction,
postrule = postaction
}
-- execute the action function corresponding to the current rule
action = function(...) return ActionsTable[SCRIPT_TYPE](...) end
其中连接数据库信息根据自己情况修改。
测试
nmap -sS -sA --script mysql-output 192.168.235.134
此处我测试的目标是metasploit 2靶机。
查看数据库,结果如下:
使用golang编写web程序显示扫描结果
我是使用了一个现成的留言板web程序,然后做了修改,变成了一个简单的显示数据库内容的web界面,以后可以进一步完善。
原程序文章链接:http://bbs.csdn.net/topics/390485541
文件结构
|----static
. |----main.css
----main.go
----index.html
main.go代码
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql" //导入了第三方包
"html/template"
"log"
"net/http"
)
type Message struct {
Hostname string
Ip string
Port int
Protocol string
State string
Service string
Version string
}
func CheckErr(err error) {
if err != nil {
fmt.Println("")
panic(err)
}
}
func List(w http.ResponseWriter, r *http.Request) {
var hostname string
var ip string
var port int
var protocol string
var state string
var service string
var version string
db, err := sql.Open("mysql", "root:123456@tcp(192.168.2.155:3306)/nmapscan?charset=utf8") //设置连接数据库相关信息
CheckErr(err)
rows, err := db.Query("select hostname, ip, port, protocol, state, service, version from scandata")
CheckErr(err)
var msgSlice []*Message
for rows.Next() {
err = rows.Scan(&hostname, &ip, &port, &protocol, &state, &service, &version)
CheckErr(err)
msg := new(Message)
msg.Hostname = hostname
msg.Ip = ip
msg.Port = port
msg.Protocol = protocol
msg.State = state
msg.Service = service
msg.Version = version
//fmt.Fprintf(w, id)
msgSlice = append(msgSlice, msg)
}
t, err := template.ParseFiles("index.html")
if err != nil {
log.Println(err)
}
t.Execute(w, &msgSlice)
}
func main() {
http.HandleFunc("/", List)
http.HandleFunc("/list", List)
http.Handle("/static/", http.FileServer(http.Dir("./")))
//http.HandleFunc("/", sayhelloName) //设置访问的路由
err := http.ListenAndServe(":9090", nil) //设置监听的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
index.html代码
<!doctype html>
<html>
<header>
<title>nmapscandata</title>
<link type="text/css" rel="stylesheet" href="static/main.css"/>
</header>
<body>
<h2>nmap扫描结果</h2>
<table class="bordered">
<thead>
<tr>
<th>Hostname</th>
<th>ip</th>
<th>Port</th>
<th>Protocol</th>
<th>State</th>
<th>Service</th>
<th>Version</th>
</tr>
</thead>
{{range .}}
<tr>
<td>{{.Hostname}}</td>
<td>{{.Ip}}</td>
<td>{{.Port}}</td>
<td>{{.Protocol}}</td>
<td>{{.State}}</td>
<td>{{.Service}}</td>
<td>{{.Version}}</td>
</tr>
{{end}}
</table>
<br><br>
<br>
</body>
</html>
mian.css代码
body {
width: 600px;
margin: 40px auto;
font-family: 'trebuchet MS', 'Lucida sans', Arial;
font-size: 14px;
color: #444;
}
table {
*border-collapse: collapse; /* IE7 and lower */
border-spacing: 0;
width: 100%;
}
.bordered {
border: solid #ccc 1px;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
-webkit-box-shadow: 0 1px 1px #ccc;
-moz-box-shadow: 0 1px 1px #ccc;
box-shadow: 0 1px 1px #ccc;
}
.bordered tr:hover {
background: #fbf8e9;
-o-transition: all 0.1s ease-in-out;
-webkit-transition: all 0.1s ease-in-out;
-moz-transition: all 0.1s ease-in-out;
-ms-transition: all 0.1s ease-in-out;
transition: all 0.1s ease-in-out;
}
.bordered td, .bordered th {
border-left: 1px solid #ccc;
border-top: 1px solid #ccc;
padding: 10px;
text-align: left;
}
.bordered th {
background-color: #dce9f9;
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebf3fc), to(#dce9f9));
background-image: -webkit-linear-gradient(top, #ebf3fc, #dce9f9);
background-image: -moz-linear-gradient(top, #ebf3fc, #dce9f9);
background-image: -ms-linear-gradient(top, #ebf3fc, #dce9f9);
background-image: -o-linear-gradient(top, #ebf3fc, #dce9f9);
background-image: linear-gradient(top, #ebf3fc, #dce9f9);
-webkit-box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
-moz-box-shadow:0 1px 0 rgba(255,255,255,.8) inset;
box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
border-top: none;
text-shadow: 0 1px 0 rgba(255,255,255,.5);
}
.bordered td:first-child, .bordered th:first-child {
border-left: none;
}
.bordered th:first-child {
-moz-border-radius: 6px 0 0 0;
-webkit-border-radius: 6px 0 0 0;
border-radius: 6px 0 0 0;
}
.bordered th:last-child {
-moz-border-radius: 0 6px 0 0;
-webkit-border-radius: 0 6px 0 0;
border-radius: 0 6px 0 0;
}
.bordered th:only-child{
-moz-border-radius: 6px 6px 0 0;
-webkit-border-radius: 6px 6px 0 0;
border-radius: 6px 6px 0 0;
}
.bordered tr:last-child td:first-child {
-moz-border-radius: 0 0 0 6px;
-webkit-border-radius: 0 0 0 6px;
border-radius: 0 0 0 6px;
}
.bordered tr:last-child td:last-child {
-moz-border-radius: 0 0 6px 0;
-webkit-border-radius: 0 0 6px 0;
border-radius: 0 0 6px 0;
}
/*----------------------*/
.zebra td, .zebra th {
padding: 10px;
border-bottom: 1px solid #f2f2f2;
}
.zebra tbody tr:nth-child(even) {
background: #f5f5f5;
-webkit-box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
-moz-box-shadow:0 1px 0 rgba(255,255,255,.8) inset;
box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;
}
.zebra th {
text-align: left;
text-shadow: 0 1px 0 rgba(255,255,255,.5);
border-bottom: 1px solid #ccc;
background-color: #eee;
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#eee));
background-image: -webkit-linear-gradient(top, #f5f5f5, #eee);
background-image: -moz-linear-gradient(top, #f5f5f5, #eee);
background-image: -ms-linear-gradient(top, #f5f5f5, #eee);
background-image: -o-linear-gradient(top, #f5f5f5, #eee);
background-image: linear-gradient(top, #f5f5f5, #eee);
}
.zebra th:first-child {
-moz-border-radius: 6px 0 0 0;
-webkit-border-radius: 6px 0 0 0;
border-radius: 6px 0 0 0;
}
.zebra th:last-child {
-moz-border-radius: 0 6px 0 0;
-webkit-border-radius: 0 6px 0 0;
border-radius: 0 6px 0 0;
}
.zebra th:only-child{
-moz-border-radius: 6px 6px 0 0;
-webkit-border-radius: 6px 6px 0 0;
border-radius: 6px 6px 0 0;
}
.zebra tfoot td {
border-bottom: 0;
border-top: 1px solid #fff;
background-color: #f1f1f1;
}
.zebra tfoot td:first-child {
-moz-border-radius: 0 0 0 6px;
-webkit-border-radius: 0 0 0 6px;
border-radius: 0 0 0 6px;
}
.zebra tfoot td:last-child {
-moz-border-radius: 0 0 6px 0;
-webkit-border-radius: 0 0 6px 0;
border-radius: 0 0 6px 0;
}
.zebra tfoot td:only-child{
-moz-border-radius: 0 0 6px 6px;
-webkit-border-radius: 0 0 6px 6px
border-radius: 0 0 6px 6px
}
运行此项目后访问127.0.0.1:9090
运行web界面效果如图
参考链接
http://www.freebuf.com/articles/network/150613.html
https://nmap.org/book/nse-api.html
http://www.cnblogs.com/liun1994/p/7041373.html
http://blog.csdn.net/xumesang/article/details/51859344
https://zhuanlan.zhihu.com/p/27224457
https://github.com/Z-0ne/ScanS2-045-Nmap/blob/master/struts2-scan.nse