Mastering Linux Fundamentals: A Deep Dive into the TryHackMe Ninja Skills Challenge
Finding the "needle in the haystack" is a core skill for any security analyst. Whether you are performing a forensic investigation or looking for a privilege escalation vector, your ability to navigate the Linux filesystem quickly is what separates a novice from a professional.
In this post, I’m walking through my journey in the TryHackMe Ninja Skills lab. This room isn't about fancy exploits; it’s about mastering the core commands that power every Linux system.
Step-by-Step Solutions: Mastering the Ninja Questions
The challenge gives us a list of 12 cryptic filenames (like 8V2L, bny0, c4ZX, D8B3, FHl1, oiMO, PFbD, rmfX, SRSq, uqyw, v2Vb and X1Uy) and tasks us with identifying their properties across the entire filesystem.
❓ The Ninja Questions
Each of the following questions requires a different Linux "jutsu" (technique) to solve. Here is what we need to find:
- Which files are owned by the "best-group" group?
- Which of these files contain an IP address?
- Which file has the SHA1 hash of 9d54da7584015647ba052173b84d45e8007eba94?
- Which file contains exactly 230 lines?
- Which file's owner has a User ID (UID) of 502?
- Which file is executable by everyone?
🛠️ Environment Setup: Preparing your Linux Dojo
One of the best habits to build when starting any cybersecurity challenge is organizing your environment for clarity. To make my workflow smoother, I’ve mapped the target machine's IP (e.g. 10.64.190.161) to a friendlier DNS name: target-system.
Why use a local DNS entry?
- Easier Navigation: Typing
ping target-systemis much more intuitive than remembering a specific IP address. - Professional Documentation: Standardized naming makes screenshots and reports much easier for others to read.
- Real-World Simulation: This mimics a corporate environment where you interact with hostnames rather than raw addresses.
Note: For this write-up, I’ll be using this standardized naming in all my terminal commands. I won’t describe the technical steps for modifying the AttackBox host file here, but if you’re interested in learning how to do this yourself, let me know in the comments, and I’ll be happy to help!
🖥️ Accessing the Dojo: Choosing Your Workflow
Once the Ninja Skills VM is deployed, TryHackMe offers three main ways to interact with the target machine:
- Split Screen Mode: A convenient in-browser terminal that sits right next to the lab questions.
- Extended/Full Screen Mode: Expands the in-browser terminal to fill your entire window for a more focused experience.
- SSH via VPN (Recommended): Connecting from your own local machine (or AttackBox) using a VPN tunnel and standard SSH credentials.
For this challenge, I chose the third option. By connecting via SSH over my VPN, I can use my personalized terminal environment, customized shortcuts, and—most importantly—the standardized target-system hostname we set up in the previous step.

As you can see in the screenshot above, I am successfully connected as new-user. The "games" have officially begun!
🚀 Strategy: The Linux Jutsu Methodology
Now that our environment is ready and our target is reachable via target-system, let’s dive into the first question...
🥷 Question 1: Identifying Group Ownership
"Which of the above files are owned by the 'best-group' group?"
In a massive filesystem, manually checking every folder for these 12 files would be impossible. Instead, we use the find command to filter specifically for files that match our list and belong to the best-group group.
You can always use the man pages to find out different options for the commands you want to use (this is how i do it) . The man page for the find command can be found here .
To solve this efficiently, I used a command that looks for all 12 filenames simultaneously and filters them by their group metadata:
find / -type f \( -name "8V2L" -o -name "bny0" -o -name "c4ZX" -o -name "D8B3" -o -name "FHl1" -o -name "oiMO" -o -name "PFbD" -o -name "rmfX" -o -name "SRSq" -o -name "uqyw" -o -name "v2Vb" -o -name "X1Uy" \) -group best-group 2>/dev/null
🛠️ Detailed Command Breakdown
\( ... -o ... \)The -o stands for "OR". This allows us to search for all 12 filenames in a single pass rather than running 12 separate commands.
-group best-groupThis is the specific filter that tells Linux to only show results that are owned by that group.
2>/dev/nullThis silences any "Permission Denied" errors, keeping our terminal output clean and professional.

🥷 Question 2: Pattern Matching inside Files
"Which of these files contain an IP address?"
For this challenge, we don't care who owns the file; we care about what is written inside it. To find a specific pattern like an IP address across our 12 target files, the grep command is your best friend.
The man page for the grep command can be found here .
If you're new to how IP addresses work, check out my Introduction to the OSI Model post."
The Technical Approach
We need to search for a pattern that looks like an IP address (four sets of numbers separated by dots). While we could use a complex Regular Expression (Regex), a simpler way is to use grep to search for any digit pattern within our specific list of files.
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' $(find / -type f \( -name "8V2L" -o -name "bny0" -o -name "c4ZX" -o -name "D8B3" -o -name "FHl1" -o -name "oiMO" -o -name "PFbD" -o -name "rmfX" -o -name "SRSq" -o -name "uqyw" -o -name "v2Vb" -o -name "X1Uy" \) 2>/dev/null)
🛠️ Detailed Command Breakdown
grep -EGlobal Regular Expression Print. The -E flag tells the system to use "Extended" regex, which allows us to use special characters like {} for more precise matching.
'[0-9]{1,3}'This looks for any digit from 0 to 9 that appears at least once, but no more than three times (matching segments like 1, 10, or 192).
\.In regex, a simple dot . matches any character. By adding a backslash \., we "escape" it, telling Linux we are looking for a literal period mark.
$()This is Command Substitution. It tells Linux: "Run the command inside these parentheses first, and then give the result to the command outside".
find / -type fThis starts the search from the root directory (/) and filters specifically for files (-type f), ignoring folders or shortcuts.
2>/dev/nullThis is your standard "cleaner." It sends any "Permission Denied" errors to the null device, so they don't clutter your results.

🥷 Question 3: Verifying Data Integrity with Hashing
"Which file has the SHA1 hash of 9d54da7584015647ba052173b84d45e8007eba94?"
In the world of cybersecurity, a hash is like a digital fingerprint. Even if a file's name changes, its hash remains the same as long as the content inside is untouched. For this challenge, we need to calculate the SHA1 hash for our target files and find the one that matches the specific string provided by TryHackMe.
The sha1sum man page can be found here .
sha1sum $(find / -type f \( -name "8V2L" -o -name "bny0" -o -name "c4ZX" -o -name "D8B3" -o -name "FHl1" -o -name "oiMO" -o -name "PFbD" -o -name "rmfX" -o -name "SRSq" -o -name "uqyw" -o -name "v2Vb" -o -name "X1Uy" \) 2>/dev/null) | grep "9d54da7584015647ba052173b84d45e8007eba94"
🛠️ Detailed Command Breakdown
sha1sumThis utility calculates the Secure Hash Algorithm 1 for any given file. It outputs a 40-character hexadecimal string followed by the filename.
$(...)This is Command Substitution. It allows the find command to run first and provide the absolute paths of our 12 files as input for sha1sum.
find / -type fThis initiates a search from the root directory specifically for files, ensuring we don't accidentally try to hash a folder (which would result in an error).
2>/dev/nullSince we are searching the whole system, we will hit many folders we don't have permission to enter. This redirects those errors to the null device to keep our output clean.
|The Pipe (|) is the secret to Linux power. It allows you to take small, simple tools and connect them together to solve complex problems—like searching a whole computer for one specific digital fingerprint in seconds.
grep "[hash]"This acts as a high-speed scanner. Instead of you manually reading all 12 fingerprints to find a match, grep looks at the data coming through the pipe and only displays the line that contains our target SHA1 hash.

🥷 Question 4: Searching by File Length
"Which file contains exactly 230 lines?"
In this challenge, we move from analyzing "what" a file is (its fingerprint) to "how much" data it contains. To find a file with a specific line count, we use the wc (Word Count) utility. Instead of opening every file manually, we automate the counting process across our 12 target files.
The man page for the wc command be found here.
wc -l $(find / -type f \( -name "8V2L" -o -name "bny0" -o -name "c4ZX" -o -name "D8B3" -o -name "FHl1" -o -name "oiMO" -o -name "PFbD" -o -name "rmfX" -o -name "SRSq" -o -name "uqyw" -o -name "v2Vb" -o -name "X1Uy" \) 2>/dev/null) | grep "230"
This command returned no result (the issue was because of the permission).
The Troubleshooting Logic
To solve this, I pivoted my strategy. I ran the wc -l command on our target list without the grep filter to see the line counts of every file I could access:
wc -l $(find / -type f \( -name "8V2L" -o -name "bny0" -o -name "c4ZX" -o -name "D8B3" -o -name "FHl1" -o -name "oiMO" -o -name "PFbD" -o -name "rmfX" -o -name "SRSq" -o -name "uqyw" -o -name "v2Vb" -o -name "X1Uy" \) 2>/dev/null)
🛠️ Detailed Command Breakdown
wc -lThis is the Word Count command. The -l flag specifically instructs the tool to only count the number of newlines (lines) in each file rather than words or characters.
$(...)Command Substitution. This runs the find search first to locate our 12 files and then inserts their full paths into the wc command automatically.
2>/dev/nullThis prevents our screen from filling with "Permission Denied" errors by sending them to the null device, ensuring only valid file counts are displayed.
🔍 Results: Identifying the Target
By identifying which filename was "missing" from my terminal output, I found the answer through the process of elimination.
The Answer: The file containing 230 lines is ???? , you can find it by yourself.

🥷 Question 5: Hunting by Numeric User ID (UID)
"Which file's owner has an ID of 502?"
In Linux, every user has a name (like n1vr3), but the system actually identifies them by a number called a User ID (UID). Sometimes, as a security analyst, you might find a file that belongs to a UID that doesn't have a name assigned to it yet, which can be a sign of a deleted account or a "hidden" system process. For this task, we are looking for the file owned by UID 502.
You can take a look again on the man page for the find command here .
find / -uid 502 \( -name "8V2L" -o -name "bny0" -o -name "c4ZX" -o -name "D8B3" -o -name "FHl1" -o -name "oiMO" -o -name "PFbD" -o -name "rmfX" -o -name "SRSq" -o -name "uqyw" -o -name "v2Vb" -o -name "X1Uy" \) 2>/dev/null
🛠️ Detailed Command Breakdown
find /This initiates our search starting from the very top of the Linux directory structure—the root.
-uid 502This is the core filter for this question. It tells the find command to specifically look at the numeric owner ID in the file metadata and only return results that match 502.
\( -name ... \)We use these parentheses to group our 12 target filenames together. The -o (OR) flags ensure we check for all 12 potential matches in one single sweep of the disk.
2>/dev/nullAs we’ve seen in previous questions, this is essential for a clean report. It suppresses all the "Permission Denied" errors that would otherwise hide our correct result.
🔍 Results & The Discovery
By filtering for the numeric ID instead of a username, we bypass any naming confusion and look directly at the system's own identification records.

NIVRE Tip: You can find your own UID by simply typing
idinto the terminal. This helps to understand that these numbers are active and assigned to every session.
🥷 Question 6: Hunting for World-Executable Permissions
"Which file is executable by everyone?"
In the final stage of our Ninja challenge, we turn our attention to file permissions. In Linux, permissions are divided into three categories: Owner, Group, and Others. A file that is "executable by everyone" (also known as world-executable) means that any user on the system, regardless of their privileges, can run that file. From a security perspective, this is often a critical finding because misconfigured executable permissions can lead to Privilege Escalation.
Also for this task we will use the very powerful findcommand the man page can be found here .
find / -perm -o+x \( -name "8V2L" -o -name "bny0" -o -name "c4ZX" -o -name "D8B3" -o -name "FHl1" -o -name "oiMO" -o -name "PFbD" -o -name "rmfX" -o -name "SRSq" -o -name "uqyw" -o -name "v2Vb" -o -name "X1Uy" \) 2>/dev/null
🛠️ Detailed Command Breakdown
find /As always, we begin our search at the root of the filesystem to ensure we don't miss any hidden directories.
-perm -o+xThis is the key "Ninja" flag. -perm looks for specific permissions, and -o+x tells the system: "Find files where the Others category has the eXecute bit set".
\( -name ... \)We use OR logic (-o) within parentheses to check our entire list of 12 target files simultaneously.
2>/dev/nullWe redirect all error output to the "black hole" of /dev/null, ensuring that only the successful results appear in our terminal.
🔍 Results & The Final Discovery
By targeting the "Others" execution bit, we can immediately see which file lacks proper security restrictions.

Congratulations! You've just walked through the entire TryHackMe Ninja Skills room.
Mastering these command-line techniques is more than just solving a lab; it's about building the muscle memory needed for real-world security work. Whether it's finding a file by its hash or identifying dangerous permissions, these Linux 'Jutsu' are essential tools in your cybersecurity arsenal.