CSAI2026 labs: Lab-2..Lab-6 (Practical + Solution, data), Module-2..Module-6 notebooks and datasets
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3d9865d1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Module 2 — Lab 6: Capstone — Investigating Suspicious Logins\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"**Topics:** Pandas, NumPy, Matplotlib, export, analyst summary\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"> **Instructions:** Run the cells in order. Complete every `TODO`, then run the **Self-check** cell. Do not open the Solution notebook before attempting the tasks yourself.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dda323ff",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Mission\n",
|
||||
"\n",
|
||||
"As a junior security analyst, you must build a complete workflow:\n",
|
||||
"\n",
|
||||
"1. load and clean authentication logs;\n",
|
||||
"2. identify IP addresses with repeated failed logins;\n",
|
||||
"3. identify off-hours activity;\n",
|
||||
"4. visualize the results;\n",
|
||||
"5. export the data and write a short conclusion.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7b91b90f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from pathlib import Path\n",
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"DATA_PATH = Path(\"data/auth_log.csv\")\n",
|
||||
"OUTPUT_DIR = Path(\"output\")\n",
|
||||
"OUTPUT_DIR.mkdir(exist_ok=True)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2e73090b",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"source": [
|
||||
"## 1. Write a reusable cleaning function\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "21e69c93",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def clean_auth_log(df):\n",
|
||||
" result = df.copy()\n",
|
||||
" # TODO 1: drop duplicate rows\n",
|
||||
" # TODO 2: parse timestamp using errors=\"coerce\" and utc=True\n",
|
||||
" # TODO 3: drop rows missing timestamp, source_ip, or status\n",
|
||||
" # TODO 4: normalize source_ip, username, and status\n",
|
||||
" # TODO 5: retain SUCCESS and FAILED records only\n",
|
||||
" # TODO 6: create hour and is_off_hours (< 6 or >= 22)\n",
|
||||
" # TODO 7: sort by timestamp and reset the index\n",
|
||||
" return result\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"raw_df = pd.read_csv(DATA_PATH)\n",
|
||||
"clean_df = clean_auth_log(raw_df)\n",
|
||||
"print(f\"Raw rows: {len(raw_df)} | Clean rows: {len(clean_df)}\")\n",
|
||||
"clean_df.head()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "57d60f86",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"source": [
|
||||
"## 2. Analyze failures and rank IP addresses\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1ea702f5",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# TODO 8: filter FAILED records\n",
|
||||
"failed_df = None\n",
|
||||
"\n",
|
||||
"# TODO 9: group by source_ip, count, sort descending, and name the Series failed_attempts\n",
|
||||
"failed_by_ip = None\n",
|
||||
"\n",
|
||||
"THRESHOLD = 3\n",
|
||||
"# TODO 10: retain IP addresses with count >= THRESHOLD\n",
|
||||
"suspicious_ips = None\n",
|
||||
"\n",
|
||||
"print(failed_by_ip)\n",
|
||||
"print(suspicious_ips)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "eba0fd3d",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"source": [
|
||||
"## 3. Calculate additional investigation metrics\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fea68f16",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# TODO 11: create status_counts in SUCCESS, FAILED order\n",
|
||||
"status_counts = None\n",
|
||||
"\n",
|
||||
"# TODO 12: filter off-hours failed events\n",
|
||||
"off_hours_failed = None\n",
|
||||
"\n",
|
||||
"# TODO 13: determine top_ip, top_ip_count, and failure_rate (%)\n",
|
||||
"top_ip = None\n",
|
||||
"top_ip_count = None\n",
|
||||
"failure_rate = None\n",
|
||||
"\n",
|
||||
"print(f\"Top suspicious IP: {top_ip} ({top_ip_count} failures)\")\n",
|
||||
"print(f\"Failure rate: {failure_rate}%\")\n",
|
||||
"print(\"Off-hours failed attempts:\", None if off_hours_failed is None else len(off_hours_failed))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "eb9420ec",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"source": [
|
||||
"## 4. Visualize the findings\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3f438336",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# TODO 14: create a figure with two charts:\n",
|
||||
"# - a SUCCESS/FAILED bar chart\n",
|
||||
"# - a horizontal bar chart of the top five IP addresses by failed attempts\n",
|
||||
"# TODO 15: add titles and labels, save to output/auth_log_analysis.png, and call plt.show()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fe92f571",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"source": [
|
||||
"## 5. Export results and write a short report\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "608ca490",
|
||||
"metadata": {
|
||||
"tags": [
|
||||
"exercise"
|
||||
]
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# TODO 16: export clean_df and suspicious_ips to CSV\n",
|
||||
"# TODO 17: create a summary string containing clean event count, FAILED count,\n",
|
||||
"# failure rate, top IP, off-hours failures, and recommendations.\n",
|
||||
"# TODO 18: save summary to output/capstone_summary.txt\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a6f05e23",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Self-check\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "10601dd1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"assert len(raw_df) > len(clean_df)\n",
|
||||
"assert clean_df.duplicated().sum() == 0\n",
|
||||
"assert failed_by_ip.index[0] == \"198.51.100.14\"\n",
|
||||
"assert top_ip_count >= THRESHOLD\n",
|
||||
"assert len(off_hours_failed) >= 1\n",
|
||||
"assert (OUTPUT_DIR / \"auth_log_analysis.png\").exists()\n",
|
||||
"assert (OUTPUT_DIR / \"capstone_summary.txt\").exists()\n",
|
||||
"print(\"✓ Capstone lab completed\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b56e4f9a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Report questions\n",
|
||||
"\n",
|
||||
"1. Which IP address should be investigated first, and what evidence supports that decision?\n",
|
||||
"2. In what situations could a threshold of three failed attempts produce a false positive?\n",
|
||||
"3. Which additional log sources should be reviewed before deciding to block an IP address?\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user