From a988d26982a1f8c853c24b39e4cff11009baf250 Mon Sep 17 00:00:00 2001 From: kris Date: Wed, 19 Dec 2007 07:23:59 +0000 Subject: [PATCH] Adding new MySQLinfo NSE script for printing MySQL server information --- CHANGELOG | 4 + scripts/MySQLinfo.nse | 218 ++++++++++++++++++++++++++++++++++++++++++ scripts/script.db | 2 + 3 files changed, 224 insertions(+) create mode 100644 scripts/MySQLinfo.nse diff --git a/CHANGELOG b/CHANGELOG index ac53ee141..f28dfe634 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -36,6 +36,10 @@ o Nmap's output options (-oA, -oX, etc.) now support strftime()-like means that "-oX 'scan-%T-%D.xml'" uses an XML file in the form of "scan-144840-121307.xml". [Kris] +o Added a new NSE script (MySQLinfo) which prints MySQL server information + such as the protocol and version numbers, status, thread id, capabilities, + and password salt. [Kris] + o Fixed Zenmap crash that occurred when selecting Help from the Compare Results window. [Kris] diff --git a/scripts/MySQLinfo.nse b/scripts/MySQLinfo.nse new file mode 100644 index 000000000..6317251c7 --- /dev/null +++ b/scripts/MySQLinfo.nse @@ -0,0 +1,218 @@ +-- Connect to MySQL server and print information such as the protocol and +-- version numbers, thread id, status, capabilities and the password salt + +-- 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) + +-- Many thanks to jah (jah@zadkiel.plus.com) for testing and enhancements + +id = "MySQL Server Information" + +description = "Connects to a MySQL server and prints information" + +author = "Kris Katterjohn " + +license = "Look at Nmap's COPYING" + +categories = { "discovery", "safe" } + +require 'bit' + +-- Grabs NUL-terminated string +local getstring = function(orig) + local str = "" + local index = 1 + + while orig:byte(index) ~= 0 do + str = str .. string.char(orig:byte(index)) + + index = index + 1 + end + + return str +end + +-- Convert two bytes into a 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 + +-- Convert three bytes into a 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 + +-- Convert four bytes into a 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 + +-- Convert number to a list of capabilities for printing +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 sock + local response = "" + local output = "" + + sock = nmap.new_socket() + + sock:set_timeout(5000) + + sock:connect(host.ip, port.number) + + while true do + local status, line = sock:receive_lines(1) + + if not status then + break + end + + response = response .. line + end + + sock:close() + + 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 + diff --git a/scripts/script.db b/scripts/script.db index dfdbfe424..fb0135411 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -4,6 +4,8 @@ Entry{ category = "intrusive", filename = "HTTPpasswd.nse" } Entry{ category = "discovery", filename = "HTTPtrace.nse" } Entry{ category = "discovery", filename = "MSSQLm.nse" } Entry{ category = "intrusive", filename = "MSSQLm.nse" } +Entry{ category = "discovery", filename = "MySQLinfo.nse" } +Entry{ category = "safe", filename = "MySQLinfo.nse" } Entry{ category = "version", filename = "PPTPversion.nse" } Entry{ category = "backdoor", filename = "RealVNC_auth_bypass.nse" } Entry{ category = "demo", filename = "SMTP_openrelay_test.nse" }