Rule packCONSTRUCTED

YARA triage samples: five heuristic rules for a web root, a script directory or a triage collection

Request-fed web shells in PHP and ASP.NET, PowerShell that decodes, executes and reaches the network in one file, ransom notes, and LSASS minidumps left on disk. Hunting rules that produce files to open, not verdicts.

version 1.0checked 2026-09-21any2 min read

T1505.003T1059.001T1027T1105T1486T1003.001

What these are for

YARA is usually shown matching a known malware family. These do something more useful for triage: they describe shapes that intrusions leave on disk, whatever the family. A web shell is request input reaching an execution function. A download cradle is decode, execute and network in one script. A ransom note has four kinds of vocabulary in a small file.

RuleFindsSweep it over
SA_Webshell_PHP_Eval_Of_Request_InputPHP passing $_POST and friends into eval, assert, system and similar, through up to three decodersWeb roots, upload directories
SA_Webshell_ASPX_Eval_Of_Request_ItemThe China Chopper shape in ASP and ASP.NETIIS directories, Exchange front-end paths
SA_PowerShell_Decode_And_Execute_DownloaderScripts with base64 decoding, an execution call and a network call togetherTemp, ProgramData, user profiles, scheduled task targets
SA_Ransom_Note_Text_HeuristicSmall text or HTML files with encryption, payment, contact and threat vocabularyFile shares, after the fact, to find the first note written
SA_Minidump_Of_LSASS_On_DiskMDMP files whose module list includes lsass.exe and lsasrv.dllTemp, Public, ProgramData, the operator's staging directory

Running them

yara -r sa_triage_samples.yar /var/www/
yara -r -s sa_triage_samples.yar /cases/0142/collection/    # -s prints the matching strings

Scan a copy or a mounted image. Scanning a live web root updates access times on file systems that record them, and those times may be evidence.

How they were tested, and how they were not

The file compiles under YARA 4.5. It was run against fourteen constructed samples: eight that should match (three PHP shells, two ASP shells, a PowerShell cradle, a ransom note and a synthetic minidump header with LSASS module names) and six that should not (ordinary PHP, ASP.NET and PowerShell, a finance memo, a notepad dump). All fourteen behaved as intended. It was then swept across this site's own source tree, about four hundred files, where the only hit was the rule file matching its own strings.

They have not been run against real malware or a production file server. The samples are constructed, which is what the CONSTRUCTED label on this page means. Expect the ransom note rule in particular to match security awareness material, and scope it to data paths.

Reading a hit

A match is a file to open. For the web shell rules, the next questions are the file's creation time against the web server's access log (what request wrote it) and what requests have reached it since. The web shell playbook takes it from there.

The files

The five rules, in one file

Compiles under YARA 4.5. Every string carries a comment saying why it is there.

Download sa_triage_samples.yar · 181 lines · 7.2 KB

/*
    Security Artifacts: YARA triage samples
    Version 1.0, 2026-09-21. Released under CC0.

    Five heuristic rules for sweeping a triage collection, a web root or a
    directory of carved files. They are written to be read: every string is
    there for a reason the comment beside it states.

    These are hunting rules, not verdicts. Each one describes a shape that
    intrusions leave behind, and each one can match something benign. A hit
    is a file to open, not a file to delete.

    Tested with YARA 4.5 against fourteen constructed samples (eight that
    should match, six that should not) and swept across this site's own
    source tree of about four hundred files, where the only hit was this
    file matching its own strings. They have not been run against real
    malware or a production file server. See the page this file ships with.
*/

rule SA_Webshell_PHP_Eval_Of_Request_Input
{
    meta:
        description = "PHP that passes request input to a code-execution function, the core of most one-line web shells"
        author = "Security Artifacts"
        date = "2026-09-21"
        version = "1.0"
        attack = "T1505.003"
        reference = "https://attack.mitre.org/techniques/T1505/003/"
        label = "CONSTRUCTED"
        falsepositives = "Old plugin code and some template engines use eval on request data. Rare, and worth finding for its own sake."

    strings:
        $php = "<?" ascii

        // Execution sinks. Word-bounded by the opening bracket so that
        // "preg_replace_eval" style names in comments do not count.
        $sink1 = /\beval\s*\(/ ascii nocase
        $sink2 = /\bassert\s*\(/ ascii nocase
        $sink3 = /\bsystem\s*\(/ ascii nocase
        $sink4 = /\bpassthru\s*\(/ ascii nocase
        $sink5 = /\bshell_exec\s*\(/ ascii nocase
        $sink6 = /\bcreate_function\s*\(/ ascii nocase

        // The sink fed directly from the request, allowing for one or two
        // wrapping decoders in between, which is how these are usually hidden.
        $direct = /\b(eval|assert|system|passthru|shell_exec)\s*\(\s*(@?\s*(base64_decode|gzinflate|gzuncompress|str_rot13|stripslashes)\s*\(\s*){0,3}@?\$_(POST|GET|REQUEST|COOKIE|SERVER)\b/ ascii nocase

    condition:
        filesize < 64KB and
        $php and
        any of ($sink*) and
        $direct
}

rule SA_Webshell_ASPX_Eval_Of_Request_Item
{
    meta:
        description = "Classic ASP or ASP.NET page that evaluates a request parameter, the China Chopper family shape"
        author = "Security Artifacts"
        date = "2026-09-21"
        version = "1.0"
        attack = "T1505.003"
        reference = "https://attack.mitre.org/software/S0020/"
        label = "CONSTRUCTED"
        falsepositives = "None expected. Evaluating a raw request parameter has no legitimate use."

    strings:
        $asp_open = "<%" ascii
        $eval_item = /eval\s*\(\s*Request(\.Item)?\s*[\[\(]\s*["'][^"']{1,40}["']\s*[\]\)]/ ascii nocase
        $execute = /\bexecute(global)?\s*\(?\s*request\s*\(\s*["'][^"']{1,40}["']\s*\)/ ascii nocase
        $unsafe = "\"unsafe\"" ascii nocase

    condition:
        filesize < 16KB and
        $asp_open and
        ($eval_item or $execute or ($unsafe and #asp_open < 6 and filesize < 1KB))
}

rule SA_PowerShell_Decode_And_Execute_Downloader
{
    meta:
        description = "PowerShell script that decodes base64, executes the result, and reaches the network: the three halves of a download cradle in one file"
        author = "Security Artifacts"
        date = "2026-09-21"
        version = "1.0"
        attack = "T1059.001, T1027, T1105"
        reference = "https://attack.mitre.org/techniques/T1059/001/"
        label = "CONSTRUCTED"
        falsepositives = "Software deployment scripts that download and run an installer. They rarely also decode base64 inline, which is why all three groups are required."

    strings:
        $decode1 = "FromBase64String" ascii wide nocase
        $decode2 = "[Convert]::" ascii wide nocase

        $exec1 = "Invoke-Expression" ascii wide nocase
        $exec2 = /\bIEX\b/ ascii wide nocase
        $exec3 = "[ScriptBlock]::Create" ascii wide nocase
        $exec4 = ".Invoke(" ascii wide nocase

        $net1 = "Net.WebClient" ascii wide nocase
        $net2 = "DownloadString" ascii wide nocase
        $net3 = "DownloadData" ascii wide nocase
        $net4 = "Invoke-WebRequest" ascii wide nocase
        $net5 = "Invoke-RestMethod" ascii wide nocase
        $net6 = "Net.Sockets.TCPClient" ascii wide nocase

    condition:
        filesize < 1MB and
        $decode1 and $decode2 and
        any of ($exec*) and
        any of ($net*)
}

rule SA_Ransom_Note_Text_Heuristic
{
    meta:
        description = "Small text or HTML file with the vocabulary of a ransom note. Finds the note, which names the family and timestamps the encryption"
        author = "Security Artifacts"
        date = "2026-09-21"
        version = "1.0"
        attack = "T1486"
        reference = "https://attack.mitre.org/techniques/T1486/"
        label = "CONSTRUCTED"
        falsepositives = "Security awareness material, incident reports and articles about ransomware, this one included. Scope the scan to user and server data paths rather than to a documents share."

    strings:
        $enc1 = "files have been encrypted" ascii wide nocase
        $enc2 = "files are encrypted" ascii wide nocase
        $enc3 = "data has been encrypted" ascii wide nocase
        $enc4 = "network has been" ascii wide nocase

        $pay1 = "bitcoin" ascii wide nocase
        $pay2 = /\bBTC\b/ ascii wide
        $pay3 = "monero" ascii wide nocase
        $pay4 = "decryption key" ascii wide nocase
        $pay5 = "decryptor" ascii wide nocase
        $pay6 = "decrypt your" ascii wide nocase

        $contact1 = ".onion" ascii wide nocase
        $contact2 = "tor browser" ascii wide nocase
        $contact3 = "torproject.org" ascii wide nocase
        $contact4 = "tox id" ascii wide nocase

        $threat1 = "do not rename" ascii wide nocase
        $threat2 = "will be published" ascii wide nocase
        $threat3 = "will be leaked" ascii wide nocase
        $threat4 = "third-party" ascii wide nocase
        $threat5 = "data leak" ascii wide nocase

    condition:
        filesize < 48KB and
        any of ($enc*) and
        any of ($pay*) and
        any of ($contact*) and
        any of ($threat*)
}

rule SA_Minidump_Of_LSASS_On_Disk
{
    meta:
        description = "A Windows minidump whose module list includes lsass.exe and the LSA server DLL: a credential dump written to disk"
        author = "Security Artifacts"
        date = "2026-09-21"
        version = "1.0"
        attack = "T1003.001"
        reference = "https://attack.mitre.org/techniques/T1003/001/"
        label = "CONSTRUCTED"
        falsepositives = "A crash dump of LSASS taken deliberately by support staff, which is a credential exposure in its own right and should be handled as one."

    strings:
        // Module names in a minidump are stored as UTF-16.
        $lsass = "lsass.exe" wide nocase
        $lsasrv = "lsasrv.dll" wide nocase

    condition:
        // "MDMP" followed by the fixed 0xA793 version word.
        uint32(0) == 0x504D444D and
        uint16(4) == 0xA793 and
        $lsass and $lsasrv
}

sources

  1. YARA documentation: Writing YARA rules · primary
  2. YARA-X, the maintained rewrite, which runs these rules unchanged
  3. MITRE ATT&CK T1505.003, Server Software Component: Web Shell
  4. MITRE ATT&CK S0020, China Chopper
  5. MITRE ATT&CK T1003.001, OS Credential Dumping: LSASS Memory

Tags: yara · webshell · powershell · ransomware · credential-access · hunting · T1505.003 · T1059.001 · T1486 · T1003.001