c4rt1y

lua之nmap插件编写-数据库编写

0x01 Nmap介绍

Nmap作为一款优秀的端口扫描器,被所有渗透测试人员当作工作中必不可少的辅助工具,它不仅支持多种扫描方式,还支持添加漏洞测试脚本,在强大的lua脚本支持下,使得nmap更加如虎添翼,官方的nmap自带有非常多的脚本,不过官网比较坑爹,没有完善的nse脚本编写资料,所以只能间接的通过官网nse-api,别人编写nse脚本与网上的资料来学习编写nmap的nse规则。

0x02 Nmap脚本流程

Nmap的脚本流程网上也有一些图片,因而这里也不举例子了,我们直接根据脚本的运行阶段不同分为四类:Prerule scripts、Host scripts、Service scripts、Postrule scripts。Prerule scripts使用于前期准备阶段Host scripts作用于主机的发现,比如版本信息、端口扫描等在代码中,Service scripts对端口或者版本信息进行操作,Postrule scripts对Nmap数据进行格式化输出。在代码中,他们被分为prerule、hostrule、portrule、postrule,分别对于上述的Prerule scripts、Host scripts、Service scripts、Postrule scripts。Prerule scripts,通过他们的之前不同的作用加上nmap默认的脚本语法,我们可以编写插件脚本。

0x03 nmap插件编写基础

#前言,nmap调用插件	
#查看80端口title,默认使用nmap下的script目录
nmap 127.0.0.1 --script http-title
#若不在该目录,则可以使用全路径或者相对路径

#-d调试,代码出错等情况
nmap 127.0.0.1 --script http-title -d

#最简陋的代码,该文件存放于nmap/script/目录下
vi prerule-test.nse

prerule

#上述代码就编写OK,会看到命令行里面存在prerule test
nmap 127.0.0.1 --script  prerule-test


#如果作为标准,放出去给大家使用,则会加上个人信息
vi prerule-test-01.nse

prerule001

#上述文就是一个类似于标准的nmap的nse文件,不过无意义罢了,比如你可以把prerule改成其他三个,不过一时间不是很容易看出他们的执行周期
#action只允许只有一个,也由于个人偷懒,直接弄个比较繁杂的代码,也比较好看

vi four-rule-to-show.nse

-- 导入nmap依赖包
local nmap= require "nmap"


-- 描述
description = [[ 
  this is test script 
]]

-- 作者与其他描述
author = "c4rt1y"
license = "Same as Nmap -- See https://namp.org/book/man-legal.html"
categories = {"default","discovery","safe"}


-- prerule,在Nmap扫描之前触发脚本执行,Nmap扫描之前结束,该类脚本作为初始化脚本。
-- hostrule,在Nmap执行主机发现完毕时触发脚本执行,Nmap扫描结束,在postrule前结束,通过主机发现的结果来触发该类脚本,该类脚本可以作为探测脚本。
-- portrule,在Nmap执行端口扫描或版本侦测时触发,在下一个端口或者版本探测之前结束,该类脚本可以作为探测脚本。
-- postrule,在Nmap执行完毕所有扫描后,通常用于扫描结果的数据提取和整理,该类型脚本用于归纳总结。

-- 对4种类型进行使用

prerule = function () return true end
hostrule = function() return true end
portrule = function() return true end
postrule = function () return true end


--  启动于Nmap扫描之前,并在扫描之前结束

function preaction()
  print("this is a preaction test")
  local pre1action="preaction test"
  return pre1action
end

-- 启动于prerule之后,Nmap扫描之前,并在扫描之后结束。

function hostaction()
  print("this is a hostaction test")
  local host1action="hostaction test"
  return host1action
end

-- 在Nmap执行端口扫描或版本侦测时触发,在下一个端口或者版本探测之前结束

function portaction()
  print("this is a portaction test")
  local port1action="portaction test"
  return port1action
end

-- Nmap执行完毕所有扫描后,归纳总结

function postaction()
  print("this is a postaction test")
  local post1action="postaction test"
  return post1action	
end


-- 定义4钟脚本函数类型,通过ActionsTable作为action

local ActionsTable = {
  prerule  = preaction,
  hostrule = hostaction,
  portrule = portaction,
  postrule = postaction
}

-- 运行action
-- execute the action function corresponding to the current rule
action = function(...) return ActionsTable[SCRIPT_TYPE](...) end

four-rule-to-show

从图中可以看到,4种函数的运行范围和周期如我在four-rule-to-show.nse所说基本相似。

0x04 nmap插件编写-数据库写入编写

现在,思路上大致可以清晰一点,基本上,我们应该最常使用的是portrule,如果某个端口存在或者某个服务存在,则可以使用portrule进行编写攻击脚本。这种例子也比较多了,比如随风浪子90,倾旋,灯塔实验室,甚至不认识,反正看他们的nse脚本然后改吧改吧,也是可以出来的。

这里咱就编写一个output-mysql.nse,至少,会比使用python、perl等语言调用更加快捷,因为按照上述的0x03,我们可以不等他执行完毕就可以进行写库操作
首先我们在数据库里面创建一个数据库,我设置的数据库名字叫做NmapScan,这是因为使用的lua的mysql库存在问题

mysql -uroot -p123456 -e "CREATE DATABASE IF NOT EXISTS NmapScan default character set utf8 COLLATE utf8_general_ci;"

如果对lua代码不懂,可以查看我的另一篇文章,也算是承上启下,《lua之安装和mysql数据库操作》,基础的安装步骤啥的就不讲了,那么,咱们就可以写一个简单的demo。

vi output-mysql.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
]]
author = "c4rt1y"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"external", "safe"}

-- 建立3种模式
prerule = function () return true end
portrule = function () return true end
postrule = function () return true end

-- 使用数据库

local env = luasql.mysql()
local conn = env:connect("NmapScan","root","123456")

conn:execute"SET NAMES UTF8"
local cur,sql

--
-- 创建数据库某表,这张表是随意构造的,木有对其优化,应该加以个iflag,判断数据库是否更新,时时读取,提升检测速度
--

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


-- 使用postaction 关闭数据库引擎

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

nmap -sS -A -F --script mysql-output  127.0.0.1
#查看信息

mysql-output

基本的思路最终结束于此,感谢倾旋6月份的文章,这个写出来也很久了,只是个人比较拙计吧,只会和部分朋友分享,有些东西,感觉让人不可理喻。未来也不知道还走不走安全这条路子,慢慢把自己会的都写出来吧,再过些时间,就忘光了。
代码地址(写的简陋,勿喷):
https://coding.net/c4rt1y/Nmap-Script
https://github.com/c4rt1y/Nmap-Script

0x05 资料来源

https://mp.weixin.qq.com/s?__biz=MzI5MDQ2NjExOQ==&mid=2247484047&idx=1&sn=73880e568c3cda7118928217ff9fccce&scene=21#wechat_redirect
http://www.cnblogs.com/liun1994/p/7041373.html
https://zhuanlan.zhihu.com/p/27224457
https://github.com/Z-0ne/ScanS2-045-Nmap/blob/master/struts2-scan.nse
http://blog.csdn.net/xumesang/article/details/51859344
https://nmap.org/book/nse-tutorial.html
https://nmap.org/book/nse-api.html
https://nmap.org/
GoTop