CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/mssql/mssql_idf.rb
Views: 11623
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
##
7
# Author: Robin Wood <[email protected]> <http://www.digininja.org>
8
# Version: 0.1
9
#
10
# This module will search the specified MSSQL server for
11
# 'interesting' columns and data
12
#
13
##
14
15
class MetasploitModule < Msf::Auxiliary
16
include Msf::Exploit::Remote::MSSQL
17
include Msf::OptionalSession::MSSQL
18
19
def initialize(info = {})
20
super(update_info(info,
21
'Name' => 'Microsoft SQL Server Interesting Data Finder',
22
'Description' => %q{
23
This module will search the specified MSSQL server for
24
'interesting' columns and data.
25
26
This module has been tested against the latest SQL Server 2019 docker container image (22/04/2021).
27
},
28
'Author' => [ 'Robin Wood <robin[at]digininja.org>' ],
29
'License' => MSF_LICENSE,
30
'References' =>
31
[
32
[ 'URL', 'http://www.digininja.org/metasploit/mssql_idf.php' ],
33
]
34
))
35
36
register_options(
37
[
38
OptString.new('NAMES', [ true, 'Pipe separated list of column names', 'passw|bank|credit|card']),
39
])
40
end
41
42
def print_with_underline(str)
43
print_line(str)
44
print_line("=" * str.length)
45
end
46
47
def run
48
headings = [
49
["Database", "Schema", "Table", "Column", "Data Type", "Row Count"]
50
]
51
52
sql = ""
53
sql += "DECLARE @dbname nvarchar(255), @id int, @sql varchar (4000); "
54
sql += "DECLARE table_cursor CURSOR FOR SELECT name FROM sys.databases "
55
sql += "OPEN table_cursor "
56
sql += "FETCH NEXT FROM table_cursor INTO @dbname "
57
sql += "WHILE (@@FETCH_STATUS = 0) "
58
sql += "BEGIN "
59
sql += "SET @sql = 'select ';"
60
sql += "SET @sql = @sql + ' ''' + @dbname + ''' as ''Database'', ';"
61
sql += "SET @sql = @sql + 'sys.schemas.name as ''Schema'', ';"
62
sql += "SET @sql = @sql + 'sys.objects.name as ''Table'', ';"
63
sql += "SET @sql = @sql + 'sys.columns.name as ''Column'', ';"
64
sql += "SET @sql = @sql + 'sys.types.name as ''Column Type'' ';"
65
sql += "SET @sql = @sql + 'from ' + @dbname + '.sys.columns ';"
66
sql += "SET @sql = @sql + 'inner join ' + @dbname + '.sys.objects on sys.objects.object_id = sys.columns.object_id ';"
67
sql += "SET @sql = @sql + 'inner join ' + @dbname + '.sys.types on sys.types.user_type_id = sys.columns.user_type_id ';"
68
sql += "SET @sql = @sql + 'inner join ' + @dbname + '.sys.schemas on sys.schemas.schema_id = sys.objects.schema_id ';"
69
70
list = datastore['Names']
71
where = "SET @sql = @sql + ' WHERE ("
72
list.split(/\|/).each { |val|
73
where += " lower(sys.columns.name) like ''%" + val + "%'' OR "
74
}
75
76
where.slice!(-3, 4)
77
78
where += ") ';"
79
80
sql += where
81
82
sql += "SET @sql = @sql + 'and sys.objects.type=''U'';';"
83
sql += "EXEC (@sql);"
84
sql += "FETCH NEXT FROM table_cursor INTO @dbname "
85
sql += "END "
86
sql += "CLOSE table_cursor "
87
sql += "DEALLOCATE table_cursor "
88
89
begin
90
if session
91
set_mssql_session(session.client)
92
else
93
unless mssql_login_datastore
94
print_error('Login failed')
95
return
96
end
97
end
98
result = mssql_query(sql, false)
99
rescue Rex::ConnectionRefused => e
100
print_error("Connection failed: #{e}")
101
return
102
end
103
104
column_data = result[:rows]
105
widths = [0, 0, 0, 0, 0, 9]
106
total_width = 0
107
108
if result[:errors] && !result[:errors].empty?
109
result[:errors].each do |err|
110
print_error(err)
111
end
112
end
113
114
if column_data.nil?
115
print_error("No columns matched the pattern #{datastore['NAMES'].inspect}. Set the NAMES option to change this search pattern.")
116
return
117
end
118
119
(column_data|headings).each { |row|
120
0.upto(4) { |col|
121
widths[col] = row[col].length if row[col].length > widths[col]
122
}
123
}
124
125
widths.each { |a|
126
total_width += a
127
}
128
129
print_line
130
131
buffer = ""
132
headings.each { |row|
133
0.upto(5) { |col|
134
buffer += row[col].ljust(widths[col] + 1)
135
}
136
print_line(buffer)
137
print_line
138
buffer = ""
139
140
0.upto(5) { |col|
141
buffer += print "=" * widths[col] + " "
142
}
143
print_line(buffer)
144
print_line
145
}
146
147
column_data.each { |row|
148
count_sql = "SELECT COUNT(*) AS count FROM "
149
150
full_table = ""
151
column_name = ""
152
buffer = ""
153
0.upto(4) { |col|
154
full_table += row[col] + '.' if col < 3
155
column_name = row[col] if col == 3
156
buffer += row[col].ljust(widths[col] + 1)
157
}
158
full_table.slice!(-1, 1)
159
count_sql += full_table
160
161
result = mssql_query(count_sql, false) if mssql_login_datastore
162
163
count_data = result[:rows]
164
row_count = count_data[0][0]
165
166
buffer += row_count.to_s
167
print_line(buffer)
168
print_line
169
}
170
171
print_line
172
disconnect
173
end
174
end
175
176