CO2115 Information Security Fundamentals
Week 4 Lab: Digital Forensics (lab in-class activities)
Duration: 120 minutes (60-80 minutes + optional extension time).
Learning goals
Explain the role and basic workflow of a Security Operations Centre (SOC).
Describe what a SIEM is and how it uses logs for monitoring and alerting.
Analyse simple log samples to spot anomalies and propose a next step.
Explain key digital forensic principles, including chain of custody and evidence handling.
What you need
On a lab classroom PC or your laptop, and a web browser (Chrome/Edge/Firefox).
A note-taking tool (Word/Google Docs) or paper notes.
Optional (for the extension): Python 3 (any recent version) or an online Python runner.
Safety note: work only with the sample data provided in this lab. Do not use or share any personal
credentials or real incident data.
Session plan
Part A (10 minutes): Warm-up quick check
Individually answer the questions below, then compare with a partner and agree on one final answer
per question.
1. In one sentence, what is a SOC?
2. In one sentence, what is a SIEM?
3. Give one example of an authentication log entry and one example of an application/web log entry.
4. True or false: it is fine to work directly on the original evidence drive if you are careful.
5. What does 'chain of custody' try to prove? (one sentence)
Part B (30 minutes): SOC + SIEM scenario: triage questions
Read the mini scenario (based on the lecture) and answer the triage questions.
Scenario: At 03:12, a user account that is normally active only 09:00-17:00 logs in from an overseas IP.
Within 5 minutes there are multiple failed attempts to access a finance system, followed by a large
download of data.
In pairs, discuss and write short notes (bullet points are fine):
What extra information would you want before deciding to block the account, investigate further, or
do nothing?
Which log sources would you check first (e.g., authentication, VPN, application, firewall, file access)?
What would be your immediate 'Tier 1' action, and what would you escalate to a Tier 2 investigator?
Question Your notes (short bullets)
Extra information needed (before
acting)
Logs to check first
Immediate action (Tier 1)
Escalation / deeper investigation
(Tier 2)
Part C (35 minutes): Log analysis: spot anomalies and build a simple timeline
Below are two small log samples. Work in pairs. Your goal is to identify what looks abnormal and explain
why.
Sample 1: Linux SSH authentication log lines
Oct 21 09:35:47 server1 sshd[1234]: Failed password for invalid user admin from [Link] port
54321 ssh2
Oct 21 09:35:52 server1 sshd[1234]: Failed password for invalid user admin from [Link] port
54388 ssh2
Oct 21 09:36:01 server1 sshd[1234]: Failed password for invalid user admin from [Link] port
54410 ssh2
Oct 21 02:11:03 server1 sshd[8821]: Accepted password for alice from [Link] port 60001 ssh2
Sample 2: Web server access log lines (simplified)
[Link] - - [21/Oct/2025:09:32:10 +0100] "GET /[Link] HTTP/1.1" 200 532 "-" "Mozilla/5.0"
[Link] - - [21/Oct/2025:09:32:11 +0100] "GET /[Link] HTTP/1.1" 200 532 "-" "Mozilla/5.0"
[Link] - - [21/Oct/2025:09:32:12 +0100] "GET /[Link] HTTP/1.1" 200 532 "-" "Mozilla/5.0"
[Link] - - [21/Oct/2025:02:10:05 +0100] "POST /[Link] HTTP/1.1" 401 215 "-"
"curl/7.68.0"
[Link] - - [21/Oct/2025:02:10:06 +0100] "POST /[Link] HTTP/1.1" 401 215 "-"
"curl/7.68.0"
[Link] - - [21/Oct/2025:02:10:07 +0100] "POST /[Link] HTTP/1.1" 401 215 "-"
"curl/7.68.0"
Tasks (write directly into the table):
Log item Why is it suspicious (or normal)? What would you check
next?
SSH: 'invalid user admin' failures repeated failed logins for a non- • Whether there are many
from one IP existent/default account (“admin”) usernames tried from this
from the same IP suggests scanning or IP; check rate and whether
brute-force attempts. the IP is seen elsewhere.
• Confirm whether any
successful SSH logins follow
shortly after.
SSH: successful login for alice at
02:11 from same IP
Web: repeated /[Link] at
09:32 from one IP (GET)
Web: repeated 401 failures at
02:10 using curl
Mini timeline (5 minutes): order the key events by time and write 3-5 bullets describing what happened.
Time (from logs) Event (your description)
02:10 automated login attempts on web login from [Link] (401 failures, curl).
Part D (30 minutes): Python mini log-checker
Goal: write a tiny Python script that scans a small log file and prints simple alerts (rule-based “mini
SIEM”).
What you need
Python 3 (no third-party libraries).
A text file called sample_logs.txt (you can copy/paste the sample lines below).
Step 1: create a small log file
Create a file named sample_logs.txt and paste the following lines:
Oct 21 09:35:47 server1 sshd[1234]: Failed password for invalid user admin from [Link] port
54321 ssh2
Oct 21 09:35:52 server1 sshd[1234]: Failed password for invalid user admin from [Link] port
54388 ssh2
Oct 21 09:36:01 server1 sshd[1234]: Failed password for invalid user admin from [Link] port
54410 ssh2
Oct 21 02:11:03 server1 sshd[8821]: Accepted password for alice from [Link] port 60001 ssh2
[Link] - - [21/Oct/2025:09:32:10 +0100] "GET /[Link] HTTP/1.1" 200 532 "-" "Mozilla/5.0"
[Link] - - [21/Oct/2025:09:32:11 +0100] "GET /[Link] HTTP/1.1" 200 532 "-" "Mozilla/5.0"
[Link] - - [21/Oct/2025:09:32:12 +0100] "GET /[Link] HTTP/1.1" 200 532 "-" "Mozilla/5.0"
[Link] - - [21/Oct/2025:02:10:05 +0100] "POST /[Link] HTTP/1.1" 401 215 "-" "curl/7.68.0"
[Link] - - [21/Oct/2025:02:10:06 +0100] "POST /[Link] HTTP/1.1" 401 215 "-" "curl/7.68.0"
[Link] - - [21/Oct/2025:02:10:07 +0100] "POST /[Link] HTTP/1.1" 401 215 "-" "curl/7.68.0"
Step 2: write the script
Create a file named log_alert.py. Implement three simple rules:
Rule A (SSH brute-force hint): if the same IP has 3+ “Failed password” lines, print an alert.
Rule B (suspicious SSH success): if there is an “Accepted password” login at an unusual time (e.g.,
00:00–05:00), print an alert.
Rule C (automated web login attempts): if the same IP has 3+ HTTP 401 responses for /[Link],
especially with a curl user agent, print an alert.
You just need to complete TODO 1 and TODO 2 only, in following reference code.
# log_alert_two_lines.py
import re
import sys
from collections import Counter
SSH_FAIL_RE = [Link](r"Failed password .* from (?P<ip>\d+\.\d+\.\d+\.\d+)")
SSH_OK_RE = [Link](
r"Oct\s+\d+\s+(?P<hh>\d{2}):(?P<mm>\d{2}):(?P<ss>\d{2}).*Accepted password for (?P<user>\w+)
from (?P<ip>\d+\.\d+\.\d+\.\d+)"
)
WEB_401_RE = [Link](
r'(?P<ip>\d+\.\d+\.\d+\.\d+).*\] "POST /login\.php .*" 401 .* "(?P<ua>[^"]+)"'
)
SSH_FAIL_THRESHOLD = 3
WEB_401_THRESHOLD = 3
UNUSUAL_HOUR_MAX = 5 # 00:00–05:59
def main(path: str) -> int:
ssh_fail = Counter()
web_401 = Counter()
curl_401 = Counter()
unusual_ssh_success = [] # list of (time, user, ip)
with open(path, "r", encoding="utf-8", errors="replace") as f:
for line in f:
m = SSH_FAIL_RE.search(line)
if m:
ip = [Link]("ip")
# TODO (1): increment SSH failure count for this IP
# something need to add
continue
m = SSH_OK_RE.search(line)
if m:
hh = int([Link]("hh"))
user = [Link]("user")
ip = [Link]("ip")
if 0 <= hh <= UNUSUAL_HOUR_MAX:
unusual_ssh_success.append((f"{[Link]('hh')}:{[Link]('mm')}:{[Link]('ss')}", user, ip))
continue
m = WEB_401_RE.search(line)
if m:
ip = [Link]("ip")
ua = [Link]("ua").lower()
# TODO (2): increment web 401 count for this IP
# something need to add
if "curl" in ua:
curl_401[ip] += 1
continue
# Print alerts (already implemented)
for ip, n in ssh_fail.items():
if n >= SSH_FAIL_THRESHOLD:
print(f"[ALERT] SSH: {n} failed logins from {ip} (possible brute-force/scanning)")
for t, user, ip in unusual_ssh_success:
print(f"[ALERT] SSH: unusual-time success at {t} for user '{user}' from {ip}")
for ip, n in web_401.items():
if n >= WEB_401_THRESHOLD:
extra = " (curl seen)" if curl_401[ip] > 0 else ""
print(f"[ALERT] WEB: {n} x 401 on /[Link] from {ip}{extra} (possible automation)")
if not (any(n >= SSH_FAIL_THRESHOLD for n in ssh_fail.values()) or unusual_ssh_success or any(n >=
WEB_401_THRESHOLD for n in web_401.values())):
print("[INFO] No rules triggered on this sample.")
return 0
if __name__ == "__main__":
if len([Link]) != 2:
print("Usage: python log_alert_two_lines.py <logfile>")
raise SystemExit(2)
raise SystemExit(main([Link][1]))
Step 3: run it
Run in a terminal:
python log_alert.py sample_logs.txt
Expected outcome: you should see a few alerts indicating suspicious patterns.
Note: this is a toy script—real SIEM rules are more robust and context-aware.
Wrap-up (last 5 minutes)
One key difference between prevention controls and detection/response controls.
One reason SIEMs can generate 'too many alerts' and what analysts do about it.
One chain-of-custody practice you will remember for future labs.