Baylen Orr

File Analysis - 2022:07:27

Analysis Trojan:Win32/AgentTesla!ml

By Baylen Orr · Report date: 28 April 2022

Network indicators on this page are defanged (e.g. example[.]com) so they can't be clicked by accident.

Samples can be downloaded here

Files

  1. TokenAccessLev.exe.7z (cd8717a51e5b9667a820f310e65669364416914b67aa9cc1fda7ac1e8deee35a)
  2. abzQueueReader.dll.7z (af1f5074eff36653e6d54c5c7aabf990aee2cc70a72db4cfb1707e452349c574)
  3. DotNetZipAdditionalPlatforms.dll.7z (91c0e6ab4dbb88f6598a8dc6496da665c2b76cc3b2de773c6347adbfa792ee9a)
  4. ACBBUrbKpBNFcXasbucMjNhXYxjTx.exe.7z (025fd34b016ccc03c7b25390c3c0478943d182fed1198311d62383475d055753)

SUMMARY

Retrieved and unpacked the individual Trojan exectubles of an Agent Tesla sample..

TokenAccessLev.exe (Stage-1)

Stage-1 is a PE32 Mono/.Net assembly GUI executable that was originally delivered as "PI-249.exe". Stage-1 disguises itself as a simple GUI game application and is a trojan for abzQueueReader.dll (Stage-2). Stage-1 is obfuscated with ambiguous method names that are likely meant to make the binary appear benign from a strings analysis. Stage-1 executes at method LX.m4m() which instantiates an XC instance class with Application.Run(new XC()). The XC class contains several key functionalities: First, XC builds strings to be passed as entry point arguments for the second stage payload. Second, XC.V4o() retrieves the resource "Xena" and passes it into a simple deobfuscation routine to transform "Xena" to Stage-2. The method XC.V4o() is sneakily called by using the set function when creating the application background color.

XC builds the method string "DictionaryEnumerator" and then creates a string[] array = new string[] object with three values and passes them into LateBinding.LateCall("DictionaryEnumerator", null, "Invoke", new object[] { 0, array }, null, null). These values are used to when Stage-2 is invoked.

To manually retrieve Stage-2, open Stage-1 using DnSpy, and navigate to the method XC.V4o() and set a breakpoint on the final return statement in the method, return Color.DarkOrchid. If the naming convention is different, try looking at functionality below any calls to instantiate a new ResourceManager(typeof(xx)).GetObject("Xena-or-other-resource");. If this also fails to yield a result, try identifiying the decryption routine which is shown below as XC.M4U(). Stage-2 is loaded into process memory in the fashion shown below in the cleaned up and deobfuscated code from the XC class.

    // The cleaned up code from XC.V4o does the following:
        stage_2 = (byte[])new ResourceManager().GetObject("Xena");

        i = 27670;
        while (i >= 0)
        {
                stage_2 = XC.decrypt_routine("7H75FP5C8YSU15478G8V5G", stage_2, i);
                i += -1;
        }
        private static object stage_2 = Assembly.Load(stage_2).GetType("Forging.Forging");

        // Original decrypt routine excerpt
        private static byte[] M4U(string \u0020, byte[] \u0020, int \u0020) {
    		\u0020[\u0020 % 13824] = XC.WXk((XC.V4l((int)((char)\u0020[\u0020 % 13824] ^  \
            XC.KXq(\u0020, \u0020 % 22))) - XC.V4l((int)\u0020[(\u0020 + 1) % 13824]) + 256) \
            % 256);
    	  return \u0020;
    	}

To summarize the code above, Stage-1 decodes the resource bitmap image "Xena" which results in our second stage .NET binary (analyzed below). Resource "Xena" is then passed into the "decrypt_routine()" method byte-by-byte until the while loop finishes execution. Finally, a new object is created using from retrieving the "Forging.Forging" class from stage_2. The decryption routine XC.M4U() is also shown for reference.

abzQueueReader.dll (Stage-2)

Stage-2 is a PE32 Mono/.Net assembly console application DLL. Stage-2 is not packed/obfuscated and contains a lot of unused code. The Forging.Forging class contains most of the interesting code, and is where the DictionaryEnumerator() method is located. Stage-2's DictionaryEnumerator() method is responsible for retrieving the third stage payload and passing execution to Forging.ParsingState() which ultimately executes Stage-3.

public static void DictionaryEnumerator(string StringTypeInfo, string InputBlockSize, string EscapedIRemotingFormatter)
    {
        typeof(Thread).InvokeMember("Sleep", BindingFlags.InvokeMethod, null, null, new object[]
        {
        41556
        });
        Bitmap serStack = Forging.LowestBreakIteration(Forging.CausalitySource(StringTypeInfo), EscapedIRemotingFormatter);
        byte[] bi = Forging.SearchResult(Forging.NamedArguments(serStack), Forging.CausalitySource(InputBlockSize));
        Assembly tp = Forging.GlobalAssemblyCache(bi);
        Forging.ParsingState(tp);
        Environment.Exit(0);
    }

The method Forging.LowestBreakIteration() instantiates a new ResourceManager with the help of arg2 via new ResourceManager(arg2 + ".Properties.Resources", Assembly.GetEntryAssembly()); and returns (Bitmap)resourceManager.GetObject(arg1). The method is two lines of code and easily identifiable.

The method Forging.SearchResult() deobfuscates the bitmap image into Stage-3.

The method Forging.GlobalAssemblyCache() simply passes its argument into the Assembly.Load() routine.

The method Forging.ParsingState() is shown below. The arguments passed to GetTypes() and GetMethods() are generated elsewhere dynamically and are located on the stack. By setting a breakpoint at Forging.ParsingState() in the DictionaryEnumerator() method we can manually dump the third stage payload and observe the arguments being passed by dumping byte[] bi and stepping into Forging.ParsingState()'s execution. In this case, the variable "methodInfo" is the string "B038iX0YZhFxPx5XDB.IVw04qGfJiZWONfmhE.NtpWh9STxe()". Method ParsingState() is shown below:

// Gets methods from Stage 3
    // `methodInfo` = "B038iX0YZhFxPx5XDB.IVw04qGfJiZWONfmhE.NtpWh9STxe()" when called via `Invoke`.	
    private static void ParsingState(object TP)
    {
        Type type = ((Assembly)TP).GetTypes()[20];
        MethodInfo methodInfo = type.GetMethods()[5];
        methodInfo.Invoke(null, null);
    }

See "stage-3-dump.png" in the attachments for screenshot image the mentioned breakpoint sequence to retrieve the payload.

DotNetZipAdditionalPlatforms.dll (Stage-3)

Stage-3 is a packed and obfuscated PE32 Mono/.Net assembly console application DLL. Stage-3 is identified as "Gen:Variant.MSILHeracles.36553" by most AV vendors (note: at time of writing, only 12 vendors identified the sample), and is obfuscated. By using the "step into" method in DnSpy, you can eventually reach the entry point of Stage-3. The process will continue execution and debugging will break. In DnSpy you can still still set a break point on the loaded module, and then restart the debugging session and take control over Stage-3's execution in that manner.

Stage-3's IVw04qGfJiZWONfmhE class handles all the important workload for dropping Stage-4. Stage-4 is loaded into the class LLJIOOUjm3KqJRKvUsO. This class contains several methods and data types to call Invoke on a passed byte array. By identifying the following line and setting a breakpoint, the final payload can be retrieved from a memory dump from the relevant local array after execution. Note that IVw04qGfJiZWONfmhE.ra7W19upKH is a type byte[].

IVw04qGfJiZWONfmhE.ra7W19upKH = LLJIOOUjm3KqJRKvUsO.yUiNNLmAt(OHHJEeZUQpZsqffLMo0.yUiNNLmAt(IVw04qGfJiZWONfmhE.qIlWJFAISv, OHHJEeZUQpZsqffLMo0.LJrU5TuToM), IVw04qGfJiZWONfmhE.JcTWNurUqJ, LLJIOOUjm3KqJRKvUsO.Y9FUICH39a);

The following code is responsible for setting up the base address and other housecleaning for Stage-4 to load and execute correctly. All initialization and execution of Stage-4 is handled by methods in the IVw04qGfJiZWONfmhE class.

    try
        {
           bool flag = !IVw04qGfJiZWONfmhE.bFZWciIEpA(\u0020, string.Empty, IntPtr.Zero, IntPtr.Zero, false, 134217732U, IntPtr.Zero, null, ref gGIi02g741UcLbiVXg, ref mcAt8rxIx2tG7XKKeC);
           if (flag)
           {
           	 throw new Exception();
           }
           int num4 = LPddxQUsivMTdNHiYcP.yUiNNLmAt(\u0020, 60, LPddxQUsivMTdNHiYcP.km3U4dEJVE);    <---- returns 0x00000080
           int num5 = LPddxQUsivMTdNHiYcP.yUiNNLmAt(\u0020, num4 + 52, LPddxQUsivMTdNHiYcP.km3U4dEJVE); <--- returns 0x00400000
           int[] array = new int[179];
           array[0] = 65538;
           if (l120ZjUTDZ4J1q58FJe.yUiNNLmAt(l120ZjUTDZ4J1q58FJe.J5DUoxR82i) != 4)
           {
           bool flag2 = !IVw04qGfJiZWONfmhE.Bk6Wajj20E(mcAt8rxIx2tG7XKKeC.va6L3NHfJr, array);
           	 if (flag2)
           	 {
           	   throw new Exception();
           	 }
           }
    	   // method continues

Execution of Stage-4 is handled by IVw04qGfJiZWONfmhE.gacWeWJFN3(), which eventually spawns Stage-4 overwriting Stage-1 and using the same name and path over Stage-1 in a new process.

ACBBUrbKpBNFcXasbucMjNhXYxjTx.exe (Stage-4)

Stage-4 is a .Net/Mono PE executable file and is lightly obfuscated. Stage-4 maintains all the characteristics of Agent Tesla info stealer, which is immediately apparent following a strings analysis on the file. We verified there was no other functionality within Stage-4, and concluded our investigations after identifying such functionality in Stage-4.