Skip to navigation

Threat reportMalwareTL-2026-5357

laZzzy Donut: Multi-Stage Loader Chain (Kramer-obfuscated Python, Donut shellcode, laZzzy loader)

mediumACTIVE

TrustedSec (Scott Nusbaum) unpacked a six-stage loader chain: a Kramer-obfuscated Python 3.13 .pyc carrying RC4-encrypted shellcode, a first Donut layer, the open-source laZzzy AES-CBC/XOR shellcode loader, a second Donut layer, and a .NET DLL with encrypted resources that are loaded into memory as shellcode.

Key facts for TL-2026-5357

IdentifiersTL-2026-5357
Also known aslaZzzy Donut
SeverityMEDIUM
Exploitation statusPublic proof-of-concept exploit
Affected productsMicrosoft Windows (x64)
MalwarelaZzzy
ToolsDonut - S0695, Kramer
MITRE ATT&CK techniquesT1027 Obfuscated Files or Information, T1027.009 Obfuscated Files or Information: Embedded Payloads, T1027.013 Obfuscated Files or Information: Encrypted/Encoded File, T1055 Process Injection, T1055.003 Process Injection: Thread Execution Hijacking, T1055.004 Process Injection: Asynchronous Procedure Call, T1059.006 Command and Scripting Interpreter: Python, T1106 Native API, T1134.004 Access Token Manipulation: Parent PID Spoofing, T1140 Deobfuscate/Decode Files or Information, T1553.002 Subvert Trust Controls: Code Signing, T1620 Reflective Code Loading and 1 more in the attack flow
MotivationUNKNOWN
Detection rules9 (1 shown free)
Sources8 cited sources

Detection coverage for TL-2026-5357

As of 2026-11-06, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-5357 across Splunk SPL, Microsoft KQL and Sigma, covering 9 indicator(s) of compromise. The whole corpus is readable without an account. Every threat comes with one complete detection in Splunk SPL, Microsoft KQL and Sigma, free for everyone; a free account adds daily TL Creds to unlock the rest. Paid plans add a larger daily allowance, correlation and the MCP server. Threadlinqs MCP server · View plans.

Free detection: laZzzy Donut Stage 1 - Python Interpreter Injecting Into Another Process

Detects python.exe, pythonw.exe or py.exe creating a remote thread (Sysmon EID 8) or opening another process with write/operation access rights (Sysmon EID 10). In the TL-2026-5357 laZzzy Donut chain, the Kramer-obfuscated Python 3.13 stage decrypts RC4 shellcode, runs a Donut layer, and the embedded laZzzy loader then injects its payload into other processes. A scripting interpreter writing into foreign processes is rare in normal operations and is a high-signal behavioural indicator that does not depend on file hashes, which the source does not publish.

  • Languages: Splunk SPL, Microsoft KQL, Sigma
  • ATT&CK: T1059.006, T1055, T1620
  • Data sources: sysmon:EventID8, sysmon:EventID10, index=sysmon sourcetype=XmlWinEventLog:Microsoft-Windows-Sysmon/Operational
  • Severity: high
  • Confidence: high

Splunk SPL

index=sysmon sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" earliest=-24h (EventCode=8 OR EventCode=10) (SourceImage="*\\python.exe" OR SourceImage="*\\pythonw.exe" OR SourceImage="*\\py.exe") | eval is_hit=if(EventCode=="8" OR (EventCode=="10" AND match(GrantedAccess, "(?i)^0x(1fffff|1f3fff|1f0fff|143a|1438|1478|28|2a|3a|38|1028|102a)$")), 1, 0) | where is_hit=1 AND lower(SourceImage)!=lower(TargetImage) | eval threat="TL-2026-5357 laZzzy Donut Python stage-1 injection" | stats count min(_time) as first_seen max(_time) as last_seen values(EventCode) as event_codes values(GrantedAccess) as granted_access values(TargetImage) as injected_targets by host, SourceImage, threat | convert ctime(first_seen) ctime(last_seen)

Microsoft KQL

// TL-2026-5357 laZzzy Donut - Python interpreter performing cross-process injection primitives (Defender XDR)
let lookback = 24h;
DeviceEvents
| where Timestamp > ago(lookback)
| where ActionType in ("CreateRemoteThreadApiCall", "NtAllocateVirtualMemoryRemoteApiCall", "WriteProcessMemoryApiCall", "QueueUserApcRemoteApiCall", "SetThreadContextRemoteApiCall", "NtMapViewOfSectionRemoteApiCall")
| where InitiatingProcessFileName in~ ("python.exe", "pythonw.exe", "py.exe")
| summarize ApiCalls = make_set(ActionType), TargetProcesses = make_set(FileName), EventCount = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by DeviceName, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine, InitiatingProcessAccountName
| order by LastSeen desc

Sigma

title: Python Interpreter Creating Remote Thread (laZzzy Donut Stage-1 Injection)
id: 1a7c9e30-5f42-4b8d-a6e1-3d0f82b97c54
status: experimental
description: Detects python.exe, pythonw.exe or py.exe creating a thread in another process. In the TL-2026-5357 laZzzy Donut chain the Kramer-obfuscated Python stage runs Donut shellcode which hands off to the laZzzy loader for process injection.
references:
    - https://trustedsec.com/blog/unpacking-a-lazzzy-donut
    - https://github.com/capt-meelo/laZzzy
author: AII-Detector — ThreadLinqs Intelligence
date: 2026/11/06
tags:
    - attack.execution
    - attack.t1059.006
    - attack.defense-evasion
    - attack.privilege-escalation
    - attack.t1055
    - attack.t1620
    - attack.s0695
logsource:
    category: create_remote_thread
    product: windows
detection:
    selection:
        SourceImage|endswith:
            - '\python.exe'
            - '\pythonw.exe'
            - '\py.exe'
    condition: selection
falsepositives:
    - Python-based debuggers, instrumentation or automation frameworks that legitimately inject threads
level: high

Known false positives:

  • Python-based debuggers, profilers or instrumentation frameworks (e.g. frida, pydevd) opening or injecting into other processes
  • Developer workstations running Python automation that uses ctypes/pywin32 against other processes

Tuning notes: Change index=sysmon to your Sysmon index. Sysmon EID 8 and EID 10 must be enabled in the Sysmon config (EID 10 targeted at write-capable GrantedAccess values). Exclude known developer hosts and sanctioned debugger/target pairs via a lookup on SourceImage+TargetImage. Add pyinstaller-style renamed interpreters if you see them in your estate.

8 more detection rules (Splunk SPL, Microsoft KQL, Sigma) · unlock with TL Creds. Sign up free to unlock the detection rules or query them with the Threadlinqs MCP server (Purple)
  • laZzzy Donut Stage 1 - Python Executing Oversized .py From User-Writable Path (Kramer Bytecode Masquerade) · unlock with TL Creds
  • laZzzy Donut Stage 4-6 - Unbacked In-Memory .NET Module Load or CLR in Python · unlock with TL Creds
  • laZzzy Donut Stage 3 - Remote Injection API Chain (Early-bird APC / Thread Hijack / Section Mapping) · unlock with TL Creds
  • laZzzy Donut Stage 1 - Python ctypes Shellcode Runner Command Line · unlock with TL Creds
  • laZzzy Donut Stage 2/4 - AMSI or WLDP Library Loaded Into Python or Utility Host (Donut Bypass) · unlock with TL Creds
  • laZzzy Donut Stage 3 - Sacrificial Windows Host Process Launched Without Arguments · unlock with TL Creds
  • laZzzy Donut Stage 2/4 - CLR Loaded Into Python or Non-.NET Host Process · unlock with TL Creds
  • laZzzy Donut Stage 3 - Process Access With Unbacked CallTrace (Direct-Syscall / Shellcode Injection) · unlock with TL Creds

Indicators of compromise for TL-2026-5357

As of 2026-11-06, Threadlinqs Intelligence tracks 9 indicators of compromise for TL-2026-5357.

9 indicators of compromise · unlock with TL Creds. Compare plans

How laZzzy Donut works

The write-up shows every layer can be unwound statically, and releases a new extraction tool, LazZzy_Dump.

TrustedSec's 'Unpacking a laZzzy Donut' (published 2026-09-17) walks through a layered loader in which each stage hides the next, so that no single signature or format-specific tool covers the whole chain. The source does not name an actor, campaign, victim, delivery vector or C2 server, and it does not state in-the-wild exploitation; severity is analyst-assigned.

Stage 1 is a Python 3.13 bytecode file (.pyc, magic number 3571, compile timestamp Wed Jun 24 06:18:29 2026 UTC, recorded .py size 8,371,083 bytes) obfuscated with the public Kramer tool (billythegoat356/Kramer). Kramer output is compiled bytecode rather than source. The analyst decompiled it with depyo and recovered the key with a modified kramer_python_deobfuscator.py, cutting a brute-force step from hours to under a minute. The recovered payload is Base64-encoded, RC4-encrypted shellcode, which the script copies into an executable memory section and runs.

Stage 2 is shellcode generated by TheWover's Donut, a position-independent shellcode generator. Volexity's donut_decryptor was used to extract the Donut instance and module. The module wraps a complete Windows PE built with laZzzy (capt-meelo/laZzzy), which is a full PE rather than shellcode, so Donut tooling alone could not unwrap it.

Stage 3 is the laZzzy loader. It AES-CBC-decrypts an embedded payload (ciphertext length 0x12a50) and applies an additional rolling 16-byte XOR layer. The upstream project is a Windows x64 shellcode loader offering ten execution techniques (Early-bird APC queue, thread hijacking, KernelCallbackTable, section view mapping, thread suspension, LineDDA callback, EnumSystemGeoID callback, FLS callback, SetTimer, clipboard), direct syscalls with Nt* functions, IAT evasion, XOR-encrypted strings, PPID spoofing, blocking of non-Microsoft-signed DLLs, and optional icon/metadata cloning and spoofed code signing. The article does not say which injection method this sample used. Because no tool handled this stage, the author wrote LazZzy_Dump (trustedsec/LazZzy_Dump), which byte-pattern scans for the compiled AESDecrypt routine, resolves RIP-relative LEA/MOV operands to recover the AES key, IV, XOR key and ciphertext, and decrypts statically without a debugger or emulator.

Stage 4 is a second Donut layer, again unwrapped with donut_decryptor, yielding a .NET DLL (stage 5; analyzable with dnSpy/ILSpy). In stage 6 the DLL's resources are encrypted; their sections are parsed, loaded into memory as shellcode, and control is transferred to them. Donut itself, per its documentation, uses Chaskey encryption, optional aPLib/LZNT1/Xpress compression, patches AMSI, WLDP and ETW, can overwrite PE headers, and hosts .NET assemblies by loading the CLR into a new AppDomain. These are properties of the tool, not behaviors the article reports for this specific sample.

Defensive value: detection should be layered across behavior and memory (Python spawning executable memory and injecting, CLR loading into unexpected processes, laZzzy-style syscall injection), and the compiled-artifact patterns LazZzy_Dump uses can support YARA/memory hunting. No network IOCs or sample hashes are published, so BeaconBeagle correlation was not applicable.

MITRE ATT&CK techniques by tactic:

Defense Evasion

T1027 Obfuscated Files or Information; T1027.009 Obfuscated Files or Information: Embedded Payloads; T1027.013 Obfuscated Files or Information: Encrypted/Encoded File; T1055 Process Injection; T1134.004 Access Token Manipulation: Parent PID Spoofing; T1140 Deobfuscate/Decode Files or Information; T1620 Reflective Code Loading

Privilege Escalation

T1055.003 Process Injection: Thread Execution Hijacking; T1055.004 Process Injection: Asynchronous Procedure Call

Execution

T1059.006 Command and Scripting Interpreter: Python; T1106 Native API

defense-impairment

T1553.002 Subvert Trust Controls: Code Signing; T1685 Disable or Modify Tools

Remediation for laZzzy Donut

Immediate actions

  • Hunt for Python 3.13 .pyc files renamed to .py, especially multi-megabyte ones, and for python.exe/pythonw.exe allocating RWX memory or spawning/injecting into other processes
  • Hunt for CLR (clr.dll/mscoree) loading into processes that do not normally host .NET, a Donut hallmark
  • Scan memory and suspect PEs with YARA built from the laZzzy AESDecrypt byte pattern described by TrustedSec

Workarounds

  • Use application allowlisting to block user-writable-path Python and unsigned PE execution
  • Use LazZzy_Dump and donut-decryptor to unpack samples statically and extract IOCs

Longer-term hardening

  • Deploy EDR with memory scanning and detection for direct-syscall process injection (APC queue, thread hijack, callback-based execution)
  • Enable AMSI, ETW and script-block telemetry and alert on tampering
  • Restrict execution of unsanctioned Python interpreters and unsigned binaries with application control

Affected and fixed versions

Timeline of laZzzy Donut

  • The stage-1 Kramer-obfuscated Python 3.13 .pyc carries a compile timestamp of Wed Jun 24 06:18:29 2026 UTC (header timestamp; attacker-controllable, not confirmed as first-use).
  • TrustedSec states LazZzy_Dump was validated against multiple independently generated locked-ioc-7 samples, indicating the byte-pattern approach generalizes beyond the analyzed sample.
  • TrustedSec reports that no public static extraction tool existed for the locked-ioc-7 encryption layer at publication, motivating LazZzy_Dump.
  • Article shows both locked-ioc-9 layers unwrapped with Volexity donut_decryptor and the final .NET DLL with encrypted resources analyzed in dnSpy/ILSpy, demonstrating the chain can be fully unpacked statically.
  • Write-up describes a modified kramer_python_deobfuscator.py that reduces locked-ioc-8 key brute-forcing from hours to under a minute.
  • TrustedSec presents LazZzy_Dump, a new static extractor that recovers locked-ioc-7 AES key, IV, XOR key and payload by byte-pattern signature and RIP-relative resolution.
  • TrustedSec publishes 'Unpacking a locked-ioc-7 locked-ioc-9' by Scott Nusbaum, documenting the six-stage Python/locked-ioc-9/locked-ioc-7/.NET chain.

Sources cited for laZzzy Donut

Drafted by the Threadlinqs research pipeline from 8 sources; published ; last updated —.

Threadlinqs Intelligence — Real-Time Threat Detection Platform

[ 0 threats ] [ 0 det ] [ CRIT: 0 ] [ HIGH: 0 ]
// threat_feed
$ sort --newest
Showing all threats

Live intelligence console

Threat level

Latest Threats