THM | AoC 2025 | Day 13

Day-13: YARA Rules - YARA mean one!
SUMMARY
On Day 13 we start out with a quick YARA 101, where we discuss what Yara Rules are, what are they used for, what problem they solve and lastly, how to exactly build and used them.
In the practical part we build a Yara Rule to identify files with a specific hidden String in them, and then assemble the hidden pieces to find McSkidy's hidden message and potential location.

YARA Rules - YARA mean one!
- TL;DR: Learn how YARA rules can be used to detect anomalies.
- Original Room: TryHackMe | Advent of Cyber 2025 | DAY 13 - YARA Rules - YARA mean one!
STORYLINE
"McSkidy, missing from TBFC, sent a hidden message to the blue team embedded in Easter-themed images. The team must create a YARA rule to scan the directory, detect a keyword paired with code words, and extract those code words in ascending order to decode her message."
THEORY
YARA is a malware detection tool that identifies threats by searching for unique patterns and digital fingerprints in code, files, and memory.
Advantages
- Speed | Quickly scans large file sets
- Flexibility | Detects text, binary patterns, and complex logic
- Control | Analysts define what's malicious
- Shareability | Rules reusable across organizations
- Visibility - Connects scattered clues into attack patterns
Common Use Cases
- Post-incident analysis | Verify malware presence across environment
- Threat hunting | Search for known/related malware families
- Intelligence scans | Apply shared rules to detect new indicators
- Memory analysis | Examine active processes for malicious code
YARA Rules
- 3 key elements:
- Metadata | info about the rule itself; who created it, when, why
- Strings | what to search for (text, byte sequences, regular expressions)
- Conditions | logic deciding when the rule triggers
- Yara Rule Example - looking for specific URLs and executable names
rule TBFC_KingMalhare_Trace
{
meta:
author = "Defender of SOC-mas"
description = "Detects traces of King Malhare’s malware"
date = "2025-10-10"
strings:
$s1 = "rundll32.exe" fullword ascii
$s2 = "msvcrt.dll" fullword wide
$url1 = /http:\/\/.*malhare.*/ nocase
condition:
any of them
} - Yara Rule Example - specific header binary, malicious binary fragment, restrict by file size
rule TBFC_Simple_MZ_Detect
{
meta:
author = "TBFC SOC L2"
description = "IcedID Rule"
date = "2025-10-10"
confidence = "low"
strings:
$mz = { 4D 5A } // "MZ" header (PE file)
$hex1 = { 48 8B ?? ?? 48 89 } // malicious binary fragment
$s1 = "malhare" nocase // story / IOC string
condition:
all of them and filesize < 10485760 // < 10MB size
} - Execution |
yara -r icedid_starter.yar C:\-r| scan directories recursively and follow symlinks-s| prints the strings found within files that match the rule
- Rule Extension | ".yar"
Strings
- represent the signatures of malicious activity in fragments of text, byte, or patterns
- Text Strings
// TEXT STRINGS - words or short text fragments
// ASCII and case-sensitive (default)
$TBFC_string = "Christmas"
// Case-insensitive
$xmas = "Christmas" nocase
// Wide-character - searching for both here
// many windows executables use two-byte Unicode characters - ***ascii*** enforces single-byte search
$xmas = "Christmas" wide ascii
// XOR strings - checks all possible single-byte XOR variations of the string
$hidden = "Malhare" xor
// Base64 strings - decodes the content and searches for the original pattern even if hidden in encoded form
$b64 = "SOC-mas" base64 - Hexadecimal strings
// Hexadecimal strings - search for specific byte patterns written in hexadecimal notion
// - useful for file headers, shellcode, binary signatures
rule TBFC_Malhare_HexDetect
{
strings:
$mz = { 4D 5A 90 00 } // MZ header of a Windows executable
$hex_string = { E3 41 ?? C8 G? VB }
condition:
$mz and $hex_string
} - Regular expression strings
// Regular expression strings - flexible search patterns, spotting URLs, encoded commands, dynamic filenames
// - BEWARE: can match wide range of data > SLOW down scans if too broad
rule TBFC_Malhare_RegexDetect
{
strings:
$url = /http:\/\/.*malhare.*/ nocase
$cmd = /powershell.*-enc\s+[A-Za-z0-9+/=]+/ nocase
condition:
$url and $cmd
}
Conditions
- match single string |
$xmas - match any string |
any of them - match all strings |
all of them- trigger only if every indicator matches - combined logic | and, or, not -
($s1 or $s2) and not $benign - comparisons - check file properties not just contents | filesize, entrypoint, hash -
any of them and (filesize < 700KB)
Q & A
So, first thing first, let's head over to the /home/ubuntu/Downloads/easter directory on the VM and take a quick look around.
ubuntu@tryhackme:~$ cd /home/ubuntu/Downloads/
ubuntu@tryhackme:~/Downloads$ ls -hla easter/
total 130M
drwxr-xr-x 2 ubuntu ubuntu 4.0K [REDACTED-TIME] .
drwxr-xr-x 3 ubuntu ubuntu 4.0K [REDACTED-TIME] ..
-rw-r--r-- 1 ubuntu ubuntu 695K [REDACTED-TIME] easter1.jpg
-rw-r--r-- 1 ubuntu ubuntu 1.3M [REDACTED-TIME] easter10.jpg
[...SNIP...]
-rw-r--r-- 1 ubuntu ubuntu 462 [REDACTED-TIME] embeds
ubuntu@tryhackme:~/Downloads$
That a lot of pictures, 61 to be exact:
ubuntu@tryhackme:~/Downloads/easter$ ls | wc -l
61
ubuntu@tryhackme:~/Downloads/easter$
Let's create a YARA Rule named "tbfc-string_detect.yar" with a bare-bone Yara Rule structure, then add one-simple text-string search with $keyword = "TBFC:" ascii:
rule TBFC_STRING_DETECT
{
meta:
author = "DefinitelyNotTheEasterBunny"
decription = "Detect keywords 'TBFC:' followed by an ASCII alphanumeric keyword"
date = "Once-Upon-A-Time"
confidence = "very-low"
strings:
$keyword = "TBFC:" ascii
condition:
$keyword
}
The rule is very simple, looks simply for the string "TBFC:" and assumes that it is ASCII encoded, which is the default setting. As for condition, it only has to match that simple keyword we defined - therefore will only trigger when the searched object (text, file, etc.) contains the specified keyword. Let's try and run it:
ubuntu@tryhackme:~/Downloads$ ls -hla
total 16K
drwxr-xr-x 3 ubuntu ubuntu 4.0K [REDACTED-TIME] .
drwxr-xr-x 20 ubuntu ubuntu 4.0K [REDACTED-TIME] ..
drwxr-xr-x 2 ubuntu ubuntu 4.0K [REDACTED-TIME] easter
-rw-r--r-- 1 ubuntu ubuntu 320 [REDACTED-TIME] tbfc-string-detect.yar
ubuntu@tryhackme:~/Downloads$ yara -s -r tbfc-string-detect.yar easter/
TBFC_STRING_DETECT easter//easter46.jpg
0x2f78a:$keyword: TBFC:
TBFC_STRING_DETECT easter//embeds
0x18f:$keyword: TBFC:
0x1bf:$keyword: TBFC:
TBFC_STRING_DETECT easter//easter10.jpg
0x137da8:$keyword: TBFC:
TBFC_STRING_DETECT easter//easter16.jpg
0x3bb7f7:$keyword: TBFC:
TBFC_STRING_DETECT easter//easter52.jpg
0x2a2ad2:$keyword: TBFC:
TBFC_STRING_DETECT easter//easter25.jpg
0x42c778:$keyword: TBFC:
ubuntu@tryhackme:~/Downloads$
Great, it worked. Let us move on to the questions.
Question-1: How many images contain the string TBFC?
5
We are almost already there to answer this question. Yeah, we could simply count them... But we can do better, let's play with linux a bit:
ubuntu@tryhackme:~/Downloads$ yara -r tbfc-string-detect.yar easter/
TBFC_STRING_DETECT easter//easter46.jpg
TBFC_STRING_DETECT easter//embeds
TBFC_STRING_DETECT easter//easter16.jpg
TBFC_STRING_DETECT easter//easter10.jpg
TBFC_STRING_DETECT easter//easter52.jpg
TBFC_STRING_DETECT easter//easter25.jpg
ubuntu@tryhackme:~/Downloads$ yara -r tbfc-string-detect.yar easter/ | grep .jpg
TBFC_STRING_DETECT easter//easter46.jpg
TBFC_STRING_DETECT easter//easter16.jpg
TBFC_STRING_DETECT easter//easter10.jpg
TBFC_STRING_DETECT easter//easter52.jpg
TBFC_STRING_DETECT easter//easter25.jpg
ubuntu@tryhackme:~/Downloads$ yara -r tbfc-string-detect.yar easter/ | grep .jpg | wc -l
5
ubuntu@tryhackme:~/Downloads$
First we remove the unnecessary string outputs that come with -s, then we focus only on .jpg files. Lastly, we count them.
Question-2: What regex would you use to match a string that begins with TBFC: followed by one or more alphanumeric ASCII characters?
/TBFC:[A-Za-z0-9]+/
Let's modify our keyword from $keyword = "TBFC:" ascii to $keyword = /TBFC:[A-Za-z0-9]+/ ascii. The part [A-Za-z0-9] denotes an alphanumeric letter, + indicates that there is at least one or more of them, and ascii makes sure that this regular expression will search for one-byte ascii encoded versions of the the specified keyword.
This is how our new modified rule might look like:
rule TBFC_STRING_DETECT
{
meta:
author = "DefinitelyNotTheEasterBunny"
decription = "Detect keywords 'TBFC:' followed by an ASCII alphanumeric keyword"
date = "Once-Upon-A-Time"
confidence = "very-low"
strings:
$keyword = /TBFC:[A-Za-z0-9]+/ ascii
condition:
$keyword
}
Question-3: What is the message sent by McSkidy?
Find me in Hopsec Island
Running our new rule, specified in the previous question brings us closer to this question.
ubuntu@tryhackme:~/Downloads$ yara -s -r tbfc-string-detect.yar easter/
TBFC_STRING_DETECT easter//easter46.jpg
0x2f78a:$keyword: TBFC:HopSec
TBFC_STRING_DETECT easter//easter10.jpg
0x137da8:$keyword: TBFC:Find
TBFC_STRING_DETECT easter//easter52.jpg
0x2a2ad2:$keyword: TBFC:Island
TBFC_STRING_DETECT easter//easter16.jpg
0x3bb7f7:$keyword: TBFC:me
TBFC_STRING_DETECT easter//easter25.jpg
0x42c778:$keyword: TBFC:in
ubuntu@tryhackme:~/Downloads$
As we can see, there is a secret message hidden here. Let's try to cut away all the unnecessary words and focus on the hidden message, starting with excluding lines that contain image extensions (".jpg").
ubuntu@tryhackme:~/Downloads$ yara -s -r tbfc-string-detect.yar easter/ | grep -v .jpg
0x2f78a:$keyword: TBFC:HopSec
0x137da8:$keyword: TBFC:Find
0x2a2ad2:$keyword: TBFC:Island
0x3bb7f7:$keyword: TBFC:me
0x42c778:$keyword: TBFC:in
ubuntu@tryhackme:~/Downloads$
Focusing only on the secret words, and trying to sort them brings us to the following words: "Find", "HopSec", "Island", "in", "me"
ubuntu@tryhackme:~/Downloads$ yara -s -r tbfc-string-detect.yar easter/ | grep -v .jpg | cut -d " " -f 2
TBFC:HopSec
TBFC:me
TBFC:Find
TBFC:Island
TBFC:in
ubuntu@tryhackme:~/Downloads$ yara -s -r tbfc-string-detect.yar easter/ | grep -v .jpg | cut -d " " -f 2 | cut -d ":" -f 2
HopSec
me
Find
Island
in
ubuntu@tryhackme:~/Downloads$ yara -s -r tbfc-string-detect.yar easter/ | grep -v .jpg | cut -d " " -f 2 | cut -d ":" -f 2 | sort
Find
HopSec
Island
in
me
ubuntu@tryhackme:~/Downloads$
Assembling them in the correct order gives us the secret message: "Find me in Hopsec Island".