Ninja Skills is not a boot to root challenge – it’s a series of linux command line exercises mostly focused on advanced use of the find command.

It starts by giving us a list of file names with a teaser: “The aim is to answer the questions as efficiently as possible."

I took that as a challenge to answer each question with a BASH one-liner and with minimal output.

Getting Started

We are provided the following list of file names without their full paths:

  • 8V2L
  • bny0
  • c4ZX
  • D8B3
  • FHl1
  • oiMO
  • PFbD
  • rmfX
  • SRSq
  • uqyw
  • v2Vb
  • X1Uy

The files are all scattered throughout the filesystem so the base of each solution requires us to iterate through the list of files and find its location to start.

We can save the list in a file and wrap our logic in a BASH for loop. The basic structure of each solution will look like this:

for filename in $(cat files); do find / -name $filename 2>/dev/null -exec ... \;; done

Question 1

Which of the above files are owned by the best-group group (enter the answer separated by spaces in alphabetical order)

This is the only solution that doesn’t involve the for loop we just covered. In this case we don’t need to iterate over all the files, we can just use find to search the system only for files belonging to the best-group group.

Then we can pipe the matches to xargs in order to execute basename for each result and strip the path prefix.

Those results get piped to sort since we need to sort them in alphabetical order. Finally we can pipe the sorted results to tr to condense matching filenames to a single line of output by replacing new lines with spaces.


find / -type f -group best-group 2>/dev/null | xargs -I{} basename {} | sort | tr '\n' ' '

Question 2

Which of these files contain an IP address?

We can use grep’s -E flag (otherwise known as extended grep) to search the files for anything matching the regular expression pattern for an IPv4 address.

Since we’re printing out each file name before executing the grep command and want to minimize the output, we can pipe the results back to grep to find any lines containing a period and use the before context flag -B 1 to include the line directly above the match.


for filename in $(cat files); do find / -name $filename 2>/dev/null -exec echo $filename \; -exec grep -E '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}' {} \;; done | grep -B 1 '\.'

Question 3

Which file has the SHA1 hash of 9d54da7584015647ba052173b84d45e8007eba94

The sha1sum command will print the sha1 hash value of a file. Once we have the hash for each file we can pipe that list go grep in order to filter out all but the matching hash.


for filename in $(cat files); do find / -name $filename 2>/dev/null -exec sha1sum {} \;; done | grep 9d54da7584015647ba052173b84d45e8007eba94

Question 4

Which file contains 230 lines?

I’ll be honest - I don’t understand this question. We can use wc -l to get the line count for each file, however all of the files contain 209 lines:

[new-user@ip-10-10-156-243 ~]$ for filename in $(cat files); do find / -name $filename 2>/dev/null -exec wc -l {} \;; done | nl
     1  209 /etc/8V2L
     2  209 /mnt/c4ZX
     3  209 /mnt/D8B3
     4  209 /var/FHl1
     5  209 /opt/oiMO
     6  209 /opt/PFbD
     7  209 /media/rmfX
     8  209 /etc/ssh/SRSq
     9  209 /var/log/uqyw
    10  209 /home/v2Vb
    11  209 /X1Uy

Piping the results to nl was a quick way to get the number of files which is 11, but if we wc -l files we’ll see there are 12 files in our source list.

bny0 is the file missing from our results and that is the accepted answer. But by searching the system for that file, we’ll see it doesn’t exist… 🙃

Question 5

Which file’s owner has an ID of 502?

This solution doesn’t require executing additional commands beyond find. We can simply include the user ID as part of the find’s search criteria.


for filename in $(cat files); do find / -uid 502 -name $filename 2>/dev/null; done

Question 6

Which file is executable by everyone?

Similar to the previous question, we can include the -executable flag as part of find’s search criteria. Since the question specifies the file should be executable by everyone we can also run ls -l on any results that are executable so we can see the permissions.


for filename in $(cat files); do find / -executable -name $filename 2>/dev/null -exec ls -l {} \;; done