1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 22:21: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-*- # 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 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 to be 32 octects when calling the ReadDir function. The bug was reported by
Djalal Harouni. [Patrik] 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 = "lexmark-config.nse", categories = { "discovery", "safe", } }
Entry { filename = "mongodb-databases.nse", categories = { "default", "discovery", "safe", } } Entry { filename = "mongodb-databases.nse", categories = { "default", "discovery", "safe", } }
Entry { filename = "mongodb-info.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-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-brute.nse", categories = { "auth", "intrusive", } }
Entry { filename = "mysql-databases.nse", categories = { "discovery", "intrusive", } } Entry { filename = "mysql-databases.nse", categories = { "discovery", "intrusive", } }
Entry { filename = "mysql-empty-password.nse", categories = { "auth", "intrusive", } } Entry { filename = "mysql-empty-password.nse", categories = { "auth", "intrusive", } }