Skip to content

Latest commit

 

History

History
138 lines (84 loc) · 11.4 KB

File metadata and controls

138 lines (84 loc) · 11.4 KB

七、编写 Nmap 脚本

现在我们已经介绍了 NSE 是如何工作的,现在是学习如何编写第一个 Nmap 脚本的时候了。由于编写 Nmap 脚本的通用性和极为定制的特性,有几种不同的方法来生成执行各种功能的脚本,也有许多优点和缺点来编写自己的脚本。

虽然从头开始创建 Nmap 脚本可能并不总是完成任务的最快方式(因为几乎总是有一个脚本已经存在,用于您可能需要的任何目的),在某些情况下,利用 Nmap 脚本引擎强大的内置功能可以完全正确地编写自己的脚本。

在本章中,我们将介绍以下主题:

  • Nmap 脚本的剖析
  • 编写 Nmap 脚本的头
  • 创建规则
  • 定义脚本的操作
  • 调试 Nmap 脚本

Nmap 脚本的剖析

Nmap 脚本由几个独特的部分组成,每个部分定义了脚本要执行的不同区域,或 Nmap 解释预期输出的不同区域。为了确保脚本有效运行(并且 Nmap 能够理解如何解释数据),我们必须在创建的任何脚本中始终包含几个主要方面。

尽管 Nmap 脚本是用 Lua(一种解释性编程语言)编写的,但重要的是要记住,这些脚本不是可以独立运行的独立可执行文件。与其运行一个需要 Nmap 的脚本,不如将 Nmap 脚本看作是一种独特的 Nmap 编程语言的简单指令集。

Nmap 脚本由三个独特的部分组成:

  • :Nmap 脚本的部分包括脚本的文档和分类,以便 Nmap 和 NSE 数据库能够成功地将脚本分类到适当的区域。
  • 规则:脚本的部分准确定义了 Nmap 脚本的执行位置和方式。因为脚本在运行时利用了 Nmap 扫描的数据,所以某些元素可以触发脚本运行。这实际上是一个触发器,用于评估脚本是否应执行。
  • 动作:最后,Nmap 脚本的部分就是动作发生的地方(你猜对了!)。这是脚本中执行大量处理的部分,在头部定义了脚本并且规则触发了操作之后。

现在我们已经了解了 Nmap 脚本是如何编写的,是时候开始工作并开始编写一个了。因为每一个 Nmap 脚本都是如此独特,我们将重新创建一个已经运行的脚本,但它显示了 NSE 的强大功能。

我们对该脚本的案例研究将是编写一个简单易用的 Nmap 脚本,该脚本使用 Nmap 的内置功能(结合 NSE 的功能)来确定 web 服务器是否有robots.txt文件。robots.txt文件表明网站的哪些区域应该(也不应该)被网络爬虫和搜索引擎索引,并且通常会列出敏感目录,并指示不为其索引。出于这个原因,它们对于安全专业人员和渗透测试人员来说非常有趣,因为我们正在寻找的正是那些敏感文件和目录!

定义 Nmap 脚本–脚本头

每个 Nmap 脚本必须使用在脚本开头定义的特定必需变量创建。成功执行所需的任何 Nmap 先决条件、脚本分类的定义(例如,脚本是否具有侵入性、安全性、是否包含漏洞等)以及许可证也是标头中必需的内容之一。

Defining an Nmap script – script headers

前面的屏幕截图说明了 Nmap 脚本所需的各个部分,每个部分对程序的成功执行都至关重要。让我们浏览一下这些元素,以确定脚本作者正在做什么。

首先,定义几个变量(由本地前缀定义)。为了确保适当地包括每个 Nmap 元素,提出了若干要求。

接下来,创建一个较长的变量来描述。这是一个多行 Lua 变量,封装在[[]]括号中。该区域应该包括 Nmap 脚本的基本描述,以便在以编程方式运行时,可以选择正确的脚本。

description 变量下面是一个完全注释的文本块,用于定义脚本的用法。在 Lua 中,--序言注释掉了那行代码,使其在脚本执行时不运行。您可以很容易地看到@usage块是如何格式化的,只需显示脚本应该如何运行,以及它可能接受的任何参数,以及@output块是如何格式化的。这些块显示了如何正确运行脚本,如何在命令行上传递参数(如果需要),以及您应该从相关脚本获得什么输出。

在注释的 out 块下面是 Nmap 解析的其他几个变量定义。具体来说,author块(这是您希望为脚本获得信任的方式)、license块(出于分发目的,通常与 Nmap 相同,但如果您希望保护脚本的某些元素,可以以某些方式指定)categories数组(其中列出了脚本应属于的类别)。例如,如果您的脚本是侵入性的,请确保将其标记为侵入性的。

对于我们的脚本,我们只需要几个必需的includes,这使得我们的标题相对较短。让我们创建我们的 head 部分,如下所示(当然,可以随意修改脚本!)

  local http = require "http"
  local nmap = require "nmap"

  description = [[
  Checks to see if robots.txt exists on a web server.
  ]]

  author = "Nmap Essentials readers"
  license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
  categories = {"default", "discovery", "safe"}

非常简单!我们需要 HTTP 模块来执行对所讨论的robots.txt的 HTTP GET 请求(在开放端口 80 上),当然我们还需要 Nmap include 来利用 Nmap 脚本引擎。您可以看到,我们的描述非常简单,我们定义了作者、许可证和类别,以帮助用户确定脚本何时可以安全有效地运行。

现在我们的脚本的开头已经完成,让我们来看看规则。

触发功能–规则

Nmap 脚本的规则或 portrule 部分确定操作应该在何时发生(我们将在下一节中介绍)。清楚地定义这一点很重要,这样我们就可以确信脚本将在每次需要时运行(基于端口号和版本)。有两种方法可以实现这种类型的规则:标准 portrule 文档和 NSE 中构建的名为shortport的助手库。

定义规则实际上非常简单,这取决于我们要寻找的内容。在我们的robots.txt检测脚本(恰当地命名为robots.nse的情况下),我们只想在端口 80 上触发,看看robots.txt是否存在。

如果我们编写的是生产脚本,而不是概念证明,那么最好使用 shortport 的端口或服务功能在端口 80 或 Nmap 通过其底层功能检测到的任何 web 服务器上触发。然而,在我们的例子中,我们可以简单地定义一些更容易理解的东西:

  portrule = function(host, port)
    return port.state == "open"
  end

如您所见,这是一个非常小的 portrule,当port.stateopen时,它将返回true。这些是内置的 Nmap 功能,当脚本运行时,将根据 portrule 检查每个端口。

虽然我们的 portrule 有意让人非常容易理解,但许多生产脚本都有非常复杂的 portrules,这些 portrules 是根据特定的版本和配置设置来触发不同的分析元素的。要了解有关 advanced portrule 和 shortport 库的更多信息,您可以在Nmap 脚本引擎文档NSEDoc门户)上阅读完整概述。

定义脚本的动作

在定义了 portrule 之后,剩下的唯一一步就是定义 portrule 返回true时执行的操作。在我们的例子中,我们想检查我们正在扫描的 web 服务器上是否存在robots.txt

为了确定服务器是否存在,我们需要了解一点关于超文本传输协议HTTP的内容。首先,请求页面的方法是通过 HTTP GET 请求。例如,如果我们想去http://google.com/images ,我们的浏览器会向Google.com的服务器发送包含GET /images的请求。

如果 GET 请求的状态为OK,则 web 服务器返回状态码200。如果存在服务器端错误,将返回一个500错误。如果页面移动,将返回范围为300的错误。最后(出于我们的目的),如果存在授权错误或文件未找到错误,服务器将分别返回403404

为了定义动作功能,我们需要执行以下步骤:

  1. 请求robots.txt页面。
  2. 看看它是否在那里。

以下动作段定义了该请求:

  action = function(host, port)
  local robots = http.get(host, port, "/robots.txt")

  if robots.status == 200 then
    return "robots.txt status 200"
  else
    return "robots.txt status: " .. robots.status
  end
  end

正如您在前面的代码片段中所看到的,这是一个非常简单的操作部分。让我们一步一步地了解这个过程:

  1. 首先,我们定义接受参数的主机和端口的操作函数。一旦 portrule 触发,这些将自动传递到操作块。

  2. 接下来,我们定义一个局部变量(称为 robots),它是 NSE 的http.get请求的 HTTP 结果。在本例中,我们正在执行对当前正在扫描的主机和端口的访问,并向/robots.txt发出请求。

  3. 一旦我们收到 HTTP 数据,我们就可以很容易地做出一个if语句来确定状态是200 OK响应还是其他什么。我们可以将它与一个较短的if语句(而不是 if/else)结合起来,但是看看如何为输出提供多种可能性是很有用的。

  4. If the output is not 200, we go to the else statement and see what the status is. For example, if the status is 404, we know that it simply doesn't exist; if we get a 500 server error or a 403 not authorized, however, it might be worth looking into a greater depth:

    Defining a script's action

如您所见,运行这个脚本(以及任何自定义 Nmap 脚本)非常简单。扫描scanme.nmap.org时,您可以清楚地看到没有robots.txt-我们只是收到一个404错误。如果我们扫描一个有robots.txt页面的服务,我在上创建了一个测试用例 http://dshaw.net/ 为此,我们看到了不同的结果。

在本例中,我们可以清楚地看到,200状态 HTTP OK 表示robots.txt确实存在:

Defining a script's action

如果这是一个生产 Nmap 脚本,那么可能值得更改与200 OK响应关联的返回,以显示更多信息,例如不允许的文件和目录。但是,不要把时间花在这个特定的脚本上!在官方的 Nmap 存储库中已经有一个很棒的 HTTProbots.txt脚本(以及更多)。

最后一组对于编写、理解和调试 Nmap 脚本非常有用的标志是--script-trace-d(调试)标志。--script-trace标志在线路上显示脚本自己发出的所有不同请求的信息,这对于确定具体发生的情况非常有用:

Defining a script's action

您可以在前面的屏幕截图中看到,虽然可能有一点信息过载,但通过使用--script-trace标志,您可以确切地看到 Nmap 脚本正在做什么。用于调试的-d标志的工作原理类似:如果您在编写脚本时遇到错误,请尝试使用-d标志进行调试。你会惊讶于你能学到的伟大的东西!

总结

本章向我们展示了如何编写自己的 Nmap 脚本!NSE 是一个功能强大(有时很复杂)的工具,可以帮助 Nmap 用户完成各种有趣的自动化任务。作为概念证明,我们编写的脚本可以轻松检测服务器上是否存在robots.txt文件,但编写 Nmap 脚本供内部使用或检测特定漏洞的可能性几乎是无限的!

在下一章中,我们将学习如何使用随 Nmap 工具套件附带的工具,以及一些有用的技巧和技巧,以充分利用这些工具。