CoolFace
Apppublic

akkki012/sysadmin_env

sourceHugging Faceupdated 6mo agoView on Hugging Face
1likes
test_all_tasks.py363 linesDownload Raw Back to tests
1"""2End-to-end attack scripts for all 16 sysadmin tasks.3 4Usage:5  Against a running server (Docker):6    python tests/test_all_tasks.py --url http://localhost:78607 8  Single task:9    python tests/test_all_tasks.py --url http://localhost:7860 --task ssh_hardening10 11  Local-only (no server, tests task setup/check directly — requires root):12    sudo python tests/test_all_tasks.py --local13"""14 15import argparse16import asyncio17import sys18from dataclasses import dataclass19from typing import List, Tuple20 21# ---------------------------------------------------------------------------22# Attack playbooks — each is a list of (command, explanation) tuples that23# a competent sysadmin would use to fix the injected problem.24# ---------------------------------------------------------------------------25 26PLAYBOOKS: dict[str, List[Tuple[str, str]]] = {27    # ── Original 8 ──────────────────────────────────────────────────────28    "ssh_hardening": [29        ("sudo sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config",30         "Disable root login"),31        ("sudo sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config",32         "Disable password authentication"),33        ("sudo sed -i 's/^MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config",34         "Reduce max auth tries to 3"),35        ("sudo service ssh reload 2>/dev/null || true",36         "Reload SSH service to apply changes"),37        ("done", "Finished SSH hardening"),38    ],39 40    "open_port": [41        ("sudo ss -tlnp | grep ':23 '",42         "Identify what is listening on port 23"),43        ("sudo pkill -f 'nc -lk 23'",44         "Kill the netcat process on port 23"),45        ("sudo ufw deny 23",46         "Block port 23 in firewall"),47        ("done", "Port 23 closed and blocked"),48    ],49 50    "malicious_cron": [51        ("sudo ls -la /etc/cron.d/",52         "List cron.d to find suspicious files"),53        ("sudo cat /etc/cron.d/backdoor",54         "Inspect the malicious cron file"),55        ("sudo rm /etc/cron.d/backdoor",56         "Remove the malicious cron file"),57        ("sudo grep -r 'curl.*|.*bash' /etc/cron* 2>/dev/null || echo clean",58         "Verify no curl-pipe-bash patterns remain"),59        ("done", "Malicious cron job removed"),60    ],61 62    "disk_cleanup": [63        ("sudo du -sh /var/log/bloat/bigfile.log",64         "Check the size of the bloated log file"),65        ("sudo rm /var/log/bloat/bigfile.log",66         "Remove the bloated log file"),67        ("sudo bash -c 'cat > /etc/logrotate.d/bloat << EOF\n/var/log/bloat/*.log {\n    weekly\n    rotate 4\n    compress\n    missingok\n    notifempty\n}\nEOF'",68         "Create logrotate config to prevent future bloat"),69        ("done", "Disk cleaned and logrotate configured"),70    ],71 72    "nginx_fix": [73        ("sudo cat /etc/nginx/sites-enabled/default",74         "Inspect broken nginx config"),75        ("sudo bash -c 'cat > /etc/nginx/sites-enabled/default << EOF\nserver {\n    listen 80;\n    server_name _;\n\n    location / {\n        root /var/www/html;\n        index index.html;\n    }\n}\nEOF'",76         "Write fixed nginx config with semicolons"),77        ("sudo nginx -t",78         "Test nginx configuration"),79        ("sudo service nginx start",80         "Start nginx service"),81        ("done", "Nginx fixed and running"),82    ],83 84    "suspicious_process": [85        ("ps aux | grep xmrig",86         "Find the xmrig_sim cryptocurrency miner process"),87        ("sudo pkill -f xmrig_sim",88         "Kill the suspicious miner process"),89        ("sudo rm /usr/local/bin/xmrig_sim",90         "Remove the miner binary"),91        ("done", "Miner process killed and binary removed"),92    ],93 94    "fail2ban_setup": [95        ("sudo cat /var/log/auth.log | tail -20",96         "Check auth.log for brute-force attempts"),97        ("sudo apt-get update -qq && sudo apt-get install -y -qq fail2ban",98         "Install fail2ban"),99        ("sudo bash -c 'cat > /etc/fail2ban/jail.local << EOF\n[sshd]\nenabled = true\nmaxretry = 3\nbantime = 3600\nfindtime = 600\nEOF'",100         "Configure fail2ban with strict settings"),101        ("sudo service fail2ban start",102         "Start fail2ban service"),103        ("done", "Fail2ban installed and configured"),104    ],105 106    "world_writable": [107        ("sudo find /etc /usr/local/bin -perm -o+w -type f 2>/dev/null",108         "Find all world-writable files"),109        ("sudo chmod o-w /etc/world_writable_test1.conf /etc/world_writable_test2.conf /usr/local/bin/world_writable_test3.sh",110         "Remove world-writable permission from all found files"),111        ("done", "World-writable permissions fixed"),112    ],113 114    # ── New 8 ───────────────────────────────────────────────────────────115    "unauthorized_ssh_keys": [116        ("sudo cat /root/.ssh/authorized_keys",117         "Inspect root authorized_keys for rogue entries"),118        ("sudo cat /home/appuser/.ssh/authorized_keys",119         "Inspect appuser authorized_keys"),120        ("sudo sed -i '/attacker@evil.com/d' /root/.ssh/authorized_keys",121         "Remove rogue key from root"),122        ("sudo sed -i '/attacker@evil.com/d' /home/appuser/.ssh/authorized_keys",123         "Remove rogue key from appuser"),124        ("sudo cat /root/.ssh/authorized_keys",125         "Verify only legitimate keys remain"),126        ("done", "Unauthorized SSH keys removed"),127    ],128 129    "rogue_user": [130        ("sudo cat /etc/passwd | grep backdoor_admin",131         "Confirm rogue user exists"),132        ("sudo cat /etc/sudoers.d/backdoor_admin",133         "Check sudoers entry for rogue user"),134        ("sudo userdel -r backdoor_admin",135         "Delete rogue user and home directory"),136        ("sudo rm -f /etc/sudoers.d/backdoor_admin",137         "Remove sudoers entry"),138        ("sudo grep -r backdoor_admin /etc/sudoers /etc/sudoers.d/ 2>/dev/null || echo clean",139         "Verify no sudoers references remain"),140        ("done", "Rogue user account fully removed"),141    ],142 143    "suid_binaries": [144        ("sudo find /tmp /var/tmp -perm -4000 -type f 2>/dev/null",145         "Find SUID binaries in temp directories"),146        ("sudo rm -f /tmp/.hidden_shell",147         "Remove hidden SUID shell from /tmp"),148        ("sudo rm -f /var/tmp/escalate",149         "Remove SUID escalation binary from /var/tmp"),150        ("sudo rm -f /tmp/fake_sudo",151         "Remove fake sudo SUID binary"),152        ("done", "All rogue SUID binaries removed"),153    ],154 155    "dns_resolver": [156        ("cat /etc/resolv.conf",157         "Check current DNS configuration"),158        ("sudo bash -c 'cat > /etc/resolv.conf << EOF\nnameserver 8.8.8.8\nnameserver 1.1.1.1\nEOF'",159         "Set valid public DNS nameservers"),160        ("sudo chmod 644 /etc/resolv.conf",161         "Fix file permissions — remove world-writable"),162        ("done", "DNS resolver fixed"),163    ],164 165    "broken_apt": [166        ("sudo rm -f /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock",167         "Remove stale lock files"),168        ("sudo sed -i '/BROKEN_ENTRY/d' /var/lib/dpkg/status",169         "Remove corrupt entry from dpkg status"),170        ("sudo dpkg --configure -a",171         "Reconfigure any interrupted packages"),172        ("sudo apt-get update -qq",173         "Verify apt-get update works"),174        ("done", "Package manager repaired"),175    ],176 177    "hosts_hijack": [178        ("cat /etc/hosts",179         "Inspect current hosts file for hijacked entries"),180        ("sudo sed -i '/198.51.100.66/d' /etc/hosts",181         "Remove all lines with the malicious IP"),182        ("grep '127.0.0.1' /etc/hosts",183         "Verify localhost entry is still intact"),184        ("done", "Hosts file cleaned"),185    ],186 187    "kernel_hardening": [188        ("sudo sysctl net.ipv4.ip_forward net.ipv4.conf.all.accept_redirects net.ipv4.tcp_syncookies",189         "Check current insecure kernel parameters"),190        ("sudo sysctl -w net.ipv4.ip_forward=0",191         "Disable IP forwarding"),192        ("sudo sysctl -w net.ipv4.conf.all.accept_redirects=0",193         "Disable ICMP redirect acceptance"),194        ("sudo sysctl -w net.ipv4.tcp_syncookies=1",195         "Enable SYN flood protection"),196        ("sudo bash -c 'cat > /etc/sysctl.d/99-hardening.conf << EOF\nnet.ipv4.ip_forward = 0\nnet.ipv4.conf.all.accept_redirects = 0\nnet.ipv4.tcp_syncookies = 1\nEOF'",197         "Persist hardened settings across reboots"),198        ("done", "Kernel parameters hardened and persisted"),199    ],200 201    "reverse_shell": [202        ("ps aux | grep .rs_agent",203         "Locate the reverse shell process"),204        ("sudo pkill -f '.rs_agent'",205         "Kill the reverse shell process"),206        ("sudo rm -f /var/tmp/.rs_agent",207         "Remove the reverse shell binary"),208        ("sudo rm -f /etc/cron.d/rs_persist",209         "Remove cron persistence"),210        ("sudo rm -f /etc/systemd/system/rs_agent.timer /etc/systemd/system/rs_agent.service",211         "Remove systemd timer and service persistence"),212        ("sudo ls /etc/cron.d/ /etc/systemd/system/rs_agent* 2>/dev/null || echo all_clean",213         "Verify all persistence mechanisms removed"),214        ("done", "Reverse shell fully eradicated"),215    ],216}217 218 219# ---------------------------------------------------------------------------220# Remote runner — talks to the environment server over WebSocket221# ---------------------------------------------------------------------------222 223async def run_remote(url: str, task_id: str) -> float:224    from sysadmin_env import SysadminEnv, SysadminAction225 226    async with SysadminEnv(base_url=url) as env:227        result = await env.reset(task_id=task_id)228        obs = result.observation229        print(f"\n{'='*70}")230        print(f"  TASK: {task_id}")231        print(f"  {obs.task_description}")232        print(f"{'='*70}")233 234        playbook = PLAYBOOKS[task_id]235        for command, explanation in playbook:236            action = SysadminAction(command=command, explanation=explanation)237            result = await env.step(action)238            obs = result.observation239 240            status = "OK" if obs.exit_code == 0 else f"EXIT {obs.exit_code}"241            print(f"  [{obs.step:2d}] [{status:>8}] $ {command[:80]}")242            if obs.stderr and obs.exit_code != 0:243                print(f"       stderr: {obs.stderr[:120]}")244            if obs.hint:245                print(f"       hint: {obs.hint}")246            if result.reward is not None:247                print(f"\n  >>> REWARD: {result.reward:.3f}")248            if obs.done:249                break250 251        reward = result.reward if result.reward is not None else 0.0252        passed = "PASS" if reward >= 0.5 else "FAIL"253        print(f"  >>> {passed} (reward={reward:.3f})\n")254        return reward255 256 257# ---------------------------------------------------------------------------258# Local runner — directly instantiates tasks (needs root, no server needed)259# ---------------------------------------------------------------------------260 261def run_local(task_id: str) -> float:262    sys.path.insert(0, "/home/akshay/Desktop/meta-ai-linuxsysadmin/sysadmin_env")263    sys.path.insert(0, "/home/akshay/Desktop/meta-ai-linuxsysadmin")264 265    import subprocess266    from server.sysadmin_environment import ALL_TASKS267 268    task = ALL_TASKS[task_id]269    print(f"\n{'='*70}")270    print(f"  TASK: {task_id} (local mode)")271    print(f"  {task.description}")272    print(f"{'='*70}")273 274    task.setup()275    print("  [setup] Broken state injected")276 277    playbook = PLAYBOOKS[task_id]278    action_history = []279 280    for command, explanation in playbook:281        if command == "done":282            action_history.append({"command": command, "explanation": explanation,283                                   "stdout": "", "stderr": "", "exit_code": 0})284            continue285 286        result = subprocess.run(command, shell=True, executable="/bin/bash",287                                capture_output=True, text=True, timeout=15)288        action_history.append({289            "command": command, "explanation": explanation,290            "stdout": result.stdout[:4000], "stderr": result.stderr[:2000],291            "exit_code": result.returncode,292        })293        status = "OK" if result.returncode == 0 else f"EXIT {result.returncode}"294        print(f"  [{status:>8}] $ {command[:80]}")295        if result.stderr and result.returncode != 0:296            print(f"       stderr: {result.stderr[:120]}")297 298    check_result = task.check(action_history)299    print(f"\n  Programmatic score : {check_result.score:.3f}")300    print(f"  Passed             : {check_result.passed}")301    print(f"  Feedback           : {check_result.feedback}")302 303    task.teardown()304    print("  [teardown] Clean state restored")305 306    passed = "PASS" if check_result.score >= 0.8 else "FAIL"307    print(f"  >>> {passed} (score={check_result.score:.3f})\n")308    return check_result.score309 310 311# ---------------------------------------------------------------------------312# Main313# ---------------------------------------------------------------------------314 315async def main():316    parser = argparse.ArgumentParser(description="Test all sysadmin RL tasks")317    parser.add_argument("--url", default="http://localhost:7860",318                        help="Server URL (default: http://localhost:7860)")319    parser.add_argument("--task", default=None,320                        help="Run a single task by ID (default: all)")321    parser.add_argument("--local", action="store_true",322                        help="Run locally without a server (requires root)")323    args = parser.parse_args()324 325    task_ids = [args.task] if args.task else list(PLAYBOOKS.keys())326 327    print(f"\nRunning {len(task_ids)} task(s) in {'local' if args.local else 'remote'} mode\n")328 329    results = {}330    for task_id in task_ids:331        try:332            if args.local:333                score = run_local(task_id)334            else:335                score = await run_remote(args.url, task_id)336            results[task_id] = score337        except Exception as e:338            print(f"  >>> ERROR on {task_id}: {e}\n")339            results[task_id] = -1.0340 341    # Summary342    print(f"\n{'='*70}")343    print("  SUMMARY")344    print(f"{'='*70}")345    for tid, score in results.items():346        if score < 0:347            status = "ERROR"348        elif score >= 0.5:349            status = " PASS"350        else:351            status = " FAIL"352        print(f"  [{status}] {tid:30s}  score={score:.3f}")353 354    passed = sum(1 for s in results.values() if s >= 0.5)355    total = len(results)356    errored = sum(1 for s in results.values() if s < 0)357    print(f"\n  {passed}/{total} passed, {errored} errors")358    print(f"{'='*70}\n")359 360 361if __name__ == "__main__":362    asyncio.run(main())363