1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 14:11:29 +00:00
Files
nmap/scripts/MySQLinfo.nse
david 8bd71aaf43 Normalize NSEDoc documentation of scripts.
I made every script follow a standard form: it starts with the id, followed by
the description. The description is contained in [[ ]] delimiters. The
description is in the global description variable, not in a LuaDoc comment.
Other LuaDoc information such as @args and @usage follows the description in a
comment.

The first paragraph of each description is a a short summary of what the script
does. More detailed information, if any, is given in following paragraphs.

I also improved some wording and formatting in a few cases.
2008-10-14 20:52:50 +00:00

216 lines
4.9 KiB
Lua

id = "MySQL Server Information"
description = [[
Connects to a MySQL server and prints information such as the protocol and
version numbers, thread ID, status, capabilities, and the password salt.
\n\n
If service detection is performed and the server appears to be blocking
our host or is blocked from too many connections, then we don't bother
running this script (see the portrule).
]]
---
--@output
-- 3306/tcp open mysql \n
-- | MySQL Server Information: Protocol: 10 \n
-- | Version: 5.0.51a-3ubuntu5.1 \n
-- | Thread ID: 7 \n
-- | Some Capabilities: Connect with DB, Compress, Transactions, Secure Connection \n
-- | Status: Autocommit \n
-- |_ Salt: bYyt\NQ/4V6IN+*3`imj
-- Many thanks to jah (jah@zadkiel.plus.com) for testing and enhancements
author = "Kris Katterjohn <katterjohn@gmail.com>"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = { "default", "discovery", "safe" }
require 'bit'
require 'comm'
--- Grabs NUL-terminated string
--@param orig Start of the string
--@return The NUL-terminated string
local getstring = function(orig)
return orig:match("^([^%z]*)");
end
--- Converts two bytes into a number
--@param num Start of the two bytes
--@return The converted number
local ntohs = function(num)
local b1 = bit.band(num:byte(1), 255)
local b2 = bit.band(num:byte(2), 255)
return bit.bor(b1, bit.lshift(b2, 8))
end
--- Converts three bytes into a number
--@param num Start of the three bytes
--@return The converted number
local ntoh3 = function(num)
local b1 = bit.band(num:byte(1), 255)
local b2 = bit.band(num:byte(2), 255)
local b3 = bit.band(num:byte(3), 255)
return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16))
end
--- Converts four bytes into a number
--@param num Start of the four bytes
--@return The converted number
local ntohl = function(num)
local b1 = bit.band(num:byte(1), 255)
local b2 = bit.band(num:byte(2), 255)
local b3 = bit.band(num:byte(3), 255)
local b4 = bit.band(num:byte(4), 255)
return bit.bor(b1, bit.lshift(b2, 8), bit.lshift(b3, 16), bit.lshift(b4, 24))
end
--- Converts a number to a string description of the capabilities
--@param num Start of the capabilities data
--@return String describing the capabilities offered
local capabilities = function(num)
local caps = ""
if bit.band(num, 1) > 0 then
caps = caps .. "Long Passwords, "
end
if bit.band(num, 8) > 0 then
caps = caps .. "Connect with DB, "
end
if bit.band(num, 32) > 0 then
caps = caps .. "Compress, "
end
if bit.band(num, 64) > 0 then
caps = caps .. "ODBC, "
end
if bit.band(num, 2048) > 0 then
caps = caps .. "SSL, "
end
if bit.band(num, 8192) > 0 then
caps = caps .. "Transactions, "
end
if bit.band(num, 32768) > 0 then
caps = caps .. "Secure Connection, "
end
return caps:gsub(", $", "")
end
portrule = function(host, port)
local extra = port.version.extrainfo
if
(port.number == 3306
or port.service == "mysql")
and port.protocol == "tcp"
and port.state == "open"
and not (extra ~= nil
and (extra:match("[Uu]nauthorized")
or extra:match("[Tt]oo many connection")))
then
return true
end
return false
end
action = function(host, port)
local output = ""
local status, response = comm.get_banner(host, port, {timeout=5000})
if not status then
return
end
local length = ntoh3(response:sub(1, 3))
if length ~= response:len() - 4 then
return "Invalid greeting (Not MySQL?)"
end
-- Keeps track of where we are in the binary data
local offset = 1 + 4
local protocol = response:byte(offset)
offset = offset + 1
-- If a 0xff is here instead of the protocol, an error occurred.
-- Pass it along to the user..
if (protocol == 255) then
output = "MySQL Error detected!\n"
local sqlerrno = ntohs(response:sub(offset, offset + 2))
offset = offset + 2
local sqlerrstr = response:sub(offset)
output = output .. "Error Code was: " .. sqlerrno .. "\n"
output = output .. sqlerrstr
return output
end
local version = getstring(response:sub(offset))
offset = offset + version:len() + 1
local threadid = ntohl(response:sub(offset, offset + 4))
offset = offset + 4
local salt = getstring(response:sub(offset))
offset = offset + salt:len() + 1
local caps = capabilities(ntohs(response:sub(offset, offset + 2)))
offset = offset + 2
offset = offset + 1
local status = ""
if ntohs(response:sub(offset, offset + 2)) == 2 then
status = "Autocommit"
end
offset = offset + 2
offset = offset + 13 -- unused
if response:len() - offset + 1 == 13 then
salt = salt .. getstring(response:sub(offset))
end
output = output .. "Protocol: " .. protocol .. "\n"
output = output .. "Version: " .. version .. "\n"
output = output .. "Thread ID: " .. threadid .. "\n"
if caps:len() > 0 then
output = output .. "Some Capabilities: " .. caps .. "\n"
end
if status:len() > 0 then
output = output .. "Status: " .. status .. "\n"
end
output = output .. "Salt: " .. salt .. "\n"
return output
end