Certificates, signatures, hardening sshd and verifying trust.
- Cap a User's Open Fileseasy · in-browser
Write /etc/security/limits.d/90-appuser.conf setting limits for the user 'appuser': a soft limit of 4096 and a hard limit of 8192 open files (the nofile item). Each line is: <domain> <type> <item> <value>.
(Authored config, graded structurally — the engine isn't run here.)
- Disconnect Idle SSH Sessionseasy · in-browser
Write /etc/ssh/sshd_config.d/30-idle.conf that drops idle interactive sessions: set ClientAliveInterval to 300 seconds and ClientAliveCountMax to 0 so the daemon disconnects after 5 minutes of inactivity.
(Authored config, graded structurally — the engine isn't run here.)
- Generate an RSA keyeasy
Generate a 2048-bit RSA private key at /etc/pki/site.key that passes an openssl key check.
- Harden the SSH Clienteasy · in-browser
Write /etc/ssh/ssh_config.d/50-hardening.conf, a system-wide SSH client drop-in that applies to all hosts. Open a 'Host *' block and set HashKnownHosts to yes and StrictHostKeyChecking to ask.
(Authored config, graded structurally — the engine isn't run here.)
- Limit Processes Per Usereasy · in-browser
Write /etc/security/limits.d/80-nproc.conf that caps every member of the @developers group to a soft limit of 150 and a hard limit of 200 processes (the nproc item) to blunt fork bombs.
(Authored config, graded structurally — the engine isn't run here.)
- Lock a key fileeasy
/etc/pki/id.key is world-readable. Make it mode 600 owned by root.
- Lock down a key directoryeasy
The directory /etc/ssl/private must be owner root and mode 700 (it is currently world-traversable).
- Lock down a private keyeasy
/etc/pki/secret.key is world-readable. Lock it down: owner root and mode 600 (owner read/write only).
- Lock down a secreteasy
Set permissions on /home/player/secret.txt to 600 (owner read/write only).
- Record a SHA-512easy
Write the SHA-512 hex digest of /opt/blob.bin to /home/player/sum.txt (just the hash).
- Show an SSH Login Bannereasy · in-browser
Write /etc/ssh/sshd_config.d/20-banner.conf that points sshd at a login banner file by setting the Banner directive to /etc/issue.net, and also sets PrintMotd to no so the post-login MOTD is left to PAM instead of being printed twice.
(Authored config, graded structurally — the engine isn't run here.)
- Verify a file's SHA-256easy
Compute the SHA-256 of /opt/app/payload.bin and write ONLY the 64-character hex digest to /home/player/sum.txt.
- Block Password Reuse in PAMmedium · in-browser
Write /etc/pam.d/password-history, a PAM fragment that loads pam_pwhistory.so in the password phase to remember the last 5 passwords (remember=5) and apply the rule to root (enforce_for_root). The line must start with the 'password' type and a 'required' control.
(Authored config, graded structurally — the engine isn't run here.)
- Disable SSH passwordsmedium
Set PasswordAuthentication no in /etc/ssh/sshd_config.
- Disable SSH root loginmedium
Harden /etc/ssh/sshd_config so root cannot log in over SSH (PermitRootLogin no).
- Disable a service account loginmedium
The user 'svc' should not be able to log in. Set its shell to /sbin/nologin.
- Disable core dumpsmedium
Disable core dumps system-wide via a limits drop-in: a file in /etc/security/limits.d setting `* hard core 0`.
- Enforce Password Complexitymedium · in-browser
Write /etc/security/pwquality.conf enforcing: minimum length 12 (minlen=12), at least one digit (dcredit=-1), at least one uppercase letter (ucredit=-1), at least one other/special character (ocredit=-1), and at least 3 characters changed from the previous password (difok=3). Use key = value lines.
(Authored config, graded structurally — the engine isn't run here.)
- Fix a permission problemmedium
Service 'confd' can't start: it can't read /etc/confd/secret (mode 000). Fix the file permissions so confd can read it, then start the service (it creates /run/confd.ok).
- Fix a world-writable configmedium
/etc/app/db.conf is world-writable. Remove write permission for group and others (owner keeps rw).
- Generate a certificate signing requestmedium
Create a private key and a CSR at /etc/pki/csr/site.key and /etc/pki/csr/site.csr, with subject CN=tmpfs.lab.
- Grant passwordless sudomedium
Give the existing user 'ops' passwordless sudo (via /etc/sudoers.d).
- Harden Sudo Defaultsmedium · in-browser
Write /etc/sudoers.d/00-defaults, a sudoers drop-in of Defaults lines that: keep a secure PATH via 'Defaults secure_path="/usr/sbin:/usr/bin:/sbin:/bin"', require a tty for sudo with 'Defaults requiretty', and log sudo I/O to /var/log/sudo-io with 'Defaults log_output' and 'Defaults iolog_dir=/var/log/sudo-io'.
(Authored config, graded structurally — the engine isn't run here.)
- Harden default umaskmedium
Set a restrictive default umask 027 via a file in /etc/profile.d (e.g. /etc/profile.d/umask.sh).
- Install an SSH keymedium
Add this public key to player's authorized_keys (correct perms):
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID3academyExampleKey academy
- Issue a self-signed certificatemedium
Generate a self-signed certificate and private key at /etc/pki/site/tls.crt and /etc/pki/site/tls.key — subject CN must be linux-lab, and the cert must stay valid at least 30 more days.
- Limit SSH auth triesmedium
Set MaxAuthTries 3 in /etc/ssh/sshd_config.
- Lock Accounts After Failed Loginsmedium · in-browser
Write /etc/security/faillock.conf so that pam_faillock locks an account for 900 seconds (unlock_time) after 5 failed authentications (deny), and also counts failures against the root account. Set deny = 5, unlock_time = 900, and include a bare even_deny_root line.
(Authored config, graded structurally — the engine isn't run here.)
- Lock a stale accountmedium
Lock the account 'olduser' so it cannot authenticate (passwd -l / usermod -L).
- Make a config immutablemedium
Protect /etc/app/policy.conf from changes by setting the immutable attribute.
- Remove a risky SUID bitmedium
An admin left /opt/risky setuid-root. Remove its setuid bit (keep the file).
- Restrict cron to rootmedium
Create /etc/cron.allow containing only root so other users can't use cron.
- Set password agingmedium
Set PASS_MAX_DAYS to 90 in /etc/login.defs.
- Strengthen Password Hashingmedium · in-browser
Write /etc/login.defs configuring the system password hash: set ENCRYPT_METHOD to SHA512, and pin the cost so passwords are expensive to crack by setting both SHA_CRYPT_MIN_ROUNDS and SHA_CRYPT_MAX_ROUNDS to 65536. login.defs uses 'KEY value' lines (whitespace separated, no equals sign).
(Authored config, graded structurally — the engine isn't run here.)
- Sudoers Cmnd_Alias Grantmedium · in-browser
Write /etc/sudoers.d/services, a syntactically valid sudoers drop-in that defines a Cmnd_Alias named SERVICES covering /usr/bin/systemctl start nginx and /usr/bin/systemctl stop nginx, then grants the %ops group passwordless use of that alias. Use a 'Cmnd_Alias SERVICES = ...' definition and a '%ops ALL=(root) NOPASSWD: SERVICES' grant.
(Authored config, graded structurally — the engine isn't run here.)
- Wire pam_pwquality Into PAMmedium · in-browser
Write /etc/pam.d/system-auth-local, a PAM password-stack fragment that invokes pam_pwquality.so in the password phase, requesting 3 retries (retry=3) and enforcing the policy even for root (enforce_for_root). The line must begin with the 'password' type and a 'requisite' control.
(Authored config, graded structurally — the engine isn't run here.)
- Cert with a SANpro
Create a self-signed cert /etc/pki/san.crt whose SubjectAltName includes DNS:tmpfs.lab.
- Generate DH Parameterspro · in-browser
Write the bash script /home/player/gen-dhparam.sh (bash shebang first) that uses 'set -euo pipefail' for safety and generates 2048-bit Diffie-Hellman parameters into /etc/ssl/dhparam.pem via openssl, then tightens that file to mode 0644. Use 'openssl dhparam -out /etc/ssl/dhparam.pem 2048' and a chmod 644 on the output.
(Authored config, graded structurally — the engine isn't run here.)
- Grant Access With setfaclpro · in-browser
Write the bash script /home/player/grant-acl.sh (starting with a bash shebang) that uses setfacl to give the 'auditor' user read-and-execute (rX) access to /var/log/app, recursively, AND sets a default ACL so new files inherit that grant. Use two setfacl calls: 'setfacl -R -m u:auditor:rX /var/log/app' and 'setfacl -R -m d:u:auditor:rX /var/log/app'.
(Authored config, graded structurally — the engine isn't run here.)
- Grant scoped passwordless sudopro
Create a system user 'deployer' and grant it passwordless sudo to run ONLY /usr/bin/systemctl restart nginx (nothing else), via a /etc/sudoers.d drop-in that passes `visudo -c`.
- Harden the SSH daemonpro
Harden sshd: disable root login AND password authentication (use a drop-in under /etc/ssh/sshd_config.d), then reload sshd. The effective config must show both disabled.
- OpenSSL x509 Extensions Filepro · in-browser
Write /home/player/v3.ext, an OpenSSL x509 v3 extension file used when signing a leaf certificate. Set basicConstraints to CA:FALSE, set keyUsage to 'digitalSignature, keyEncipherment', set extendedKeyUsage to serverAuth, and add a subjectAltName line referencing an alt_names section that defines DNS.1 = tmpfs.lab.
(Authored config, graded structurally — the engine isn't run here.)
- Revoke an attacker SSH keypro
An attacker added their key to /root/.ssh/authorized_keys. Remove ONLY the line containing the comment attacker@evil, keeping the legitimate keys.
- Serve HTTPS with a self-signed certpro
Generate a self-signed certificate and configure nginx to serve HTTPS on port 8443 returning the body "SECURE".
- Verify a signaturepro
/opt/sig/msg was signed. Use /opt/sig/pub.pem and /opt/sig/msg.sig to verify it, and write 'valid' or 'invalid' to /home/player/verdict.txt.