1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

o Improved the mysql library to handle multiple columns with the same name,

added a formatResultset function to format a query response to a table
  suitable for script output. [Patrik Karlsson]
This commit is contained in:
patrik
2012-05-19 12:23:41 +00:00
parent 660cb42825
commit 425ced35ab
7 changed files with 69 additions and 36 deletions

View File

@@ -1,5 +1,9 @@
# Nmap Changelog ($Id$); -*-text-*-
o Improved the mysql library to handle multiple columns with the same name,
added a formatResultset function to format a query response to a table
suitable for script output. [Patrik Karlsson]
o The message "nexthost: failed to determine route to ..." is now a
warning rather than a fatal error. Addresses that are skipped in
this way are recorded in the XML output as <target> elements. [David

View File

@@ -3,7 +3,7 @@ require("tab")
TEMPLATE_NAME="CIS MySQL Benchmarks v1.0.2"
-- These accounts should be treated as admins and excluded from some of the results
local ADMIN_ACCOUNTS={"root", "debian-sys-maint"}
ADMIN_ACCOUNTS={"root", "debian-sys-maint"}
-- Checks whether a resultset is empty or not
local function isEmpty(rows)
@@ -12,9 +12,19 @@ local function isEmpty(rows)
end
-- Extracts a column from a row and return all occurances as an array
local function col2tab(rows, cname)
local function col2tab(rs, cname)
local tab = {}
for _, row in ipairs(rows) do table.insert(tab, row[cname]) end
local cpos
for i=1, #rs.cols do
if ( rs.cols[i].name == cname ) then
cpos = i
break
end
end
if ( not(cpos) ) then
return
end
for _, row in ipairs(rs.rows) do table.insert(tab, row[cpos]) end
return tab
end
@@ -92,10 +102,9 @@ test { id="5.1", desc="Access to mysql database",
local result = tab.new(2)
tab.addrow(result, "user", "host")
for _, rows in ipairs(rowstab) do
for _, row in ipairs(rows) do
tab.addrow( result, row.user, row.host )
end
local rs = rowstab[1]
for _, row in ipairs(rs.rows) do
tab.addrow( result, row[1], row[2] )
end
return { status = false, review = true, result = { tab.dump(result), name="Verify the following users that have access to the MySQL database" } }

View File

@@ -17,6 +17,8 @@ module(... or "mysql", package.seeall)
-- fixed a number of incorrect receives and changed
-- them to receive_bytes instead.
local tab = require('tab')
local HAVE_SSL = false
if pcall(require,'openssl') then
@@ -455,11 +457,10 @@ end
-- ref: http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Row_Data_Packet
--
-- @param data string containing the row data packet
-- @param fields table containing the field data as recieved from <code>decodeFieldPackets</code>
-- @param count number containing the number of fields to decode
-- @return status true on success, false on failure
-- @return rows table containing row tables
function decodeDataPackets( data, fields, count )
function decodeDataPackets( data, count )
local len, pos = 0, 1, 1
local header, row, rows = {}, {}, {}
@@ -470,7 +471,7 @@ function decodeDataPackets( data, fields, count )
for i=1, count do
pos, len = bin.unpack("C", data, pos )
pos, row[fields[i].name] = bin.unpack("A" .. len, data, pos)
pos, row[i] = bin.unpack("A" .. len, data, pos)
end
table.insert( rows, row )
@@ -530,12 +531,39 @@ function sqlQuery( socket, query )
return false, fields
end
status, rows = decodeDataPackets(rs.data, fields, field_count)
status, rows = decodeDataPackets(rs.data, field_count)
if not status then
return false, rows
end
return true, rows
return true, { cols = fields, rows = rows }
end
---
-- Formats the resultset returned from <code>sqlQuery</code>
--
-- @param rs table as returned from <code>sqlQuery</code>
-- @param options table containing additional options, currently:
-- - <code>noheaders</code> - does not include column names in result
-- @return string containing the formated resultset table
function formatResultset(rs, options)
options = options or {}
if ( not(rs) or not(rs.cols) or not(rs.rows) ) then
return
end
local restab = tab.new(#rs.cols)
local colnames = {}
if ( not(options.noheaders) ) then
for _, col in ipairs(rs.cols) do table.insert(colnames, col.name) end
tab.addrow(restab, unpack(colnames))
end
for _, row in ipairs(rs.rows) do
tab.addrow(restab, unpack(row))
end
return tab.dump(restab)
end

View File

@@ -86,7 +86,7 @@ require 'shortport'
require 'mysql'
portrule = shortport.port_or_service(3306, "mysql")
local TEMPLATE_NAME = ""
local TEMPLATE_NAME, ADMIN_ACCOUNTS = "", ""
local function loadAuditRulebase( filename )
@@ -103,6 +103,7 @@ local function loadAuditRulebase( filename )
file()
TEMPLATE_NAME = getfenv(file)["TEMPLATE_NAME"]
ADMIN_ACCOUNTS = getfenv(file)["ADMIN_ACCOUNTS"]
return true, rules
end
@@ -121,7 +122,7 @@ action = function( host, port )
end
local status, tests = loadAuditRulebase( filename )
if( not(status) ) then return rules end
if( not(status) ) then return tests end
local socket = nmap.new_socket()
status = socket:connect(host, port)
@@ -166,7 +167,10 @@ action = function( host, port )
socket:close()
results.name = TEMPLATE_NAME
table.insert(results, {"", ("The audit was performed using the db-account: %s"):format(username)})
table.insert(results, "")
table.insert(results, {name = "Additional information", ("The audit was performed using the db-account: %s"):format(username),
("The following admin accounts were excluded from the audit: %s"):format(stdnse.strjoin(",", ADMIN_ACCOUNTS))
})
return stdnse.format_output(true, { results })
end

View File

@@ -78,12 +78,9 @@ action = function( host, port )
status, response = mysql.loginRequest( socket, { authversion = "post41", charset = response.charset }, username, password, response.salt )
if status and response.errorcode == 0 then
status, rows = mysql.sqlQuery( socket, "show databases" )
local status, rs = mysql.sqlQuery( socket, "show databases" )
if status then
for i=1, #rows do
-- cheap way of avoiding duplicates
dbs[rows[i]['Database']] = rows[i]['Database']
end
result = mysql.formatResultset(rs, { noheaders = true })
-- if we got here as root, we've got them all
-- if we're here as someone else, we cant be sure
@@ -94,11 +91,5 @@ action = function( host, port )
end
socket:close()
end
for _, v in pairs( dbs ) do
table.insert(result, v)
end
return stdnse.format_output(true, result)
end

View File

@@ -81,12 +81,9 @@ action = function( host, port )
status, response = mysql.loginRequest( socket, { authversion = "post41", charset = response.charset }, username, password, response.salt )
if status and response.errorcode == 0 then
status, rows = mysql.sqlQuery( socket, "SELECT DISTINCT user FROM mysql.user" )
status, rs = mysql.sqlQuery( socket, "SELECT DISTINCT user FROM mysql.user" )
if status then
for i=1, #rows do
table.insert(result, rows[i]['user'])
end
break
result = mysql.formatResultset(rs, { noheaders = true })
end
end
socket:close()

View File

@@ -89,10 +89,10 @@ action = function( host, port )
status, response = mysql.loginRequest( socket, { authversion = "post41", charset = response.charset }, username, password, response.salt )
if status and response.errorcode == 0 then
status, rows = mysql.sqlQuery( socket, "show variables" )
local status, rs = mysql.sqlQuery( socket, "show variables" )
if status then
for i=1, #rows do
table.insert(result, string.format("%s: %s" , rows[i]['Variable_name'], rows[i]['Value']) )
for _, row in ipairs(rs.rows) do
table.insert(result, ("%s: %s"):format(row[1], row[2]) )
end
end
end