Lab โ Sandbox & Isolation: Containment Strategies for Malicious Code¶
| Field | Details |
|---|---|
| Course | SCIA-360 OS Security |
| Topic | Sandbox & Isolation: Containment Strategies for Malicious Code |
| Chapter | 11 โ Linux Security Architecture In Depth |
| Difficulty | โญโญ Intermediate |
| Estimated Time | 75โ90 minutes |
| Requires | Docker Desktop, terminal |
Overview¶
When malicious code executes on a system it attempts to: read sensitive files, escalate privileges, communicate with attacker-controlled servers, persist via the filesystem, and exhaust resources to deny service. Sandboxing and isolation are the OS-level mechanisms that contain malicious code within strict boundaries so that even if it runs, it cannot cause catastrophic harm.
Docker containers are an ideal vehicle for studying these mechanisms because each docker run flag directly corresponds to a Linux kernel isolation primitive. In this lab you will observe โ with live proof โ how five layered containment strategies work together:
| Layer | Mechanism | Kernel Primitive |
|---|---|---|
| Process isolation | PID namespace | clone(CLONE_NEWPID) |
| Filesystem isolation | Overlay FS + read-only mounts | OverlayFS, MS_RDONLY |
| Syscall filtering | seccomp-BPF | prctl(PR_SET_SECCOMP) |
| Privilege restriction | Capabilities | CAP_* via prctl |
| Resource limits | Memory/CPU caps | cgroups v2 |
| Network isolation | Network namespace | clone(CLONE_NEWNET) |
| Privilege escalation prevention | NoNewPrivileges | prctl(PR_SET_NO_NEW_PRIVS) |
Learning Objectives¶
By the end of this lab you will be able to:
- Explain how Linux namespaces isolate containers from the host and from each other
- Demonstrate that a container's writes do NOT persist to the host filesystem
- Apply a custom seccomp profile to block specific dangerous syscalls
- Show how
--cap-drop=ALLrestricts root inside a container - Prove that cgroup resource limits kill runaway processes (OOM scenario)
- Use
--network=noneto air-gap a malware analysis sandbox - Verify that
--no-new-privilegesprevents setuid escalation
Prerequisites¶
- Docker Desktop installed and running
- A terminal (PowerShell on Windows, Terminal on macOS/Linux)
- Basic Linux command familiarity
Part 1 โ PID Namespace Isolation¶
Linux PID namespaces give each container its own process tree starting at PID 1. A malicious process inside the container cannot see, signal, or kill processes on the host.
Step 1.1 โ Launch the sandbox container¶
Step 1.2 โ Observe the isolated PID namespace¶
Inside the container, run:
echo "=== Container process tree ==="
ps aux
echo ""
echo "=== Total visible processes ==="
ps aux | wc -l
Expected output:
=== Container process tree ===
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4372 3328 ? Ss 17:58 0:00 bash
root 7 0.0 0.0 7072 3108 ? R 17:58 0:00 ps aux
=== Total visible processes ===
4
The container sees only 2 processes (bash + ps) โ not the hundreds of processes running on your host. Container PID 1 is the shell, not the host's systemd or init. A malicious process cannot enumerate host processes, inject into them, or signal them.
Exit the container with exit before moving to the next step.
๐ธ Screenshot checkpoint Sa: Capture the ps aux output showing only 2โ4 processes with PID 1 being bash.
Part 2 โ Filesystem Isolation¶
Docker uses OverlayFS to give each container an isolated copy-on-write layer over the base image. Writes inside the container never touch the host filesystem.
Step 2.1 โ Simulate malware writing to sensitive locations¶
This simulates what malware typically does after gaining code execution: modify credential files and plant persistence mechanisms.
docker run --rm ubuntu:22.04 bash -c '
echo "=== Malware writes inside container ==="
echo "PWNED" > /etc/malicious.txt
cat /etc/malicious.txt
echo ""
ls -la /etc/malicious.txt
echo "File exists and is writable inside the container"
'
Expected output:
=== Malware writes inside container ===
PWNED
-rw-r--r-- 1 root root 6 Apr 20 17:58 /etc/malicious.txt
File exists and is writable inside the container
Step 2.2 โ Verify the host is unaffected¶
After the container exits (it used --rm), check the host:
ls /etc/malicious.txt 2>/dev/null && echo "LEAKED TO HOST" || echo "/etc/malicious.txt does NOT exist on host โ isolation works!"
Expected output:
The container's write layer was discarded on exit. The host /etc is completely untouched.
๐ธ Screenshot checkpoint Sb: Capture both the container output (showing the file was written) and the host verification (showing the file does not exist on the host).
Part 3 โ Read-Only Filesystem Enforcement¶
For malware analysis sandboxes, --read-only mounts the entire container filesystem read-only. Even if malicious code runs, it cannot modify any file โ persistence is structurally impossible.
Step 3.1 โ Run malware in a read-only sandbox¶
docker run --rm --read-only ubuntu:22.04 bash -c '
echo "=== Read-only root filesystem ==="
echo "Attempting to write to /etc/cron.d (persistence via cron)..."
echo "malware" > /etc/cron.d/evil 2>&1 || echo "/etc write BLOCKED โ read-only filesystem"
echo ""
echo "Attempting to write to /tmp (staging area for malware)..."
echo "test" > /tmp/evil.sh 2>&1 || echo "/tmp write BLOCKED โ read-only filesystem"
echo ""
echo "Read operations still work fine:"
cat /etc/os-release | head -3
'
Expected output:
=== Read-only root filesystem ===
Attempting to write to /etc/cron.d (persistence via cron)...
/etc write BLOCKED โ read-only filesystem
Attempting to write to /tmp (staging area for malware)...
/tmp write BLOCKED โ read-only filesystem
Read operations still work fine:
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
Step 3.2 โ Production pattern: read-only root + ephemeral /tmp¶
Real applications need a writable scratch space. The standard pattern gives --tmpfs /tmp while keeping the rest immutable:
docker run --rm --read-only --tmpfs /tmp ubuntu:22.04 bash -c '
echo "=== Read-only root + tmpfs /tmp (production pattern) ==="
echo ""
echo "Writing to /etc (still blocked):"
echo "evil" > /etc/passwd_mod 2>&1 || echo "/etc write BLOCKED"
echo ""
echo "Writing to /tmp (allowed via ephemeral tmpfs):"
echo "safe scratch space" > /tmp/workfile.txt
cat /tmp/workfile.txt
echo "/tmp write allowed โ ephemeral tmpfs, cleared on container stop"
'
Expected output:
=== Read-only root + tmpfs /tmp (production pattern) ===
Writing to /etc (still blocked):
/etc write BLOCKED
Writing to /tmp (allowed via ephemeral tmpfs):
safe scratch space
/tmp write allowed โ ephemeral tmpfs, cleared on container stop
๐ธ Screenshot checkpoint Sc: Capture the output showing /etc writes blocked and /tmp writes allowed with --tmpfs.
Part 4 โ seccomp: Syscall-Level Filtering¶
seccomp-BPF (Secure Computing Mode with Berkeley Packet Filter) lets you define a policy that permits only specific system calls. Docker applies a default seccomp profile that blocks ~44 dangerous syscalls (including ptrace, reboot, kexec_load). You can write custom profiles to block additional calls.
Step 4.1 โ Observe Docker's default seccomp blocking dangerous syscalls¶
docker run --rm ubuntu:22.04 bash -c '
echo "=== Default seccomp: mount() is blocked ==="
mount --bind /tmp /mnt 2>&1 || echo "mount BLOCKED by seccomp/capabilities โ as expected"
echo ""
echo "=== Kernel module loading is also blocked ==="
apt-get install -qq -y kmod 2>/dev/null
modprobe dummy 2>&1 || echo "modprobe BLOCKED โ container cannot load kernel modules"
'
Expected output:
=== Default seccomp: mount() is blocked ===
mount: /mnt: permission denied.
mount BLOCKED by seccomp/capabilities โ as expected
=== Kernel module loading is also blocked ===
modprobe BLOCKED โ container cannot load kernel modules
Step 4.2 โ Write a custom seccomp profile to block chmod¶
Create a custom profile that blocks the chmod family of syscalls. This simulates a malware analysis sandbox where you want to prevent the sample from changing file permissions to execute dropped payloads.
First, exit any running containers. On your host terminal, create the profile file:
cat > /tmp/block-chmod.json << 'EOF'
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"names": ["chmod", "fchmod", "fchmodat"],
"action": "SCMP_ACT_ERRNO",
"errnoRet": 1
}
]
}
EOF
Now run the container with the custom profile:
docker run --rm --security-opt seccomp=/tmp/block-chmod.json ubuntu:22.04 bash -c '
echo "=== Custom seccomp: chmod family is blocked ==="
touch /tmp/test.txt
chmod 777 /tmp/test.txt 2>&1 || echo "chmod BLOCKED by custom seccomp profile โ as expected!"
echo ""
echo "=== Other operations (write, read) still work ==="
echo "hello sandbox" > /tmp/test.txt
cat /tmp/test.txt
echo "read/write allowed!"
'
Expected output:
=== Custom seccomp: chmod family is blocked ===
chmod: changing permissions of '/tmp/test.txt': Operation not permitted
chmod BLOCKED by custom seccomp profile โ as expected!
=== Other operations (write, read) still work ==="
hello sandbox
read/write allowed!
How seccomp profiles work
"defaultAction": "SCMP_ACT_ALLOW"โ allow all syscalls by default (allowlist exceptions)"SCMP_ACT_ERRNO"โ return an error code instead of executing the syscall- This is kernel-level enforcement โ it cannot be bypassed from user space, even by root inside the container
๐ธ Screenshot checkpoint Sd: Capture the seccomp output showing chmod BLOCKED and read/write allowed.
Part 5 โ Linux Capabilities: Least-Privilege Root¶
By default, Docker's root has a reduced but still significant capability set. The --cap-drop=ALL flag removes every capability, then --cap-add restores only what is needed. This implements the principle of least privilege even for root inside the container.
Step 5.1 โ Compare capability sets¶
echo "=== Default container capabilities (CapEff in hex) ==="
docker run --rm ubuntu:22.04 grep "^Cap" /proc/self/status
echo ""
echo "=== --cap-drop=ALL: zero capabilities ==="
docker run --rm --cap-drop=ALL ubuntu:22.04 grep "^Cap" /proc/self/status
Expected output:
=== Default container capabilities (CapEff in hex) ===
CapInh: 0000000000000000
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb โ many capabilities active
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
=== --cap-drop=ALL: zero capabilities ===
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000 โ no capabilities at all
CapBnd: 0000000000000000
CapAmb: 0000000000000000
CapEff=0000000000000000 means even root inside this container has no special OS privileges.
Step 5.2 โ Demonstrate capability enforcement¶
docker run --rm --cap-drop=ALL ubuntu:22.04 bash -c '
echo "=== --cap-drop=ALL: even root cannot use capabilities ==="
echo ""
echo "Attempt chown (needs CAP_CHOWN):"
touch /tmp/t.txt
chown nobody /tmp/t.txt 2>&1 || echo "chown BLOCKED - CAP_CHOWN dropped"
echo ""
echo "Attempt mount (needs CAP_SYS_ADMIN):"
mount --bind /tmp /mnt 2>&1 || echo "mount BLOCKED โ CAP_SYS_ADMIN dropped"
'
Expected output:
=== --cap-drop=ALL: even root cannot use capabilities ===
Attempt chown (needs CAP_CHOWN):
chown: changing ownership of '/tmp/t.txt': Operation not permitted
chown BLOCKED - CAP_CHOWN dropped
Attempt mount (needs CAP_SYS_ADMIN):
mount: /mnt: permission denied.
mount BLOCKED โ CAP_SYS_ADMIN dropped
๐ธ Screenshot checkpoint Se: Capture both grep "^Cap" outputs showing the hex capability values, and the blocked operations output.
Part 6 โ cgroups: Resource Containment¶
Linux cgroups (control groups) enforce hard limits on CPU, memory, and I/O. Malware commonly attempts denial-of-service by consuming all available memory or CPU (e.g., crypto-mining). cgroup limits contain this to the sandbox.
Step 6.1 โ Verify the memory limit is enforced¶
docker run --rm --memory=64m --memory-swap=64m ubuntu:22.04 bash -c '
echo "=== cgroup memory limit ==="
cat /sys/fs/cgroup/memory.max 2>/dev/null || cat /sys/fs/cgroup/memory/memory.limit_in_bytes
echo "bytes = 64 MB hard limit"
'
Expected output:
Step 6.2 โ Simulate a memory bomb โ OOM kill in action¶
This simulates malware attempting to exhaust system memory. The cgroup OOM killer terminates the process before it can impact the host.
docker run --rm --memory=64m --memory-swap=64m python:3.11-slim python3 -c "
data = []
for i in range(300):
data.append(b'X' * 1024 * 1024)
print(f'Allocated {i+1} MB', flush=True)
print('survived')
"
echo "Container exit code: $?"
Expected output:
Exit code 137 = 128 + 9 = SIGKILL. The kernel's OOM killer sent SIGKILL at ~59 MB (slightly below the 64 MB limit due to interpreter overhead). The host system is completely unaffected โ only the sandboxed container was terminated.
Why this matters
Without cgroup limits, a single compromised container could malloc() the host into a system-wide OOM condition, crashing every service running on the machine. cgroup limits contain the blast radius to one container.
๐ธ Screenshot checkpoint Sf: Capture the allocation output showing the last line printed and exit code 137.
Part 7 โ Network Isolation: Air-Gapped Sandbox¶
Malware almost always attempts to phone home โ downloading additional payloads, exfiltrating data, or receiving commands from a C2 server. Network namespace isolation severs this channel entirely.
Step 7.1 โ Air-gapped container (--network=none)¶
docker run --rm --network=none ubuntu:22.04 bash -c '
echo "=== --network=none: container is air-gapped ==="
echo "Network interfaces visible:"
ls /sys/class/net/
echo ""
echo "Attempting outbound connection to 8.8.8.8 (Google DNS)..."
timeout 3 bash -c "echo > /dev/tcp/8.8.8.8/53" 2>&1 || echo "TCP connection BLOCKED โ no network namespace"
echo ""
echo "Only loopback (lo) exists โ no eth0, no internet access"
'
Expected output:
=== --network=none: container is air-gapped ===
Network interfaces visible:
lo
Attempting outbound connection to 8.8.8.8 (Google DNS)...
bash: connect: Network is unreachable
bash: line 1: /dev/tcp/8.8.8.8/53: Network is unreachable
TCP connection BLOCKED โ no network namespace
Only loopback (lo) exists โ no eth0, no internet access
Step 7.2 โ Network segmentation between containers¶
Two containers on separate Docker bridge networks cannot communicate, even if they are both running. This prevents lateral movement: a compromised container in one segment cannot reach services in another.
# Create two isolated bridge networks
docker network create --driver bridge net-sandbox-a
docker network create --driver bridge net-sandbox-b
# Start a "victim" service on network A
docker run -d --rm --network=net-sandbox-a --name sandbox-a ubuntu:22.04 sleep 60
# Get victim's IP address
IP_A=$(docker inspect sandbox-a --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}')
echo "Container A (victim) IP: $IP_A"
# Try to reach it from network B (attacker in different segment)
docker run --rm --network=net-sandbox-b ubuntu:22.04 bash -c "
echo '=== Container on net-sandbox-b cannot reach net-sandbox-a ==='
echo 'Attempting TCP connection to '$IP_A'...'
timeout 3 bash -c 'echo > /dev/tcp/'$IP_A'/53' 2>&1 || echo 'BLOCKED โ network isolation between bridges works!'
"
# Cleanup
docker kill sandbox-a
docker network rm net-sandbox-a net-sandbox-b
Expected output:
Container A (victim) IP: 172.18.0.2
=== Container on net-sandbox-b cannot reach net-sandbox-a ===
Attempting TCP connection to 172.18.0.2...
BLOCKED โ network isolation between bridges works!
๐ธ Screenshot checkpoint Sg: Capture the --network=none output showing only lo and the TCP connection blocked message.
Part 8 โ Privileged vs. Unprivileged: Understanding the Risk¶
Docker's --privileged flag disables virtually all isolation. It is the opposite of sandboxing. Seeing what --privileged enables makes clear why the default restrictions matter.
Step 8.1 โ Privileged container (for comparison โ never use in production)¶
docker run --rm --privileged ubuntu:22.04 bash -c '
echo "=== PRIVILEGED container capabilities ==="
grep "^CapEff" /proc/self/status
echo "(nearly all bits set = full root equivalent)"
echo ""
echo "=== Can mount kernel filesystems ==="
mkdir -p /mnt/hostproc
mount -t proc proc /mnt/hostproc 2>&1 && echo "mount proc: SUCCESS โ privileged is dangerous!" || echo "blocked"
ls /mnt/hostproc | head -5
'
Expected output:
=== PRIVILEGED container capabilities ===
CapEff: 000001ffffffffff
(nearly all bits set = full root equivalent)
=== Can mount kernel filesystems ===
mount proc: SUCCESS โ privileged is dangerous!
1
11
12
acpi
bootconfig
Step 8.2 โ Default (unprivileged) container blocks the same actions¶
docker run --rm ubuntu:22.04 bash -c '
echo "=== Unprivileged container (default) capabilities ==="
grep "^CapEff" /proc/self/status
echo ""
echo "=== Attempting same mount (should fail) ==="
mkdir -p /mnt/testproc
mount -t proc proc /mnt/testproc 2>&1 || echo "mount BLOCKED โ seccomp/capabilities protect the host"
echo ""
echo "=== PID 1 is the sandbox shell, not host init ==="
ps aux | head -5
'
Expected output:
=== Unprivileged container (default) capabilities ===
CapEff: 00000000a80425fb
=== Attempting same mount (should fail) ===
mount: /mnt/testproc: permission denied.
mount BLOCKED โ seccomp/capabilities protect the host
=== PID 1 is the sandbox shell, not host init ===
USER PID ... COMMAND
root 1 ... bash -c ...
root 11 ... ps aux
๐ธ Screenshot checkpoint Sh: Capture side-by-side: privileged CapEff value vs. unprivileged CapEff value, and the mount success vs. mount blocked outputs.
Part 9 โ NoNewPrivileges: Blocking Setuid Escalation¶
setuid binaries (like su, passwd, ping) are owned by root and gain elevated privileges when executed โ regardless of who runs them. The --no-new-privileges flag uses prctl(PR_SET_NO_NEW_PRIVS) to make this impossible.
Step 9.1 โ Verify NoNewPrivileges is set in the kernel¶
docker run --rm --security-opt no-new-privileges:true ubuntu:22.04 bash -c '
echo "=== no-new-privileges flag verification ==="
grep "NoNewPrivs" /proc/self/status
echo ""
echo "NoNewPrivs: 1 = setuid/setgid/capabilities CANNOT be gained via exec"
echo "This prevents setuid-based privilege escalation attacks"
'
Expected output:
=== no-new-privileges flag verification ===
NoNewPrivs: 1
NoNewPrivs: 1 = setuid/setgid/capabilities CANNOT be gained via exec
This prevents setuid-based privilege escalation attacks
Step 9.2 โ Confirm setuid binaries are visible but cannot escalate¶
docker run --rm --user 1000:1000 ubuntu:22.04 bash -c '
echo "=== Setuid binaries exist in the container ==="
ls -la /usr/bin/passwd /usr/bin/su 2>/dev/null || apt-get install -qq -y passwd 2>/dev/null && ls -la /usr/bin/passwd
echo ""
echo "These have the setuid bit (s in permissions)"
echo "Without --no-new-privileges, executing them would grant CAP_SETUID/SETGID"
echo "With --no-new-privileges, exec cannot raise privilege โ the setuid bit is ignored"
'
Expected output:
=== Setuid binaries exist in the container ===
-rwsr-xr-x 1 root root 59976 Feb 6 2024 /usr/bin/passwd
-rwsr-xr-x 1 root root 55680 Mar 6 16:10 /usr/bin/su
These have the setuid bit (s in permissions)
๐ธ Screenshot checkpoint Si: Capture the NoNewPrivs: 1 output from /proc/self/status and the ls -la showing the setuid binaries (rwsr-xr-x).
Part 10 โ The Hardened Sandbox: All Layers Combined¶
This final step assembles all isolation layers into a single hardened sandbox command โ the kind used in production malware analysis pipelines and security scanners.
Step 10.1 โ Run the fully hardened sandbox¶
docker run --rm \
--read-only \
--tmpfs /tmp:size=32m,noexec \
--network=none \
--cap-drop=ALL \
--security-opt no-new-privileges:true \
--security-opt seccomp=/tmp/block-chmod.json \
--memory=64m \
--memory-swap=64m \
--cpus=0.5 \
ubuntu:22.04 bash -c '
echo "=== Fully hardened sandbox โ verification ==="
echo ""
echo "1. PID namespace:"
ps aux | wc -l
echo " (only 3-4 processes visible โ isolated PID namespace)"
echo ""
echo "2. Capabilities:"
grep "^CapEff" /proc/self/status
echo " (0000000000000000 = zero capabilities)"
echo ""
echo "3. NoNewPrivileges:"
grep "NoNewPrivs" /proc/self/status
echo " (1 = escalation impossible)"
echo ""
echo "4. Read-only filesystem:"
echo "evil" > /etc/evil.txt 2>&1 || echo " /etc write BLOCKED"
echo ""
echo "5. Network isolation:"
ls /sys/class/net/
echo " (lo only โ air-gapped)"
echo ""
echo "6. seccomp (chmod blocked):"
touch /tmp/test.txt && chmod 777 /tmp/test.txt 2>&1 || echo " chmod BLOCKED"
echo ""
echo "7. Memory limit:"
cat /sys/fs/cgroup/memory.max 2>/dev/null || cat /sys/fs/cgroup/memory/memory.limit_in_bytes
echo " bytes = 64MB hard limit"
echo ""
echo "All containment layers active. Malicious code is fully sandboxed."
'
Expected output:
=== Fully hardened sandbox โ verification ===
1. PID namespace:
3
(only 3-4 processes visible โ isolated PID namespace)
2. Capabilities:
CapEff: 0000000000000000
(0000000000000000 = zero capabilities)
3. NoNewPrivileges:
NoNewPrivs: 1
(1 = escalation impossible)
4. Read-only filesystem:
/etc write BLOCKED
5. Network isolation:
lo
(lo only โ air-gapped)
6. seccomp (chmod blocked):
chmod BLOCKED
7. Memory limit:
67108864
bytes = 64MB hard limit
All containment layers active. Malicious code is fully sandboxed.
Real-World Use
This is the pattern used by security tools like VirusTotal, Any.run, Cuckoo Sandbox, and cloud CI/CD pipelines. Each untrusted artifact runs in an isolated container with all layers enforced โ even if malicious code executes, it cannot touch the host, reach the network, escalate privileges, or exhaust resources.
๐ธ Screenshot checkpoint Sj: Capture the full hardened sandbox output showing all 7 verification checks passing.
Cleanup¶
Assessment¶
Screenshot Checklist¶
| ID | Description | Points |
|---|---|---|
| Sa | ps aux inside container showing only 2โ4 processes with PID 1 = bash | 4 |
| Sb | Container write to /etc/malicious.txt + host verification showing file absent | 5 |
| Sc | --read-only blocking /etc write + --tmpfs allowing /tmp write | 5 |
| Sd | Custom seccomp: chmod BLOCKED + read/write allowed | 5 |
| Se | Capability hex values (default a80425fb vs cap-drop=ALL = 0) + blocked chown | 5 |
| Sf | Memory bomb output: allocation lines + exit code 137 | 5 |
| Sg | --network=none showing only lo + TCP connection blocked | 4 |
| Sh | Privileged CapEff vs unprivileged CapEff + mount success vs blocked | 4 |
| Si | /proc/self/status NoNewPrivs: 1 + setuid binary ls -la | 4 |
| Sj | Full hardened sandbox โ all 7 verification checks passing | 9 |
| Screenshot subtotal | 50 |
Grading Rubric
| Component | Points |
|---|---|
| Screenshots (checklist above) | 50 |
| Isolation analysis (written โ see below) | 10 |
| Reflection questions (4 ร 10 pts each) | 40 |
| Total | 100 |
Isolation Analysis (complete and submit)¶
In 200โ250 words, analyze the hardened sandbox command from Part 10. Your analysis must cover:
- Which flag addresses which threat vector (list all 7 flags and their threat model)
- What can malicious code still do inside this sandbox? (hint: read its own files, use the CPU, make loopback connections โ what else?)
- Give one real-world example of a security product that uses this pattern and explain why Docker-based sandboxing is preferred over VM-based sandboxing for high-throughput malware scanning
Reflection Questions¶
Answer each question in 150โ200 words.
-
Defense in depth: This lab used 7 distinct isolation mechanisms simultaneously. Explain why each layer is necessary even though the others exist. Pick two specific layers and construct a realistic attack scenario that would succeed if that layer were removed, but fails when all layers are present.
-
Containment failure โ escape vectors: A
--privilegedcontainer with the host/var/run/docker.sockmounted is considered equivalent to root on the host. Explain why mounting the Docker socket is dangerous. What two actions could an attacker inside such a container take to escape to the host? What does this tell you about the principle of least surface area? -
seccomp policy design: You are writing a seccomp profile for a Python-based static analysis tool that reads files but makes no network connections and should not spawn child processes. List the syscalls it legitimately needs and the syscalls that should be blocked. Explain why
execvewould be particularly dangerous to allow and what attacker technique it enables. -
Resource exhaustion as a weapon: Crypto-mining malware and ransomware both abuse resources โ one for computational gain, one to encrypt files as fast as possible. Explain how
--memory,--cpus, and--pids-limiteach limit a different dimension of resource abuse. What happens to the host system if none of these limits are applied and malware performs a fork bomb (:(){ :|:& };:) inside the container?