From 8c10485689dc39ab461be993cb783f3c657f2b89 Mon Sep 17 00:00:00 2001 From: dmiller Date: Thu, 25 Aug 2016 23:05:50 +0000 Subject: [PATCH] Fix MySQL version detection, greeting parsing. Fixes #529 --- nselib/mysql.lua | 44 ++++++++++++++++++++++++++++++---------- scripts/mysql-info.nse | 46 +++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/nselib/mysql.lua b/nselib/mysql.lua index ec18f4c0b..355af1842 100644 --- a/nselib/mysql.lua +++ b/nselib/mysql.lua @@ -13,6 +13,7 @@ local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local math = require "math" _ENV = stdnse.module("mysql", stdnse.seeall) -- Version 0.3 @@ -50,7 +51,8 @@ Capabilities = ExtCapabilities = { SupportsMultipleStatments = 0x1, - SupportsMultipleResults = 0x2 + SupportsMultipleResults = 0x2, + SupportsAuthPlugins = 0x8, } Charset = @@ -123,23 +125,43 @@ function receiveGreeting( socket ) pos, is_error = bin.unpack( "C", data, pos ) if ( is_error == 0xff ) then - pos, response.errorcode = bin.unpack( "S", data, pos ) + pos, response.errorcode = bin.unpack( " 0 then + pos, tmp = bin.unpack("A" .. math.max(13, auth_plugin_len - 8), data, pos) + response.salt = response.salt .. tmp + end + if response.extcapabilities & ExtCapabilities.SupportsAuthPlugins > 0 then + response.auth_plugin_name = bin.unpack("z", data, pos) + end + end + elseif response.proto == 9 then + pos, response.auth_plugin_data = bin.unpack( "z", data, pos ) + else + stdnse.debug2("Unknown MySQL protocol version: %d", response.proto) + end - response.salt = response.salt .. tmp response.errorcode = 0 return true, response diff --git a/scripts/mysql-info.nse b/scripts/mysql-info.nse index cfb54c362..5bb648120 100644 --- a/scripts/mysql-info.nse +++ b/scripts/mysql-info.nse @@ -49,10 +49,10 @@ categories = { "default", "discovery", "safe" } --- Converts a number to a string description of the capabilities --@param num Start of the capabilities data --@return table containing the names of the capabilities offered -local capabilities = function(num) +local bitset = function(num, lookup) local caps = {} - for k, v in pairs(mysql.Capabilities) do + for k, v in pairs(lookup) do if bit.band(num, v) > 0 then caps[#caps+1] = k end @@ -100,24 +100,34 @@ action = function(host, port) output["Version"] = info.version output["Thread ID"] = info.threadid - output["Capabilities flags"] = info.capabilities - local caps = capabilities(info.capabilities) - if #caps > 0 then - setmetatable(caps, { - __tostring = function (self) - return table.concat(self, ", ") - end - }) - output["Some Capabilities"] = caps - end + if info.proto == 10 then + output["Capabilities flags"] = info.capabilities + local caps = bitset(info.capabilities, mysql.Capabilities) + if info.extcapabilities then + local extcaps = bitset(info.extcapabilities, mysql.ExtCapabilities) + for i, c in ipairs(extcaps) do + caps[#caps+1] = c + end + end + if #caps > 0 then + setmetatable(caps, { + __tostring = function (self) + return table.concat(self, ", ") + end + }) + output["Some Capabilities"] = caps + end - if info.status == 2 then - output["Status"] = "Autocommit" - else - output["Status"] = info.status - end + if info.status == 2 then + output["Status"] = "Autocommit" + else + output["Status"] = info.status + end - output["Salt"] = info.salt + output["Salt"] = info.salt + + output["Auth Plugin Name"] = info.auth_plugin_name + end return output end