前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Nmap NSE 库分析 >>> shortport

Nmap NSE 库分析 >>> shortport

作者头像
意大利的猫
发布2020-08-20 14:45:21
7020
发布2020-08-20 14:45:21
举报
文章被收录于专栏:漫流砂漫流砂漫流砂

https://nmap.org/nsedoc/lib/shortport.html

0x00 简介

这个库是专门为了端口规则 (portrules) 而准备的,用来构造端口规则,从下面这个图就可以看出来了

基本上都是调用 shortport 的方法来判定是否符合相关规则,返回 true or false 来绝对是否进入 action 函数

0x01 方法

函数名

描述

http(host, port)

匹配比较可能是 http 服务的端口规则

port_is_excluded(port, proto)

检查是否给定的端口和协议已经被排除在外了

port_or_service(ports, services, protos, states)

当给定开放端口匹配到端口或者服务规则,则返回一个令 portrule 为 true 的函数

port_range(range)

当给定开放端口在指定的端口范围内时,返回一个令 portrule 为 true 的函数

portnumber(ports, protos, states)

当给定的开放端口匹配到一个独立端口或者一系列端口,返回 true

service(services, protos, states)

当给定开放端口匹配到指定服务,则返回一个令 portrule 为 true 的函数

ssl(host, port)

匹配到类似 ssl 服务时返回 true

version_port_or_service(ports, services, protos, states, rarity)

返回一个portrule,该portrule在给定与端口号或服务名称匹配的开放端口时返回true,并且未在nmap service probes文件的exclude port指令中列出。如果版本强度小于rarity,则portrule始终返回false(暂不理解这个版本强度)

0x02 方法实战

这回我们要折腾端口规则了,action 可以先放一放,端口规则同样是一个函数

0x001 port_is_excluded

port_is_excluded 有两个参数, port, proto ,即端口,协议 ,如果端口和协议被排除了,则返回 true

这个不是返回一个函数,而是返回一个值,所以无法作为端口规则,应该作为检查过程中调用

0x002 portnumber

portnumber 函数有三个参数: ports, protos, states

  • ports 一个端口或者端口列表
  • protos 协议,默认是 tcp
  • states 状态,默认为 open , open | filtered

我们看一下其他脚本是怎么使用这个规则的

我的编程与理解能力实在是不高,导致我一看上面这个图当时就蒙了,参数端口都是确定的,而不是我们我想象的扫描的端口或者端口们,所以我就从代码上看看咋回事吧!

portnumber = function(ports, protos, states)
  protos = protos or "tcp"
  states = states or {"open", "open|filtered"}

  if type(ports) ~= "table" then
    ports = {ports}
  end
  if type(protos) ~= "table" then
    protos = {protos}
  end
  if type(states) ~= "table" then
    states = {states}
  end

  return function(host, port)
    return port_includes(ports, port.number)
      and tableaux.contains(protos, port.protocol, true)
      and tableaux.contains(states, port.state, true)
  end
end

前面是比较好理解的,就是构造 protos、states、以及ports,关键在于 port_includes 和后面这几个函数,先看 port_includes 吧

local function port_includes(t, value)
  for _, elem in ipairs(t) do
    if elem == value then
      return true
    elseif type(elem) == "string" then
      local pstart, pend = elem:match("^(%d+)%-(%d+)$")
      if not pstart then
        pstart = elem:match("^(%d+)$")
        pend = pstart
      end
      pstart, pend = tonumber(pstart), tonumber(pend)
      assert(pstart,"Incorrect port range specification.")
      assert(pstart<=pend,"Incorrect port range specification, the starting port should have a smaller value than the ending port.")
      assert(pstart>-1 and pend<65536, "Port range number out of range (0-65535).")
      if value >= pstart and value <= pend then
        return true
      end
    end
  end
  return false
end

portnumber 给port_includes 传递的参数为 ports, port.number ,其中 port.number 就是我们扫描的端口(们)。之后在 port_includes 中会将 ports 遍历,之后与我们扫描的做对比,如果我们扫描的端口在 portnumber 的端口参数范围内就会返回 true 那这样就可以理解了,这个函数参数就是限定了要去匹配的端口和服务,而不是全部都匹配

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---

local url = require "url"
local stdnse = require "stdnse"
local base64 = require "base64"
local shortport = require "shortport"

description = [[
This is a test for http.lua's functions
]]

author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}

prerule = function()
    print("functest running")
end
portrule = shortport.portnumber({80, 443}, 'tcp')

action = function()
    local output = stdnse.output_table()
    local result = "True"
    output.result = result
    return output
end

这里只规定了80,443 ,协议为 tcp ,如果返回true,说明匹配上了

可以看到返回 True,匹配成功,现在我把端口不变,协议变成 udp


可以看到,我们规定匹配到的协议是 udp 后,没有 result 返回

0x003 service

service 函数有三个参数:services, protos, states

  • services 服务名或者服务名列表,例如 http
  • protos 协议名或列表,默认 tcp
  • states 状态,默认为 open , open | filtered

我们看一下其他脚本们是如何调用这个函数的

大家基本上很少直接使用这个,使用也就是直接用第一个参数

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---

local url = require "url"
local stdnse = require "stdnse"
local base64 = require "base64"
local shortport = require "shortport"

description = [[
This is a test for http.lua's functions
]]

author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}

prerule = function()
    print("functest running")
end
portrule = shortport.service('http','tcp')

action = function()
    local output = stdnse.output_table()
    local result = "True"
    output.result = result
    return output
end

测试一下

可以看到,返回 true ,识别为http服务了,现在我们换成 https, tcp

可以看到,这回就没有返回 True 了

0x004 port_or_service

port_or_service 函数有四个参数:ports, services, protos, states

这个其实就是把上面的两个函数 portnumber 和 service 合在了一起,在我印象中应该是使用的更加频繁

参数比较完整的是这一条

portrule = shortport.port_or_service({50000,60000}, {"drda","ibm-db2"}, "tcp", {"open", "open|filtered"})

可以看到四个参数都用了

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---

local url = require "url"
local stdnse = require "stdnse"
local base64 = require "base64"
local shortport = require "shortport"

description = [[
This is a test for http.lua's functions
]]

author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}

prerule = function()
    print("functest running")
end
portrule = shortport.port_or_service({80, 443},{'https','http'})

action = function()
    local output = stdnse.output_table()
    local result = "True"
    output.result = result
    return output
end

还是用 nc 来测试一下

可以看到成功识别到

0x005 version_port_or_service

version_port_or_service 有5个参数 ports, services, protos, states, rarity

  • ports 端口列表
  • services 服务列表
  • protos 协议列表
  • states 状态
  • rarity 这个是扫描强度,强度越高版本识别可能会越精确,0-9 范围,默认是 7

这个其实就是将 port_or_service 和 port_is_excluded 再加上 nmap.version_intensity 结合在一起

我们看一下这个函数大家是怎么用的

基本上都是只用了四个参数,最后一个强度基本没有用的,我们演示尽量用的全一些吧

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---

local url = require "url"
local stdnse = require "stdnse"
local base64 = require "base64"
local shortport = require "shortport"
local nmap = require "nmap"

description = [[
This is a test for http.lua's functions
]]

author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}

prerule = function()
    print("functest running")
end
portrule = shortport.version_port_or_service({80, 443},{'https','http'},'tcp', 'open', 8)

action = function()
    local output = stdnse.output_table()
    local result = "True"
    output.result = result
    return output
end

测试一下

可以看到,返回了 True

这里我就有一个好奇了,根据以下代码

version_port_or_service = function(ports, services, protos, states, rarity)
  return function(host, port)
    local p_s_check = port_or_service(ports, services, protos, states)
    return p_s_check(host, port)
      and not(port_is_excluded(port.number, port.protocol))
      and (nmap.version_intensity() >= (rarity or 7))
  end
end

只有当 nmap.version_intensity() >= 我们提供的值或者7的时候才会返回 true ,我们设置rarity为 8,那么 nmap.version_intensity() 是多少呢?搞一下不就知道了

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---

local url = require "url"
local stdnse = require "stdnse"
local base64 = require "base64"
local shortport = require "shortport"
local nmap = require "nmap"

description = [[
This is a test for http.lua's functions
]]

author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}

prerule = function()
    print("functest running")
end
portrule = shortport.version_port_or_service({80, 443},{'https','http'},'tcp', 'open', 8)

action = function()
    local output = stdnse.output_table()
    local result = "True"
    output.ver = nmap.version_intensity()
    output.result = result
    return output
end

我们把这个信息用 ver 来承接并打印出来

可以看到, nmap.version_intensity() 的值为9 所以肯定是大于等于 rarity (0-9),其实这个值我们可以在调用函数的时候设置超过 9,但是没有意义,超过 9 就没有定义了

为了显示效果,我想把 nmap.version_intensity() 降低一下,经过查询,nmap提供了一个参数 --version-intensity

现在我们调用时设置是 8, 我们把 nmap.version_intensity() 设置为 7 ,这样的话应该就不会显示 True 了

怪事来了,即使我们通过参数设置了 nmap.version_intensity() 为 7 ,但是结果还是 9 ,不知道因为啥

所以这样大家调用这个函数的时候都不加最后一个参数也就可以理解了,具体因为什么以后问问开发者吧!

0x006 http

http 函数有两个默认参数 host,port ,一般都是直接 shortport.http 不加参数的,我们看一下大家怎么用的

可以看到,大家都是不加参数直接用的,就表示是http服务

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---

local url = require "url"
local stdnse = require "stdnse"
local base64 = require "base64"
local shortport = require "shortport"
local nmap = require "nmap"

description = [[
This is a test for http.lua's functions
]]

author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}

prerule = function()
    print("functest running")
end
portrule = shortport.http

action = function()
    local output = stdnse.output_table()
    local result = "True"
    output.result = result
    return output
end

测试一下

可以看到识别为了 http 服务,实际上是因为我们监听的是 80 端口,如果我换一个 2333 端口呢?

可以看到,已经不再被识别为 http了,自然脚本中 action 代码也就没有执行

那么问题来了,这个 http 函数是怎么判断 http 服务的呢?

http = port_or_service(LIKELY_HTTP_PORTS, LIKELY_HTTP_SERVICES)

这个函数就这么一行代码,其中有两个参数比较重要 LIKELY_HTTP_PORTS, LIKELY_HTTP_SERVICES ,那这两个常量都包含什么呢?

LIKELY_HTTP_PORTS = {
  80, 443, 631, 7080, 8080, 8443, 8088, 5800, 3872, 8180, 8000
}
LIKELY_HTTP_SERVICES = {
  "http", "https", "ipp", "http-alt", "https-alt", "vnc-http", "oem-agent",
  "soap", "http-proxy", "caldav", "carddav", "webdav",
}

可以看到这个函数会将 80、443、631 .... 一些端口识别为 http ;会将 http、https、webdav ......一些服务识别为 http ,当然获取的目标信息都是由nmap主程序给的,所以如果我们觉得这里不全的可以添加进去,比如 weblogic 的 7001 ,那我们就是可以添加进去,就像我们之前修改 User-Agent

0x007 ssl

与 http 一样,默认参数

可以看到在端口规则处使用 ssl 函数的只有一个脚本,使用方法也是和 http 一毛一样

ssl 的判断更加复杂,其中有一项也是端口以及服务,我们看一下列表

local LIKELY_SSL_PORTS = {
  261, -- nsiiops
  271, -- pt-tls
  324, -- rpki-rtr-tls
  443, -- https
  465, -- smtps
  563, -- snews/nntps
  585, -- imap4-ssl
  636, -- ldapssl
  853, -- domain-s
  989, -- ftps-data
  990, -- ftps-control
  992, -- telnets
  993, -- imaps
  994, -- ircs
  995, -- pop3s
  2221, -- ethernet-ip-s
  2252, -- njenet-ssl
  2376, -- docker-s
  3269, -- globalcatLDAPssl
  3389, -- ms-wbt-server
  4911, -- ssl/niagara-fox
  5061, -- sip-tls
  5986, -- wsmans
  6679,
  6697,
  8443, -- https-alt
  9001, -- tor-orport
  8883, -- secure-mqtt
}
local LIKELY_SSL_SERVICES = {
  "ftps", "ftps-data", "ftps-control", "https", "https-alt", "imaps", "ircs",
  "ldapssl", "ms-wbt-server", "pop3s", "sip-tls", "smtps", "telnets", "tor-orport",
}

同样的,你觉得使用了 ssl 却不在里面的可以自行添加

0x008 port_range

port_range 只有一个参数:range 是一个范围,格式案例 "T:80,1-30,U:31337,21-25"

我们还是来看一下大家使用这个脚本的方法

只有一条,其中 portarg 似乎是一个自定义的参数

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---

local url = require "url"
local stdnse = require "stdnse"
local base64 = require "base64"
local shortport = require "shortport"
local nmap = require "nmap"

description = [[
This is a test for http.lua's functions
]]

author = "test94"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default"}

prerule = function()
    print("functest running")
end
portrule = shortport.port_range("T:2333,4000-5555")

action = function()
    local output = stdnse.output_table()
    local result = "True"
    output.result = result
    return output
end

测试一下,nc监听 2333端口

可以看到返回 True ,匹配成功

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 NOP Team 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 简介
  • 0x01 方法
  • 0x02 方法实战
    • 0x001 port_is_excluded
      • 0x002 portnumber
        • 0x003 service
          • 0x004 port_or_service
            • 0x005 version_port_or_service
              • 0x006 http
                • 0x007 ssl
                  • 0x008 port_range
                  相关产品与服务
                  SSL 证书
                  腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档