1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 14:11:29 +00:00

o [NSE] Added a library for Microsoft SQL Server and 7 new scripts. The new

scripts are:
  - ms-sql-brute.nse uses the unpwdb library to guess credentials for MSSQL
  - ms-sql-config retrieves various configuration details from the server		
  - ms-sql-empty-password checks if the sa account has an empty password
  - ms-sql-hasdbaccess lists database access per user
  - ms-sql-query add support for running custom queries against the database
  - ms-sql-tables lists databases, tables, columns and datatypes with optional
    keyword filtering
  - ms-sql-xp-cmdshell adds support for OS command execution to privileged
    users
  [Patrik]
This commit is contained in:
patrik
2010-04-04 10:11:54 +00:00
parent 231bc9f02e
commit 1d26975ede
10 changed files with 1940 additions and 0 deletions

View File

@@ -1,5 +1,18 @@
# Nmap Changelog ($Id$); -*-text-*-
o [NSE] Added a library for Microsoft SQL Server and 7 new scripts. The new
scripts are:
- ms-sql-brute.nse uses the unpwdb library to guess credentials for MSSQL
- ms-sql-config retrieves various configuration details from the server
- ms-sql-empty-password checks if the sa account has an empty password
- ms-sql-hasdbaccess lists database access per user
- ms-sql-query add support for running custom queries against the database
- ms-sql-tables lists databases, tables, columns and datatypes with optional
keyword filtering
- ms-sql-xp-cmdshell adds support for OS command execution to privileged
users
[Patrik]
o [NSE] Fixed bug in rpc.lua library that incorrectly required file handles
to be 32 octects when calling the ReadDir function. The bug was reported by
Djalal Harouni. [Patrik]

1030
nselib/mssql.lua Normal file

File diff suppressed because it is too large Load Diff

93
scripts/ms-sql-brute.nse Normal file
View File

@@ -0,0 +1,93 @@
description = [[
Performs password guessing against Microsoft SQL Server (mssql)
]]
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"auth", "intrusive"}
require 'shortport'
require 'stdnse'
require 'mssql'
require 'unpwdb'
---
--
-- @output
-- PORT STATE SERVICE
-- 1433/tcp open ms-sql-s
-- | mssql-brute:
-- | webshop_reader:secret => Login Success
-- | testuser:secret1234 => Must change password at next logon
-- |_ lordvader:secret1234 => Login Success
--
--
-- Version 0.1
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
portrule = shortport.port_or_service(1433, "ms-sql-s")
action = function( host, port )
local result, response, status, aborted = {}, nil, nil, false
local valid_accounts = {}
local usernames, passwords
local username, password
local max_time = unpwdb.timelimit() ~= nil and unpwdb.timelimit() * 1000 or -1
local clock_start = nmap.clock_ms()
local helper = mssql.Helper:new()
status, usernames = unpwdb.usernames()
if ( not(status) ) then
return " \n\nFailed to load usernames.lst"
end
status, passwords = unpwdb.passwords()
if ( not(status) ) then
return " \n\nFailed to load usernames.lst"
end
for username in usernames do
for password in passwords do
if max_time>0 and nmap.clock_ms() - clock_start > max_time then
aborted=true
break
end
status, result = helper:Connect(host, port)
if( not(status) ) then
return " \n\n" .. result
end
stdnse.print_debug( "Trying %s/%s ...", username, password )
status, result = helper:Login( username, password, "tempdb", host.ip )
helper:Disconnect()
if status then
-- Add credentials for other mysql scripts to use
table.insert( valid_accounts, string.format("%s:%s => %s", username, password:len()>0 and password or "<empty>", result ) )
-- don't add accounts that need to change passwords to the registry
if ( result ~= "Login Success") then
break
end
if nmap.registry.mssqlusers == nil then
nmap.registry.mssqlusers = {}
end
nmap.registry.mssqlusers[username]=password
break
end
end
passwords("reset")
end
local output = stdnse.format_output(true, valid_accounts)
if max_time > 0 and aborted then
output = output .. string.format(" \n\nscript aborted execution after %d seconds", max_time/1000 )
end
return output
end

109
scripts/ms-sql-config.nse Normal file
View File

@@ -0,0 +1,109 @@
description = [[
Queries Microsoft SQL Server (MSSQL) for a list of:
* Databases
* Linked Servers
* Configuration settings
]]
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
require 'shortport'
require 'stdnse'
require 'mssql'
dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
--
-- @args mssql.username specifies the username to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql.password specifies the password to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql-config.showall if set shows all configuration options.
--
-- Version 0.1
-- Created 04/02/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
portrule = shortport.port_or_service(1433, "ms-sql-s")
action = function( host, port )
local status, helper, response
local username = nmap.registry.args['mssql.username']
local password = nmap.registry.args['mssql.password'] or ""
local result, result_part = {}, {}
local conf_filter = ( nmap.registry.args['mssql-config.showall'] ) and "" or " WHERE configuration_id > 16384"
local db_filter = ( nmap.registry.args['mssql-config.showall'] ) and "" or " WHERE name NOT IN ('master','model','tempdb','msdb')"
local queries = {
[2]={ ["Configuration"] = [[ SELECT name,
cast(value as varchar) value,
cast(value_in_use as varchar) inuse,
description
FROM sys.configurations ]] .. conf_filter },
[3]={ ["Linked Servers"] = [[ SELECT srvname, srvproduct, providername
FROM master..sysservers
WHERE srvid > 0 ]] },
[1]={ ["Databases"] = [[ CREATE TABLE #nmap_dbs(name varchar(255), db_size varchar(255), owner varchar(255),
dbid int, created datetime, status varchar(512), compatibility_level int )
INSERT INTO #nmap_dbs EXEC sp_helpdb
SELECT name, db_size, owner
FROM #nmap_dbs ]] .. db_filter .. [[
DROP DATABASE #nmap_dbs ]] }
}
if ( not(username) and nmap.registry.mssqlusers ) then
-- do we have a sysadmin?
if ( nmap.registry.mssqlusers.sa ) then
username = "sa"
password = nmap.registry.mssqlusers.sa
else
-- ok were stuck with some non sysadmin account, just get the first one
for user, pass in pairs(nmap.registry.mssqlusers) do
username = user
password = pass
break
end
end
end
-- If we don't have a valid username, simply fail silently
if ( not(username) ) then
return
end
helper = mssql.Helper:new()
status, response = helper:Connect(host, port)
if ( not(status) ) then
return " \n\n" .. response
end
status, response = helper:Login( username, password, nil, host.ip )
if ( not(status) ) then
return " \n\nERROR: " .. response
end
for _, v in ipairs( queries ) do
for header, query in pairs(v) do
status, result_part = helper:Query( query )
if ( not(status) ) then
return " \n\nERROR: " .. result_part
end
result_part = mssql.Util.FormatOutputTable( result_part, true )
result_part.name = header
table.insert( result, result_part )
end
end
helper:Disconnect()
return stdnse.format_output( true, result )
end

View File

@@ -0,0 +1,52 @@
description = [[
Attempts to authenticate using an empty password for the sysadmin (sa) account.
]]
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"auth","intrusive"}
require 'shortport'
require 'stdnse'
require 'mssql'
---
--
-- @output
-- PORT STATE SERVICE
-- 1433/tcp open ms-sql-s
-- | mssql-empty-password:
-- |_ sa:<empty> => Login Correct
--
--
-- Version 0.1
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
portrule = shortport.port_or_service(1433, "ms-sql-s")
action = function( host, port )
local helper, status, result
local username, password, database, valid_accounts = "sa", "", "tempdb", {}
helper = mssql.Helper:new()
status, result = helper:Connect(host, port)
if( not(status) ) then
return " \n\n" .. result
end
status, result = helper:Login( username, password, database, host.ip )
helper:Disconnect()
if status then
nmap.registry.mssqlusers = nmap.registry.mssqlusers or {}
nmap.registry.mssqlusers[username]=password
table.insert( valid_accounts, string.format("%s:%s => Login Success", username, password:len()>0 and password or "<empty>" ) )
end
return stdnse.format_output(true, valid_accounts)
end

View File

@@ -0,0 +1,143 @@
description = [[
Queries Microsoft SQL Server (MSSQL) for a list of databases a user has access to.
]]
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"auth", "discovery","safe"}
require 'shortport'
require 'stdnse'
require 'mssql'
dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
---
-- @args mssql.username specifies the username to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql.password specifies the password to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql-hasdbaccess.limit limits the amount of databases per-user
-- that are returned (default 5). If set to zero or less all
-- databases the user has access to are returned.
--
-- @output
-- PORT STATE SERVICE
-- 1433/tcp open ms-sql-s
-- | mssql-hasdbaccess:
-- | webshop_reader
-- | dbname owner
-- | hr sa
-- | finance sa
-- | webshop sa
-- | lordvader
-- | dbname owner
-- | testdb CQURE-NET\Administr
-- |_ webshop sa
--
-- The script needs an account with the sysadmin server role to work.
-- It needs to be fed credentials through the script arguments or from
-- the scripts mssq-brute or mssq-empty-password.
--
-- When run, the script iterates over the credentials and attempts to run
-- the command until either all credentials are exhausted or until the
-- command is executed.
--
-- Version 0.1
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
portrule = shortport.port_or_service(1433, "ms-sql-s")
local function table_contains( tbl, val )
for k,v in pairs(tbl) do
if ( v == val ) then
return true
end
end
return false
end
action = function( host, port )
local status, result, helper, rs
local username = nmap.registry.args['mssql.username']
local password = nmap.registry.args['mssql.password'] or ""
local creds
local query, limit
local output = {}
local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" }
local RS_LIMIT = nmap.registry.args["mssql-hasdbaccess.limit"] and tonumber(nmap.registry.args["mssql-hasdbaccess.limit"]) or 5
if ( RS_LIMIT <= 0 ) then
limit = ""
else
limit = string.format( "TOP %d", RS_LIMIT )
end
local query = { [[CREATE table #hasaccess(dbname varchar(255), owner varchar(255),
DboOnly bit, ReadOnly bit, SingelUser bit, Detached bit,
Suspect bit, Offline bit, InLoad bit, EmergencyMode bit,
StandBy bit, [ShutDown] bit, InRecovery bit, NotRecovered bit )]],
"INSERT INTO #hasaccess EXEC sp_MShasdbaccess",
("SELECT %s dbname, owner FROM #hasaccess WHERE dbname NOT IN(%s)"):format(limit, stdnse.strjoin(",", exclude_dbs)),
"DROP TABLE #hasaccess" }
if ( username ) then
creds = {}
creds[username] = password
elseif ( not(username) and nmap.registry.mssqlusers ) then
-- do we have a sysadmin?
creds = nmap.registry.mssqlusers
end
-- If we don't have valid creds, simply fail silently
if ( not(creds) ) then
return
end
for username, password in pairs( creds ) do
helper = mssql.Helper:new()
status, result = helper:Connect(host, port)
if ( not(status) ) then
return " \n\n" .. result
end
status, result = helper:Login( username, password, nil, host.ip )
if ( not(status) ) then
stdnse.print_debug("ERROR: %s", result)
break
end
for _, q in pairs(query) do
status, result = helper:Query( q )
if ( status ) then
-- Only the SELECT statement should produce output
if ( #result.rows > 0 ) then
rs = result
end
end
end
helper:Disconnect()
if ( status ) then
result = mssql.Util.FormatOutputTable( rs, true )
result.name = username
if ( RS_LIMIT > 0 ) then
result.name = result.name .. (" (Showing %d first results)"):format(RS_LIMIT)
end
table.insert( output, result )
end
end
return stdnse.format_output( true, output )
end

96
scripts/ms-sql-query.nse Normal file
View File

@@ -0,0 +1,96 @@
description = [[
Runs a Query against Microsoft SQL Server (MSSQL).
]]
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
require 'shortport'
require 'stdnse'
require 'mssql'
dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
--
-- @args mssql-query.query specifies the query to run against the server.
-- (default SELECT @@version version)
--
-- @output
--
-- PORT STATE SERVICE
-- 1433/tcp open ms-sql-s
-- | mssql-query:
-- |
-- | Microsoft SQL Server 2005 - 9.00.3068.00 (Intel X86)
-- | Feb 26 2008 18:15:01
-- | Copyright (c) 1988-2005 Microsoft Corporation
-- |_ Express Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
--
--
-- Version 0.1
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
portrule = shortport.port_or_service(1433, "ms-sql-s")
action = function( host, port )
local status, result, helper
local username = nmap.registry.args['mssql.username']
local password = nmap.registry.args['mssql.password'] or ""
-- the tempdb should be a safe guess, anyway the library is set up
-- to continue even if the DB is not accessible to the user
local database = nmap.registry.args['mssql.database'] or "tempdb"
local query = nmap.registry.args['mssql-query.query'] or "SELECT @@version version"
if ( not(username) and nmap.registry.mssqlusers ) then
-- do we have a sysadmin?
if ( nmap.registry.mssqlusers.sa ) then
username = "sa"
password = nmap.registry.mssqlusers.sa
else
-- ok were stuck with some n00b account, just get the first one
for user, pass in pairs(nmap.registry.mssqlusers) do
username = user
password = pass
break
end
end
end
-- If we don't have a valid username, simply fail silently
if ( not(username) ) then
return
end
helper = mssql.Helper:new()
status, result = helper:Connect(host, port)
if ( not(status) ) then
return " \n\n" .. result
end
status, result = helper:Login( username, password, database, host.ip )
if ( not(status) ) then
return " \n\nERROR: " .. result
end
status, result = helper:Query( query )
helper:Disconnect()
if ( not(status) ) then
return " \n\nERROR: " .. result
end
result = mssql.Util.FormatOutputTable( result, true )
if ( not(nmap.registry.args['mssql-query.query']) ) then
table.insert(result, 1, query)
result = stdnse.format_output( true, result )
result = "(Use --script-args=mssql-query.query='<QUERY>' to change query.)" .. result
else
result = stdnse.format_output( true, result )
end
return result
end

251
scripts/ms-sql-tables.nse Normal file
View File

@@ -0,0 +1,251 @@
description = [[
Queries Microsoft SQL Server (MSSQL) for a list of tables per database.
]]
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
require 'shortport'
require 'stdnse'
require 'mssql'
dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
---
-- @args mssql.username specifies the username to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql.password specifies the password to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql-tables.maxdb Limits the amount of databases that are
-- processed and returned (default 5). If set to zero or less
-- all databases are processed.
--
-- @args mssql-tables.maxtables Limits the amount of tables returned
-- (default 5). If set to zero or less all tables are returned.
--
-- @args mssql-tables.keywords If set shows only tables or columns matching
-- the keywords
--
-- @output
-- PORT STATE SERVICE
-- 1433/tcp open ms-sql-s
-- | mssql-tables:
-- | webshop
-- | table column type length
-- | payments user_id int 4
-- | payments purchase_id int 4
-- | payments cardholder varchar 50
-- | payments cardtype varchar 50
-- | payments cardno varchar 50
-- | payments expiry varchar 50
-- | payments cvv varchar 4
-- | products id int 4
-- | products manu varchar 50
-- | products model varchar 50
-- | products productname varchar 100
-- | products price float 8
-- | products imagefile varchar 255
-- | products quantity int 4
-- | products keywords varchar 100
-- | products description text 16
-- | users id int 4
-- | users username varchar 50
-- | users password varchar 50
-- |_ users fullname varchar 100
--
--
-- The sysdatabase table should be accessible by more or less everyone
-- The script attempts to use the sa account over some n00b if it has
-- the password in the registry. If not the first account in the
-- registry is used.
--
-- Once we have a list of DBs we iterate over it and attempt to extract
-- table names. In order for this to succeed we need to have either
-- sysadmin privileges or an account with access to the db. So, for each
-- db we successfully enumerate tables from we mark as finnished, we then
-- iterate over our know user accounts until either we exhausted our users
-- or we found all tables in all dbs.
--
-- Oh, and exclude all MS default dbs from this excercise.
--
-- Version 0.1
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 04/02/2010 - v0.2
-- - Added support for filters
-- - Changed output formatting of restrictions
-- - Added parameter information in output if parameters are using their
-- defaults.
portrule = shortport.port_or_service(1433, "ms-sql-s")
local function table_contains( tbl, val )
for k,v in pairs(tbl) do
if ( v == val ) then
return true
end
end
return false
end
action = function( host, port )
local status, result, dbs, tables, helper
local username = nmap.registry.args['mssql.username']
local password = nmap.registry.args['mssql.password'] or ""
local output = {}
local exclude_dbs = { "'master'", "'tempdb'", "'model'", "'msdb'" }
local db_query
local done_dbs = {}
local creds = {}
local db_limit, tbl_limit
local DB_COUNT = nmap.registry.args["mssql-tables.maxdb"] and tonumber(nmap.registry.args["mssql-tables.maxdb"]) or 5
local TABLE_COUNT = nmap.registry.args["mssql-tables.maxtables"] and tonumber(nmap.registry.args["mssql-tables.maxtables"]) or 2
local keywords_filter = ""
if ( DB_COUNT <= 0 ) then
db_limit = ""
else
db_limit = string.format( "TOP %d", DB_COUNT )
end
if (TABLE_COUNT <= 0 ) then
tbl_limit = ""
else
tbl_limit = string.format( "TOP %d", TABLE_COUNT )
end
-- Build the keyword filter
if ( nmap.registry.args['mssql-tables.keywords'] ) then
local keywords = nmap.registry.args['mssql-tables.keywords']
local tmp_tbl = {}
if( type(keywords) == 'string' ) then
keywords = { keywords }
end
for _, v in ipairs(keywords) do
table.insert(tmp_tbl, ("'%s'"):format(v))
end
keywords_filter = (" AND ( so.name IN (%s) or sc.name IN (%s) ) "):format(
stdnse.strjoin(",", tmp_tbl),
stdnse.strjoin(",", tmp_tbl)
)
end
db_query = ("SELECT %s name from master..sysdatabases WHERE name NOT IN (%s)"):format(db_limit, stdnse.strjoin(",", exclude_dbs))
if ( username ) then
creds[username] = password
elseif ( not(username) and nmap.registry.mssqlusers ) then
-- do we have a sysadmin?
if ( nmap.registry.mssqlusers.sa ) then
creds["sa"] = nmap.registry.mssqlusers.sa
else
creds = nmap.registry.mssqlusers
end
end
-- If we don't have valid creds, simply fail silently
if ( not(creds) ) then
return
end
for username, password in pairs( creds ) do
helper = mssql.Helper:new()
status, result = helper:Connect(host, port)
if ( not(status) ) then
return " \n\n" .. result
end
status, result = helper:Login( username, password, nil, host.ip )
if ( not(status) ) then
stdnse.print_debug("ERROR: %s", result)
break
end
status, dbs = helper:Query( db_query )
if ( status ) then
-- all done?
if ( #done_dbs == #dbs.rows ) then
break
end
for k, v in pairs(dbs.rows) do
if ( not( table_contains( done_dbs, v[1] ) ) ) then
query = [[ SELECT so.name 'table', sc.name 'column', st.name 'type', sc.length
FROM %s..syscolumns sc, %s..sysobjects so, %s..systypes st
WHERE so.id = sc.id AND sc.xtype=st.xtype AND
so.id IN (SELECT %s id FROM %s..sysobjects WHERE xtype='U') %s ORDER BY so.name, sc.name, st.name]]
query = query:format( v[1], v[1], v[1], tbl_limit, v[1], keywords_filter)
status, tables = helper:Query( query )
if ( not(status) ) then
stdnse.print_debug(tables)
else
local item = {}
item = mssql.Util.FormatOutputTable( tables, true )
if ( #item == 0 and keywords_filter ~= "" ) then
table.insert(item, "Filter returned no matches")
end
item.name = v[1]
table.insert(output, item)
table.insert(done_dbs, v[1])
end
end
end
end
helper:Disconnect()
end
local pos = 1
local restrict_tbl = {}
if ( nmap.registry.args['mssql-tables.keywords'] ) then
tmp = nmap.registry.args['mssql-tables.keywords']
if ( type(tmp) == 'table' ) then
tmp = stdnse.strjoin(',', tmp)
end
table.insert(restrict_tbl, 1, ("Filter: %s"):format(tmp))
pos = pos + 1
else
table.insert(restrict_tbl, 1, "No filter (see mssql-tables.keywords)")
end
if ( DB_COUNT > 0 ) then
local tmp = ("Output restricted to %d databases"):format(DB_COUNT)
if ( not(nmap.registry.args['mssql-tables.maxdb']) ) then
tmp = tmp .. " (see mssql-tables.maxdb)"
end
table.insert(restrict_tbl, 1, tmp)
pos = pos + 1
end
if ( TABLE_COUNT > 0 ) then
local tmp = ("Output restricted to %d tables"):format(TABLE_COUNT)
if ( not(nmap.registry.args['mssql-tables.maxtables']) ) then
tmp = tmp .. " (see mssql-tables.maxtables)"
end
table.insert(restrict_tbl, 1, tmp)
pos = pos + 1
end
if ( 1 < pos and #output > 0) then
restrict_tbl.name = "Restrictions"
table.insert(output, "")
table.insert(output, restrict_tbl)
end
output = stdnse.format_output( true, output )
return output
end

View File

@@ -0,0 +1,146 @@
description = [[
Queries Microsoft SQL Server (MSSQL) for a list of tables per database.
]]
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"intrusive"}
require 'shortport'
require 'stdnse'
require 'mssql'
dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
---
-- @args mssql.username specifies the username to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql.password specifies the password to use to connect to
-- the server. This option overrides any accounts found by
-- the mssql-brute and mssql-empty-password scripts.
--
-- @args mssql-xp-cmdshell.cmd specifies the OS command to run.
-- (default is ipconfig /all)
--
-- @output
-- PORT STATE SERVICE
-- 1433/tcp open ms-sql-s
-- | mssql-xp-cmdshell:
-- | Command: ipconfig /all; User: sa
-- | output
-- |
-- | Windows IP Configuration
-- |
-- | Host Name . . . . . . . . . . . . : EDUSRV011
-- | Primary Dns Suffix . . . . . . . : cqure.net
-- | Node Type . . . . . . . . . . . . : Unknown
-- | IP Routing Enabled. . . . . . . . : No
-- | WINS Proxy Enabled. . . . . . . . : No
-- | DNS Suffix Search List. . . . . . : cqure.net
-- |
-- | Ethernet adapter Local Area Connection 3:
-- |
-- | Connection-specific DNS Suffix . :
-- | Description . . . . . . . . . . . : AMD PCNET Family PCI Ethernet Adapter #2
-- | Physical Address. . . . . . . . . : 08-00-DE-AD-C0-DE
-- | DHCP Enabled. . . . . . . . . . . : Yes
-- | Autoconfiguration Enabled . . . . : Yes
-- | IP Address. . . . . . . . . . . . : 192.168.56.3
-- | Subnet Mask . . . . . . . . . . . : 255.255.255.0
-- | Default Gateway . . . . . . . . . :
-- | DHCP Server . . . . . . . . . . . : 192.168.56.2
-- | Lease Obtained. . . . . . . . . . : den 21 mars 2010 00:12:10
-- | Lease Expires . . . . . . . . . . : den 21 mars 2010 01:12:10
-- |_
--
-- The script needs an account with the sysadmin server role to work.
-- It needs to be fed credentials through the script arguments or from
-- the scripts mssq-brute or mssq-empty-password.
--
-- When run, the script iterates over the credentials and attempts to run
-- the command until either all credentials are exhausted or until the
-- command is executed.
--
-- Version 0.1
-- Created 01/17/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
portrule = shortport.port_or_service(1433, "ms-sql-s")
local function table_contains( tbl, val )
for k,v in pairs(tbl) do
if ( v == val ) then
return true
end
end
return false
end
action = function( host, port )
local status, result, helper
local username = nmap.registry.args['mssql.username']
local password = nmap.registry.args['mssql.password'] or ""
local creds
local query
local cmd = nmap.registry.args['mssql-xp-cmdshell.cmd'] or 'ipconfig /all'
local output = {}
query = ("EXEC master..xp_cmdshell '%s'"):format(cmd)
if ( username ) then
creds = {}
creds[username] = password
elseif ( not(username) and nmap.registry.mssqlusers ) then
-- do we have a sysadmin?
creds = {}
if ( nmap.registry.mssqlusers.sa ) then
creds["sa"] = nmap.registry.mssqlusers.sa
else
creds = nmap.registry.mssqlusers
end
end
-- If we don't have valid creds, simply fail silently
if ( not(creds) ) then
return
end
for username, password in pairs( creds ) do
helper = mssql.Helper:new()
status, result = helper:Connect(host, port)
if ( not(status) ) then
return " \n\n" .. result
end
status, result = helper:Login( username, password, nil, host.ip )
if ( not(status) ) then
stdnse.print_debug("ERROR: %s", result)
break
end
status, result = helper:Query( query )
helper:Disconnect()
if ( status ) then
output = mssql.Util.FormatOutputTable( result, true )
if ( not(nmap.registry.args['mssql-xp-cmdshell.cmd']) ) then
table.insert(output, 1, cmd)
output = stdnse.format_output( true, output )
output = "(Use --script-args=mssql-xp-cmdshell.cmd='<CMD>' to change command.)" .. output
else
output = stdnse.format_output( true, output )
end
break
elseif ( result:gmatch("xp_configure") ) then
if( nmap.verbosity() > 1 ) then
return " \nProcedure xp_cmdshell disabled, for more information see \"Surface Area Configuration\" in Books Online."
end
end
end
return output
end

View File

@@ -52,7 +52,14 @@ Entry { filename = "ldap-search.nse", categories = { "discovery", "safe", } }
Entry { filename = "lexmark-config.nse", categories = { "discovery", "safe", } }
Entry { filename = "mongodb-databases.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "mongodb-info.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "ms-sql-brute.nse", categories = { "auth", "intrusive", } }
Entry { filename = "ms-sql-config.nse", categories = { "discovery", "safe", } }
Entry { filename = "ms-sql-empty-password.nse", categories = { "auth", "intrusive", } }
Entry { filename = "ms-sql-hasdbaccess.nse", categories = { "auth", "discovery", "safe", } }
Entry { filename = "ms-sql-info.nse", categories = { "default", "discovery", "intrusive", } }
Entry { filename = "ms-sql-query.nse", categories = { "discovery", "safe", } }
Entry { filename = "ms-sql-tables.nse", categories = { "discovery", "safe", } }
Entry { filename = "ms-sql-xp-cmdshell.nse", categories = { "intrusive", } }
Entry { filename = "mysql-brute.nse", categories = { "auth", "intrusive", } }
Entry { filename = "mysql-databases.nse", categories = { "discovery", "intrusive", } }
Entry { filename = "mysql-empty-password.nse", categories = { "auth", "intrusive", } }