-
Notifications
You must be signed in to change notification settings - Fork 1
/
ms-sql-dump-hashes.nse
135 lines (112 loc) · 3.9 KB
/
ms-sql-dump-hashes.nse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
local io = require "io"
local mssql = require "mssql"
local stdnse = require "stdnse"
local string = require "string"
local table = require "table"
description = [[
Dumps the password hashes from an MS-SQL server in a format suitable for
cracking by tools such as John-the-ripper. In order to do so the user
needs to have the appropriate DB privileges.
Credentials passed as script arguments take precedence over credentials
discovered by other scripts.
]]
---
-- @usage
-- nmap -p 1433 <ip> --script ms-sql-dump-hashes
--
-- @output
-- PORT STATE SERVICE
-- 1433/tcp open ms-sql-s
-- | ms-sql-dump-hashes:
-- | nmap_test:0x01001234567890ABCDEF01234567890ABCDEF01234567890ABCDEF01234567890ABCDEF01234567890ABCDEF0123
-- | sa:0x01001234567890ABCDEF01234567890ABCDEF01234567890ABCDEF01234567890ABCDEF01234567890ABCDEF0123
-- |_ webshop_dbo:0x01001234567890ABCDEF01234567890ABCDEF01234567890ABCDEF01234567890ABCDEF01234567890ABCDEF0123
--
--
-- Version 0.1
-- Created 08/03/2011 - v0.1 - created by Patrik Karlsson <[email protected]>
--
author = "Patrik Karlsson"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"auth", "discovery", "safe"}
dependencies = {"ms-sql-brute", "ms-sql-empty-password"}
hostrule = mssql.Helper.GetHostrule_Standard()
portrule = mssql.Helper.GetPortrule_Standard()
local function process_instance(instance)
local helper = mssql.Helper:new()
local status, errorMessage = helper:ConnectEx( instance )
if ( not(status) ) then
return false, {
['name'] = string.format( "[%s]", instance:GetName() ),
"ERROR: " .. errorMessage
}
end
status, errorMessage = helper:LoginEx( instance )
if ( not(status) ) then
return false, {
['name'] = string.format( "[%s]", instance:GetName() ),
"ERROR: " .. errorMessage
}
end
local result
local query = [[
IF ( OBJECT_ID('master..sysxlogins' ) ) <> 0
SELECT name, password FROM master..sysxlogins WHERE password IS NOT NULL
ELSE IF ( OBJECT_ID('master.sys.sql_logins') ) <> 0
SELECT name, password_hash FROM master.sys.sql_logins
]]
status, result = helper:Query( query )
local output = {}
if ( status ) then
for _, row in ipairs( result.rows ) do
table.insert(output, ("%s:%s"):format(row[1] or "",row[2] or "") )
end
end
helper:Disconnect()
local instanceOutput = {}
instanceOutput["name"] = string.format( "[%s]", instance:GetName() )
table.insert( instanceOutput, output )
return true, instanceOutput
end
-- Saves the hashes to file
-- @param filename string name of the file
-- @param response table containing the resultset
-- @return status true on success, false on failure
-- @return err string containing the error if status is false
local function saveToFile(filename, response)
local f = io.open( filename, "w")
if ( not(f) ) then
return false, ("Failed to open file (%s)"):format(filename)
end
for _, row in ipairs(response) do
if ( not(f:write(row .."\n" ) ) ) then
return false, ("Failed to write file (%s)"):format(filename)
end
end
f:close()
return true
end
action = function( host, port )
local dir = stdnse.get_script_args("ms-sql-dump-hashes.dir")
local scriptOutput = {}
local status, instanceList = mssql.Helper.GetTargetInstances( host, port )
if ( not status ) then
return stdnse.format_output( false, instanceList )
else
for _, instance in pairs( instanceList ) do
local status, instanceOutput = process_instance( instance )
if ( status ) then
local filename
if ( dir ) then
local instance = instance:GetName():match("%\\+(.+)$") or instance:GetName()
filename = ("%s/%s_%s_ms-sql_hashes.txt"):format(dir, host.ip, instance)
saveToFile(filename, instanceOutput[1])
end
end
table.insert( scriptOutput, instanceOutput )
end
end
if ( #scriptOutput == 0 ) then return end
local output = ( #scriptOutput > 1 and scriptOutput or scriptOutput[1] )
return stdnse.format_output( true, output )
end