{
	"id": "cfa526c3-eebd-49b8-b08f-fdd2e39cc1a5",
	"created_at": "2026-04-06T00:08:18.451739Z",
	"updated_at": "2026-04-10T03:23:52.021534Z",
	"deleted_at": null,
	"sha1_hash": "2d71226e8e3f2ef2010a3c9eb693782ac4174845",
	"title": "How Analysing an AgentTesla Could Lead To Attackers Inbox - Part II",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1089615,
	"plain_text": "How Analysing an AgentTesla Could Lead To Attackers Inbox - Part II\r\nBy Suraj Malhotra\r\nPublished: 2020-04-15 · Archived: 2026-04-05 23:45:50 UTC\r\nI hope you’ve read the Part I of this series.\r\nThere we discussed some techniques to do basic analysis, tested the sample on any.run and most importantly the\r\n“Decrypting Strings” part where we learned how it uses AES encrypted strings to evade some simple detections.\r\nSo Lets get started !!\r\nSome Tidbits\r\nTo continue with where we left earlier, the next fcn called is tlg() and it copies the malware into the default temporary\r\nlocation as TMP#{Millisecond}.bin\r\nLater it starts to execute the fcn tkq.tjg in a thread.\r\nIt uses tkq.tjg to perform some registry key modifications usually for persistence and execute some system commands.\r\nIt uses that temporary file it just created as well.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 1 of 15\n\nStealing Credentials\r\nPS This is the core part of the series and its important to understand.\r\nSo, The next function to notice is kqe which returns a list.\r\nThe first statement gets the path to the AppData/Local.\r\nThen the execution is passed to zla.zgh with the location of Chrome concatenated with the AppData location.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 2 of 15\n\nIt also concatenates \\Default\\Login Data and \\Login Data and saves those 2 results in a list.\r\nNext it looks whether the Directory User Data exists in the particular location.\r\nIf the directory is present, it iterates over it to find its subdirectories.\r\nAnd at last compares if the string Profile is present in any of the items in the directories list.\r\nBasically It checks if any subdirectory named Profile exists. This could be the case when I would have installed other\r\nbrowsers such as Firefox, etc.\r\nPS I only have only installed Chrome on my Victim VM and We’ll be only exploring the process of credential stealer in case\r\nof Chrome.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 3 of 15\n\nFinally It checks for the real Login Data file in both locations User Data\\Default\\, \\User Data\\ (from items of prev list)\r\nand if it exists it executes fcn. emx.\r\nNow vcx contains the content of the Login Data file.\r\nThe emx function is interesting.\r\nTBH I didn’t had any installation of Chrome on my VM but this function looks like it does a strict checking on the contents\r\nof the Login Data file and I needed to get a legitimate one.\r\nSo First it wants the 52th byte in the file to be 0.\r\nThen it compares var vjl to 0.\r\nFor vjl we need to analyse eco fcn and I found out it just returns ‘arg2’ no. of bytes starting from ‘arg1’ index from vcx.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\npublic emx(string baseName)\r\n{\r\n this.vja = new byte[]{0,1,2,3,4,6,8,8,0,0};\r\n if (File.Exists(baseName))\r\n {\r\n this.vcx = this.vcl(baseName);\r\n if (this.vcx[52] != 0)\r\n {\r\n return;\r\n }\r\n this.vjo = checked((ushort)this.eco(16, 2));\r\n this.vjl = this.eco(56, 4);\r\n if (decimal.Compare(new decimal(this.vjl), 0m) == 0)\r\n {\r\n this.vjl = 1UL;\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 4 of 15\n\n16\r\n17\r\n18\r\n19\r\n }\r\n this.ejo(100UL);\r\n }\r\n}\r\nIf it succeeds and passes all of the checks, control is passed over to fcn ejo.\r\nThe ejo fcn is cool as I thought that it would execute sql queries over the Login Data file to get the credentials but there is no\r\nneed of doing this, we’ll see how :)\r\nFirst It creates an obj list with 5 elements and has main elements as item_name, item_type,sql_statement. These all fields are\r\nfilled by taking strings from different indexes from the original Login Data file.\r\nAlso I don’t know why but ejo first adds data to the beginning 6 elements of vjb and then another loop adds 11 elements to it\r\nand fills them.\r\nView whole content of vjb here.\r\nNext It searches for vjb[2] element and extracts all the words within parantheses and splits them with ‘,’ as a delimiter from\r\nthe sql_statement.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 5 of 15\n\nThe resulting list looks like the following…\r\nAlso it strips the spaces which we can notice at the beginning now.\r\nNow the resulting list is copied into the vjh array.\r\nAfterwards it iterates over its elements, splits them with “ “ as a delimiter and then only keeps the first element.\r\nThe resulting array looks like the following..\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 6 of 15\n\nNow it initialises another array as vjg and has the structure from emx.emg.\r\nAs you can see below it has a single element with two fields as content \u0026 row_id. From this point I can guess that the\r\ncontent field is what we are looking for.\r\nAlso another variable array is initialised with the structure of emx.ema.\r\nIts elements have a size \u0026 type field.\r\nAnd it fills both of them with some calculations done on obj2 and obj4.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 7 of 15\n\nAnd it iterates till an element with type \u003e 9 exists in the array.\r\nSome of the elements are as follows..\r\nWe’ll see how is it used now.\r\nAfter this, it initialises the content field of vjg and we can see that it’ll have the same number of elements as of array. Hmm..\r\nLooks like some operation will be done on array.\r\nAnd Woah.. after some loops we can observe that it was successful in extracting some strings from the sqlite Login Data\r\nfile.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 8 of 15\n\nNow lets dig into what happened with the array and what it did behind the scenes.\r\nSo the statement in the above screenshot looks like the following.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\nthis.vjg[num8 + num5].content[num13] = Encoding.Default.GetString(\r\n this.vcx,\r\n Convert.ToInt32(\r\n decimal.Add(\r\n decimal.Add(\r\n new decimal(num6), new decimal(num14)),\r\n new decimal(num15))),\r\n (int)array[num13].size);\r\nNow at this point we can utilise the Locals window to check the values of some variables including num8, num5, num13,\r\nnum6, num14, num15.\r\nI made some notes and added a watch over those variables.\r\nAs anybody can tell that num13 is the index of the content field but I noticed that num8, num5, num6, num14 remained the\r\nsame for every value of num13.\r\nSo its basically accessing data from a particular index which is (num6 + num14 + num15) out of which (num6 + num14) is a\r\nconstant, for me ie. 6797 so the only index to note is num15.\r\nAlso if you’d observe that array[x].size is what we previously initialised for every item in the array and its basically the\r\nstring length record.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\nvjg[0].content[0x2] = (this.vcx, 6797 + num15, 0x8)\r\nthen num15 = 0x3e\r\nvjg[0].content[0x3] = (this.vcx, 6797 + num15, 0xf)\r\nthen num15 = 0x46\r\nvjg[0].content[0x4] = (this.vcx, 6797 + num15, 0x8)\r\nnum15 = 0x4e\r\nvjg[0].content[0x5] = (this.vcx, 6797 + num15, 0x30)\r\nnum15 = 0x74\r\nvjg[0].content[0x6] = (this.vcx, 6797 + num15, 0)\r\nAfter the function ends we get to see every item in the locals.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 9 of 15\n\nAhmm.. we get it on some functions as listed below. Now you know what to do.. Set a Breakpoint on them where they use it\r\nthis deadly API Call :)\r\nNow everybody knows there is only one way to decrypt that password from Login Data ie CryptUnprotectData fcn Call. So\r\nI searched for any references to where its used..\r\nAnd BoomYa we hit one of them and we can also see our encrypted password in the locals window. Now we can copy the\r\nresult from this call from this local by simply stepping into it.\r\nBut wait thats not it.. Sh*t It has a whole function to decrypt it too to which it has passed the result of unprotected data and\r\nour original encrypted password.\r\nThis was something new for me coz I’m not use to C# and the decryption function in C looks very different.\r\nWhat I can observe from this is that it uses AES_GCM mode but don’t know the use of BCRYPT here. (Maybe It is the only\r\none to include AES GCM Mode) ¯\\_(ツ)_/¯\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 10 of 15\n\nAnd Then fortunately I found some reference which made my task easy.\r\nI was finally successful to implement this in python.\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n11\r\n12\r\n13\r\nfrom Cryptodome.Cipher import AES\r\ndef dec(pwd, unproc_key):\r\n auth_tag = pwd[-16:]\r\n pwd = pwd.replace(auth_tag,'')\r\n nonce, proc_pwd = pwd[3:15], pwd[15:]\r\n cipher = AES.new(unproc_key, AES.MODE_GCM, nonce=nonce)\r\n print cipher.decrypt_and_verify(proc_pwd,auth_tag)\r\npwd = \"763130492BD2706140CDA41C2701F3B4C2B5153DE018BA5512897731F1A1BB7D7982AA2BF3DEA4B299145D88B040ED58\".deco\r\nunproc_key = \"2295D977B8F09202A4F8F7ACAF15C1B9EC411B126A0335208BE3DB8F14CA1551\".decode('hex')\r\ndec(pwd, unproc_key)\r\nMoving on, It creates another list zah where its elements have 3 fields named Item1, Item2 and Item3.\r\nHere,\r\nItem1 = Browser Name\r\nItem2 = Browser Data Location\r\nitem3 = bool if it exists (maybe)\r\nNext It checks if whether it exists or not similarly it checked the chrome location.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 11 of 15\n\nBut now It doesn’t do anything (I don’t have Opera installed), instead I see the credentials from Chrome being added to a\r\nlist. Now we have the decrypted password in it :)\r\nLater it continues to check for different browsers and some FTP Clients as well.\r\nAnd After adding some of the Browser Names \u0026 Location it checks for them in chunks.\r\nHere you can check it does the same process with Yandex Browser.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 12 of 15\n\nCommunication through SMTP\r\nNow we know some part of how it carries out its stealthy process of stealing credentials from the browswers without any sql\r\nquery. So I ended up searching for some functions which used the SMTP client responsible for sending the credentials.\r\nAnd I found the only function which used it was tkq.tyx().\r\nLuckily It was not as obfuscated as I thought it to be.\r\nWe can clearly observe our system and browser information which its sending over.\r\nAlong with them we can also see the plaintext credentials of the author’s email account at yandex.ru which is used to send it.\r\nAnd to no surprise, these credentials were working as we previously checked the any.run results.\r\nAlso The funny thing is that I had the credentials before this part of the blog as they were just decrypted using the same\r\nprocess I explained.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 13 of 15\n\nWe can view our browser credentials in memory dump and the message body is formatted as html.\r\nIt uses different classes such as mailMessage to construct the message body.\r\nAnd Finally It initializes some other variables such as..\r\nPort = 587 (default for SMTP)\r\nHost = yandex.ru,\r\nTo and From fields were the same…\r\nAnd when it sends over the data it deletes itself from the disk. I didn’t explore it that much and I wasn’t sure maybe it was\r\nexecuted in a thread.\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 14 of 15\n\nThanks\r\nI hope this 2 part series was insightful and you guys enjoyed it. Well If you are reading this line you really liked it.\r\nTBH It really took a lot of work to put it all together including taking screenshots, and not to forget… opening the malware\r\nagain in dnspy.. everytime it removed itself.\r\nSee ya guys next time…\r\nTill then Take Care and make use of this Lockdown to learn new stuff.\r\nAlso Keep sharing your findings with the community.\r\nSource: https://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nhttps://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/\r\nPage 15 of 15",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://mrt4ntr4.github.io/How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2/"
	],
	"report_names": [
		"How-Analysing-an-AgentTesla-Could-Lead-To-Attackers-Inbox-2"
	],
	"threat_actors": [
		{
			"id": "d90307b6-14a9-4d0b-9156-89e453d6eb13",
			"created_at": "2022-10-25T16:07:23.773944Z",
			"updated_at": "2026-04-10T02:00:04.746188Z",
			"deleted_at": null,
			"main_name": "Lead",
			"aliases": [
				"Casper",
				"TG-3279"
			],
			"source_name": "ETDA:Lead",
			"tools": [
				"Agentemis",
				"BleDoor",
				"Cobalt Strike",
				"CobaltStrike",
				"RbDoor",
				"RibDoor",
				"Winnti",
				"cobeacon"
			],
			"source_id": "ETDA",
			"reports": null
		}
	],
	"ts_created_at": 1775434098,
	"ts_updated_at": 1775791432,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/2d71226e8e3f2ef2010a3c9eb693782ac4174845.pdf",
		"text": "https://archive.orkl.eu/2d71226e8e3f2ef2010a3c9eb693782ac4174845.txt",
		"img": "https://archive.orkl.eu/2d71226e8e3f2ef2010a3c9eb693782ac4174845.jpg"
	}
}