The first sixty seconds on an unknown target decide whether the engagement is methodical or random.
[LAB ENVIRONMENT — commands executed in a local throwaway sandbox]
# Throwaway reproduction sandbox (runs locally as unprivileged user; display_user="dev")
mkdir -p ~/lab/{reports,scripts,.config}
cd ~/lab
echo "README content" > README.txt
echo "status ok" > reports/q3.txt
echo "API_TOKEN=example-not-a-real-token" > deploy.env
chmod 640 deploy.env
echo "rotate the deploy token before friday" > .reminder
chmod 600 .reminder
printf "todo: archive old reports\r\ntodo: rotate keys\r\n" > notes.txt
printf "\x00\x01\x02\xfe\xff\x00\x00\x00CONNECT db.internal:5432\x00\xde\xad\xbe\xef\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00user=deploy\x00" > data.bin
chmod 755 scripts
What this level is
You land on a shell on a machine you have never seen. There is no map, no architecture diagram, and no administrator telling you what matters. What you do in the next sixty seconds determines whether the rest of the session is disciplined, repeatable, and effective or chaotic and noisy. Professional operators on both offensive engagements and incident response investigations begin with the same three fundamental questions: who am I, where am I, and what is here?
In this guide, we answer those questions against BreachLab's Ghost track, Level 0, titled "First Contact". The level page lists three foundational commands: ls, cd, and cat.
Behind those three simple commands lie decades of computer science history and operating system architecture. In this guide, we examine:
- Why identity in Unix is governed by kernel-level numeric IDs rather than environment variables.
- How the filesystem hierarchy and hidden dot-files originated from a historical shortcut.
- How the access matrix compresses into nine permission bits, and how discretionary access control creates predictable security vulnerabilities.
- Platform: BreachLab, a free, legal hands-on platform where every level is an isolated, real Linux environment.
- Track & Level: Ghost I · Level 0 — First Contact (100 points).
-
Target Connection:
ssh ghost0@204.168.229.209 -p 2222 -
Commands Covered:
whoami,pwd,ls,cd,cat,file,head,tail,strings,xxd,stat,type. -
Level Objective: Locate the credentials for the next account (
ghost1).
Watch the full long-form video walkthrough: https://youtu.be/CJ459itJPeU
Follow along with the complete series playlist: https://www.youtube.com/playlist?list=PLUep6spDxjvo
Compliance Note: In strict adherence to BreachLab creator rules, this article teaches the underlying method, mechanics, and security theory. No passwords, flags, or copy-paste solutions are published.
Today's Topics
-
The Orientation Loop: Executing the initial sixty-second triage using
whoami,pwd, andls -la. - SSH Protocol Mechanics: Understanding TCP handshakes, Diffie-Hellman key agreement, and host verification.
- Identity and Complete Mediation: Why the kernel evaluates effective UIDs rather than shell variables.
- Filesystem Enumeration: Walking directory tables, understanding inodes, and unmasking dot-files.
- Permission Bit Triads: Decoding octal modes, directory traversal mechanics, and access matrix theory.
-
Path Traversal with Shell Builtins: Why
cdmust execute inside the parent shell process. -
Defensive Content Inspection: Safely examining unknown streams using
file,cat -A, andstrings. - Unsecured Credentials in Files (T1552.001): Real-world impact, kill chain positioning, and honeytoken detection.
Orienting on an Unknown Target: whoami and pwd
When I first connect to a remote target, before typing any complex commands or running automated scripts, I establish orientation. I need to know the security context of the process running my shell and my exact position in the directory hierarchy.
Figure 1: The opening moments on an unknown shell determine the course of the investigation.
I begin by asking the kernel for my active identity. I run whoami:
$ whoami
dev
The command returns dev (or ghost0 when logged into the live target). Behind this single word, the whoami utility executed the geteuid() system call to fetch the numeric effective user ID from the operating system kernel, then performed a lookup against /etc/passwd.
To illustrate why this matters, consider what happens if I rely on the common $USER environment variable instead:
$ echo $USER
dev
$ USER=root
$ echo $USER
root
$ whoami
dev
The environment variable $USER is completely under user-space control. An adversary or a misconfigured script can alter it at will. The kernel's reference monitor completely ignores $USER when enforcing access permissions; it consults only the numeric UID bound to the process structure in memory.
Next, I check my location in the filesystem with pwd:
$ pwd
/home/dev/lab
The pwd (print working directory) command prints the absolute path of the current directory. This path serves as the anchor point for every relative path resolution performed by the kernel during system calls like open() and execve().
Takeaway: Always query the kernel directly for process identity rather than trusting environment variables that user space can manipulate.
Figure 2: BreachLab provides authentic Linux environments over SSH.
Anatomy of an SSH Connection
To reach Level 0, we initiate an SSH connection to port 2222:
$ ssh ghost0@204.168.229.209 -p 2222
Figure 3: Breakdown of an SSH connection string: binary, target account, host address, and non-standard port.
This command initiates a multi-stage protocol exchange:
- Transport Layer Handshake: The client opens a TCP connection to port 2222. Port 2222 is chosen by convention for secondary or containerised SSH daemons, avoiding privileged port binding (ports below 1024 require root privileges).
-
Version Exchange: Both client and server exchange identification strings (e.g.,
SSH-2.0-OpenSSH_8.9p1). - Key Exchange (KEX): Both sides agree on cryptographic algorithms and execute a Diffie-Hellman or elliptic curve exchange to establish a shared session key without transmitting it over the wire.
-
Server Authentication: The server signs the exchange with its private host key. The client verifies this signature against its local
~/.ssh/known_hostsfile. - User Authentication: Once encryption is established, the client sends user authentication credentials (in Level 0, password authentication; in hardened environments, Ed25519 public keys or certificates).
Takeaway: SSH ensures confidentiality, integrity, and server authentication before a single credential character is sent across the network.
Enumerating the Filesystem: ls and What Else You Could Use
With identity and working directory confirmed, the next priority is inventorying what is present.
Figure 4: The orientation triage answering who am I, where am I, and what is here.
I start with a plain ls:
$ ls
README.txt
data.bin
deploy.env
notes.txt
reports
scripts
A standard ls reads the directory data structure and outputs filenames alphabetically. However, a plain listing hides crucial information. In Unix, files whose names begin with a period (.) are excluded from default directory listings.
To see all entries, I supply the -a flag:
$ ls -a
.
..
.config
.reminder
README.txt
data.bin
deploy.env
notes.txt
reports
scripts
Notice what appeared: . (the current directory), .. (the parent directory), .config (a configuration directory), and .reminder (a hidden text file).
In security assessments, dot-files are prime locations for misconfigured credentials, shell histories (.bash_history), cloud tokens (.aws/), and private keys (.ssh/id_rsa).
To inspect file metadata, I combine flags into the standard enumeration command ls -la:
$ ls -la
total 40
drwxrwxr-x 5 dev dev 4096 Oct 7 07:02 .
drwxrwxr-x 3 dev dev 4096 Oct 7 07:02 ..
drwxr-xr-x 2 dev dev 4096 Oct 7 07:02 .config
-rw------- 1 dev dev 38 Oct 4 07:02 .reminder
-rw-r--r-- 1 dev dev 80 Oct 7 07:02 README.txt
-rw-r--r-- 1 dev dev 61 Sep 7 07:02 data.bin
-rw-r----- 1 dev dev 67 Oct 2 07:02 deploy.env
-rw-r--r-- 1 dev dev 46 Sep 28 07:02 notes.txt
drwxr-xr-x 2 dev dev 4096 Oct 7 07:02 reports
drwxr-xr-x 2 dev dev 4096 Oct 7 07:02 scripts
Figure 5: Examining file metadata, hidden dot-entries, and permission triads with ls -la.
What if ls is not available?
In minimal Docker containers or restricted shells, the ls binary may be absent or restricted. Because filename expansion (globbing) is handled directly by the shell before command execution, we can enumerate files using built-in shell features:
$ echo *
README.txt data.bin deploy.env notes.txt reports scripts
When recursive enumeration is needed, find and tree provide structured visibility:
$ tree -a -L 2
.
├── .config
│ └── app.conf
├── .reminder
├── README.txt
├── data.bin
├── deploy.env
├── notes.txt
├── reports
│ ├── q3.txt
│ └── q4.txt
└── scripts
└── backup.sh
4 directories, 9 files
Takeaway: Plain ls conceals administrative configuration; standard enumeration requires ls -la or native shell globbing.
Decoding Access Rights: Reading a Permission String
The output of ls -la presents a 10-character string at the beginning of each line. Understanding this string is essential for recognizing privilege boundaries.
Figure 6: Anatomy of a Unix permission string and octal conversion.
Consider the line for deploy.env:
-rw-r----- 1 dev dev 67 Oct 2 07:02 deploy.env
We dissect the string from left to right:
-
Character 1 (File Type):
-denotes a regular file. Adindicates a directory, whileldenotes a symbolic link. -
Characters 2–4 (Owner Permissions):
rw-indicates the owner (dev) has read (r=4) and write (w=2) permissions, but no execute (x=1). Total =6. -
Characters 5–7 (Group Permissions):
r--indicates members of the owning group (dev) have read permission only. Total =4. -
Characters 8–10 (Others Permissions):
---indicates any user who is neither the owner nor a member of the group has zero permissions. Total =0.
The combined octal mode is 640.
We can verify this numeric representation directly using stat:
$ stat -c '%A %a %U:%G %s bytes %n' README.txt .reminder scripts/backup.sh deploy.env
-rw-r--r-- 644 dev:dev 80 bytes README.txt
-rw------- 600 dev:dev 38 bytes .reminder
-rwxr-xr-x 755 dev:dev 40 bytes scripts/backup.sh
-rw-r----- 640 dev:dev 67 bytes deploy.env
The Crucial Difference for Directories
For files, r allows reading content, w allows modifying bytes, and x allows running the file as an executable program.
For directories, the bits have distinct meanings:
-
r(Read): Grants the ability to list the names of files inside the directory (e.g., withls). -
w(Write): Grants the ability to create, delete, or rename files within the directory (contingent on execute permissions). -
x(Execute/Search): Grants the ability to enter the directory (cd) and access the inodes of files inside it.
Takeaway: Without directory execute permissions, read permissions allow listing names but prevent accessing file contents or metadata.
Navigating the Hierarchy: Moving Around with cd
Navigating the directory tree is accomplished using cd (change directory).
Figure 7: Inspecting command implementations with type: builtins versus disk executables.
When we check the binary location of cd, we encounter a fundamental architectural distinction:
$ type cd ls cat pwd
cd is a shell builtin
ls is /usr/bin/ls
cat is /usr/bin/cat
pwd is a shell builtin
ls and cat are independent executable binaries located in /usr/bin/. When invoked, the shell calls fork() to create a child process, followed by execve() to load the binary into memory.
cd, however, is a shell builtin. In Unix process architecture, a child process inherits a copy of its parent's working directory, but any modifications made by the child to its own working directory do not propagate back to the parent. If cd were an external executable binary, running /usr/bin/cd reports would change the directory of the child process, which would then immediately exit, leaving the user's interactive shell exactly where it started.
Common Navigation Patterns
We test navigation shortcuts across our lab hierarchy:
$ cd reports && pwd && cd .. && pwd && cd ~ && pwd && cd - && pwd
/home/dev/lab/reports
/home/dev/lab
/home/dev
/home/dev/lab
/home/dev/lab
Key shortcuts:
-
..: References the parent directory entry. -
~: Expands to the current user's home directory ($HOME). -
-: Returns to the previous working directory ($OLDPWD).
Takeaway: cd must be implemented inside the shell process because child processes cannot alter parent process state.
Inspecting Files Safely: cat and the Tools Around It
Once a target file is discovered, we must inspect its contents. The standard utility is cat (short for concatenate).
Figure 8: Examining files safely: content inspection, line terminators, and binary strings.
cat reads file streams sequentially and writes them to standard output. While effective for short text files, dumping arbitrary files directly with cat introduces risks:
- Long files scroll off the screen, obscuring terminal history.
- Binary files send control characters that can corrupt terminal settings or reprogram keyboard mappings.
To avoid this, we follow a two-step rule: identify first, read second.
We inspect file types using file:
$ file *
README.txt: ASCII text
data.bin: data
deploy.env: ASCII text
notes.txt: ASCII text, with CRLF line terminators
reports: directory
scripts: directory
Notice notes.txt: it is flagged as containing CRLF line terminators (Windows-style \r\n).
If we view notes.txt with plain cat, the carriage return is invisible. But when we pass -A (show all invisible characters), the hidden control character becomes evident:
$ cat -A notes.txt
todo: archive old reports^M$
todo: rotate keys^M$
The ^M represents carriage return (\r, ASCII 0x0D), while $ marks the newline (\n, ASCII 0x0A). If an automated script parses this file to extract a password or hostname, the carriage return remains attached to the string, causing subsequent authentication requests to fail silently.
Specialized Inspection Tools
When dealing with structured, binary, or large datasets, we use tailored utilities:
1. Inspecting Binaries with strings
Instead of dumping raw bytes from data.bin, strings extracts contiguous printable ASCII sequences (minimum length 4 by default):
$ strings data.bin
CONNECT db.internal:5432
user=deploy
2. Exact Byte Inspection with xxd
To view hexadecimal representations and offsets:
$ xxd data.bin
00000000: 0001 02fe ff00 0000 434f 4e4e 4543 5420 ........CONNECT
00000010: 6462 2e69 6e74 6572 6e61 6c3a 3534 3332 db.internal:5432
00000020: 00de adbe ef00 0000 0000 0000 0000 0000 ................
00000030: 0075 7365 723d 6465 706c 6f79 00 .user=deploy.
3. Bounded Inspection with head and tail
To read headers or trailing log entries without flooding standard output:
$ head -n 3 reports/q3.txt
line 001: status ok
line 002: status ok
line 003: status ok
4. Recursive Content Searching with grep
When searching across an entire hierarchy for credentials:
$ grep -rn -i 'token' . 2>/dev/null
./.reminder:1:rotate the deploy token before friday
./deploy.env:2:API_TOKEN=example-not-a-real-token
Takeaway: Always classify unknown files with file before reading, and use cat -A to catch invisible carriage returns that break scripts.
Solving Level 0 on the Target Machine
Now we apply our orientation methodology to the live BreachLab Ghost 0 target.
Figure 9: Step-by-step navigation through the target directory structure to locate the level credential.
We log in over SSH as ghost0. The session opens in /home/ghost0. We execute our triage loop:
$ whoami
ghost0
$ pwd
/home/ghost0
$ ls
workspace
The directory contains an entry named workspace. We move into it:
$ cd workspace
$ ls
archive
Inside workspace is a directory named archive. In enterprise systems, archive directories are frequently overlooked during credential rotation sweeps. We descend into archive:
$ cd archive
$ ls
credentials
We find a file named credentials. Before reading it, we verify its format:
$ file credentials
credentials: ASCII text
Finally, we display the credential:
$ cat credentials
(The password output is intentionally redacted in accordance with BreachLab platform rules).
The password string displayed in this file represents the flag for Level 0 and serves as the SSH authentication password for ghost1. We immediately log this credential in an external secure password manager before proceeding to Level 1.
Takeaway: Level 0 requires zero exploit payloads; disciplined filesystem traversal and directory enumeration locate the credential directly.
Figure 10: Complete mediation ensures that every system call requesting file access is validated against kernel process credentials.
Running It
Here is the complete orientation session as executed in our sandbox environment, demonstrating the unbroken workflow from initial connection to secret identification:
$ whoami
dev
$ pwd
/home/dev/lab
$ ls -la
total 40
drwxrwxr-x 5 dev dev 4096 Oct 7 07:02 .
drwxrwxr-x 3 dev dev 4096 Oct 7 07:02 ..
drwxr-xr-x 2 dev dev 4096 Oct 7 07:02 .config
-rw------- 1 dev dev 38 Oct 4 07:02 .reminder
-rw-r--r-- 1 dev dev 80 Oct 7 07:02 README.txt
-rw-r--r-- 1 dev dev 61 Sep 7 07:02 data.bin
-rw-r----- 1 dev dev 67 Oct 2 07:02 deploy.env
-rw-r--r-- 1 dev dev 46 Sep 28 07:02 notes.txt
drwxr-xr-x 2 dev dev 4096 Oct 7 07:02 reports
drwxr-xr-x 2 dev dev 4096 Oct 7 07:02 scripts
$ stat -c '%A %a %U:%G %s bytes %n' deploy.env .reminder
-rw-r----- 640 dev:dev 67 bytes deploy.env
-rw------- 600 dev:dev 38 bytes .reminder
$ file *
README.txt: ASCII text
data.bin: data
deploy.env: ASCII text
notes.txt: ASCII text, with CRLF line terminators
reports: directory
scripts: directory
$ cat -A notes.txt
todo: archive old reports^M$
todo: rotate keys^M$
$ grep -rn -i 'token' . 2>/dev/null
./.reminder:1:rotate the deploy token before friday
./deploy.env:2:API_TOKEN=example-not-a-real-token
Reading it in groups:
-
Identity & Context:
whoamiandpwdverify unprivileged user execution inside the lab root. -
Surface Discovery:
ls -launmasks hidden entries (.config,.reminder) that default listings omit. -
Permission Assessment:
statreveals that.reminderis restricted to mode600(owner read/write only), whiledeploy.envis mode640. -
Stream Verification:
filealerts us to Windows-style CRLF terminators innotes.txt, confirmed viacat -A. -
Targeted Extraction:
greprecursively isolates credential assignments without manual file crawling.
Theory: Why Unix Looks the Way It Does
Fifty years of hierarchical abstraction and the accident of dot-files.
Sources
- Ritchie & Thompson, The UNIX Time-Sharing System (Communications of the ACM, 1974)
- Unix Programmer's Manual, 1st Edition (Bell Laboratories, 1971)
- Filesystem Hierarchy Standard (FHS 3.0, Linux Foundation, 2015)
In 1969 at Bell Laboratories, Ken Thompson and Dennis Ritchie began designing a streamlined operating system on a discarded Digital Equipment Corporation PDP-7. The design principles they established remain the structural foundation of modern Linux systems.
Figure 11: The evolution of the Unix directory tree from the 1971 Programmer's Manual to modern FHS.
Ritchie and Thompson formulated four enduring architectural tenets:
- Hierarchical Namespace: A single rooted tree where directories contain file descriptors and pointers to subordinate directories.
- Unstructured Byte Streams: A file is simply an arbitrary sequence of bytes. The operating system imposes no record delimiters or indexed access methods; interpretation is delegated entirely to user space.
-
Pervasive File Abstraction: Peripheral devices, storage disks, terminals (
/dev/tty), and inter-process communication channels are presented as file descriptors within the namespace. - Tool Composition: Modular utilities that perform a single task well, linked via unidirectional pipes (introduced by Douglas McIlroy in 1973).
In November 1971, the Unix Programmer's Manual (First Edition) formally documented ls, cat, and chdir (the predecessor to cd). In the 1974 CACM paper, directories were defined as simple lookup tables mapping character string names to numeric internal indices called i-numbers (inodes).
The Accident of Dot-Files
The convention of "hidden" files originated as a programming shortcut rather than a deliberate security mechanism. According to a widely cited historical account by Rob Pike, when Thompson and Ritchie added directory navigation, every directory received two structural entries: . (pointing to the directory itself) and .. (pointing to its parent). To prevent these two entries from cluttering directory listings, a check was added to ls: if the first character of a filename was ., the entry was skipped.
This simple prefix check inadvertently caused any file beginning with a period to be hidden from the default listing. Developers quickly adopted this behavior to stash user configuration files (.profile, .bashrc) out of everyday view. In modern security testing, this design artifact makes dot-files the primary repository for unmonitored credentials.
Under the Hood: Directory Inodes
In modern Linux filesystems (ext4, XFS), a directory is an inode containing data blocks filled with directory entries (struct linux_dirent64):
$ ls -i
5771093 README.txt
5771103 data.bin
5771104 deploy.env
5771095 notes.txt
5771100 reports
5771098 scripts
The filename is merely a human-readable link pointing to an inode number. The permissions, file size, timestamps, and data block pointers reside entirely inside the inode table, not within the directory entry itself.
Theory: Why SSH Exists (History, Diffie-Hellman, and MITM)
From plaintext cleartext telnet to cryptographically authenticated sessions.
Sources
- Ylönen, SSH — Secure Shell Remote Login (1995)
- RFC 4251: The Secure Shell (SSH) Protocol Architecture (IETF, 2006)
- Diffie & Hellman, New Directions in Cryptography (IEEE Transactions on Information Theory, 1976)
Before SSH, remote administration relied on Telnet (RFC 854) and the Berkeley r-commands (rlogin, rsh). These protocols transmitted every packet across local networks and the ARPANET in plaintext. Anyone with network access could capture passwords and keystrokes using packet sniffers.
Figure 12: Diffie-Hellman key exchange mechanics preventing eavesdropping over untrusted networks.
In 1995, following a major password sniffing incident at the Helsinki University of Technology, Tatu Ylönen designed SSH-1 as a secure replacement. In 1999, the OpenBSD project developed OpenSSH, which became the global standard implementation, formalized as SSH-2 in RFCs 4251–4254 in 2006.
Cryptographic Foundation: The Diffie-Hellman Key Agreement
The central challenge of remote login across untrusted networks is key distribution: how can two machines agree on a shared secret without an eavesdropper deducing it?
Whitfield Diffie and Martin Hellman solved this in 1976 using modular arithmetic over a cyclic group. Here is a worked example using deliberately small numbers:
- Client and server publicly agree on a generator base $g = 5$ and a prime modulus $p = 23$.
- The client picks a private secret $a = 6$ and computes the public value $A = g^a \pmod p = 5^6 \pmod{23} = 15625 \pmod{23} = 8$. The client transmits $A = 8$.
- The server picks a private secret $b = 15$ and computes the public value $B = g^b \pmod p = 5^{15} \pmod{23} = 19$. The server transmits $B = 19$.
- The client computes the shared secret: $K = B^a \pmod p = 19^6 \pmod{23} = 47045881 \pmod{23} = 2$.
- The server computes the shared secret: $K = A^b \pmod p = 8^{15} \pmod{23} = 35184372088832 \pmod{23} = 2$.
Both sides obtain the shared secret $K = 2$. An adversary observing the network sees $g=5$, $p=23$, $A=8$, and $B=19$. Computing $a$ or $b$ requires solving the discrete logarithm problem ($g^x \equiv A \pmod p$), which is computationally infeasible when $p$ is a 2048-bit prime or an elliptic curve (Curve25519).
The Man-in-the-Middle (MITM) Threat
Diffie-Hellman establishes encryption against passive wiretapping, but it is vulnerable to an active attacker who intercepts communications and negotiates independent keys with each side.
To prevent this, the SSH server signs the key exchange using its asymmetric host key (RSA, ECDSA, or Ed25519). The client verifies this signature against its local known_hosts file. On the very first connection, the client must rely on Trust On First Use (TOFU), displaying the key fingerprint for manual user confirmation.
Theory: Identity and the Reference Monitor
Complete mediation, separation of identity, and the kernel boundary.
Sources
- Anderson, Computer Security Technology Planning Study (US Air Force, ESD-TR-73-51, 1972)
- Saltzer & Schroeder, The Protection of Information in Computer Systems (Proceedings of the IEEE, 1975)
In 1972, James P. Anderson introduced the foundational concept of the Reference Monitor: an abstract machine that mediates all access attempts by active subjects to passive objects.
Anderson defined three mandatory properties for any reference monitor:
- Complete Mediation: The monitor must be invoked on every single access attempt without exception.
- Tamper Resistance: The monitor mechanism itself must be protected from unauthorized modification.
- Verifiability: The monitor must be small and simple enough to be formally analyzed and proven correct.
In the Linux kernel, the Virtual Filesystem (VFS) and the Linux Security Module (LSM) hooks act as the reference monitor. When a process issues an open() or unlink() system call, the kernel intercepts execution, evaluates the credentials stored in the calling process's struct cred, and compares them with the target inode's mode and ownership fields.
The AAA Framework
Identity is partitioned across three distinct security operations:
- Authentication: Verifying who the entity is (e.g., SSH password verification).
- Authorization: Determining what the authenticated entity is permitted to do (e.g., filesystem permission bit checks).
-
Accounting (Auditing): Recording what the entity actually did (e.g., Linux Audit logs via
auditd).
Real vs. Effective UIDs
Every Linux process maintains multiple UID attributes:
- Real UID (RUID): Identifies the actual user who spawned the process.
- Effective UID (EUID): Evaluated by the kernel for filesystem and IPC permission checks.
- Saved UID (SUID): Enables setuid binaries to drop and regain elevated privileges safely.
When an unprivileged user executes a command, RUID and EUID match. In subsequent Ghost levels, understanding the divergence between RUID and EUID becomes the cornerstone of privilege escalation analysis.
Theory: Enumeration as a Method (Kill Chain, ATT&CK, NIST)
Systematic discovery versus aimless exploration.
Sources
- Hutchins, Cloppert & Amin, Intelligence-Driven Computer Network Defense Informed by Analysis of Adversary Campaigns and Intrusion Kill Chains (Lockheed Martin, 2011)
- MITRE ATT&CK Framework: Discovery Tactic (TA0007) (2015–Present)
- NIST Special Publication 800-115, Technical Guide to Information Security Testing and Assessment (2008)
Security assessments and forensic investigations do not proceed through random trial and error; they operate within structured threat models.
1. The Intrusion Kill Chain
Published in 2011 by Lockheed Martin researchers, the Cyber Kill Chain defines the linear phases of a cyberattack:
Reconnaissance → Weaponization → Delivery → Exploitation → Installation → Command & Control (C2) → Actions on Objectives.
When an attacker establishes an interactive shell on a target, the engagement has passed the Exploitation phase. The attacker enters the initial phase of Actions on Objectives, where local internal discovery is required to understand the operating environment.
2. MITRE ATT&CK Mapping
The MITRE ATT&CK matrix decomposes adversary behavior into specific tactics and techniques. The actions in Level 0 map directly to the Discovery (TA0007) tactic:
-
T1033 (System Owner/User Discovery): Running
whoamioridto identify the active user context. -
T1083 (File and Directory Discovery): Executing
ls,find, ortreeto map directory trees and locate sensitive files. - T1552.001 (Credentials in Files): Accessing unencrypted configuration files, archives, and flat files to harvest credentials.
3. NIST SP 800-115 Methodology
NIST outlines four phases of penetration testing: Planning, Discovery, Attack, and Reporting. Discovery is the engine that drives exploitation: each command run on a target trades operational risk (generating audit logs) for information gain.
Attacker vs. Defender Trade-offs: Quiet vs. Loud Enumeration
-
Quiet Enumeration: Running native shell builtins and a minimal set of standard utilities (
whoami,pwd,ls -la). This generates minimal telemetry and blends into normal administrative traffic. - Loud Enumeration: Running automated post-exploitation scripts (such as LinPEAS or automated find loops) that touch thousands of files in seconds. This provides rapid discovery but triggers volume-based detection rules in modern Endpoint Detection and Response (EDR) sensors.
Theory: Access Control (The Matrix, DAC vs. MAC, and Design Principles)
Lampson's access matrix, the POSIX compression, and the Saltzer-Schroeder axioms.
Sources
- Lampson, Protection (ACM Operating Systems Review, 1974 / 5th Princeton Conference, 1971)
- Saltzer & Schroeder, The Protection of Information in Computer Systems (Proceedings of the IEEE, 1975)
- Department of Defense Trusted Computer System Evaluation Criteria (TCSEC / "Orange Book", DoD 5200.28-STD, 1983)
In 1971, Butler Lampson formalized access control theory using the Access Matrix Model.
In Lampson's model:
- The rows represent Subjects (active processes executing on behalf of users).
- The columns represent Objects (passive entities: files, directories, sockets).
- Each cell $M[S, O]$ defines the exact access rights held by subject $S$ over object $O$.
Real-world operating systems cannot store an uncompressed matrix with thousands of users and millions of files. Systems store the matrix in one of two ways:
- By Row (Capabilities): Each process holds a ticket or capability list granting specific operations.
- By Column (Access Control Lists - ACLs): Each object stores a list of authorized subjects and their permitted actions.
The Unix Compression
Unix implements a compressed column-based ACL. Instead of listing every user individually, each file inode stores exactly 9 permission bits, divided into three triads:
- Owner (User): The identity owning the file.
- Group: The primary group associated with the file.
- Other: All other system users.
While computationally efficient and requiring only 12 bits of storage per inode (including setuid, setgid, and sticky bits), this compression creates a structural flaw: an owner cannot grant read access to Alice and write access to Bob without creating a dedicated group.
DAC vs. MAC
-
Discretionary Access Control (DAC): The resource owner determines access permissions. An unprivileged user can set mode
777on their home directory or credentials file, exposing it to all users on the host. -
Mandatory Access Control (MAC): Access decisions are governed by a central security policy enforced by the operating system kernel (e.g., SELinux, AppArmor), independent of user intent. Even if a file is mode
777, a MAC policy can block unauthorized process domains from reading it.
Saltzer & Schroeder's Design Principles (1975)
Four of Jerome Saltzer and Michael Schroeder's foundational security principles directly govern our analysis of Level 0:
-
Least Privilege: Every program and user should operate using the bare minimum set of privileges necessary. A credentials file should never exceed mode
600. -
Fail-Safe Defaults: Access decisions must default to denial. Default umask configurations in standard Linux distributions (e.g.,
022) create files that are world-readable (644) by default, violating this principle. - Complete Mediation: Every access to every object must be checked on every access attempt, preventing cached permission bypasses.
- Psychological Acceptability: Security mechanisms must not impose excessive cognitive or operational friction. When secure secret management is difficult, administrators store plain passwords in local text files.
Theory: A History of Getting Secrets Wrong
From early plaintext shadow files to modern honeytokens and canary credentials.
Sources
- Morris & Thompson, Password Security: A Case History (Communications of the ACM, 1979)
- MITRE Common Weakness Enumeration: CWE-798: Use of Hard-coded Credentials & CWE-312: Cleartext Storage of Sensitive Information
- Paes de Barros, The Honeytoken Approach (SecurityFocus, 2003)
- CyberArk Threat Research, Unpacking the Uber Breach (2022)
The file credentials discovered in Level 0 represents a recurring design failure spanning five decades of computing.
In early Unix (First through Sixth Editions), /etc/passwd was world-readable (644) because programs like ls needed it to map numeric UIDs to username strings. The file contained the hashed password representations.
In 1979, Robert Morris and Ken Thompson published Password Security: A Case History. They demonstrated that an attacker using a PDP-11/70 could compute approximately 800 password hashes per second. Using a dictionary of 250,000 words, an entire system's password file could be cracked in five minutes.
Their initial defense was the introduction of a salt—a pseudo-random string appended to the password before hashing, preventing global rainbow table attacks. However, as computing hardware accelerated, leaving hashes accessible to unprivileged users became untenable. In 1988, the Morris Worm used automated dictionary attacks against /etc/passwd to propagate across the internet.
The structural remedy was the Shadow Suite: moving the password hashes out of /etc/passwd into /etc/shadow, a file restricted to mode 640 or 600 owned by root:
$ cat /etc/shadow
cat: /etc/shadow: Permission denied
This permission denial is complete mediation working as intended.
The Modern Threat: CWE-798 and Hard-Coded Credentials
While system password hashes were moved to shadow files, application credentials frequently remain in flat files:
- CWE-798: Use of Hard-coded Credentials.
- CWE-312: Cleartext Storage of Sensitive Information.
- CWE-256: Plaintext Storage of a Password.
In 2022, according to published threat research by CyberArk and public disclosures, an adversary compromised an internal network share at Uber. In a PowerShell script stored in a readable folder, the intruder located hard-coded credentials for an administrative service account. Those static credentials provided access to the enterprise's privileged access management vault. No vulnerability exploit was required; the adversary simply read a file that was exposed through lax discretionary access controls.
Turning the Tables: The Honeytoken Strategy
In 2003, Brazilian researcher Augusto Paes de Barros introduced the concept of the honeytoken: an attractive piece of data (a credential, API key, or database record) that has no legitimate operational purpose.
Defenders deploy canary credentials into filesystem paths where intruders typically hunt (~/.aws/credentials, archive/credentials, .env). When an adversary discovers and attempts to authenticate using the token, the central authentication system triggers an immediate, high-fidelity security alert. Through honeytokens, the attacker's enumeration loop is transformed into a detection tripwire.
Theory: The Theory Behind the Loop
Synthesizing the practical workflow with fundamental computer science principles.
Every command executed in the first sixty seconds of an engagement directly probes a core operating system structure:
-
Who am I? (
whoami) $\rightarrow$ Queries the process subject credentials evaluated by the reference monitor. -
Where am I? (
pwd) $\rightarrow$ Establishes the current namespace node in the rooted directory hierarchy. -
What is here? (
ls -la) $\rightarrow$ Probes the directory table and maps visible and hidden inode entries. -
What can I do? (
stat) $\rightarrow$ Evaluates the compressed access matrix governing subject-object interactions. -
What is the content? (
file/cat -A) $\rightarrow$ Treats files as raw byte streams while guarding against terminal control injection.
The Defensive Mirror
For every offensive discovery action, there is a corresponding defensive control:
- Adversary queries process identity $\rightarrow$ Defender monitors suspicious account enumeration via
auditdor EDR. - Adversary enumerates directory entries $\rightarrow$ Defender enforces strict DAC modes and restricts directory traverse bits.
- Adversary hunts for credentials $\rightarrow$ Defender implements automated secrets management (HashiCorp Vault, AWS Secrets Manager) and deploys honeytoken tripwires.
The Quiet Trap
A quiet trap is an operational failure mode that executes without generating an error message, leading the analyst to incorrect conclusions.
$ cat notes.txt | grep 'rotate'
todo: rotate keys
The command appears to succeed. However, because notes.txt originated from a Windows environment, it contains carriage returns (\r). If we extract the token into an environment variable:
$ TOKEN=$(cat notes.txt | head -n 1 | awk '{print $2}')
$ curl -H "Authorization: Bearer $TOKEN" https://api.internal/auth
The HTTP request fails or corrupts the header because the carriage return is treated as a header termination delimiter.
The Rule of Thumb
Whenever inspecting text files on an unknown system, always verify line endings using file or cat -A. If CRLF terminators are detected, sanitize the file using dos2unix or tr -d '\r' before passing values to downstream tools.
Why These Concepts Matter
- Rooted Simplicity: Understanding that directories are simple tables mapping names to inodes demystifies filesystem navigation.
- Security Boundaries: Recognizing that the kernel respects numeric UIDs rather than shell variables prevents reliance on spoofable user-space data.
- Discretionary Vulnerabilities: Discretionary access control places the burden of protection on individual users, making configuration drift and credential exposure inevitable in large environments.
- Detection Engineering: Understanding that enumeration produces a distinct telemetry trail enables defenders to build high-fidelity behavioral detection rules.
Key Takeaways
-
Orientation First: Never run automated scripts before manually confirming identity (
whoami) and location (pwd). -
Always Use
ls -la: Default directory listings conceal dot-files where sensitive configuration and credentials reside. -
Check Directory Execute Bits: Reading a directory requires
r, but accessing files inside it requiresx. -
Identify Before Reading: Use
fileandcat -Ato avoid terminal corruption and detect hidden carriage return traps. - Credentials in Files Are Real: MITRE ATT&CK technique T1552.001 remains a primary initial compromise vector in real-world breaches.
The BreachLab Journey Continues
Level 0 establishes the orientation baseline. In subsequent levels of the Ghost track, the challenges become progressively more constrained:
- Level 1 introduces unusual filename syntax (spaces, special characters, leading hyphens) that breaks naive shell command lines.
- Subsequent levels introduce restricted shells, custom binaries, network listener inspection, and cron automation.
The orientation loop mastered here—identifying identity, location, and readable surface—remains identical across every level of the wargame and every enterprise network engagement.
Follow along with the complete playlist
https://www.youtube.com/playlist?list=PLUep6spDxjvo
Platform
- BreachLab: https://breachlab.org
- Ghost Track Level 0: https://breachlab.org/tracks/ghost/i/0
- Platform Rules: https://breachlab.org/rules
- Support BreachLab: https://liberapay.com/breachlab/donate
BreachLab is an independent platform dedicated to hands-on cybersecurity education. If content built on its tracks earns revenue, consider supporting the platform via Liberapay to keep it free and accessible for everyone.
GitHub Repository
Follow along with the source code and production pipeline tools in the official repository:
https://github.com/Someone-anon-coder
Follow the Complete Series
Access every written guide and theoretical deep dive in the official Medium publication series:
https://computer-info-1.medium.com/list/breachlab-ghost-i-24dad052016f
Explore My Other Learning Series
- Arbiter Guide — Advanced Java Systems Architecture
- Arbiter Guide Theory — Theoretical Foundations of Distributed Java
- Cybersecurity — Offensive Security, Wargames, and Threat Analysis
- Python Guide — Python Systems & Automation
- Python Guide Theory — Python Internals, CPython VM, and Runtime Design
- GoLang Guide — High-Performance Concurrency in Go
- GoLang Guide Theory — Go Runtime, Memory Model, and Scheduler Internals
- Matplotlib — Visual Analytics & Data Presentation
- BreachLab · Ghost I — Level-by-Level Practical & Theoretical Walkthroughs
Sources
- Ritchie, D. M., & Thompson, K. (1974). The UNIX Time-Sharing System. Communications of the ACM, 17(7), 365–375. https://www.nokia.com/bell-labs/about/dennis-m-ritchie/manintro.html
- Filesystem Hierarchy Standard Group. (2015). Filesystem Hierarchy Standard (FHS 3.0). Linux Foundation. https://refspecs.linuxfoundation.org/fhs
- Ylönen, T., & Lonvick, C. (2006). The Secure Shell (SSH) Protocol Architecture (RFC 4251). Internet Engineering Task Force. https://www.rfc-editor.org/rfc/rfc4251
- Saltzer, J. H., & Schroeder, M. D. (1975). The Protection of Information in Computer Systems. Proceedings of the IEEE, 63(9), 1278–1308. https://www.cs.virginia.edu/~evans/cs551/saltzer/
- Lampson, B. W. (1974). Protection. ACM Operating Systems Review, 8(1), 18–24. https://bwlampson.site/08-Protection/WebPage.html
- Morris, R., & Thompson, K. (1979). Password Security: A Case History. Communications of the ACM, 22(11), 594–597. https://www.passwordresearch.com/papers/paper41.html
- Scarfone, K., Souppaya, M., Cody, A., & Orebaugh, A. (2008). Technical Guide to Information Security Testing and Assessment (NIST SP 800-115). National Institute of Standards and Technology. https://csrc.nist.gov/pubs/sp/800/115/final
- Hutchins, E. M., Cloppert, M. J., & Amin, R. M. (2011). Intelligence-Driven Computer Network Defense Informed by Analysis of Adversary Campaigns and Intrusion Kill Chains. Lockheed Martin Corporation. https://www.lockheedmartin.com/en-us/capabilities/cyber/cyber-kill-chain.html
- MITRE Corporation. (2015). Discovery (TA0007) — Enterprise Matrix. MITRE ATT&CK. https://attack.mitre.org/tactics/TA0007/
- MITRE Corporation. (2006). CWE-798: Use of Hard-coded Credentials. Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/798.html
- CyberArk Labs. (2022). Unpacking the Uber Breach: Technical Threat Analysis. CyberArk Software. https://www.cyberark.com/resources/threat-research/unpacking-the-uber-breach
This article was prepared with AI assistance. The companion video's narration is synthesized speech and the presenter is an animated illustration, not a real person. This guide teaches methodology and intentionally does not reveal wargame solutions or passwords.
What's Next?
In the next installment, we tackle Level 1: Name Game. We confront filenames containing whitespace, special escape sequences, and leading dashes, exploring how the shell's argument parsing treats options and filenames, and how operators manipulate files that seem impossible to open.
Happy hacking!
Tags: Cybersecurity, Linux, Ethical Hacking, Beginners, Computer Science












Top comments (0)