Linux File System Hunting: What the OS Reveals When You Start Digging
Most people treat the Linux file system like a drawer; you open it, grab what you need, and close it. But once you start treating it like a crime scene, things get interesting fast.
This isn't a list of commands. It's a record of what I found when I stopped using Linux and started investigating it.
1. /etc/passwd and /etc/shadow - The Split Identity System
What it is: /etc/passwd is a colon-delimited file where each line represents a user account. /etc/shadow stores the actual password hashes, separately.
Why the split exists: Historically, passwords lived directly in /etc/passwd. The problem? That file needs to be world-readable (many programs query it for usernames, UIDs, and home directories). Storing password hashes there meant any user on the system could read them and run offline cracking attacks.
The solution was to split the data. /etc/passwd stays readable. /etc/shadow is owned by root and restricted to the shadow group:
-rw-r----- 1 root shadow 609 Apr 11 00:13 /etc/shadow
What's interesting: Look at the entries in /etc/passwd - most system users like daemon, bin, sys have /usr/sbin/nologin as their shell. This means they exist purely for the OS to assign file ownership and run services under. They're functional identities, not human ones. The OS is full of "ghost users" that never log in but are essential for everything to work.
2. /etc/nsswitch.conf - The Traffic Controller for Name Resolution
What it is: The Name Service Switch configuration file. It tells the OS where to look when it needs to resolve names - username, hostnames, group memberships, network protocols.
hosts: files dns
passwd: files
Why it exists: Linux doesn't hardcode "always check DNS for hostnames." Instead, nsswitch.conf defines a lookup chain. For hosts, it says: check /etc/hosts first (files), then ask DNS. This is why you override any domain locally - your machine checks its own file before ever hitting the network.
What's interesting: This file is the single point that decides whether your system is /etc/hosts - first or DNS-first. If someone tampers with this ordering, they can silently redirect all network lookups without touching DNS at all. It's a subtle but powerful attack surface.
3. /proc/net/tcp - Your Live Network State, in Hex
What it is: A virtual file inside /proc that exposes every active TCP socket on the system, updated in real time. The data is raw hex - IP addresses are in little-endian byte order, ports in hex.
sl local_address rem_address st
3: 00000000:07E8 00000000:0000 0A ← LISTEN
17: CC000415:07E8 4342040A:EA48 01 ← ESTABLISHED
Decoded, 07E8 is port 2024. 0A = LISTEN. 01 = ESTABLISHED.
Why it exists: The kernel maintains socket state internally, and /proc/net/tcp is the kernel directly exposing that table to userspace as a file. Tools like ss and netstat simply read this file and pretty-print it.
What's interesting: You can see every open connection without installing a single tool. In a minimal container or a stripped-down server where netstat isn't available, this file is your raw network state. Reading kernel internals through a file interface is one of Linux's most elegant design decisions.
4. /proc/self/maps - A Running Process's Memory Blueprint
What it is: For any process, /proc/<pid>/maps shows the complete virtual memory layout - every region mapped into the process's address space, with permissions and backing files.
557315b8a000-557315b90000 r-xp ... /usr/bin/head ← executable code (read + execute)
557315b94000-557315bb5000 rw-p ... [heap] ← heap (read + write, no execute)
7eb212228000-7eb2123b0000 r-xp ... /libc.so.6 ← shared library code
Why it exists: The OS needs a per-process virtual address space map to manage memory allocation, enforce permissions, and handle page faults. This file is the kernel letting you read that map directly.
What's interesting: Notice the permissions are tightly scoped. The executable code region is r-xp (read + execute, no write). The heap is rw-p (read + write, no execute). This separation is what makes NX/DEP (No-Execute) work - even if an attacker injects shellcode into the heap, the CPU refuses to execute it because that memory region has no execute permission. You can see the security model directly in this file.
5. /proc/sys/net/ipv4/ip_forward - A Single Byte That Turns Your Machine Into a Router
What it is: A file containing either 0 or 1. When set to 1, the kernel will forward IP packets between network interfaces - turning a regular Linux machine into a router.
$ cat /proc/sys/net/ipv4/ip_forward
0
Why it exists: By default, if a packet arrives on eth0 destined for a different network, Linux drops it. It's not the packet's destination. IP forwarding changes that behaviour - the kernel will now route the packet onward through another interface.
What's interesting: This is how Docker and VPNs work. When you run Docker, it sets ip_forward = 1 so containers can reach the internet. When you set up a VPN server, same thing. A single byte toggle in a file controls fundamental routing behaviour at the kernel level. You can also change it live - write 1 to the file, and it takes effect immediately, no reboot needed. That's the /proc/sys design: runtime kernel configuration through the file system.
6. /etc/login.defs - The Policy File Nobody Talks About
What it is: A configuration file that defines system-wide defaults for user account creation - password ageing, UUID ranges, password length requirements.
PASS_MAX_DAYS 99999
UID_MIN 1000
UID_MAX 60000
Why it exists: When you run useradd, where does it know to start assigning UIDs from 1000? What's the default password expiry? These aren't hardcoded in the binary - they're read from login.defs at runtime.
What's interesting: PASS_MAX_DAYS 99999 means passwords effectively never expire - which is fine for a personal machine, but a misconfiguration on a production server. This is also why 0-999 UIDs are reserved for system accounts and 1000+ are for humans. The entire user ID design of Linux comes from this single config file. Most hardening guides specifically target this file because a lot of systems ship with weak defaults here.
7. /proc/self/status + CapEff - Capabilities, Not Just Root
What it is: /proc/<pid>/status gives a snapshot of a process's state - its PID, parent PID, memory usage, thread count, and critically, its capability bitmask.
CapEff: 00000000a82c35fb
Why it exists: Linux doesn't just have "root" and "not root." It has a fine-grained capability system - 40+ individual privileges like CAP_NET_BAND_SERVICE (bind ports below 1024), CAP_SYS_PTRACE (trace other processes), CAP_CHOWN (change file ownership). A process's effective capabilities (CapEff) are the ones it can currently exercise.
What's interesting: A process can run as a non-root user but still hold specific elevated capabilities - and vice versa, a process running as root might have capabilities dropped intentionally. Containers use this heavily: they drop dangerous capabilities (like CAP_SYS_ADMIN ) even from root processes inside the container. The bitmask in CapEff is the actual truth above what a process can do, not just whether it's UID 0.
8. /dev/null/ , /dev/zero, /dev/random - The Devices That Aren't Devices
What it is: Special device files in /dev that have no physical hardware behind them. They're kernel-implemented abstractions that behave like files.
/dev/null- reads return EOF, writes are discarded/dev/zero- reads return an infinite stream of zero bytes/dev/random- reads return cryptographically secure random bytes (from hardware entropy)/dev/urandom- same, but non-blocking (uses a CSPRNG when entropy is low)
Why they exist: Because Unix's "everything is a file" philosophy means even synthetic, infinite, or void data sources should have file interfaces. > /dev/null to throw away output. dd if=/dev/zero of=file bs=1M count=100 to create a 100MB zero-filled file. /dev/urandom is the source of entropy for TLS key generation, password salts, and UUID generation.
What's interesting: /dev/random historically blocked when kernel entropy was low, causing slowdowns in VMs during key generation. In Linux 5.6+, this was changed - /dev/random and /dev/urandom now behave identically after initial boot entropy is gathered, because the kernel's entropy pool is considered sufficient. A design decision invisible to most users but baked into these files.
9. /etc/pam.d/ - The Authentication Plugin System
What it is: A directory of configuration files that define how authentication works for every service on the system - login, sudo, ssh, passwd, and more. PAM (Pluggable Authentication Modules) is a middleware layer between applications and the actual auth logic.
$ ls /etc/pam.d/
common-auth common-account common-password common-session login sudo ...
Why it exists: Before PAM, every application that needed to authenticate a user had to implement its own logic. If you wanted to add LDAP auth or 2FA, you'd have to patch every binary. PAM separates the authentication mechanism from the application. An app calls PAM, and PAM reads its config to decide what modules to run - local passwords, LDAP, TOTP, smart cards, whatever.
What's interesting: common-auth is a shared config that most services include. If you modify common-auth to require a hardware key, every service that includes it inherits that requirement automatically. Conversely, this is why a misconfiguration in PAM can lock you out of the entire system - it controls authentication at the system layer, not the application layer.
10. /proc/mounts - What the Kernel Actually Thinks Is Mounted
What it is: A live, kernel-maintained view of every filesystem currently mounted on the system, including mount options.
none /sys sysfs ro,noexec,nosuid ...
none /dev/shm tmpfs rw,noexec,nosuid,mode=1777 ...
none /proc proc rw ...
Why it exists: /etc/fstab is what you want mounted at boot. /proc/mounts is what's actually mounted right now. The kernel writes this file dynamically as filesystems are mounted and unmounted.
What's interesting: Look at the mount options./sys is mounted ro (read-only) and noexec - you can't execute files from it or write to it. /dev/shm (shared memory) is noexec, nosuid - shared memory that could be written by any process is explicitly prevented from running code. These aren't defaults you set - they're security decisions baked into the kernel's virtual filesystem mounts. Reading /proc/mounts tells you more about the system's actual security posture than any config file.
The Bigger Picture
What strikes me about Linux's file system is how honest it is. The kernel doesn't hide its state - it exposes it through files. Network connections, memory maps, capabilities, mount options, resolution chains - all of it is readable if you know where to look.
This is by design. The Unix philosophy of "everything is a file" isn't just a cute abstraction. It means the entire operating system is introspectable with the same tools you'd use to read any text file.
If you want to understand a Linux system, don't start with commands. Start with files.
Want More?
Blog: https://blogs.kanishk.codes
Twitter: https://x.com/kanishk_fr
LinkedIn: https://linkedin.com/in/kanishk-chandna
Instagram: https://instagram.com/kanishk__fr


