#100DaysofYARA 2024 – Day 41 – Base64-Encoded CobaltStrike PowerShell Loader

In my day job I most commonly find CobaltStrike Beacon payloads executed via base64-encoded PowerShell following an initial compromise; maybe phishing or a web application vulnerability leading to command execution. Encoding the command means the threat actor doesn’t need to worry about matching quotes, brackets, etc when passing the command over the channel.

This rule uses YARA’s base64 modifier to match encoded variants of the loader command.

rule MAL_CobaltStrike_Powershell_loader_base64 {
    meta:
        description = "Matches base64-encoded strings found in CobaltStrike PowerShell loader commands."
        last_modified = "2024-02-10"
        author = "@petermstewart"
        DaysofYara = "41/100"

    strings:
        $a1 = "=New-Object IO.MemoryStream(" base64 wide
        $a2 = "[Convert]::FromBase64String(" base64 wide
        $a3 = "IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd()" base64 wide

    condition:
        all of them
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 40 – CobaltStrike PowerShell Loader

I deal with CobaltStrike pretty much every day in my job and in my experience it is by far the most commonly abused C2 framework. CobaltStrike isn’t new and there is already a huge collection of public research and detections available; Google, for example, published an extensive collection of YARA rules in 2022. One aspect that I did not find a public rule for though was the PowerShell Beacon loader:

rule MAL_CobaltStrike_Powershell_loader {
    meta:
        description = "Matches strings found in CobaltStrike PowerShell loader samples."
        last_modified = "2024-02-09"
        author = "@petermstewart"
        DaysofYara = "40/100"
        sha256 = "9c9e8841d706406bc23d05589f77eec6f8df6d5e4076bc6a762fdb423bfe8c24"
        sha256 = "6881531ab756d62bdb0c3279040a5cbe92f9adfeccb201cca85b7d3cff7158d3"
        ref = "https://medium.com/@cybenfolland/deobfuscating-a-powershell-cobalt-strike-beacon-loader-c650df862c34"
        ref = "https://forensicitguy.github.io/inspecting-powershell-cobalt-strike-beacon/"

    strings:
        $a1 = "=New-Object IO.MemoryStream("
        $a2 = "[Convert]::FromBase64String("
        $a3 = "IEX (New-Object IO.StreamReader(New-Object IO.Compression.GzipStream($s,[IO.Compression.CompressionMode]::Decompress))).ReadToEnd()"
        $b1 = "Set-StrictMode -Version 2"
        $b2 = "$DoIt = @'"
        $b3 = "[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($DoIt))"
        $b4 = "start-job { param($a) IEX $a }"

    condition:
        all of ($a*) or
        all of ($b*)
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 39 – Mythic Athena Agent

Mythic is an open-source C2 framework designed to be modular and compatible with multiple agents and C2 profiles.

Today’s rule matches strings found in the cross-platform .NET Athena agent:

rule MAL_Mythic_Athena_strings {
    meta:
        description = "Matches strings found in samples of the Athena agent used by the open-source Mythic framework."
        last_modified = "2024-02-08"
        author = "@petermstewart"
        DaysofYara = "39/100"
        sha256 = "8075738035ac361d50db2c2112a539acc3f1ad4d4ed5f971b2e18c687fc029da"
        sha256 = "ce66c7487e56722f34e5fd0fea167f9c562a0bbb0d13128b0313e4d3eabff697"
        ref = "https://github.com/MythicAgents/athena"

    strings:
        $a = "Athena"
        $b1 = "\"Athena.Commands\":"
        $b2 = "\"Athena.Forwarders.SMB\":"
        $c1 = "\"cat\":"
        $c2 = "\"drives\":"
        $c3 = "\"get-clipboard\":"
        $c4 = "\"get-localgroup\":"
        $c5 = "\"get-sessions\":"
        $c6 = "\"get-shares\":"
        $c7 = "\"hostname\":"
        $c8 = "\"ifconfig\":"
        $c9 = "\"ls\":"
        $c10 = "\"mkdir\":"
        $c11 = "\"mv\":"
        $c12 = "\"ps\":"
        $c13 = "\"pwd\":"
        $c14 = "\"rm\":"
        $c15 = "\"shell\":"
        $c16 = "\"shellcode\":"
        $c17 = "\"whoami\":"

    condition:
        uint16(0) == 0x5a4d and
        #a > 100 and
        all of ($b*) and
        8 of ($c*)
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 38 – Mythic Apfell Agent

Mythic is an open-source C2 framework designed to be modular and compatible with multiple agents and C2 profiles.

Today’s rule matches strings found in the macOS Apfell agent:

rule MAL_Mythic_Apfell_strings {
    meta:
        description = "Matches strings found in samples of the macOS Apfell Javascript agent used by the open-source Mythic framework."
        last_modified = "2024-02-07"
        author = "@petermstewart"
        DaysofYara = "38/100"
        sha256 = "8962ad7c608962c637637b9d3aef101a87cfb71873210046d5a49cfa6f47a712"
        ref = "https://github.com/MythicAgents/apfell"

    strings:
        $a1 = "C2.checkin(ip,apfell.pid,apfell.user,ObjC.unwrap(apfell.procInfo.hostName),apfell.osVersion,"
        $a2 = "return this.interval + (this.interval * (this.get_random_int(this.jitter)/100));"
        $a3 = "let info = {'ip':ip,'pid':pid,'user':user,'host':host,'uuid':apfell.uuid, \"os\":os, \"architecture\": arch, \"domain\": domain, \"action\": \"checkin\"};"
        $b1 = "\"user\": apfell.user,"
        $b2 = "\"fullName\": apfell.fullName,"
        $b3 = "\"ips\": apfell.ip,"
        $b4 = "\"hosts\": apfell.host,"
        $b5 = "\"environment\": apfell.environment,"
        $b6 = "\"uptime\": apfell.uptime,"
        $b7 = "\"args\": apfell.args,"
        $b8 = "\"pid\": apfell.pid,"
        $b9 = "\"apfell_id\": apfell.id,"
        $b10 = "\"payload_id\": apfell.uuid"
        $c1 = "-IMPLANT INFORMATION-"
        $c2 = "-Base C2 INFORMATION-"
        $c3 = "-RESTFUL C2 mechanisms -"
        $c4 = "- INSTANTIATE OUR C2 CLASS BELOW HERE IN MAIN CODE-"
        $c5 = "-SHARED COMMAND CODE -"
        $c6 = "-GET IP AND CHECKIN -"
        $c7 = "-MAIN LOOP -"
        $c8 = "//To create your own C2, extend this class and implement the required functions"
        $c9 = "//gets a file from the apfell server in some way"
        $c10 = "//there is a 3rd slash, so we need to splice in the port"
        $c11 = "//generate a time that's this.interval += (this.interval * 1/this.jitter)"
        $c12 = "// now we need to prepend the IV to the encrypted data before we base64 encode and return it"
        $c13 = "// Encrypt our initial message with sessionID and Public key with the initial AES key"
        $c14 = "//depending on the amount of data we're sending, we might need to chunk it"
        $c15 = "//if we do need to decrypt the response though, do that"
        $c16 = "// don't spin out crazy if the connection fails"
        $c17 = "// always round up to account for chunks that are < chunksize;"
        $c18 = "//simply run a shell command via doShellScript and return the response"
        $c19 = "//  so I'll just automatically fix this so it's not weird for the operator"
        $c20 = "//  params should be {\"cmds\": \"cmd1 cmd2 cmd3\", \"file_id\": #}"

    condition:
        (all of ($a*) and 8 of ($b*)) or
        (15 of ($c*))
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 37 – Mythic Apollo Agent

Mythic is an open-source C2 framework designed to be modular and compatible with multiple agents and C2 profiles.

Today’s rule matches strings found in the Windows Apollo agent:

rule MAL_Mythic_Apollo_strings {
    meta:
        description = "Matches strings found in samples of the Windows Apollo agent used by the open-source Mythic framework."
        last_modified = "2024-02-06"
        author = "@petermstewart"
        DaysofYara = "37/100"
        sha256 = "bf3d47335b7c10f655987cfdefecdb2856c0ac90f2f1cedcd67067760a80aa98"
        sha256 = "67b2c1c5d96a7c70b2bc111ace08b35e0db63bef40534dc50a692d46f832d61a"
        ref = "https://github.com/MythicAgents/apollo"

    strings:
        $pdb = "Apollo.pdb"
        $a = "ApolloInterop"
        $b1 = "ApolloTrackerUUID"
        $b2 = "Apollo.Peers.SMB"
        $b3 = "Apollo.Peers.TCP"
        $b4 = "C2ProfileData"
        $b5 = "mythicFileId"
        $b6 = "IMythicMessage"
        $b7 = ".MythicStructs"
        $b8 = ".ApolloStructs"
        $b9 = "Apollo.Api"
        $b10 = "ApolloLogonInformation"

    condition:
        uint16(0) == 0x5a4d and
        ($pdb and #a > 15) or
        ($a and (6 of ($b*)))
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 36 – Nimplant

Nimplant is an open-source, lightweight, first-stage implant initially developed by Cas van Cooten and available for download on Github.

rule MAL_Nimplant_strings {
    meta:
        description = "Matches strings found in open-source Nimplant samples."
        last_modified = "2024-02-05"
        author = "@petermstewart"
        DaysofYara = "36/100"
        sha256 = "4d7eb09c35a644118af702dd402fd9f5a75e490d33e86b6746e6eb6112c5caa7"
        sha256 = "90a5e330d411d84a09ef4af07d2b9c808acc028a91fa7e1d57c4f063e91fad49"
        ref = "https://github.com/chvancooten/NimPlant"

    strings:
        $ver = "NimPlant v"
        $header1 = "@Content-Type"
        $header2 = "@X-Identifier"
        $header3 = "@User-Agent"
        $cmd1 = "getLocalAdm"
        $cmd2 = "getAv"

    condition:
        uint16(0) == 0x5a4d and
        filesize > 300KB and filesize < 1MB and
        all of them
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 35 – Sliver C2 Framework

Sliver is an open-source, cross-platform C2 framework developed by Bishop Fox. This rule matches strings found in the Windows, Linux, and macOS variants of the Sliver implant.

rule MAL_Sliver_implant_strings {
	meta:
		description = "Matches strings found in open-source Sliver beacon samples."
		last_modified = "2024-02-04"
		author = "@petermstewart"
		DaysofYara = "35/100"
		sha256 = "6037eaaa80348d44a51950b45b98077b3aeb16c66a983a8cc360d079daaaf53e"
		sha256 = "98df535576faab0405a2eabcd1aac2c827a750d6d4c3d76a716c24353bedf0b5"
		sha256 = "789e5fcb242ee1fab8ed39e677d1bf26c7ce275ae38de5a63b4d902c58e512ec"

	strings:
		$a1 = "bishopfox/sliver"
		$a2 = "sliver/protobuf"
		$a3 = "protobuf/commonpbb"
		$b1 = "ActiveC2Fprotobuf:\"bytes,11,opt,name="
		$b2 = "ProxyURLFprotobuf:\"bytes,14,opt,name="
		$b3 = "BeaconJitterNprotobuf:\"varint,3,opt,name="
		$b4 = "BeaconIntervalRprotobuf:\"varint,2,opt,name="
		$b5 = "BeaconIDEprotobuf:\"bytes,8,opt,name="
		$b6 = "BeaconID"
		$b7 = "GetBeaconJitter"
		$b8 = "BeaconRegister"

	condition:
		(filesize > 5MB and filesize < 20MB) and
		(uint16(0) == 0x5a4d or 		//PE
		uint32(0) == 0x464c457f or 		//ELF
		uint32(0) == 0xfeedface or  	//MH_MAGIC
		uint32(0) == 0xcefaedfe or  	//MH_CIGAM
		uint32(0) == 0xfeedfacf or  	//MH_MAGIC_64
		uint32(0) == 0xcffaedfe or 	 	//MH_CIGAM_64
		uint32(0) == 0xcafebabe or  	//FAT_MAGIC
		uint32(0) == 0xbebafeca) and	//FAT_CIGAM
		2 of ($a*) or
		6 of ($b*)
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 34 – Brute Ratel (BRC4)

Brute Ratel is another commercial C2 framework marketed towards Red Teams but known to be used by malicious actors.

This rule matches a byte pattern used to obfuscate strings in publicly available samples.

rule MAL_BRC4_string_obfuscation_bytes {
	meta:
		description = "Matches hex byte pattern used to obfuscate strings in Brute Ratel (BRC4) samples."
		last_modified = "2024-02-03"
		author = "@petermstewart"
		DaysofYara = "34/100"
		sha256 = "3ad53495851bafc48caf6d2227a434ca2e0bef9ab3bd40abfe4ea8f318d37bbe"
		sha256 = "973f573cab683636d9a70b8891263f59e2f02201ffb4dd2e9d7ecbb1521da03e"

	strings:
		$a1 = { 50 48 B8 74 00 20 00 64 00 6F 00 50 48 } //PH,t. .d.o.PH
		$a2 = { 50 48 B8 6E 00 73 00 68 00 6F 00 50 48 } //PH,n.s.h.o.PH
		$a3 = { 50 48 B8 63 00 72 00 65 00 65 00 50 48 } //PH,c.r.e.e.PH
		$b1 = { 50 48 B8 69 00 6D 00 61 00 67 00 50 48 } //PH,i.m.a.g.PH
		$b2 = { 50 48 B8 32 64 2E 70 6E 67 00 00 50 48 } //PH,2d.png..PH
		$c1 = { 50 48 B8 6E 00 67 00 3A 00 20 00 50 48 } //PH,n.g.:. .PH
		$c2 = { 50 48 B8 65 00 72 00 79 00 69 00 50 48 } //PH,e.r.y.i.PH
		$c3 = { 50 48 B8 5D 00 20 00 51 00 75 00 50 48 } //PH,]. .Q.u.PH

	condition:
		uint16(0) == 0x5a4d and
		5 of them
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 33 – Nighthawk

Nighthawk is an advanced C2 framework developed and sold by MDSec. Proofpoint published some analysis back in November 2022. TL;DR – Nighthawk is pretty good!

This rule is based on the Proofpoint blog post combined with a bit of trial-and-error wildcarding to match the samples available on vx-underground.

rule MAL_Nighthawk_bytes {
	meta:
		description = "Matches hex byte pattern referenced in Proofpoint blog reversing Nighthawk malware."
		last_modified = "2024-02-02"
		author = "@petermstewart"
		DaysofYara = "33/100"
		ref = "https://web.archive.org/web/20221122125826/https://www.proofpoint.com/us/blog/threat-insight/nighthawk-and-coming-pentest-tool-likely-gain-threat-actor-notice"
		sha256 = "9a57919cc5c194e28acd62719487c563a8f0ef1205b65adbe535386e34e418b8"
		sha256 = "0551ca07f05c2a8278229c1dc651a2b1273a39914857231b075733753cb2b988"

	strings:
		//   { 48 8d 0d f9 ff ff ff 51 5a 48 81 c1 20 4e 00 00 48 81 c2 64 27 00 00 ff e2 }
		$a = { 48 8d 0d ?? ff ff ff ?? ?? ?? ?? ?? ?? ?? 00 00 }

	condition:
		filesize > 500KB and filesize < 1MB and
		uint16(0) == 0x5a4d and
		$a
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.

#100DaysofYARA 2024 – Day 32 – Generic Cryptominer Strings

Here is a simple rule to catch the Stratum URL strings commonly found in cryptominer binaries.

rule TTP_cryptominer_stratum_strings {
	meta:
		description = "Matches stratum URL strings commonly found in cryptominers."
		last_modified = "2024-02-01"
		author = "@petermstewart"
		DaysofYara = "32/100"

	strings:
		$a1 = "stratum+tcp" ascii wide
		$a2 = "stratum+udp" ascii wide
		$a3 = "stratum+ssl" ascii wide

	condition:
		(uint16(0) == 0x5a4d or			//PE
		uint32(0) == 0x464c457f or		//ELF
		uint32(0) == 0xfeedface or		//MH_MAGIC
		uint32(0) == 0xcefaedfe or		//MH_CIGAM
		uint32(0) == 0xfeedfacf or		//MH_MAGIC_64
		uint32(0) == 0xcffaedfe or		//MH_CIGAM_64
		uint32(0) == 0xcafebabe or		//FAT_MAGIC
		uint32(0) == 0xbebafeca) and	//FAT_CIGAM
		any of them
}

Find the rest of my 100DaysofYARA posts here, and the rules themselves on my Github repository.