# 🔒 The Security Monitor Command Bible
# 🔒 The Security Monitor Command Bible
## A Deep-Dive Into Every Pipe, Redirect, and Subshell
*By FrankSx - When you need to know WHY it works, not just THAT it works*
---
## PREAMBLE: The Philosophy of Defensive Bash
Listen up. Most "security scripts" you'll find online are garbage copy-pasta written by people who think `ps aux | grep nc` is elite. We're going deeper. This document dissectsevery single command, every pipe, every file descriptor manipulation in the Security Monitor Suite.
We will continue this as a ongoing mission to ensure we are adding in new techniques as we find them and allow transparency for public knowlegde of the current state of security and its on-going struggles.
We will try to Keep it funny but we are only robots more or less than others in a
</html>&feline=cat&&F="/"&&{$feline}+{$F}+etc+{$F}+passwd..
Why? Because when you're hunting intruders at 3 AM, you need to know exactly what your tools are doing. No surprises. No black boxes.
---
## PART I: PROCESS ENUMERATION & ANALYSIS
### 1.1 The `ps aux` Pipeline
```bash
ps aux | grep -E '\b(nc|netcat)\b' | grep -v grep
```
**The Breakdown:**
- **`ps aux`** - Process status, All users, User-oriented format, eXtended info
- `a` = Show processes for all users (not just your UID)
- `u` = Display user-oriented format (CPU%, MEM%, START, TIME, COMMAND)
- `x` = Include processes without a TTY (daemons, orphans, potential backdoors)
*Why this matters:* Attackers love orphaned processes. If a shell has no TTY, it's often a sign of a daemonized reverse shell.
- **`|` (Pipe)** - Takes stdout from `ps` and feeds it as stdin to `grep`
- Under the hood: Kernel creates a pipe buffer (typically 64KB on Linux)
- Processes run concurrently; grep starts processing before ps finishes
- **`grep -E '\b(nc|netcat)\b'`** - Extended regex with word boundaries
- `-E` = Extended regex (no need to escape parens for grouping)
- `\b` = Word boundary anchor. Critical here - prevents false positives on words containing "nc"
- Matches: "nc", "netcat", "/usr/bin/nc"
- Excludes: "ncurses", "pnc", "incident"
- `(...|...)` = Alternation group
- **`| grep -v grep`** - Inverted match to filter out the grep process itself
- `-v` = Invert match (return lines that DON'T match)
- Without this, you'd always see the grep command in output (it contains "nc")
**Alternative Approaches (and why we didn't use them):**
```bash
# NO: pgrep -f nc (misses arguments, less visibility)
# NO: pidof nc (only matches exact binary name)
# YES: ps aux ... (gives full command line for analysis)
```
---
### 1.2 Process Substitution with `/proc` Traversal
```bash
inode=$(cat /proc/net/tcp | grep "$(printf '%04X' 38101)" | awk '{print $10}')
find /proc -maxdepth 2 -type l -name "fd" -exec ls -la {} \; 2>/dev/null | grep "socket:[$inode]"
```
**Holy grail of socket-to-process mapping.** This is how you find who owns a port when `lsof` and `fuser` aren't available.
**The Breakdown:**
- **`cat /proc/net/tcp`** - Kernel's TCP socket table exposed as pseudo-file
- Format: `sl local_address rem_address st tx_queue:rx_queue tr:tm->when retrnsmt uid timeout inode`
- `st` = State (0A = LISTEN, 01 = ESTABLISHED)
- `inode` = Socket inode number - the key to finding the owner
- **`printf '%04X' 38101`** - Convert decimal port to hex (required for /proc/net/tcp)
- Port 38101 → 0x94D5
- `%04X` = 4-digit uppercase hex, zero-padded
- Why? Kernel stores addresses in network byte order hex
- **`awk '{print $10}'`** - Extract the inode field (10th column)
- Default field separator is whitespace
- `$10` = inode number
- **`find /proc -maxdepth 2`** - Limit recursion for performance
- `/proc/[PID]/fd/` contains file descriptor symlinks
- `maxdepth 2` = Only check /proc/[PID], not deeper
- **`-type l`** - Look for symbolic links (file descriptors are symlinks)
- **`-exec ls -la {} \;`** - Execute ls on each fd directory found
- `{}` = placeholder for found path
- `\;` = terminator for -exec (escaped for shell)
- **`2>/dev/null`** - Redirect stderr to /dev/null (bit bucket)
- Suppresses "Permission denied" errors for other users' processes
- The `2>` means "redirect file descriptor 2 (stderr)"
- **`grep "socket:[$inode]"`** - Match the socket inode in format `socket:[9683]`
**Why This Matters:**
When you see a listening port but `ss -p` shows no process, this technique finds the culprit. Rootkits often hide from standard tools but can't hide from `/proc` traversal without kernel-level manipulation.
---
## PART II: NETWORK RECONNAISSANCE
### 2.1 The `ss` (Socket Statistics) Arsenal
```bash
ss -tulnp | grep LISTEN
ss -tunp state established | head -15
```
**Modern replacement for `netstat`. Faster because it reads directly from kernel via Netlink sockets instead of parsing `/proc`.**
**Flag Decryption:**
- **`-t`** = TCP sockets only
- **`-u`** = UDP sockets included
- **`-l`** = Listening sockets only
- **`-n`** = Numeric output (don't resolve hostnames or services)
- Critical for speed - DNS lookups can hang for seconds
- Also prevents information leakage to external DNS
- **`-p`** = Show process using socket
- Requires appropriate permissions (root for other users' processes)
**The Pipe to `state established`:**
```bash
ss -tunp state established
```
- `state` = Filter expression
- `established` = Only TCP connections in ESTABLISHED state
- Other states: `syn-sent`, `syn-recv`, `fin-wait-1`, `close-wait`, etc.
**Performance Note:** `ss` is O(1) for most operations vs `netstat` which is O(n) because it has to read and parse `/proc/net/tcp`, `/proc/net/udp`, etc.
---
### 2.2 Connection State Analysis with `awk`
```bash
ps aux | awk '$7 == "?" {print}'
```
**The Breakdown:**
- **`awk`** - Pattern-directed text processing language
- Named after creators: Aho, Weinberger, Kernighan
- **`$7 == "?"`** - Pattern: Match lines where 7th field equals "?"
- In `ps aux` output, field 7 is the TTY (terminal)
- `"?"` means no controlling TTY (daemon process)
- **`{print}`** - Action: Print the entire matching line
- Could be `{print $1, $2, $11}` for just PID and command
**Why Care About "?" TTYs:**
Reverse shells spawned by attackers often have no TTY. They might be:
- Backgrounded shells (`bash &`)
- Netcat listeners
- Python/Perl one-liners spawned by exploits
- Process injection results
---
### 2.3 Port Scanning with Brace Expansion
```bash
for port in "${SUSPICIOUS_PORTS[@]}"; do
ss -tunp | grep -c ":${port}"
done
```
**Array Iteration and Port Checking:**
- **`"${SUSPICIOUS_PORTS[@]}"`** - Quote-protected array expansion
- `@` = Expand all elements as separate words
- Quotes prevent word splitting on elements with spaces
- Without quotes: `"${SUSPICIOUS_PORTS[*]}"` = all elements as single string
- **`grep -c`** = Count matches (returns number, not lines)
- Returns 0 if no matches (important for arithmetic)
- **`":${port}"`** - Port pattern with leading colon
- Matches `:4444` but not `14444` or `44441`
- The colon is the address/port separator in ss output
**The Arithmetic Context:**
```bash
suspicious_conns=$((suspicious_conns + count))
```
- **`$((...))`** = Arithmetic expansion
- No `$` needed for variables inside
- Integer math only (no floats)
- Returns 0 on success, non-zero on overflow
---
## PART III: LOG MANIPULATION & REDIRECTION
### 3.1 Advanced Redirection Patterns
```bash
echo "[$timestamp] [$level] $message" >> "$ALERT_LOG"
```
**Redirection Deep Dive:**
- **`>>`** = Append redirect (creates if doesn't exist, appends if does)
- **`>`** = Overwrite redirect (truncates existing file to 0 bytes)
- **`$ALERT_LOG`** = Variable expansion happens BEFORE redirection
**File Descriptor Internals:**
```bash
echo "text" >> file
# Equivalent to:
echo "text" 1>> file # File descriptor 1 (stdout) appended to file
```
**The Stderr Dance:**
```bash
command 2>/dev/null
# or
command 2>&1 # Redirect stderr (2) to same place as stdout (1)
```
- **`2>&1`** = "Make fd 2 a copy of fd 1"
- Order matters: `>file 2>&1` vs `2>&1 >file` produce different results
---
### 3.2 Process Substitution (The Advanced Pipe)
```bash
comm -23 <(echo "$current_conns") <(echo "$prev_conns")
```
**This is where bash gets sexy.**
- **`<(...)`** = Process substitution (input)
- Runs command and substitutes filename of a FIFO or /dev/fd file
- Allows treating command output as a file
- **`comm -23`** = Compare two sorted files
- `-2` = Suppress lines unique to file 2
- `-3` = Suppress lines common to both
- Result: Only lines unique to file 1 (new connections)
**Why Not Just Use `diff`?**
```bash
# diff shows ALL differences with context
# comm shows set operations (union, intersection, difference)
# comm requires sorted input (hence piping through sort)
```
**The Full Pattern for Connection Diffing:**
```bash
# Get new connections that weren't there before
new_conns=$(comm -23 <(echo "$current_conns" | sort) <(echo "$prev_conns" | sort))
```
---
### 3.3 Here-Strings and Here-Documents
```bash
wc -l <<< "$connections"
grep -q "$pattern" <<< "$data"
```
- **`<<<`** = Here-string (string as input to command)
- No need for `echo "$var" | command`
- Avoids subshell overhead
- Variable expansion happens before passing
**Comparison:**
```bash
# Subshell approach (slower, spawns new process)
echo "$data" | wc -l
# Here-string (faster, no subshell)
wc -l <<< "$data"
```
---
## PART IV: CONTROL STRUCTURES & LOGIC
### 4.1 The Double-Bracket Test
```bash
if [[ -f "$PID_FILE" ]]; then
kill $(cat "$PID_FILE")
fi
```
**`[[` vs `[` vs `test`:**
- **`[[ ... ]]`** = Bash conditional expression (keyword, not builtin)
- No word splitting or pathname expansion
- Supports `&&`, `||` inside
- `=~` for regex matching
- `==` for pattern matching (globbing)
- **`[ ... ]`** = POSIX test command (builtin)
- Older, more portable
- Requires quoting variables (word splitting occurs)
**File Test Operators:**
- `-f` = Regular file exists
- `-d` = Directory exists
- `-e` = Anything exists (file, dir, symlink)
- `-s` = File exists and has size > 0
- `-r` = Readable
- `-w` = Writable
- `-x` = Executable
---
### 4.2 Arithmetic Evaluation Contexts
```bash
if [[ $found -eq 1 ]]; then
return 0
fi
```
**Multiple Ways to Compare Numbers:**
```bash
# Inside [[ ]]
[[ $a -eq $b ]] # numeric equality
[[ $a -lt $b ]] # less than
[[ $a -gt $b ]] # greater than
# Inside (( ))
(( a == b )) # C-style operators
(( a < b ))
(( a > b ))
(( a++ )) # increment
# String comparison (lexicographic)
[[ "$a" == "$b" ]]
[[ "$a" < "$b" ]] # sorts by ASCII value
```
**Exit Code Magic:**
```bash
if check_netcat; then
alerts=$((alerts + 1))
fi
```
- `if command; then` = True if command exits with status 0
- `check_netcat` returns 0 if threats found, 1 if clean
- This is "true when bad" logic - common in security tools
---
### 4.3 Loop Control Structures
```bash
while IFS=':' read -r key value; do
echo " \"$key\": $value,"
done <<< "$stats"
```
**The `read` Built-in:**
- **`IFS=':'`** = Internal Field Separator set to colon
- Only for this command (temporary)
- Default IFS is space/tab/newline
- **`-r`** = Raw mode (don't interpret backslashes)
- Prevents escape sequence interpretation
- ALWAYS use `-r` unless you specifically need escapes
- **`key value`** = Variables to populate
- First field → key
- Remaining fields → value (because only two vars specified)
**The Here-String Input:**
- `<<< "$stats"` feeds the variable content as stdin
- More efficient than `echo "$stats" | while ...`
---
### 4.4 Case Statements for Command Dispatch
```bash
case "$1" in
"--daemon"|"-d")
start_daemon
;;
"")
"$UI_SCRIPT"
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
```
**Pattern Matching:**
- `"--daemon"|"-d"` = OR pattern (either match triggers)
- `""` = Empty string (no arguments provided)
- `*)` = Default case (wildcard)
- **`;;`** = Terminate case (break)
- **`;&`** = Fall-through to next case (rarely used)
- **`;;&`** = Test subsequent patterns (bash 4.0+)
---
## PART V: SUBSHELLS AND BACKGROUNDING
### 5.1 The Subshell Operator
```bash
(
while true; do
"$CORE_SCRIPT" monitor >> "$DAEMON_LOG" 2>&1
sleep 30
done
) &
```
**Parentheses = Subshell:**
- Commands run in a separate process (fork)
- Variable changes don't affect parent shell
- `&` at end backgrounds the entire subshell
**Why Use a Subshell Here?**
- Isolates the daemon logic from main script
- Allows `cd`, variable changes without side effects
- Easier to kill as a unit
**Process Management:**
```bash
local daemon_pid=$!
# $! = PID of last backgrounded command
```
---
### 5.2 Command Substitution
```bash
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
daemon_pid=$!
report_file="$HOME/security_report_$(date +%Y%m%d_%H%M%S).txt"
```
**Two Forms:**
- **`$(command)`** = Modern POSIX form
- Nestable: `$(echo $(echo nested))`
- Easier to read
- Preferred in all modern scripts
- **` `command` `** = Legacy backtick form
- Not nestable without escaping
- Harder to read
- Deprecated but still works
**Word Splitting Dangers:**
```bash
# WRONG: Word splitting occurs
files=$(ls)
for f in $files; do ... # Fails on filenames with spaces
# RIGHT: Quote properly
files=$(ls)
for f in "$files"; do ... # Still wrong - treats all as one
# BETTER: Use globbing
for f in *; do ... # Each file is separate word
```
---
## PART VI: TEXT PROCESSING PIPELINES
### 6.1 The `grep | sed | awk` Trinity
```bash
echo "$line" | grep -oE 'users:\(\("[^"]+"' | sed 's/users:(("//;s/"$//'
```
**Step-by-Step:**
1. **`grep -oE`**:
- `-o` = Only output matching part (not entire line)
- `-E` = Extended regex
- Pattern matches: `users:(("firefox-esr"`
2. **`sed`** stream editor:
- `'s/users:(("//'` = Substitute/remove `users:(("`
- `;` = Separate commands
- `'s/"$//'` = Remove trailing quote
- Result: `firefox-esr`
**Why Chain These?**
- `grep` extracts the relevant substring
- `sed` cleans up the extraction
- Could use `awk -F'"' '{print $2}'` as alternative
---
### 6.2 Sorting and Uniquing
```bash
ss -tunp | grep -oE 'users:\(\("[^"]+"' | sed 's/users:(("//;s/"$//' | sort | uniq -c | sort -rn
```
**The Pipeline Flow:**
1. Extract process names from socket output
2. Clean up the format
3. **`sort`** = Group identical lines together (required for uniq)
4. **`uniq -c`** = Count occurrences of each unique line
- Output: ` 12 firefox-esr`
5. **`sort -rn`** = Reverse numeric sort
- `-r` = Reverse (highest first)
- `-n` = Numeric comparison (not lexicographic)
**Result:** Top processes using network connections, ranked by connection count.
---
### 6.3 Multi-file Output with Group Commands
```bash
{
echo "=== SECURITY MONITOR REPORT ==="
echo "Generated: $(date)"
"$CORE_SCRIPT" stats
} > "$report_file"
```
**Curly Braces `{...}`** = Group command
- Runs in CURRENT shell (not subshell)
- Single redirect applies to ALL output
- All commands share the same stdin/stdout/stderr
**vs Parentheses `(...)`:**
```bash
# Curly braces - same shell, variables persist
{ var=1; }
echo $var # Outputs: 1
# Parentheses - subshell, variables don't persist
( var=2; )
echo $var # Outputs: 1 (unchanged)
```
---
## PART VII: SPECIAL VARIABLES AND PARAMETERS
### 7.1 Positional Parameters
```bash
case "$1" in
"--cli")
"$UI_SCRIPT" --cli
;;
esac
```
**The `$` Variables:**
- **`$0`** = Script name/path
- **`$1` to `$9`** = Positional arguments
- **`${10}`+** = Requires braces (not `$10` which is `$1` + `0`)
- **`$#`** = Number of arguments
- **`$@`** = All arguments ("$@" preserves quotes)
- **`$*`** = All arguments as single word
- **`$?`** = Exit status of last command
- **`$$`** = PID of current shell
- **`$!`** = PID of last background job
**Quote Everything:**
```bash
"$UI_SCRIPT" # Quote variables containing paths
```
---
### 7.2 Default Values and Parameter Expansion
```bash
${total_listening:-0}
${report_file:-/tmp/default_report.txt}
```
**Parameter Expansion Modifiers:**
- `${var:-default}` = Use default if var unset or null
- `${var:=default}` = Set var to default if unset/null
- `${var:?message}` = Display error and exit if unset/null
- `${var:+replacement}` = Use replacement if var is set
**String Manipulation:**
```bash
${var#pattern} # Remove shortest match from beginning
${var##pattern} # Remove longest match from beginning
${var%pattern} # Remove shortest match from end
${var%%pattern} # Remove longest match from end
${var/old/new} # Replace first occurrence
${var//old/new} # Replace all occurrences
${var:offset:length} # Substring extraction
```
---
## PART VIII: ERROR HANDLING AND SIGNALS
### 8.1 The `trap` Command
```bash
trap "rm -f '$PID_FILE'" EXIT
```
**Signal Handling:**
- **`EXIT`** = Pseudo-signal, fires on script exit (normal or error)
- **`INT`** = Ctrl+C (SIGINT)
- **`TERM`** = Termination signal (SIGTERM)
- **`HUP`** = Hangup signal (SIGHUP)
**Multiple Traps:**
```bash
trap cleanup EXIT
trap 'echo "Interrupted"; exit 1' INT TERM
```
**Why Quote the Command:**
- Variables expand when trap is DEFINED, not when executed
- Use single quotes to delay expansion: `trap 'rm -f "$file"' EXIT`
- Double quotes expand immediately: `trap "rm -f '$file'" EXIT` (file locked at trap time)
---
### 8.2 Exit Codes and Boolean Logic
```bash
check_netcat() {
# ... detection logic ...
if [[ $found -eq 1 ]]; then
return 0 # Success (we found threats)
else
return 1 # Failure (no threats found)
fi
}
```
**Exit Code Semantics:**
- `0` = Success / True / Found
- `1-255` = Error / False / Not found
- `126` = Command not executable
- `127` = Command not found
- `130` = Script terminated by Ctrl+C (128 + 2)
**Chaining:**
```bash
command1 && command2 # Run command2 ONLY if command1 succeeds
command1 || command2 # Run command2 ONLY if command1 fails
command1 ; command2 # Run both (sequential)
```
---
## PART IX: ADVANCED PATTERNS
### 9.1 Debugging Techniques
```bash
#!/bin/bash
set -euo pipefail
# -e = Exit on error
# -u = Exit on unset variable reference
# -o pipefail = Pipeline fails if ANY command fails (not just last)
```
**Why We Didn't Use These:**
The security monitor scripts are designed to be resilient. A single failed `ss` command shouldn't kill the entire monitoring operation.
**Selective Debugging:**
```bash
# Enable debug mode for specific section
set -x
sensitive_operation
set +x
```
---
### 10.1 The Complete Monitoring Pipeline
```bash
ss -tunp state established 2>/dev/null | \
grep -v "127.0.0.1\|::1" | \
head -15
```
**Line Continuation:**
- `\` at end of line = Continues command on next line
- Required for readability in long pipelines
- Must be LAST character on line (no trailing spaces)
**The 2>/dev/null Placement:**
- Applied to `ss` command specifically
- Could be at end: `| head -15 2>/dev/null`
- At beginning: suppresses errors from the tool itself
---
## APPENDIX: QUICK REFERENCE TABLE
| Command | Purpose | Key Flags |
|---------|---------|-----------|
| `ps aux` | Process listing | a=all, u=user format, x=no tty |
| `ss -tulnp` | Socket stats | t=tcp, u=udp, l=listen, n=numeric, p=process |
| `grep -E` | Extended regex | -E=extended, -v=invert, -c=count, -o=only-match |
| `awk '{print $1}'` | Field extraction | $N = Nth field |
| `sed 's/old/new/g'` | Stream editor | s=substitute, g=global |
| `sort | uniq -c` | Count unique | -c=count, sort required first |
| `head -n` / `tail -n` | Line limiting | -n=number of lines |
| `wc -l` | Line count | -l=lines only |
| `find /proc` | File search | -type f/d/l, -name pattern, -exec cmd {} \; |
| `trap 'cmd' SIGNAL` | Signal handling | EXIT, INT, TERM, HUP |
| `$((expr))` | Arithmetic | Integer math, no $ needed inside |
| `$(cmd)` | Command substitution | Modern form, nestable |
| `<(cmd)` | Process substitution | Treat output as file |
| `<<< "string"` | Here-string | String as stdin |
| `cmd &` | Background | $! gets PID |
| `cmd1 \| cmd2` | Pipeline | stdout→stdin, concurrent |
| `cmd >file` | Redirect stdout | > = overwrite, >> = append |
| `cmd 2>&1` | Redirect stderr | Merge stderr to stdout |
| `cmd 2>/dev/null` | Suppress errors | Send stderr to void |
---
## FINAL WORDS
This isn't just documentation. It's a survival guide. When you're in the trenches at 3 AM responding to an incident, understanding WHY `2>/dev/null` silences that permission denied error could be the difference between finding the backdoor and missing it.
Every pipe is a decision. Every redirect is data flow. Every subshell is isolation. Master these primitives and you master the shell.
*Stay paranoid. Stay safe.*
— FrankSx
---
*Document Version: 1.0*
*Generated for Security Monitor Suite v2.0*
*License: Use it, share it, learn from it.*
Comments
Post a Comment