diff --git a/docs/scripting.xml b/docs/scripting.xml
index 0c59cb083..d3a09e6a9 100644
--- a/docs/scripting.xml
+++ b/docs/scripting.xml
@@ -2004,128 +2004,113 @@ function bit.band(...)
Version Detection Using NSENmap Scripting Engine (NSE)sample scriptsversion detectionusing NSE
+
+ The version detection system built into Nmap was designed to
+ efficiently recognize the vast majority of protocols with a simple
+ pattern matching syntax. Some protocols require a more complex
+ approach though, and a generalized scripting language is perfect for
+ this.
+
- The version detection system built into Nmap was designed to
- efficiently recognize the vast majority of protocols with a
- simple pattern matching syntax. Some protocols require a more
- complex approach, and a generalized scripting language is
- perfect for this. Skype v2 is one such protocol. It pretends to
- be an HTTP server, requiring multiple queries to determine its
- true nature. NSE has been integrated into Nmap's version
- detection framework to handle these cases. The scripts which
- extend the version scanner belong to the reserved category
- version.version script category
- This category cannot be run from
- the command line. It is only executed if the user has required a
- version scan. The following listing shows a simple script which
- demonstrates the use of the NSE version detection API. If either
- the TCP port 80 is open or the service has been determined to be
- HTTP, the script is triggered. Although it could be extended to
- recognize different HTTP servers, its only purpose is to show off
- the version detection API. It is not advisable to use NSE for
- version detection in the simple case of HTTP servers. The
- version detection variables have been filled with dummy entries
- to illustrate their effect on the Nmap output.
+
+ NSE's versionversion script category
+ category contains the scripts that enhance standard version
+ detection. Scripts in this category are run whenever you request
+ version detection with ; you don't need to use
+ to get version-detection scripts. (This cuts
+ the other way too: if you use you won't get
+ version scripts unless you also use
+ .)
+
+
+ This script detects version 2 of the Skype VoIP protocol, one which
+ is difficult to identify with version detection alone. If Skype gets
+ an HTTP GET request, it pretends to be an HTTP server and sends back
+ a 404. But for any other request it sends back a chunk of
+ random-looking data. Proper identification requires sending two
+ probes and comparing the two responses—an ideal task for NSE.
+
-
-description = "Demonstration of a version detection NSE script. It checks \
-and reports the version of a remote web server. For real life purposes it is \
-better to use Nmap version detection (-sV)."“description” script variable
-author = "Diman Todorov <diman.todorov@gmail.at>"Todorov, Diman“author” script variable
-license = "Same as Nmap--See http://nmap.org/book/man-legal.html"“license” script variable
+id = "Skype v2"
+description = [[
+Detects the Skype version 2 service.
+]]
+author = "Brandon Enright <bmenrigh@ucsd.edu>"
+license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
+categories = {"version"}
-id = "HTTP version"“id” script variable
+require "comm"
-categories = {"version"}“categories” script variable
-
-runlevel = 1.0“runlevel” script variable
-
-portrule = function(host, port)“portrule” script variable
- if (port.number == 80
- or port.service == "http" )
- and port.protocol == "tcp"
- then
- return true
- else
- return false
- end
+portrule = function(host, port)
+ if (port.number == 80 or
+ port.number == 443 or
+ port.service == nil or
+ port.service == "" or
+ port.service == "unknown")
+ and port.protocol == "tcp"
+ and port.state == "open"
+ and port.service ~= "http"
+ and port.service ~= "ssl/http"
+ then
+ return true
+ else
+ return false
+ end
end
-action = function(host, port)“action” script variable
- local query = "GET / HTTP/2.1\r\n"
- query = query .. "Accept: */*\r\n"
- query = query .. "Accept-Language: en\r\n"
- query = query .. "User-Agent: Nmap NSE\r\n"
- query = query .. "Host: " .. host.ip .. ":" .. port.number .. "\r\n\r\n"
+action = function(host, port)
+ local status, result = comm.exchange(host, port,
+ "GET / HTTP/1.0\r\n\r\n", {bytes=26, proto=port.protocol})
- local socket = nmap.new_socket()
- local catch = function()
- socket:close()
- end
+ if (not status) then
+ return
+ end
- local try = nmap.new_try(catch)
+ if (result ~= "HTTP/1.0 404 Not Found\r\n\r\n") then
+ return
+ end
+
+ -- So far so good, now see if we get random data for another request
- try(socket:connect(host.ip, port.number))
- try(socket:send(query))
+ status, result = comm.exchange(host, port,
+ "random data\r\n\r\n", {bytes=15, proto=port.protocol})
- local response = ""
- local lines
- local status
- local value
+ if (not status) then
+ return
+ end
- while true do
- status, lines = socket:receive_lines(1)
+ if string.match(result, "[^%s!-~].*[^%s!-~].*[^%s!-~]") then
+ -- Detected
+ port.version.name = "skype2"
+ port.version.product = "Skype"
+ nmap.set_port_version(host, port, "hardmatched")
+ return
+ end
- if not status or value then
- break
- end
-
- response = response .. lines
- value = string.match(response, "Server: (.-)\n")
- end
-
- try(socket:close())
-
- if value then
- port.version.name = "[Name]"
- port.version.name_confidence = 10
- port.version.product = "[Product]"
- port.version.version = "[Version]"
- port.version.extrainfo = "[ExtraInfo]"
- port.version.hostname = "[HostName]"
- port.version.ostype = "[OSType]"
- port.version.devicetype = "[DeviceType]"
-
- port.version.service_tunnel = "none"
- port.version.fingerprint = nil
- nmap.set_port_version(host, port, "hardmatched")
- end
+ return
end
-
-
-
- This is what the output of this script looks like:
-
-$ nmap -sV localhost -p 80
+
-Starting Nmap ( http://nmap.org )
-Interesting ports on localhost (127.0.0.1):
-PORT STATE SERVICE VERSION
-80/tcp open [Name] [Product] [Version] ([ExtraInfo])
-Service Info: Host: [HostName]; OS: [OSType]; Device: [DeviceType]
-
-Nmap done: 1 IP address (1 host up) scanned in 9.32 seconds
-
-
- The name variable denotes the detected protocol name.
- The product, version and extrainfo variables are used
- to produce a human readable description of the server
- version. The remaining variables provide information deduced
- from the output of the server concerning the target host.
+ If the script detects Skype, it augments its port
+ table with now-known name and
+ product fields. It then sends this new
+ information to Nmap by calling
+ nmap.set_port_version(). Several other version
+ fields are available to be set if they are known, but in this case
+ we only have the name and product. For the full list of version
+ fields refer to the documentation of
+ nmap.set_port_version().
+
+
+
+ Notice that if the script does not detect the protocol, it does
+ nothing. This is considered good practice; a script shouldn't
+ produce output (other than debug output) just to say it didn't learn
+ anything.
diff --git a/scripts/skype_v2-version.nse b/scripts/skype_v2-version.nse
index 97613d83f..ac5b215dd 100644
--- a/scripts/skype_v2-version.nse
+++ b/scripts/skype_v2-version.nse
@@ -5,6 +5,7 @@ Detects the Skype version 2 service.
author = "Brandon Enright "
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"version"}
+
require "comm"
portrule = function(host, port)
@@ -25,7 +26,8 @@ portrule = function(host, port)
end
action = function(host, port)
- local status, result = comm.exchange(host, port, "GET / HTTP/1.0\r\n\r\n", {bytes=26, proto=port.protocol})
+ local status, result = comm.exchange(host, port,
+ "GET / HTTP/1.0\r\n\r\n", {bytes=26, proto=port.protocol})
if (not status) then
return
@@ -37,20 +39,19 @@ action = function(host, port)
-- So far so good, now see if we get random data for another request
- status, result = comm.exchange(host, port, "random data\r\n\r\n", {bytes=15, proto=port.protocol})
+ status, result = comm.exchange(host, port,
+ "random data\r\n\r\n", {bytes=15, proto=port.protocol})
if (not status) then
return
end
if string.match(result, "[^%s!-~].*[^%s!-~].*[^%s!-~]") then
+ -- Detected
port.version.name = "skype2"
port.version.product = "Skype"
- port.version.confidence = 10
- port.version.fingerprint = nil
nmap.set_port_version(host, port, "hardmatched")
return
- -- return "Skype v2 server detected"
end
return