Chapter 7 — Digital forensics and malware analysis: controls and verification
Lesson map
Lesson 07 published. Map, example, EX031.
flowchart TD
N0["Learning outcomes"]
N1["7.1 Integrity verification"]
N2["Lab — manifest check"]
N3["7.2 Reading the result"]
N4["7.3 Verifying containment"]
N5["7.4 Control review"]
N6["7.5 Control changes"]
N7["7.6 Recording"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
N7 --> EX["Worked example"]
EX --> Q["Exercise EX031"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["7.1 Integrity verification"]
N2["Lab — manifest check"]
N3["7.2 Reading the result"]
N4["7.3 Verifying containment"]
N5["7.4 Control review"]
N6["7.5 Control changes"]
N7["7.6 Recording"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX031"]
[Learning outcomes]
|
v
[7.1 Integrity verification]
|
v
[Lab — manifest check]
|
v
[7.2 Reading the result]
|
v
[7.3 Verifying containment]
|
v
[7.4 Control review]
|
v
[7.5 Control changes]
|
v
[7.6 Recording]
|
v
[Worked example] --> [Exercise EX031]
Learning outcomes
You will (1) verify evidence integrity with a manifest; (2) verify containment worked; (3) check controls that should have stopped the attack; (4) record verification results.
7.1 Integrity verification
Before analysis and handover, each working copy is re-hashed and compared with the manifest made at collection. In Marlow's case the manifest was made at download, when each export was hashed with SHA-256. Re-hashing before analysis confirms Lena is working on what she collected, and re-hashing before handover gives Dev or a peer the same assurance. The lab below uses three small synthetic files and simulates an accidental edit to message_trace.csv, which is exactly the kind of change the check is meant to catch.
Lab — manifest check
"""Build and check a SHA-256 manifest for synthetic exported evidence."""
import hashlib
files = {"signin.csv": b"time,user,ip,result\n", "rules.json": b"[]\n", "message_trace.csv": b"time,from,to,subject\n"}
manifest = {n: hashlib.sha256(d).hexdigest() for n, d in files.items()}
files["message_trace.csv"] += b"edited\n" # simulate an accidental change to the working copy
for n, d in files.items():
ok = hashlib.sha256(d).hexdigest() == manifest[n]
print(f"{n:18} {manifest[n][:12]} {'OK' if ok else 'MISMATCH'}")
Run with python3 lab_manifest.py. Verified output:
signin.csv 73e095a99de8 OK
rules.json 37517e5f3dc6 OK
message_trace.csv 6d8fe704b35e MISMATCH
7.2 Reading the result
signin.csv and rules.json verify OK. message_trace.csv shows MISMATCH: the working copy was edited. Lena had added a note column in a spreadsheet and saved over the file. She discards the working copy, makes a fresh one from the read-only original, verifies it OK, and keeps notes in a separate file from now on. The mismatch is not evidence of tampering by anyone else; the case log records it as Lena's own error, with time, cause and fix. The read-only original never changed, which is why the problem was easy to recover from.
7.3 Verifying containment
Containment is checked, not assumed: the sign-in log shows no further successes from 203.0.113.50 after 10:05; the rule list for Joy no longer contains "fwd"; the proxy log shows a blocked attempt to the look-alike domain from a test PC. Each check uses the same kind of record that showed the attack: the sign-in log for access, the rule list for forwarding and the proxy log for the domain. The test PC attempt proves the block works from inside Marlow's network, not just that a setting was saved. Lena records each check with time and name in the verification table.
7.4 Control review
Which controls should have helped? Multi-factor authentication was not enforced for Joy (she was in an exemption group set up years ago); the mail filter did not flag the look-alike domain, registered two days earlier; external forwarding was allowed by default. None of these was a technical surprise; each was a known setting nobody had reviewed. The exemption group meant the captured password alone was enough, the domain's age gave the filter a clue it did not use, and default forwarding let 'fwd' send eleven messages out before anyone noticed.
7.5 Control changes
Remove the exemption group; block automatic external forwarding by default; add new-domain warnings to the mail filter. Each change gets a ticket and a test. The tests are concrete: a test rule forwarding outside the company should be rejected, a sign-in by a former exemption-group member should ask for a second factor, and a message from a newly registered domain should carry a warning. The forwarding test was rejected at 16:20 on 3 March, as the verification row records. Removing the exemption group also needs a check that no other staff still depend on it.
7.6 Recording
A verification table records what was checked, how, when and by whom. The table has one row per check: what was checked, the record or test used, the result, the time and the person. For example, the forward rule's absence was confirmed at 14:02 and the proxy block at 14:05. A row also says what a check cannot show; an empty sign-in log for 203.0.113.50 does not rule out access from another address. Dev reads the table at the conclusions checkpoint, and it later goes into the report's appendix.
Who verifies
Ideally someone other than the collector verifies hashes, which guards against one person's mistake going unnoticed.
Worked example
Verification row: "Containment — sign-ins from 203.0.113.50 after 10:05: none (checked 14:00, L. Hart). Forward rule absent (14:02). Proxy block confirmed (14:05). External forwarding now blocked: test rule rejected (16:20)."
Synthetic case. Results come from the lab script and invented records.
Errors and limits
A clean check today does not prove the attacker has no other access; review again after a few days.
Exercises
- EX031 — Mismatch cause. Why did message_trace.csv mismatch, and what fixed it? Rubric: 3 = notes saved into working copy; fresh copy from original, verified, notes kept separately; 2 = partial; 1 = ignored; 0 = none.
- EX032 — Containment proof. Give three checks that containment worked. Rubric: 3 = no sign-ins from IP after 10:05; rule absent; proxy block confirmed; 2 = two; 1 = one; 0 = none.
- EX033 — Failed controls. Which three controls failed or were missing? Rubric: 3 = MFA exemption; filter missed new domain; external forwarding allowed; 2 = two; 1 = one; 0 = none.
- EX034 — Testing a change. How was the forwarding block tested? Rubric: 3 = test rule rejected; 2 = partial; 1 = assumed; 0 = none.
- EX035 — Later review. Why review again after a few days? Rubric: 3 = attacker may have other access not yet visible; 2 = partial; 1 = unnecessary; 0 = none.
Synthesis
Verify evidence, containment and controls with recorded checks rather than assumptions.
Continue studying — chapter 07 of 12
← Chapter 06 (draft) · Course chapter index · Chapter 08 (draft) →