Nezha Malware Detection Framework: Multi-Layer Rules Covering the Full Attack Lifecycle

YARA Rules

Rule 1: Nezha Core Malware Detection

yara

rule Nezha_Malware_Core
{
    meta:
        description = "Detects Nezha RAT/Botnet core components"
        author = "SOC Threat Intelligence"
        date = "2024-12-25"
        severity = "critical"
        malware_family = "Nezha"
        target_platform = "Linux, Windows"
        reference = "Chinese C2 Infrastructure Campaign Dec 2024"
        
    strings:
        // Chinese language strings in Simplified Chinese
        $chinese1 = "nezha" ascii wide nocase
        $chinese2 = {E5 93 AA E5 90 92} // 哪吒 (Nezha in UTF-8)
        $chinese3 = "配置文件" wide // Configuration file
        $chinese4 = "命令执行" wide // Command execution
        $chinese5 = "连接服务器" wide // Connect to server
        $chinese6 = "心跳包" wide // Heartbeat packet
        
        // Network communication patterns
        $net1 = "ws://" ascii
        $net2 = "wss://" ascii
        $net3 = "/api/v1/ws/agent" ascii
        $net4 = "User-Agent: nezha-agent" ascii
        $net5 = "X-Nezha-Token" ascii
        
        // Installation and persistence
        $install1 = "/tmp/.nezha" ascii
        $install2 = "/var/tmp/nezha" ascii
        $install3 = "nezha.service" ascii
        $install4 = "nezha-agent" ascii
        $install5 = "/usr/local/bin/nezha" ascii
        
        // C2 communication
        $c2_1 = "heartbeat" ascii
        $c2_2 = "execute_command" ascii
        $c2_3 = "report_status" ascii
        $c2_4 = "agent_secret" ascii
        
        // Crypto operations
        $crypto1 = "AES-256-GCM" ascii
        $crypto2 = "cipher.NewGCM" ascii
        $crypto3 = "crypto/aes" ascii
        
    condition:
        uint32(0) == 0x464c457f or uint16(0) == 0x5a4d and
        (
            (2 of ($chinese*) and 2 of ($net*)) or
            (3 of ($install*) and any of ($c2_*)) or
            (any of ($chinese*) and 2 of ($install*) and 1 of ($crypto*))
        )
}

Rule 2: Nezha Installation Scripts

yara

rule Nezha_Installation_Scripts
{
    meta:
        description = "Detects Nezha installation and deployment scripts"
        author = "SOC Threat Intelligence"
        severity = "high"
        malware_family = "Nezha"
        
    strings:
        // Script patterns
        $script1 = "#!/bin/bash" ascii
        $script2 = "#!/bin/sh" ascii
        
        // Installation commands
        $install1 = "wget" ascii
        $install2 = "curl -fsSL" ascii
        $install3 = "chmod +x" ascii
        $install4 = "systemctl enable" ascii
        $install5 = "systemctl start" ascii
        
        // Nezha specific
        $nezha1 = "nezha-agent" ascii
        $nezha2 = "nezha.service" ascii
        $nezha3 = "/opt/nezha" ascii
        $nezha4 = "NEZHA_" ascii
        
        // Chinese comments in scripts
        $comment1 = "# 安装" wide ascii // Install
        $comment2 = "# 配置" wide ascii // Configuration
        $comment3 = "# 启动" wide ascii // Start
        $comment4 = "# 守护进程" wide ascii // Daemon
        
        // Alibaba Cloud indicators
        $cloud1 = "aliyuncs.com" ascii
        $cloud2 = "alibabacloud.com" ascii
        $cloud3 = "oss-ap-northeast-1" ascii
        
        // Service configuration
        $service1 = "[Unit]" ascii
        $service2 = "ExecStart=" ascii
        $service3 = "Restart=always" ascii
        $service4 = "RestartSec=" ascii
        
    condition:
        (any of ($script*)) and
        (
            (2 of ($install*) and 2 of ($nezha*)) or
            (any of ($nezha*) and any of ($comment*)) or
            (2 of ($nezha*) and any of ($cloud*)) or
            (2 of ($service*) and any of ($nezha*))
        )
}

Rule 3: Nezha Network Communication Module

yara

rule Nezha_Network_Communication
{
    meta:
        description = "Detects Nezha C2 communication components"
        author = "SOC Threat Intelligence"
        severity = "critical"
        
    strings:
        // WebSocket communication
        $ws1 = "gorilla/websocket" ascii
        $ws2 = "websocket.Upgrader" ascii
        $ws3 = "websocket.Dial" ascii
        $ws4 = "Sec-WebSocket-Key" ascii
        
        // Protocol strings
        $proto1 = "agent_hello" ascii
        $proto2 = "server_hello" ascii
        $proto3 = "ping_pong" ascii
        $proto4 = "command_request" ascii
        $proto5 = "command_response" ascii
        
        // JSON structures
        $json1 = "\"agent_id\":" ascii
        $json2 = "\"secret\":" ascii
        $json3 = "\"timestamp\":" ascii
        $json4 = "\"command\":" ascii
        $json5 = "\"result\":" ascii
        
        // Alibaba Cloud endpoints
        $cloud1 = ".aliyuncs.com" ascii
        $cloud2 = "oss-ap-northeast" ascii
        $cloud3 = "47.74." ascii
        $cloud4 = "47.245." ascii
        $cloud5 = "161.117." ascii
        
        // Chinese error messages
        $error1 = "连接失败" wide // Connection failed
        $error2 = "认证失败" wide // Authentication failed
        $error3 = "超时" wide // Timeout
        
    condition:
        (
            (2 of ($ws*) and 2 of ($proto*)) or
            (3 of ($json*) and any of ($cloud*)) or
            (any of ($proto*) and any of ($cloud*) and any of ($error*))
        )
}

Rule 4: Nezha Persistence Mechanisms

yara

rule Nezha_Persistence
{
    meta:
        description = "Detects Nezha persistence techniques"
        author = "SOC Threat Intelligence"
        severity = "high"
        
    strings:
        // Systemd service
        $systemd1 = "[Unit]" ascii
        $systemd2 = "Description=Nezha" ascii nocase
        $systemd3 = "[Service]" ascii
        $systemd4 = "Type=simple" ascii
        $systemd5 = "ExecStart=/usr/local/bin/nezha-agent" ascii
        $systemd6 = "Restart=always" ascii
        $systemd7 = "RestartSec=5" ascii
        
        // Cron job patterns
        $cron1 = "*/5 * * * *" ascii
        $cron2 = "nezha-agent" ascii
        $cron3 = "/tmp/.nezha" ascii
        
        // Init script
        $init1 = "#!/bin/sh" ascii
        $init2 = "# chkconfig:" ascii
        $init3 = "start-stop-daemon" ascii
        
        // Binary locations
        $path1 = "/usr/local/bin/nezha" ascii
        $path2 = "/opt/nezha/agent" ascii
        $path3 = "/var/lib/nezha" ascii
        $path4 = "$HOME/.nezha" ascii
        
        // Chinese descriptions
        $desc1 = "监控代理" wide // Monitoring agent
        $desc2 = "守护进程" wide // Daemon process
        $desc3 = "自动启动" wide // Auto start
        
    condition:
        (
            (4 of ($systemd*)) or
            (2 of ($cron*) and any of ($path*)) or
            (2 of ($init*) and any of ($path*)) or
            (2 of ($path*) and any of ($desc*))
        )
}

Rule 5: Nezha Anti-Analysis and Obfuscation

yara

rule Nezha_Anti_Analysis
{
    meta:
        description = "Detects anti-analysis techniques in Nezha malware"
        author = "SOC Threat Intelligence"
        severity = "medium"
        
    strings:
        // VM/Sandbox detection
        $vm1 = "/proc/self/cgroup" ascii
        $vm2 = "docker" ascii
        $vm3 = "lxc" ascii
        $vm4 = "/sys/class/dmi" ascii
        $vm5 = "vmware" nocase ascii
        $vm6 = "virtualbox" nocase ascii
        
        // Debugger detection
        $debug1 = "ptrace" ascii
        $debug2 = "TracerPid" ascii
        $debug3 = "/proc/self/status" ascii
        
        // Sleep/timing checks
        $timing1 = "time.Sleep" ascii
        $timing2 = "time.Now" ascii
        $timing3 = "time.Since" ascii
        
        // Process checks
        $proc1 = "ps aux" ascii
        $proc2 = "/proc/" ascii
        $proc3 = "wireshark" ascii
        $proc4 = "tcpdump" ascii
        $proc5 = "strace" ascii
        
        // String obfuscation
        $obf1 = "base64.StdEncoding.DecodeString" ascii
        $obf2 = "hex.DecodeString" ascii
        $obf3 = "strings.Replace" ascii
        
        // Environment checks
        $env1 = "os.Getenv" ascii
        $env2 = "HOSTNAME" ascii
        $env3 = "USER" ascii
        
    condition:
        (
            (2 of ($vm*) and any of ($debug*)) or
            (2 of ($timing*) and 2 of ($proc*)) or
            (2 of ($obf*) and any of ($env*))
        )
}

Rule 6: Nezha Credential Harvesting Module

yara

rule Nezha_Credential_Theft
{
    meta:
        description = "Detects credential harvesting components"
        author = "SOC Threat Intelligence"
        severity = "critical"
        
    strings:
        // SSH key theft
        $ssh1 = ".ssh/id_rsa" ascii
        $ssh2 = ".ssh/authorized_keys" ascii
        $ssh3 = "known_hosts" ascii
        
        // Password files
        $pass1 = "/etc/shadow" ascii
        $pass2 = "/etc/passwd" ascii
        $pass3 = ".mysql_history" ascii
        $pass4 = ".bash_history" ascii
        
        // Browser credential locations
        $browser1 = "Login Data" ascii
        $browser2 = "Cookies" ascii
        $browser3 = ".mozilla/firefox" ascii
        $browser4 = "Google/Chrome" ascii
        
        // Config files with credentials
        $config1 = "database.yml" ascii
        $config2 = ".env" ascii
        $config3 = "config.json" ascii
        $config4 = "credentials" ascii
        
        // Regex patterns for credentials
        $regex1 = "password\\s*[:=]" nocase ascii
        $regex2 = "api[_-]?key" nocase ascii
        $regex3 = "secret[_-]?key" nocase ascii
        
        // Chinese strings
        $cn1 = "密码" wide // Password
        $cn2 = "凭据" wide // Credentials
        $cn3 = "密钥" wide // Secret key
        
    condition:
        (
            (2 of ($ssh*)) or
            (2 of ($pass*)) or
            (2 of ($browser*)) or
            (2 of ($config*) and any of ($regex*)) or
            (any of ($cn*) and 2 of them)
        )
}

Sigma Rules

Sigma Rule 1: Nezha Network Communication to Alibaba Cloud

yaml

title: Nezha Malware Communication to Alibaba Cloud Japan Infrastructure
id: a7c9e3f1-4b8d-4f2a-9e5c-7d6b8a2f9e3c
status: experimental
description: Detects network connections to Alibaba Cloud infrastructure in Japan associated with Nezha C2 servers
author: SOC Threat Intelligence Team
date: 2024/12/25
modified: 2024/12/25
tags:
    - attack.command_and_control
    - attack.t1071.001
    - attack.t1573
logsource:
    category: firewall
    product: any
detection:
    selection_alibaba_ip:
        destination.ip|startswith:
            - '47.74.'
            - '47.245.'
            - '161.117.'
            - '47.91.'
            - '47.243.'
    selection_alibaba_domain:
        destination.domain|contains:
            - '.aliyuncs.com'
            - '.alibabacloud.com'
            - 'oss-ap-northeast-1'
            - 'ecs.ap-northeast-1'
    selection_websocket:
        destination.port: 
            - 443
            - 8080
            - 8443
            - 5555
        protocol: 'tcp'
    selection_suspicious_pattern:
        destination.url|contains:
            - '/api/v1/ws/agent'
            - '/ws/agent'
            - '/agent/connect'
            - '/nezha'
    condition: (selection_alibaba_ip or selection_alibaba_domain) and selection_websocket or selection_suspicious_pattern
fields:
    - source.ip
    - destination.ip
    - destination.domain
    - destination.port
    - destination.url
    - bytes.sent
    - bytes.received
    - timestamp
falsepositives:
    - Legitimate use of Alibaba Cloud services
    - Organizations with business operations in Japan using Alibaba infrastructure
level: high

Sigma Rule 2: Nezha Installation and Persistence

yaml

title: Nezha Malware Installation and Persistence Mechanism
id: b8d4f2e7-5c9a-4e3b-8f6d-9a1c7b3e5f4a
status: experimental
description: Detects installation activities and persistence mechanisms associated with Nezha malware
author: SOC Threat Intelligence Team
date: 2024/12/25
tags:
    - attack.persistence
    - attack.t1543.002
    - attack.t1053.003
    - attack.execution
    - attack.t1059.004
logsource:
    category: process_creation
    product: linux
detection:
    selection_download:
        CommandLine|contains:
            - 'wget'
            - 'curl -fsSL'
            - 'curl -sL'
        CommandLine|contains:
            - 'nezha'
            - '.aliyuncs.com'
            - 'oss-ap-northeast'
    selection_installation:
        CommandLine|contains:
            - 'chmod +x'
            - 'mv'
            - 'cp'
        CommandLine|contains:
            - 'nezha-agent'
            - '/usr/local/bin/nezha'
            - '/opt/nezha'
            - '/tmp/.nezha'
    selection_persistence_systemd:
        CommandLine|contains:
            - 'systemctl enable'
            - 'systemctl start'
            - 'systemctl daemon-reload'
        CommandLine|contains:
            - 'nezha'
    selection_persistence_cron:
        CommandLine|contains:
            - 'crontab -e'
            - 'echo'
        CommandLine|contains:
            - 'nezha-agent'
            - '*/5 * * * *'
    selection_service_creation:
        Image|endswith:
            - '/systemctl'
            - '/service'
        CommandLine|contains: 'nezha.service'
    timeframe: 5m
    condition: 1 of selection_*
fields:
    - user.name
    - process.command_line
    - process.parent.name
    - process.working_directory
    - host.name
falsepositives:
    - Legitimate system monitoring agent installations
    - Authorized deployment of Nezha monitoring software
level: high

Sigma Rule 3: Nezha Suspicious Script Execution

yaml

title: Nezha Installation Script with Chinese Language Elements
id: c9e5f3a2-6d8b-4f7e-9a3c-8b1d7f4e2a9b
status: experimental
description: Detects execution of scripts containing Chinese language elements associated with Nezha malware installation
author: SOC Threat Intelligence Team
date: 2024/12/25
tags:
    - attack.execution
    - attack.t1059.004
    - attack.defense_evasion
    - attack.t1027
logsource:
    category: process_creation
    product: linux
detection:
    selection_shell:
        Image|endswith:
            - '/bash'
            - '/sh'
            - '/dash'
    selection_script_location:
        CommandLine|contains:
            - '/tmp/'
            - '/var/tmp/'
            - '/dev/shm/'
    selection_chinese_comments:
        CommandLine|contains:
            - '安装'  # Install
            - '配置'  # Configuration
            - '启动'  # Start
            - '哪吒'  # Nezha
            - '守护'  # Daemon
    selection_nezha_specific:
        CommandLine|contains:
            - 'nezha-agent'
            - 'nezha.service'
            - 'NEZHA_'
    selection_download_execute:
        CommandLine|contains:
            - 'wget'
            - 'curl'
        CommandLine|contains:
            - '| bash'
            - '| sh'
    condition: selection_shell and (selection_script_location or selection_chinese_comments or (selection_nezha_specific and selection_download_execute))
fields:
    - process.command_line
    - process.parent.command_line
    - user.name
    - process.working_directory
falsepositives:
    - Legitimate scripts with Chinese documentation
    - System administrators in Chinese-speaking regions
level: high

Sigma Rule 4: Nezha WebSocket Connection Pattern

yaml

title: Nezha WebSocket C2 Communication Pattern
id: d7f4e8a3-7c9b-4e2d-9f5a-8c6d7b3e4f2a
status: experimental
description: Detects WebSocket connections consistent with Nezha C2 communication patterns
author: SOC Threat Intelligence Team
date: 2024/12/25
tags:
    - attack.command_and_control
    - attack.t1071.001
    - attack.t1573.002
logsource:
    category: proxy
    product: any
detection:
    selection_websocket:
        http.request.method: 'GET'
        http.request.headers|contains:
            - 'Upgrade: websocket'
            - 'Connection: Upgrade'
    selection_nezha_pattern:
        url.path|contains:
            - '/api/v1/ws/agent'
            - '/ws/agent'
            - '/agent/ws'
    selection_user_agent:
        http.user_agent|contains:
            - 'nezha-agent'
            - 'Go-http-client'
            - 'websocket'
    selection_headers:
        http.request.headers|contains:
            - 'X-Nezha-Token'
            - 'X-Agent-Secret'
            - 'X-Agent-ID'
    selection_destination:
        destination.domain|contains:
            - 'aliyuncs.com'
            - 'alibabacloud.com'
        destination.geo.country: 'JP'
    condition: selection_websocket and (selection_nezha_pattern or selection_headers or (selection_user_agent and selection_destination))
fields:
    - source.ip
    - destination.ip
    - destination.domain
    - url.full
    - http.user_agent
    - http.request.headers
falsepositives:
    - Legitimate WebSocket applications
    - Monitoring and management tools
level: high

Sigma Rule 5: Nezha Credential Harvesting Activity

yaml

title: Nezha Credential and Configuration File Access
id: e8f5a4b2-8d9c-4f3e-9b6a-7c5d8e4f3a2b
status: experimental
description: Detects file access patterns consistent with Nezha credential harvesting operations
author: SOC Threat Intelligence Team
date: 2024/12/25
tags:
    - attack.credential_access
    - attack.t1552.001
    - attack.t1552.004
    - attack.collection
    - attack.t1005
logsource:
    category: file_access
    product: linux
detection:
    selection_ssh_keys:
        file.path|contains:
            - '/.ssh/id_rsa'
            - '/.ssh/id_dsa'
            - '/.ssh/id_ecdsa'
            - '/.ssh/authorized_keys'
            - '/.ssh/known_hosts'
    selection_shadow:
        file.path:
            - '/etc/shadow'
            - '/etc/gshadow'
    selection_history:
        file.path|endswith:
            - '.bash_history'
            - '.zsh_history'
            - '.mysql_history'
            - '.psql_history'
    selection_config:
        file.path|contains:
            - 'database.yml'
            - 'credentials'
            - '.env'
            - 'config.json'
        file.path|contains:
            - 'password'
            - 'secret'
            - 'api_key'
    selection_process:
        process.name|contains:
            - 'nezha'
            - 'agent'
        process.executable|contains:
            - '/tmp/'
            - '/var/tmp/'
            - '.nezha'
    timeframe: 10m
    condition: 1 of selection_ssh_keys or selection_shadow or (2 of selection_history or selection_config) and selection_process
fields:
    - file.path
    - process.name
    - process.command_line
    - user.name
    - host.name
falsepositives:
    - Legitimate system administration activities
    - Backup operations
    - Configuration management tools
level: high

Sigma Rule 6: Nezha Process Injection and Memory Manipulation

yaml

title: Nezha Process Injection and Memory Manipulation
id: f9a6b5c3-7e8d-4f2a-9c5b-8d7e6f3a4b2c
status: experimental
description: Detects process injection techniques used by Nezha malware
author: SOC Threat Intelligence Team
date: 2024/12/25
tags:
    - attack.privilege_escalation
    - attack.t1055
    - attack.defense_evasion
    - attack.t1055.001
logsource:
    category: process_creation
    product: linux
detection:
    selection_ptrace:
        CommandLine|contains:
            - 'ptrace'
            - 'PTRACE_ATTACH'
            - 'PTRACE_POKETEXT'
    selection_proc_mem:
        file.path|contains:
            - '/proc/'
            - '/mem'
    selection_ld_preload:
        CommandLine|contains:
            - 'LD_PRELOAD'
            - 'LD_LIBRARY_PATH'
    selection_suspicious_parent:
        process.parent.name|contains:
            - 'nezha'
            - 'agent'
        process.parent.executable|contains:
            - '/tmp/'
            - '/var/tmp/'
    selection_memory_access:
        syscall:
            - 'ptrace'
            - 'process_vm_readv'
            - 'process_vm_writev'
    condition: (selection_ptrace or selection_proc_mem or selection_ld_preload) and selection_suspicious_parent or selection_memory_access
fields:
    - process.name
    - process.parent.name
    - process.command_line
    - syscall
    - user.name
falsepositives:
    - Debuggers and development tools
    - System monitoring software
level: medium
```

## Snort/Suricata Rules

### Rule 1: Nezha WebSocket C2 Communication
```
alert tcp $HOME_NET any -> $EXTERNAL_NET [443,8080,8443,5555] (
    msg:"MALWARE Nezha WebSocket C2 Communication";
    flow:established,to_server;
    content:"GET"; http_method;
    content:"Upgrade|3a| websocket"; http_header;
    content:"/api/v1/ws/agent"; http_uri;
    content:"User-Agent|3a|"; http_header;
    pcre:"/User-Agent\x3a\s+(nezha-agent|Go-http-client)/i";
    threshold:type limit, track by_src, count 1, seconds 300;
    classtype:trojan-activity;
    sid:6000001;
    rev:1;
    metadata:
        malware_family nezha,
        target multi_platform,
        severity critical;
)
```

### Rule 2: Nezha Heartbeat Pattern
```
alert tcp $HOME_NET any -> $EXTERNAL_NET any (
    msg:"MALWARE Nezha Heartbeat Communication Pattern";
    flow:established,to_server;
    content:"|00 00 00|"; depth:3;
    content:"heartbeat"; distance:0;
    content:"agent_id"; distance:0;
    content:"timestamp"; distance:0;
    dsize:<512;
    threshold:type both, track by_src, count 3, seconds 300;
    classtype:trojan-activity;
    sid:6000002;
    rev:1;
    metadata:
        malware_family nezha,
        c2_pattern heartbeat;
)
```

### Rule 3: Nezha to Alibaba Cloud Infrastructure
```
alert tcp $HOME_NET any -> [47.74.0.0/16,47.245.0.0/16,161.117.0.0/16] 443 (
    msg:"MALWARE Nezha Connection to Alibaba Cloud Japan C2";
    flow:established,to_server;
    ssl_state:client_hello;
    content:"|16 03|"; depth:2;
    threshold:type threshold, track by_src, count 5, seconds 60;
    classtype:trojan-activity;
    sid:6000003;
    rev:1;
    metadata:
        malware_family nezha,
        c2_location alibaba_cloud_japan,
        severity high;
)
```

### Rule 4: Nezha Installation Script Download
```
alert http $EXTERNAL_NET any -> $HOME_NET any (
    msg:"MALWARE Nezha Installation Script Download";
    flow:established,to_client;
    file_data;
    content:"#!/bin/"; depth:8;
    content:"nezha-agent"; distance:0;
    content:"systemctl"; distance:0;
    content:"aliyuncs.com"; distance:0;
    classtype:trojan-activity;
    sid:6000004;
    rev:1;
    metadata:
        malware_family nezha,
        delivery_method script;
)
```

### Rule 5: Nezha DNS Tunneling
```
alert dns $HOME_NET any -> any 53 (
    msg:"MALWARE Nezha Potential DNS Tunneling";
    content:"|01 00 00 01|";
    content:"|00 00 10 00 01|";
    pcre:"/[a-z0-9]{32,}/i";
    byte_extract:1,12,query_len;
    byte_test:1,>,50,12;
    threshold:type both, track by_src, count 10, seconds 60;
    classtype:policy-violation;
    sid:6000005;
    rev:1;
    metadata:
        malware_family nezha,
        exfiltration_method dns_tunnel;
)
```

### Rule 6: Nezha Command Execution Response
```
alert tcp $HOME_NET any -> $EXTERNAL_NET any (
    msg:"MALWARE Nezha Command Execution Response";
    flow:established,to_server;
    content:"command_response"; offset:0; depth:100;
    content:"\"status\""; distance:0;
    content:"\"output\""; distance:0;
    content:"\"error\""; distance:0;
    dsize:>512;
    classtype:trojan-activity;
    sid:6000006;
    rev:1;
    metadata:
        malware_family nezha,
        activity command_execution;
)
```

### Rule 7: Nezha Agent Registration
```
alert tcp $HOME_NET any -> $EXTERNAL_NET [443,8080] (
    msg:"MALWARE Nezha Agent Registration Attempt";
    flow:established,to_server;
    content:"POST"; http_method;
    content:"agent_hello"; http_client_body;
    content:"secret"; http_client_body;
    content:"version"; http_client_body;
    content:"hostname"; http_client_body;
    classtype:trojan-activity;
    sid:6000007;
    rev:1;
    metadata:
        malware_family nezha,
        activity agent_registration;
)
```

### Rule 8: Nezha Encrypted Data Exfiltration
```
alert tcp $HOME_NET any -> $EXTERNAL_NET 443 (
    msg:"MALWARE Nezha Large Encrypted Data Exfiltration";
    flow:established,to_server;
    dsize:>10240;
    content:!"Host|3a| www.google.com"; http_header;
    content:!"Host|3a| www.microsoft.com"; http_header;
    byte_test:4,>,1048576,0,relative;
    threshold:type threshold, track by_src, count 5, seconds 300;
    classtype:policy-violation;
    sid:6000008;
    rev:1;
    metadata:
        malware_family nezha,
        activity data_exfiltration;
)

Splunk Detection Queries

Query 1: Nezha Alibaba Cloud C2 Communication

spl

index=firewall OR index=proxy
(dest_ip="47.74.*" OR dest_ip="47.245.*" OR dest_ip="161.117.*"
OR dest_domain="*.aliyuncs.com" OR dest_domain="*.alibabacloud.com"
OR dest_domain="*oss-ap-northeast-1*")
dest_port IN (443, 8080, 8443, 5555)
| eval is_japan_cloud=if(match(dest_domain, "ap-northeast-1") OR match(dest_ip, "^(47\.74\.|47\.245\.|161\.117\.)"), 1, 0)
| eval suspicious_path=if(match(url, "(/ws/agent|/api/v1/ws|/nezha)"), 1, 0)
| where is_japan_cloud=1 OR suspicious_path=1
| stats count, 
        dc(dest_ip) as unique_destinations,
        sum(bytes_out) as total_bytes_sent,
        values(dest_domain) as domains,
        values(url) as urls,
        values(user_agent) as user_agents,
        earliest(_time) as first_seen,
        latest(_time) as last_seen
  by src_ip, dest_port
| eval duration_hours=round((last_seen-first_seen)/3600, 2)
| eval data_sent_mb=round(total_bytes_sent/1048576, 2)
| where count > 5 OR data_sent_mb > 10
| eval severity=case(
    count > 50 AND data_sent_mb > 100, "critical",
    count > 20 OR data_sent_mb > 50, "high",
    "medium")
| eval threat_family="Nezha"
| eval c2_location="Alibaba Cloud Japan"
| table first_seen, src_ip, dest_port, domains, count, unique_destinations, 
        data_sent_mb, duration_hours, severity, threat_family
| sort -severity, -count

Query 2: Nezha Installation Detection

spl

index=linux sourcetype=linux_audit OR sourcetype=bash_history OR sourcetype=syslog
(
    (CommandLine="*wget*" OR CommandLine="*curl*") 
    (CommandLine="*nezha*" OR CommandLine="*aliyuncs.com*" OR CommandLine="*oss-ap-northeast*")
)
OR (CommandLine="*chmod +x*" CommandLine="*nezha*")
OR (CommandLine="*systemctl*" CommandLine="*nezha*")
OR (CommandLine="*crontab*" CommandLine="*nezha*")
| rex field=CommandLine "(?<download_url>https?://[^\s]+)"
| eval action=case(
    match(CommandLine, "wget|curl"), "Download",
    match(CommandLine, "chmod"), "Execute_Permission",
    match(CommandLine, "systemctl enable|systemctl start"), "Persistence_Systemd",
    match(CommandLine, "crontab"), "Persistence_Cron",
    true(), "Other")
| transaction host maxspan=10m
| where mvcount(action) >= 2
| stats count,
        values(CommandLine) as commands,
        values(action) as actions,
        values(download_url) as download_urls,
        values(User) as users,
        min(_time) as start_time,
        max(_time) as end_time
  by host
| eval installation_duration_min=round((end_time-start_time)/60, 2)
| eval threat_indicators=mvappend(
    if(match(commands, "aliyuncs\.com"), "Alibaba Cloud Source", null()),
    if(match(commands, "systemctl.*nezha"), "Systemd Persistence", null()),
    if(match(commands, "crontab.*nezha"), "Cron Persistence", null()),
    if(installation_duration_min < 5, "Rapid Installation", null()))
| table start_time, host, users, actions, installation_duration_min, 
        download_urls, threat_indicators
| eval severity="high"
| eval malware_family="Nezha"
| sort -start_time

Query 3: Nezha WebSocket Communication Pattern

spl

index=proxy OR index=web
http_method="GET"
(uri_path="*/ws/agent*" OR uri_path="*/api/v1/ws*" OR uri_path="*nezha*")
http_header="*Upgrade: websocket*"
| eval is_alibaba=if(match(dest_domain, "(aliyuncs\.com|alibabacloud\.com)"), 1, 0)
| eval is_japan=if(match(dest_domain, "ap-northeast"), 1, 0)
| eval suspicious_ua=if(match(user_agent, "(nezha-agent|Go-http-client)"), 1, 0)
| eval has_custom_headers=if(match(http_header, "(X-Nezha-Token|X-Agent-Secret|X-Agent-ID)"), 1, 0)
| where is_alibaba=1 OR is_japan=1 OR suspicious_ua=1 OR has_custom_headers=1
| stats count as connection_count,
        dc(src_ip) as unique_sources,
        values(dest_domain) as c2_domains,
        values(user_agent) as user_agents,
        values(uri_path) as paths,
        sum(bytes_in) as total_received,
        sum(bytes_out) as total_sent,
        earliest(_time) as first_connection,
        latest(_time) as last_connection
  by src_ip, dest_ip
| eval session_duration_hours=round((last_connection-first_connection)/3600, 2)
| eval total_data_mb=round((total_received+total_sent)/1048576, 2)
| eval websocket_score=0
| eval websocket_score=websocket_score + if(is_alibaba=1, 30, 0)
| eval websocket_score=websocket_score + if(is_japan=1, 20, 0)
| eval websocket_score=websocket_score + if(suspicious_ua=1, 25, 0)
| eval websocket_score=websocket_score + if(has_custom_headers=1, 25, 0)
| where websocket_score >= 40
| eval severity=case(
    websocket_score >= 70, "critical",
    websocket_score >= 50, "high",
    "medium")
| table first_connection, src_ip, dest_ip, c2_domains, connection_count, 
        session_duration_hours, total_data_mb, websocket_score, severity
| eval threat_type="Nezha WebSocket C2"
| sort -websocket_score

Query 4: Nezha Credential Harvesting Activity

spl

index=linux sourcetype=linux_audit type=PATH
(name="*/.ssh/id_rsa*" OR name="*/.ssh/authorized_keys*" 
OR name="*/etc/shadow*" OR name="*/.bash_history*" 
OR name="*/.mysql_history*" OR name="*/database.yml*"
OR name="*/.env*" OR name="*/credentials*")
| rex field=exe "(?<process_path>\/[^\s]+)"
| eval suspicious_location=if(match(process_path, "(\/tmp\/|\/var\/tmp\/|\.nezha)"), 1, 0)
| eval file_category=case(
    match(name, "\.ssh"), "SSH_Keys",
    match(name, "shadow"), "System_Passwords",
    match(name, "history"), "Command_History",
    match(name, "(database|\.env|credentials)"), "Config_Credentials",
    true(), "Other")
| stats count as access_count,
        dc(name) as unique_files,
        values(name) as accessed_files,
        values(file_category) as file_categories,
        values(exe) as processes,
        values(comm) as commands,
        earliest(_time) as first_access,
        latest(_time) as last_access
  by host, uid, auid
| eval access_duration_min=round((last_access-first_access)/60, 2)
| where unique_files >= 3 OR suspicious_location=1
| eval risk_score=0
| eval risk_score=risk_score + (unique_files * 10)
| eval risk_score=risk_score + if(suspicious_location=1, 30, 0)
| eval risk_score=risk_score + if(mvcount(file_categories) >= 2, 20, 0)
| where risk_score >= 40
| join host [
    search index=firewall dest_domain="*aliyuncs.com*" OR dest_domain="*alibabacloud*"
    | stats count by src_ip
    | rename src_ip as host
]
| eval severity=case(
    risk_score >= 70, "critical",
    risk_score >= 50, "high",
    "medium")
| table first_access, host, uid, commands, file_categories, unique_files, 
        access_duration_min, risk_score, severity
| eval attack_type="Credential Harvesting"
| eval suspected_malware="Nezha"
| sort -risk_score

Query 5: Nezha Persistence Mechanism Detection

spl

index=linux (sourcetype=linux_audit OR sourcetype=syslog)
(
    (type=SERVICE_START name="*nezha*")
    OR (CommandLine="*systemctl enable*" CommandLine="*nezha*")
    OR (CommandLine="*systemctl daemon-reload*" file="*nezha.service*")
    OR (type=CRON CommandLine="*nezha*")
    OR (file="/etc/systemd/system/*nezha*.service" OR file="/lib/systemd/system/*nezha*.service")
)
| eval persistence_type=case(
    match(_raw, "systemctl enable"), "Systemd_Enable",
    match(_raw, "SERVICE_START"), "Service_Started",
    match(_raw, "daemon-reload"), "Service_Reload",
    match(_raw, "CRON"), "Cron_Job",
    match(file, "\.service$"), "Service_File_Created",
    true(), "Other")
| stats count,
        values(persistence_type) as persistence_methods,
        values(CommandLine) as commands,
        values(file) as files,
        values(exe) as executables,
        min(_time) as first_seen,
        max(_time) as last_seen
  by host, User
| eval persistence_count=mvcount(persistence_methods)
| where persistence_count >= 2 OR match(commands, "nezha")
| eval time_range_hours=round((last_seen-first_seen)/3600, 2)
| join type=left host [
    search index=linux sourcetype=bash_history 
    (CommandLine="*wget*" OR CommandLine="*curl*") 
    (CommandLine="*aliyuncs.com*" OR CommandLine="*nezha*")
    | stats earliest(_time) as download_time by host
]
| eval installation_to_persistence_min=if(isnotnull(download_time), 
    round((first_seen-download_time)/60, 2), null())
| eval rapid_persistence=if(installation_to_persistence_min < 10 AND installation_to_persistence_min > 0, 1, 0)
| eval severity=case(
    rapid_persistence=1 AND persistence_count >= 2, "critical",
    persistence_count >= 2, "high",
    "medium")
| table first_seen, host, User, persistence_methods, commands, files, 
        persistence_count, installation_to_persistence_min, severity
| eval threat_family="Nezha"
| eval alert_type="Persistence Mechanism"
| sort -severity, -persistence_count

Query 6: Nezha Lateral Movement Detection

spl

(index=linux sourcetype=linux_secure OR index=auth)
(
    (action=success user=* src_ip=* dest_ip=*)
    OR (EventCode IN (4624, 4625) Logon_Type=3)
    OR (sshd session opened OR sshd Accepted publickey)
)
| eval auth_method=case(
    match(_raw, "publickey"), "SSH_Key",
    match(_raw, "password"), "Password",
    match(_raw, "keyboard-interactive"), "Interactive",
    true(), "Unknown")
| stats count as auth_attempts,
        dc(dest_ip) as unique_destinations,
        dc(user) as unique_users,
        values(dest_ip) as target_hosts,
        values(user) as users,
        values(auth_method) as methods,
        earliest(_time) as first_attempt,
        latest(_time) as last_attempt
  by src_ip
| eval timespan_minutes=round((last_attempt-first_attempt)/60, 2)
| where unique_destinations >= 3 OR (auth_attempts >= 10 AND timespan_minutes < 30)
| join src_ip [
    search index=firewall dest_domain="*aliyuncs.com*" OR dest_domain="*alibabacloud*"
    | stats count by src_ip
]
| join type=left src_ip [
    search index=linux sourcetype=bash_history CommandLine="*nezha*"
    | stats count as nezha_commands by src_ip
]
| eval lateral_movement_score=0
| eval lateral_movement_score=lateral_movement_score + (unique_destinations * 15)
| eval lateral_movement_score=lateral_movement_score + if(timespan_minutes < 30, 20, 0)
| eval lateral_movement_score=lateral_movement_score + if(match(methods, "SSH_Key"), 25, 0)
| eval lateral_movement_score=lateral_movement_score + if(nezha_commands > 0, 40, 0)
| where lateral_movement_score >= 50
| eval severity=case(
    lateral_movement_score >= 80, "critical",
    lateral_movement_score >= 60, "high",
    "medium")
| table first_attempt, src_ip, unique_destinations, target_hosts, users, 
        auth_attempts, timespan_minutes, methods, lateral_movement_score, severity
| eval attack_stage="Lateral Movement"
| eval suspected_threat="Nezha"
| sort -lateral_movement_score

Microsoft Sentinel KQL Queries


KQL Query 1: Nezha Alibaba Cloud C2 Communication

kql

// Nezha C2 Communication to Alibaba Cloud Japan Infrastructure
let AlibabaIPRanges = dynamic([
    "47.74.0.0/16", "47.245.0.0/16", "161.117.0.0/16", 
    "47.91.0.0/16", "47.243.0.0/16"
]);
let AlibabaDomains = dynamic([
    "aliyuncs.com", "alibabacloud.com", "oss-ap-northeast-1"
]);
let SuspiciousPorts = dynamic([443, 8080, 8443, 5555]);
let TimeWindow = 24h;
CommonSecurityLog
| where TimeGenerated > ago(TimeWindow)
| where DeviceVendor in ("Palo Alto Networks", "Fortinet", "Check Point") or DeviceProduct == "Firewall"
| where DestinationPort in (SuspiciousPorts)
| where (ipv4_is_in_any_range(DestinationIP, AlibabaIPRanges) 
    or DestinationHostName has_any (AlibabaDomains))
| extend IsWebSocket = iff(RequestContext has "websocket" or RequestContext has "Upgrade:", true, false)
| extend SuspiciousPath = iff(RequestURL has_any ("/ws/agent", "/api/v1/ws", "/nezha"), true, false)
| summarize 
    ConnectionCount = count(),
    TotalBytesSent = sum(SentBytes),
    TotalBytesReceived = sum(ReceivedBytes),
    UniqueDestinations = dcount(DestinationIP),
    DestinationIPs = make_set(DestinationIP),
    DestinationDomains = make_set(DestinationHostName),
    URLs = make_set(RequestURL),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated),
    WebSocketConnections = countif(IsWebSocket),
    SuspiciousPathCount = countif(SuspiciousPath)
    by SourceIP, SourceHostName, DestinationPort
| extend 
    DurationHours = datetime_diff('hour', LastSeen, FirstSeen),
    TotalDataMB = (TotalBytesSent + TotalBytesReceived) / 1048576.0,
    C2Score = 0
| extend C2Score = C2Score + iff(ConnectionCount > 50, 30, 
    iff(ConnectionCount > 20, 20, iff(ConnectionCount > 10, 10, 0)))
| extend C2Score = C2Score + iff(TotalDataMB > 100, 25, 
    iff(TotalDataMB > 50, 15, iff(TotalDataMB > 10, 5, 0)))
| extend C2Score = C2Score + iff(WebSocketConnections > 0, 20, 0)
| extend C2Score = C2Score + iff(SuspiciousPathCount > 0, 25, 0)
| where C2Score >= 30
| extend 
    Severity = case(
        C2Score >= 70, "Critical",
        C2Score >= 50, "High",
        "Medium"),
    ThreatFamily = "Nezha",
    C2Location = "Alibaba Cloud Japan",
    ThreatType = "Command and Control"
| project 
    TimeGenerated = LastSeen,
    SourceIP,
    SourceHostName,
    DestinationIPs,
    DestinationDomains,
    URLs,
    ConnectionCount,
    TotalDataMB,
    DurationHours,
    WebSocketConnections,
    C2Score,
    Severity,
    ThreatFamily,
    C2Location
| sort by C2Score desc, ConnectionCount desc

KQL Query 2: Nezha Installation and Persistence

kql

// Nezha Installation Process and Persistence Detection
let TimeFrame = 1h;
let NezhaKeywords = dynamic(["nezha", "nezha-agent", "nezha.service"]);
let AlibabaKeywords = dynamic(["aliyuncs.com", "alibabacloud.com", "oss-ap-northeast"]);
let InstallCommands = 
    Syslog
    | where TimeGenerated > ago(TimeFrame)
    | where Facility == "authpriv" or Facility == "user"
    | where SyslogMessage has_any (NezhaKeywords) 
        or SyslogMessage has_any (AlibabaKeywords)
    | where SyslogMessage has_any ("wget", "curl", "chmod", "mv", "cp")
    | extend 
        CommandLine = extract(@"(?:sudo\s+)?(.+)", 1, SyslogMessage),
        IsDownload = iff(SyslogMessage has_any ("wget", "curl"), true, false),
        IsExecution = iff(SyslogMessage has "chmod +x", true, false),
        IsMovement = iff(SyslogMessage has_any ("mv", "cp"), true, false)
    | project TimeGenerated, Computer, ProcessName, CommandLine, IsDownload, IsExecution, IsMovement;
let PersistenceActions = 
    Syslog
    | where TimeGenerated > ago(TimeFrame)
    | where SyslogMessage has_any (NezhaKeywords)
    | where SyslogMessage has_any ("systemctl", "crontab", "service", "chkconfig")
    | extend 
        CommandLine = extract(@"(?:sudo\s+)?(.+)", 1, SyslogMessage),
        PersistenceType = case(
            SyslogMessage has "systemctl enable", "Systemd_Enable",
            SyslogMessage has "systemctl start", "Systemd_Start",
            SyslogMessage has "daemon-reload", "Service_Reload",
            SyslogMessage has "crontab", "Cron_Job",
            "Other")
    | project TimeGenerated, Computer, ProcessName, CommandLine, PersistenceType;
InstallCommands
| join kind=inner (PersistenceActions) on Computer
| summarize 
    InstallCommands = make_set(CommandLine),
    PersistenceTypes = make_set(PersistenceType),
    InstallStart = min(TimeGenerated),
    PersistenceEnd = max(TimeGenerated1),
    DownloadCount = countif(IsDownload),
    ExecutionCount = countif(IsExecution),
    MovementCount = countif(IsMovement)
    by Computer
| extend 
    InstallationDurationMinutes = datetime_diff('minute', PersistenceEnd, InstallStart),
    TotalActions = DownloadCount + ExecutionCount + MovementCount,
    RapidInstallation = iff(InstallationDurationMinutes < 10, true, false)
| where TotalActions >= 2
| extend 
    RiskScore = 0,
    RiskScore = RiskScore + iff(RapidInstallation, 30, 0),
    RiskScore = RiskScore + (TotalActions * 10),
    RiskScore = RiskScore + (array_length(PersistenceTypes) * 15)
| extend 
    Severity = case(
        RiskScore >= 70, "Critical",
        RiskScore >= 50, "High",
        "Medium"),
    ThreatFamily = "Nezha",
    AttackStage = "Installation + Persistence"
| project 
    InstallStart,
    Computer,
    InstallCommands,
    PersistenceTypes,
    InstallationDurationMinutes,
    TotalActions,
    RapidInstallation,
    RiskScore,
    Severity,
    ThreatFamily
| sort by RiskScore desc

KQL Query 3: Nezha WebSocket Communication Pattern

kql

// Nezha WebSocket C2 Communication Detection
let TimeWindow = 6h;
let WebSocketPaths = dynamic(["/ws/agent", "/api/v1/ws", "/agent/ws", "/nezha"]);
let NezhaUserAgents = dynamic(["nezha-agent", "Go-http-client", "websocket"]);
let NezhaHeaders = dynamic(["X-Nezha-Token", "X-Agent-Secret", "X-Agent-ID"]);
let AlibabaDomains = dynamic(["aliyuncs.com", "alibabacloud.com"]);
W3CIISLog
| where TimeGenerated > ago(TimeWindow)
| where csMethod == "GET"
| where csUriStem has_any (WebSocketPaths) 
    or csUserAgent has_any (NezhaUserAgents)
    or csReferer has_any (AlibabaDomains)
| extend 
    IsWebSocket = iff(csUriStem has "Upgrade" or csUserAgent has "websocket", true, false),
    HasNezhaPath = iff(csUriStem has_any (WebSocketPaths), true, false),
    HasNezhaUA = iff(csUserAgent has_any (NezhaUserAgents), true, false),
    HasAlibabaRef = iff(csReferer has_any (AlibabaDomains) or sIP has_any (AlibabaDomains), true, false)
| summarize 
    RequestCount = count(),
    UniqueURIs = dcount(csUriStem),
    URIs = make_set(csUriStem),
    UserAgents = make_set(csUserAgent),
    TotalBytesSent = sum(csbytes),
    TotalBytesReceived = sum(scbytes),
    FirstRequest = min(TimeGenerated),
    LastRequest = max(TimeGenerated),
    WebSocketCount = countif(IsWebSocket),
    NezhaPathCount = countif(HasNezhaPath),
    NezhaUACount = countif(HasNezhaUA),
    AlibabaCount = countif(HasAlibabaRef)
    by cIP, sIP, sComputerName
| extend 
    SessionDurationHours = datetime_diff('hour', LastRequest, FirstRequest),
    TotalDataMB = (TotalBytesSent + TotalBytesReceived) / 1048576.0,
    WebSocketScore = 0
| extend WebSocketScore = WebSocketScore + iff(WebSocketCount > 0, 25, 0)
| extend WebSocketScore = WebSocketScore + iff(NezhaPathCount > 0, 30, 0)
| extend WebSocketScore = WebSocketScore + iff(NezhaUACount > 0, 25, 0)
| extend WebSocketScore = WebSocketScore + iff(AlibabaCount > 0, 20, 0)
| where WebSocketScore >= 40
| extend 
    Severity = case(
        WebSocketScore >= 70, "Critical",
        WebSocketScore >= 50, "High",
        "Medium"),
    ThreatType = "Nezha WebSocket C2",
    ThreatFamily = "Nezha"
| project 
    FirstRequest,
    ClientIP = cIP,
    ServerIP = sIP,
    ServerName = sComputerName,
    RequestCount,
    URIs,
    UserAgents,
    SessionDurationHours,
    TotalDataMB,
    WebSocketScore,
    Severity,
    ThreatType
| sort by WebSocketScore desc

KQL Query 4: Nezha Credential Harvesting

kql

// Nezha Credential and Sensitive File Access
let TimeFrame = 12h;
let SensitiveFiles = dynamic([
    ".ssh/id_rsa", ".ssh/id_dsa", ".ssh/id_ecdsa", ".ssh/authorized_keys",
    "/etc/shadow", "/etc/gshadow", ".bash_history", ".mysql_history",
    "database.yml", ".env", "config.json", "credentials"
]);
let SuspiciousLocations = dynamic(["/tmp/", "/var/tmp/", ".nezha"]);
Syslog
| where TimeGenerated > ago(TimeFrame)
| where Facility == "authpriv" or SyslogMessage has_any ("open", "read", "cat", "cp")
| where SyslogMessage has_any (SensitiveFiles)
| extend 
    AccessedFile = extract(@"([\/\w\.\-]+(?:\.ssh|shadow|history|yml|env|json|credentials)[\/\w\.\-]*)", 1, SyslogMessage),
    ProcessPath = extract(@"(?:sudo\s+)?(\S+)", 1, ProcessName),
    IsSuspiciousLocation = iff(ProcessName has_any (SuspiciousLocations), true, false)
| extend 
    FileCategory = case(
        AccessedFile has ".ssh", "SSH_Keys",
        AccessedFile has "shadow", "System_Passwords",
        AccessedFile has "history", "Command_History",
        AccessedFile has_any ("database", ".env", "credentials", "config"), "Config_Credentials",
        "Other")
| summarize 
    AccessCount = count(),
    UniqueFiles = dcount(AccessedFile),
    AccessedFiles = make_set(AccessedFile),
    FileCategories = make_set(FileCategory),
    Processes = make_set(ProcessPath),
    FirstAccess = min(TimeGenerated),
    LastAccess = max(TimeGenerated),
    SuspiciousLocCount = countif(IsSuspiciousLocation)
    by Computer, ProcessName
| extend 
    AccessDurationMinutes = datetime_diff('minute', LastAccess, FirstAccess),
    MultiCategoryAccess = iff(array_length(FileCategories) >= 2, true, false)
| where UniqueFiles >= 3 or SuspiciousLocCount > 0
| join kind=leftouter (
    CommonSecurityLog
    | where TimeGenerated > ago(TimeFrame)
    | where DestinationHostName has_any ("aliyuncs.com", "alibabacloud.com")
    | distinct SourceIP
    | extend Computer = SourceIP
) on Computer
| extend HasC2Connection = iff(isnotnull(SourceIP), true, false)
| extend 
    RiskScore = 0,
    RiskScore = RiskScore + (UniqueFiles * 10),
    RiskScore = RiskScore + iff(SuspiciousLocCount > 0, 30, 0),
    RiskScore = RiskScore + iff(MultiCategoryAccess, 20, 0),
    RiskScore = RiskScore + iff(HasC2Connection, 40, 0)
| where RiskScore >= 40
| extend 
    Severity = case(
        RiskScore >= 80, "Critical",
        RiskScore >= 60, "High",
        "Medium"),
    AttackType = "Credential Harvesting",
    SuspectedMalware = "Nezha"
| project 
    FirstAccess,
    Computer,
    ProcessName,
    FileCategories,
    UniqueFiles,
    AccessedFiles,
    AccessDurationMinutes,
    HasC2Connection,
    RiskScore,
    Severity,
    SuspectedMalware
| sort by RiskScore desc

KQL Query 5: Nezha Lateral Movement

kql

// Nezha Lateral Movement Detection
let TimeFrame = 6h;
let NezhaIndicators = 
    Syslog
    | where TimeGenerated > ago(TimeFrame)
    | where SyslogMessage has "nezha"
    | distinct Computer
    | extend HasNezhaActivity = true;
SecurityEvent
| where TimeGenerated > ago(TimeFrame)
| where EventID in (4624, 4625, 4648, 4768, 4769)
| where LogonType in (3, 10)
| extend 
    SourceIP = iff(IpAddress == "-", "0.0.0.0", IpAddress),
    AuthResult = iff(EventID == 4625, "Failed", "Success")
| summarize 
    TotalAttempts = count(),
    SuccessCount = countif(AuthResult == "Success"),
    FailureCount = countif(AuthResult == "Failed"),
    UniqueDestinations = dcount(Computer),
    UniqueAccounts = dcount(TargetUserName),
    DestinationHosts = make_set(Computer),
    Accounts = make_set(TargetUserName),
    FirstAttempt = min(TimeGenerated),
    LastAttempt = max(TimeGenerated)
    by SourceIP, LogonType
| extend TimeSpanMinutes = datetime_diff('minute', LastAttempt, FirstAttempt)
| where UniqueDestinations >= 3 or (TotalAttempts >= 10 and TimeSpanMinutes < 30)
| join kind=leftouter (NezhaIndicators) on $left.SourceIP == $right.Computer
| join kind=leftouter (
    CommonSecurityLog
    | where TimeGenerated > ago(TimeFrame)
    | where DestinationHostName has_any ("aliyuncs.com", "alibabacloud.com")
    | distinct SourceIP
) on SourceIP
| extend 
    HasC2Connection = iff(isnotnull(SourceIP1), true, false),
    LateralMovementScore = 0
| extend LateralMovementScore = LateralMovementScore + (UniqueDestinations * 15)
| extend LateralMovementScore = LateralMovementScore + iff(TimeSpanMinutes < 30, 20, 0)
| extend LateralMovementScore = LateralMovementScore + iff(LogonType == 10, 10, 0)
| extend LateralMovementScore = LateralMovementScore + iff(HasNezhaActivity, 40, 0)
| extend LateralMovementScore = LateralMovementScore + iff(HasC2Connection, 35, 0)
| where LateralMovementScore >= 50
| extend 
    Severity = case(
        LateralMovementScore >= 90, "Critical",
        LateralMovementScore >= 70, "High",
        "Medium"),
    AttackStage = "Lateral Movement",
    SuspectedThreat = "Nezha"
| project 
    FirstAttempt,
    SourceIP,
    UniqueDestinations,
    DestinationHosts,
    Accounts,
    TotalAttempts,
    SuccessCount,
    FailureCount,
    TimeSpanMinutes,
    HasNezhaActivity,
    HasC2Connection,
    LateralMovementScore,
    Severity,
    SuspectedThreat
| sort by LateralMovementScore desc

KQL Query 6: Nezha Complete Attack Chain

kql

// Nezha Complete Attack Chain Analysis
let TimeWindow = 24h;
let NezhaKeywords = dynamic(["nezha", "nezha-agent"]);
let AlibabaIndicators = dynamic(["aliyuncs.com", "alibabacloud.com", "47.74.", "47.245.", "161.117."]);
// Stage 1: Initial Access and Installation
let Installation = 
    Syslog
    | where TimeGenerated > ago(TimeWindow)
    | where SyslogMessage has_any (NezhaKeywords) or SyslogMessage has_any (AlibabaIndicators)
    | where SyslogMessage has_any ("wget", "curl", "chmod")
    | summarize InstallTime = min(TimeGenerated) by Computer
    | extend Stage1_Installation = true;
// Stage 2: Persistence
let Persistence = 
    Syslog
    | where TimeGenerated > ago(TimeWindow)
    | where SyslogMessage has_any (NezhaKeywords)
    | where SyslogMessage has_any ("systemctl", "crontab", "service")
    | summarize PersistenceTime = min(TimeGenerated) by Computer
    | extend Stage2_Persistence = true;
// Stage 3: C2 Communication
let C2Communication = 
    CommonSecurityLog
    | where TimeGenerated > ago(TimeWindow)
    | where DestinationHostName has_any (AlibabaIndicators) 
        or ipv4_is_in_any_range(DestinationIP, dynamic(["47.74.0.0/16", "47.245.0.0/16", "161.117.0.0/16"]))
    | summarize 
        C2StartTime = min(TimeGenerated),
        C2Connections = count(),
        C2DataSent = sum(SentBytes)
        by SourceIP
    | extend 
        Stage3_C2 = true,
        Computer = SourceIP;
// Stage 4: Credential Access
let CredentialAccess = 
    Syslog
    | where TimeGenerated > ago(TimeWindow)
    | where SyslogMessage has_any (".ssh", "shadow", "history", "credentials")
    | summarize 
        CredAccessTime = min(TimeGenerated),
        SensitiveFileAccess = count()
        by Computer
    | extend Stage4_CredentialAccess = true;
// Stage 5: Lateral Movement
let LateralMovement = 
    SecurityEvent
    | where TimeGenerated > ago(TimeWindow)
    | where EventID in (4624, 4648)
    | where LogonType == 3
    | summarize 
        LateralMoveTime = min(TimeGenerated),
        UniqueTargets = dcount(Computer)
        by IpAddress
    | extend 
        Stage5_LateralMovement = true,
        Computer = IpAddress;
// Combine all stages
Installation
| join kind=fullouter (Persistence) on Computer
| join kind=fullouter (C2Communication) on Computer
| join kind=fullouter (CredentialAccess) on Computer
| join kind=fullouter (LateralMovement) on Computer
| extend Computer = coalesce(Computer, Computer1, Computer2, Computer3, Computer4)
| summarize arg_min(InstallTime, *) by Computer
| extend 
    StagesCompleted = 
        iff(Stage1_Installation, 1, 0) +
        iff(Stage2_Persistence, 1, 0) +
        iff(Stage3_C2, 1, 0) +
        iff(Stage4_CredentialAccess, 1, 0) +
        iff(Stage5_LateralMovement, 1, 0)
| extend 
    AttackTimeline = pack_array(
        iff(Stage1_Installation, strcat("Installation: ", InstallTime), ""),
        iff(Stage2_Persistence, strcat("Persistence: ", PersistenceTime), ""),
        iff(Stage3_C2, strcat("C2: ", C2StartTime), ""),
        iff(Stage4_CredentialAccess, strcat("Cred Access: ", CredAccessTime), ""),
        iff(Stage5_LateralMovement, strcat("Lateral Move: ", LateralMoveTime), "")
    )
| where StagesCompleted >= 2
| extend 
    TotalDurationHours = datetime_diff('hour', 
        max_of(PersistenceTime, C2StartTime, CredAccessTime, LateralMoveTime),
        InstallTime),
    Severity = case(
        StagesCompleted >= 4, "Critical",
        StagesCompleted >= 3, "High",
        "Medium"),
    ThreatFamily = "Nezha",
    CompromiseLevel = case(
        StagesCompleted >= 4, "Full Compromise",
        StagesCompleted == 3, "Significant Compromise",
        "Initial Compromise")
| project 
    Computer,
    FirstActivity = InstallTime,
    StagesCompleted,
    CompromiseLevel,
    TotalDurationHours,
    AttackTimeline,
    C2Connections,
    C2DataSentMB = C2DataSent / 1048576.0,
    SensitiveFileAccess,
    UniqueTargets,
    Severity,
    ThreatFamily
| sort by StagesCompleted desc, Severity desc

These detection rules provide comprehensive coverage across multiple security platforms and techniques to identify Nezha malware throughout its attack lifecycle from initial installation through C2 communication, persistence, credential theft, and lateral movement.


Aegiron

Backed by 11+ years in cybersecurity and incident response, we decode the latest threats shaping today’s digital battlefield. This blog cuts through the noise with clear insights on vulnerabilities, emerging exploits, and the cyber news defenders can’t afford to miss.