#100DaysofYARA 2024 – Day 11 – Tor Hidden Service Descriptors

Along with cryptocurrency addresses, Tor Hidden Service descriptors (.onion URLs) are weird enough that their presence in a file often points to interesting things.

Like my cryptocurrency address rules, this relies on regular expression matching and so may result in significant performance hits.

rule TTP_contains_onion_address {
	meta:
		description = "Matches regex for .onion addresses associated with Tor Hidden Services."
		last_modified = "2024-01-11"
        author = "@petermstewart"
        DaysofYara = "11/100"

	strings:
		$r1 = /[a-z2-7]{16}\.onion/ fullword ascii wide
		$r2 = /[a-z2-7]{55}d\.onion/ fullword ascii wide

	condition:
		filesize < 5MB and
		any of them
}

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

#100DaysofYARA 2024 – Day 10 – Monero Address

Today’s rule again uses regular expressions to match cryptocurrency wallet addresses – this time it’s Monero.

rule TTP_contains_XMR_address {
	meta:
		description = "Matches regex for Monero wallet addresses."
		last_modified = "2024-01-10"
        author = "@petermstewart"
        DaysofYara = "10/100"

	strings:
		$r1 = /4[0-9AB][1-9A-HJ-NP-Za-km-z]{93}/ fullword ascii wide

	condition:
		filesize < 5MB and
		$r1
}

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

#100DaysofYARA 2024 – Day 9 – Ethereum Address

Another cryptocurrency rule today, this time focused on matching Ethereum wallet addresses using regular expressions.

rule TTP_contains_ETH_address {
	meta:
		description = "Matches regex for Ethereum wallet addresses."
		last_modified = "2024-01-09"
        author = "@petermstewart"
        DaysofYara = "9/100"

	strings:
		$r1 = /0x[a-fA-F0-9]{40}/ fullword ascii wide

	condition:
		filesize < 5MB and
		$r1
}

After yesterday’s post I asked the #100DaysofYARA group on Twitter if they had any suggestions to decrease the performance hit of using regular expressions like this. Answer: use YARA-X (when it’s ready)

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

#100DaysofYARA 2024 – Day 8 – Bitcoin Address

In my threat hunting role I mostly focus on financially motivated threat actors, particularly ransomware groups. Given the central role that cryptocurrency has had in enabling ransomware attacks at scale, it can sometimes be useful to find files containing cryptocurrency wallet addresses.

Today’s rule uses regular expressions to match Bitcoin wallet addresses.

rule TTP_contains_BTC_address {
	meta:
		description = "Matches regex for Bitcoin wallet addresses."
		last_modified = "2024-01-08"
        author = "@petermstewart"
        DaysofYara = "8/100"

	strings:
		$r1 = /(bc1|[13])[a-km-zA-HJ-NP-Z1-9]{25,34}/ fullword ascii wide

	condition:
		filesize < 5MB and
		$r1
}

Regular expression matching in YARA can be very slow, so it is best practice to “anchor” the regex pattern with as many static characters as possible. I wasn’t able to do that in this case so there will likely be a significant performance hit using this rule. Increase or remove the upper limit on filesize if you want to be more thorough.

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

#100DaysofYARA 2024 – Day 7 – SQLMaggie DLL Export

The final rule for week one is an alternative method of identifying the SQLMaggie backdoor used by a China-nexus threat actor tracked by SentinelLabs as WIP19.

Examining the debug output from the YARA PE module I found that my SQLMaggie sample DLL only exported a single function – maggie. This rule matches any PE file with a single export, named maggie.

import "pe"

rule MAL_SQLMaggie_dll_export {
	meta:
		description = "Matches DLL export found in SQLMaggie backdoor used by China-nexus threat actor WIP19."
		last_modified = "2024-01-07"
        author = "@petermstewart"
        DaysofYara = "7/100"
		ref = "https://www.sentinelone.com/labs/wip19-espionage-new-chinese-apt-targets-it-service-providers-and-telcos-with-signed-malware/"
		sha256 = "f29a311d62c54bbb01f675db9864f4ab0b3483e6cfdd15a745d4943029dcdf14"

	condition:
		uint16(0) == 0x5a4d and
		pe.number_of_exports == 1 and
		pe.export_details[0].name == "maggie"
}

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

#100DaysofYARA 2024 – Day 6 – SQLMaggie Strings

This rule matches samples of the SQLMaggie backdoor utilised by a China-nexus threat actor tracked by SentinelLabs as WIP19.

Whilst we did not observe the initial infection vector in this intrusion, the SQLmaggie malware dropped on victim networks targets Windows systems and has to be executed in an MSSQL server.

We found that SQLMaggie masquerades as a legitimate DLL containing extended stored procedure functions for an MSSQL Server … After registering the DLL into the MSSQL server, the threat actor is able to fully control the server machine and use this backdoor to conduct reconnaissance in the internal network.

SentinelLabs, New Chinese APT Targets IT Service Providers and Telcos With Signed Malware
rule MAL_SQLMaggie_strings {
	meta:
		description = "Matches strings found in SQLMaggie backdoor used by China-nexus threat actor WIP19."
		last_modified = "2024-01-06"
        author = "@petermstewart"
        DaysofYara = "6/100"
		ref = "https://www.sentinelone.com/labs/wip19-espionage-new-chinese-apt-targets-it-service-providers-and-telcos-with-signed-malware/"
		sha256 = "f29a311d62c54bbb01f675db9864f4ab0b3483e6cfdd15a745d4943029dcdf14"
	
	strings:
		$a1 = "Account Owner Not Found For The SID"
		$a2 = "%s Isn't Successfully Hooked Yet"
		$a3 = "About To Execute: %s %s %s"
		$a4 = "RunAs User Password Command"
		$a5 = "Wait 5 To 10 Seconds For TS Taking Effect"
		$a6 = "Re-Install TS Successfullly"
		$a7 = "ImpersonateLoggedOnUser = %d"
		$a8 = "The Account %s Has Been Cloned To %s"
		$a9 = "Fileaccess ObjectName [TrusteeName] [Permission] Options"
		$a10 = "SQL Scan Already Running"
		$a11 = "HellFire2050"

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

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

#100DaysofYARA 2024 – Day 5 – Known Bad Signing Certificate

Today’s rule is the first in a short series covering a China-nexus threat actor tracked by SentinelLabs as WIP19.

SentinelLabs has been monitoring a threat cluster we track as WIP19, a group characterized by the usage of a legitimate, stolen digital certificate issued by a company called “DEEPSoft”. Based on our investigations, WIP19 has been targeting telecommunications and IT service providers in the Middle East and Asia.

WIP19 has been observed signing malware with a valid digital certificate issued for DEEPSoft Co., Ltd., a Korean company specializing in messaging solutions. The threat actor used the certificate to sign several malware components, some of which were tailor-made for specific targets. We assess that it is highly likely the certificate was stolen, as it was also used to sign legitimate software used by DEEPSoft in the past.

SentinelLabs, New Chinese APT Targets IT Service Providers and Telcos With Signed Malware

Building on yesterday’s work on signed PE files, we can also match any binary signed with a particular certificate based on the certificate serial number.

import "pe"

rule TTP_WIP19_bad_cert {
	meta:
		description = "Matches known bad signing certificate serial number used by China-nexus threat actor WIP19."
		last_modified = "2024-01-05"
        author = "@petermstewart"
        DaysofYara = "5/100"
		ref = "https://www.sentinelone.com/labs/wip19-espionage-new-chinese-apt-targets-it-service-providers-and-telcos-with-signed-malware/"
		sha256 = "f29a311d62c54bbb01f675db9864f4ab0b3483e6cfdd15a745d4943029dcdf14"
		sha256 = "2f2f165ee5b81a101ebda0b161f43b54bc55afd8e4702c9b8056a175a1e7b0e0"
		
	condition:
		uint16(0) == 0x5a4d and
		pe.number_of_signatures > 0 and
		for any sig in pe.signatures:
		(
			sig.serial == "02:10:36:b9:e8:0d:16:ea:7f:8c:f0:e9:06:2b:34:55"
		)
}

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

#100DaysofYARA 2024 – Day 4 – Signed PE files

This rule introduces the YARA PE module which allows more fine-grained examination of Portable Executable files by providing easy access to various attributes of the PE file format.

Today’s rule matches PE files which have at least one cryptographic signature. This isn’t malicious in itself but is often interesting depending on the context of the binary. The PE module is smart enough to check for PE files so we don’t really need to specify the magic bytes here, but I’ve included them for completeness anyway.

import "pe"

rule file_pe_signed {
    meta:
        description = "Finds signed Windows executables"
        last_modified = "2024-01-04"
        author = "@petermstewart"
        DaysofYara = "4/100"
        
    condition:
        uint16(0) == 0x5a4d and
        pe.number_of_signatures >= 1
}

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

#100DaysofYARA 2024 – Day 3 – MachO Header

The last rule (at least for now) to identify particular types of executable file. This rule is a bit more complicated due to the number of variations in the MachO specification. It works in the same way as the PE header and ELF header rules though – a simple check for the magic bytes at the beginning of the file.

rule file_macho_header {
    meta:
        description = "Matches Mach-O file headers as uint32"
        last_modified = "2024-01-03"
        author = "@petermstewart"
        DaysofYara = "3/100"

    condition:
        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     //FAT_CIGAM
}

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

#100DaysofYARA 2024 – Day 2 – ELF Header

Another utility rule, this time to match the little-endian hex representation of the header for Executable and Linkable Format (ELF) files commonly found on Linux systems.

rule file_elf_header {
    meta:
        description = "Matches ELF file \x7fELF header as uint32"
        last_modified = "2024-01-02"
        author = "@petermstewart"
        DaysofYara = "2/100"

    condition:
        uint32(0) == 0x464c457f
}

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