From d23823322f905628ef91ef89d6027057d2ae109d Mon Sep 17 00:00:00 2001 From: Wum1ng <1210078968@qq.com> Date: Wed, 29 May 2024 20:48:13 +0800 Subject: [PATCH] remove all about windows --- challenge/Dockerfile_amd64 | 5 +- challenge/Dockerfile_arm64 | 5 +- challenge/docker-entrypoint.d/10_start_vm.sh | 5 - challenge/services.d/desktop-win | 20 - challenge/windows/windows | 346 --------- docker-compose.yml | 8 - dojo_plugin/api/v1/docker.py | 15 +- dojo_plugin/config.py | 1 - dojo_plugin/pages/workspace.py | 3 +- script/container-setup.sh | 1 - windows/Autounattend.xml | 200 ----- windows/Dockerfile | 110 --- windows/README.md | 133 ---- windows/challenge-proxy/Cargo.lock | 732 ------------------- windows/challenge-proxy/Cargo.toml | 17 - windows/challenge-proxy/src/main.rs | 227 ------ windows/full.yml | 15 - windows/none.yml | 6 - windows/setup.ps1 | 198 ----- windows/shutdown.py | 66 -- windows/sshd_config | 88 --- windows/startup.ps1 | 40 - 22 files changed, 5 insertions(+), 2236 deletions(-) delete mode 100755 challenge/services.d/desktop-win delete mode 100755 challenge/windows/windows delete mode 100644 windows/Autounattend.xml delete mode 100644 windows/Dockerfile delete mode 100644 windows/README.md delete mode 100644 windows/challenge-proxy/Cargo.lock delete mode 100644 windows/challenge-proxy/Cargo.toml delete mode 100644 windows/challenge-proxy/src/main.rs delete mode 100644 windows/full.yml delete mode 100644 windows/none.yml delete mode 100644 windows/setup.ps1 delete mode 100644 windows/shutdown.py delete mode 100644 windows/sshd_config delete mode 100644 windows/startup.ps1 diff --git a/challenge/Dockerfile_amd64 b/challenge/Dockerfile_amd64 index e15f2401b..5cd090c73 100644 --- a/challenge/Dockerfile_amd64 +++ b/challenge/Dockerfile_amd64 @@ -577,7 +577,6 @@ COPY services.d /opt/pwn.college/services.d COPY setuid_interpreter.c /opt/pwn.college/setuid_interpreter.c COPY bash.bashrc /opt/pwn.college/bash.bashrc COPY vm /opt/pwn.college/vm -COPY windows /opt/pwn.college/windows COPY .tmux.conf /opt/pwn.college/.tmux.conf COPY .gdbinit /opt/pwn.college/.gdbinit COPY .radare2rc /opt/pwn.college/.radare2rc @@ -602,7 +601,6 @@ COPY --link --from=builder-pwn.college /opt/pwn.college /opt/pwn.college RUN < /opt/pwn.college/build EOF diff --git a/challenge/Dockerfile_arm64 b/challenge/Dockerfile_arm64 index 064d1438b..983cfc058 100644 --- a/challenge/Dockerfile_arm64 +++ b/challenge/Dockerfile_arm64 @@ -514,7 +514,6 @@ COPY docker-entrypoint.sh /opt/pwn.college/docker-entrypoint.sh COPY setuid_interpreter.c /opt/pwn.college/setuid_interpreter.c COPY bash.bashrc /opt/pwn.college/bash.bashrc COPY vm /opt/pwn.college/vm -COPY windows /opt/pwn.college/windows COPY .tmux.conf /opt/pwn.college/.tmux.conf COPY .gdbinit /opt/pwn.college/.gdbinit #COPY .radare2rc /opt/pwn.college/.radare2rc @@ -539,7 +538,6 @@ COPY --link --from=builder-pwn.college /opt/pwn.college /opt/pwn.college RUN < /opt/pwn.college/build EOF diff --git a/challenge/docker-entrypoint.d/10_start_vm.sh b/challenge/docker-entrypoint.d/10_start_vm.sh index 481c7e6d0..1cf4189f1 100755 --- a/challenge/docker-entrypoint.d/10_start_vm.sh +++ b/challenge/docker-entrypoint.d/10_start_vm.sh @@ -4,8 +4,3 @@ if ! find /challenge -name '*.ko' -exec false {} + then vm start fi - -if ! find /challenge -name '*.exe' -exec false {} + -then - windows start -fi diff --git a/challenge/services.d/desktop-win b/challenge/services.d/desktop-win deleted file mode 100755 index 5f424b73a..000000000 --- a/challenge/services.d/desktop-win +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -ps aux | grep -q [d]ojo-user:6082 && exit - -mkdir -p /tmp/.dojo/vnc /home/hacker/.vnc -start-stop-daemon --start \ - --pidfile /tmp/.dojo/vnc/websockify-windows.pid \ - --make-pidfile \ - --background \ - --no-close \ - --startas /usr/bin/websockify \ - -- \ - --web /usr/share/novnc/ \ - dojo-user:6082 \ - localhost:5912 \ - >/tmp/.dojo/vnc/websockify-windows.log \ - 2>&1 - -until curl -s dojo-user:6080 >/dev/null; do sleep 0.1; done diff --git a/challenge/windows/windows b/challenge/windows/windows deleted file mode 100755 index d8ac07c93..000000000 --- a/challenge/windows/windows +++ /dev/null @@ -1,346 +0,0 @@ -#!/opt/pwn.college/python - -import os -import sys -import socket -import subprocess -import time -import tempfile -import shutil -import textwrap -import grp -import argparse -from pathlib import Path - -VOLUME_PATH = Path("/run/media/windows") -# /run is not world writeable. this should prevent race conditions. -STATEFUL_PATH = Path("/run/windows") -IMAGE_PATH = STATEFUL_PATH / "windows_img.qcow2" -VM_PIDFILE = STATEFUL_PATH / "vm.pid" -VM_LOGFILE = STATEFUL_PATH / "vm.log" -STATEFUL_WORLD_WRITEABLE_PATH = STATEFUL_PATH / "world-writeable" -virtfs_sock_path = lambda dir_path, tag: dir_path / f"virtfs-{tag}.sock" -virtfs_pidfile_path = lambda dir_path, tag: dir_path / f"virtfs-{tag}.pid" -virtfs_log_path = lambda dir_path, tag: dir_path / f"virtfs-{tag}.log" -VIRTIOFSD_PATH = "/opt/virtiofsd/virtiofsd" -FLAG_SHARE_PATH = STATEFUL_PATH / "flag-volume" - - -def error(msg): - print(msg, file=sys.stderr) - exit(1) - - -def initialize(): - if not VOLUME_PATH.is_dir(): - raise AssertionError("Dojo was not configured with WINDOWS_VM=full") - - if not (VOLUME_PATH / "image-built").exists(): - raise AssertionError("For security reasons, cannot interact with VM while it is building") - - os.setegid(os.geteuid()) - try: - STATEFUL_PATH.mkdir() - except FileExistsError: - pass - try: - STATEFUL_WORLD_WRITEABLE_PATH.mkdir() - except FileExistsError: - pass - STATEFUL_WORLD_WRITEABLE_PATH.chmod(0o777) - try: - FLAG_SHARE_PATH.mkdir() - except FileExistsError: - pass - - -def vm_hostname(): - with open("/etc/hosts") as f: - if "127.0.0.1\tvm" in f.read(): - return "vm" - else: - return "127.0.0.1" - - -def is_privileged(): - groups = set(grp.getgrgid(group).gr_name for group in os.getgroups()) - return os.getuid() == 0 or "sudo" in groups - - -def execve(argv): - os.seteuid(os.getuid()) - os.setegid(os.getgid()) - os.execve(argv[0], argv, os.environ) - - -def start_daemon(pidfile, logfile, child_argv, drop_privs=False): - def preexec_drop_privs(): - os.seteuid(os.getuid()) - os.setegid(os.getgid()) - - preexec_fn = None - if drop_privs: - preexec_fn = preexec_drop_privs - - daemon_argv = [ - "/usr/sbin/start-stop-daemon", - "--start", - "--pidfile", - str(pidfile), - "--make-pidfile", - "--background", - "--no-close", - "--quiet", - "--oknodo", - "--startas", - child_argv[0], - "--", - *child_argv[1:], - ] - - subprocess.run( - daemon_argv, - stdin=subprocess.DEVNULL, - stdout=open(logfile, "a"), - stderr=subprocess.STDOUT, - check=True, - preexec_fn=preexec_fn, - ) - - -def reset_image(): - try: - IMAGE_PATH.unlink() - except FileNotFoundError: - pass - - subprocess.check_call( - [ - "/usr/bin/qemu-img", - "create", - "-f", - "qcow2", - "-o", - f"backing_file={VOLUME_PATH / 'clean.qcow2'}", - "-o", - "backing_fmt=qcow2", - str(IMAGE_PATH), - "51200M", - ], - stdin=subprocess.DEVNULL, - stdout=sys.stdout, - stderr=sys.stderr, - ) - - -def kill(): - for pidfile in STATEFUL_PATH.glob("*.pid"): - argv = [ - "/usr/sbin/start-stop-daemon", - "--stop", - "--pidfile", - str(pidfile), - "--remove-pidfile", - "--quiet", - "--oknodo", - ] - - subprocess.run( - argv, - stdin=subprocess.DEVNULL, - stdout=open(VM_LOGFILE, "a"), - stderr=subprocess.STDOUT, - check=True, - ) - - for logfile in STATEFUL_PATH.glob("*.log"): - logfile.unlink() - - -def fs_bridge_running(): - procfs = Path("/proc") - pid_dirs = [d for d in procfs.iterdir() if d.name.isdigit()] - for pid in pid_dirs: - try: - exe_link = Path("/proc") / str(pid) / "exe" - if os.readlink(str(exe_link)) == str(VIRTIOFSD_PATH): - return True - except FileNotFoundError: - pass - return False - - -def start(): - if not Path("/dev/kvm").exists(): - raise NotImplementedError( - "Running the windows VM without KVM is not implemented" - ) - - if not IMAGE_PATH.exists(): - reset_image() - - # We need to pass the flag into the VM for the initial boot, before the FS bridge - # starts. - # The FS bridge lets an unprivileged Windows user access the shared filesystem with - # root privileges, so it would be quite bad if we were to set up the flag again. - # This function gets called even if the VM is already running, so we need to make - # sure the bridge isn't running. - if not fs_bridge_running(): - with open("/flag", "r") as f: - flag = f.read() - fd = os.open( - path=str(FLAG_SHARE_PATH / "flag"), - flags=(os.O_WRONLY | os.O_CREAT | os.O_TRUNC), - mode=0o600 - ) - os.fchmod(fd, 0o600) - with open(fd, "w") as f: - f.write(flag) - - if is_privileged(): - (FLAG_SHARE_PATH / "practice-mode-enabled").touch() - - mem = "4096M" - # fmt: off - qemu_argv = [ - "/usr/bin/qemu-system-x86_64", - "-name", "dojo", - "-machine", "type=pc,accel=kvm", - "-m", mem, - "-smp", "4", - "-display", "none", - "-device", "virtio-net,netdev=user.0", - # 5985: WinRM, 22: SSH, 5912: VNC, 4001: ChallengeProxy - "-netdev", "user,id=user.0,hostfwd=tcp::5985-:5985,hostfwd=tcp::22-:22,hostfwd=tcp::5912-:5912,hostfwd=tcp::4001-:4001", - "-serial", "null", - "-monitor", "none", - "-drive", f"file={IMAGE_PATH},if=virtio,cache=writeback,discard=ignore,format=qcow2", - "-drive", f"file={VOLUME_PATH / 'virtio-win-processed.iso'},media=cdrom", - "-object", f"memory-backend-memfd,id=mem,size={mem},share=on", - "-numa", "node,memdev=mem" - ] - # fmt: on - mounts = { - "challenge": ("/challenge", False), - "home": ("/home/hacker", False), - "flag": (str(FLAG_SHARE_PATH), True) - } - for tag, (mountpoint, needs_root) in mounts.items(): - dir_path = STATEFUL_PATH if needs_root else STATEFUL_WORLD_WRITEABLE_PATH - sock_path = virtfs_sock_path(dir_path, tag) - start_daemon( - virtfs_pidfile_path(dir_path, tag), - virtfs_log_path(dir_path, tag), - # fmt: off - [ - str(VIRTIOFSD_PATH), - "--writeback", - "--socket-path", str(sock_path), - "--sandbox", "chroot" if needs_root else "none", - "--shared-dir", str(mountpoint) - ], - # fmt: on - drop_privs=not needs_root - ) - - # fmt: off - qemu_argv += [ - "-chardev", f"socket,id={tag}-sock,path={sock_path}", - "-device", f"vhost-user-fs-pci,queue-size=1024,chardev={tag}-sock,tag={tag}", - ] - # fmt: on - - start_daemon(VM_PIDFILE, VM_LOGFILE, qemu_argv) - - -def wait(): - for _ in range(50): - try: - connection = socket.create_connection((vm_hostname(), 22), timeout=30) - data = connection.recv(3) - connection.close() - if data == b"SSH": - break - except (ConnectionRefusedError, socket.timeout): - pass - time.sleep(0.1) - else: - error("Error: could not connect to vm!") - - -def connect(): - wait() - execve(["/usr/bin/ssh", vm_hostname()]) - - -def exec_(*args): - wait() - if sys.stdout.isatty(): - execve(["/usr/bin/ssh", "-t", vm_hostname(), "--", *args]) - else: - execve(["/usr/bin/ssh", vm_hostname(), "--", *args]) - - -def logs(): - argv = [ - "/usr/bin/tail", - "-F", - "-n+1", - str(VM_LOGFILE), - ] - - while True: - subprocess.run(argv, stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - - time.sleep(0.1) - - -def main(): - global args - - initialize() - - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="command", required=True) - - connect_parser = subparsers.add_parser("connect", help="connect to vm") - - exec_parser = subparsers.add_parser("exec", help="exec command in vm") - exec_parser.add_argument("exec_command") - exec_parser.add_argument("exec_command_args", nargs=argparse.REMAINDER) - - start_parser = subparsers.add_parser("start", help="start vm") - - stop_parser = subparsers.add_parser("stop", help="stop vm") - - kill_parser = subparsers.add_parser("kill", help="kill vm") - - restart_parser = subparsers.add_parser("restart", help="restart vm") - - forcerestart_parser = subparsers.add_parser( - "forcerestart", help="kill and restart vm" - ) - - reset_parser = subparsers.add_parser("reset", help="reset VM image") - - args = parser.parse_args() - - commands = { - "connect": lambda: (start(), connect()), - "exec": lambda: (start(), exec_(args.exec_command, *args.exec_command_args)), - "start": lambda: (kill(), start()), - "stop": lambda: exec_("powershell", "-command", "stop-computer -force"), - "kill": lambda: kill(), - "restart": lambda: exec_("powershell", "-command", "restart-computer -force"), - "forcerestart": lambda: (kill(), start()), - "reset": lambda: reset_image(), - } - - try: - commands[args.command]() - except KeyboardInterrupt: - pass - - -if __name__ == "__main__": - main() diff --git a/docker-compose.yml b/docker-compose.yml index b2c3f2157..bf92bfb15 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,6 @@ services: - INSTALL_TOOLS_APT=${INSTALL_TOOLS_APT:-${DEFAULT_INSTALL_SELECTION}} - INSTALL_TOOLS_PIP=${INSTALL_TOOLS_PIP:-${DEFAULT_INSTALL_SELECTION}} - INSTALL_VIRTIOFSD=${INSTALL_VIRTIOFSD:-${DEFAULT_INSTALL_SELECTION}} - - INSTALL_WINDOWS=${INSTALL_WINDOWS:-${DEFAULT_INSTALL_SELECTION}} - UBUNTU_VERSION=${UBUNTU_VERSION} - DOJO_CHALLENGE=${DOJO_CHALLENGE} platform: linux/${ARCH} @@ -70,7 +69,6 @@ services: - DOJO_HOST=${DOJO_HOST} - HOST_DATA_PATH=/opt/pwn.college/data - INTERNET_FOR_ALL=${INTERNET_FOR_ALL} - - WINDOWS_VM=${WINDOWS_VM} - VIRTUAL_HOST=${DOJO_HOST} - VIRTUAL_PORT=8000 - LETSENCRYPT_HOST=${DOJO_HOST} @@ -188,18 +186,12 @@ services: - acme:/etc/acme.sh - /var/run/docker.sock:/var/run/docker.sock:ro - windows: - extends: - file: ./windows/${WINDOWS_VM}.yml - service: windows - volumes: conf: html: dhparam: certs: acme: - windows: networks: user_network: diff --git a/dojo_plugin/api/v1/docker.py b/dojo_plugin/api/v1/docker.py index dca7a16b2..3bd4824a7 100644 --- a/dojo_plugin/api/v1/docker.py +++ b/dojo_plugin/api/v1/docker.py @@ -11,7 +11,7 @@ from CTFd.utils.user import get_current_user, is_admin from CTFd.utils.decorators import authed_only -from ...config import HOST_DATA_PATH, INTERNET_FOR_ALL, WINDOWS_VM_ENABLED, SECCOMP, USER_FIREWALL_ALLOWED +from ...config import HOST_DATA_PATH, INTERNET_FOR_ALL, SECCOMP, USER_FIREWALL_ALLOWED from ...models import Dojos, DojoModules, DojoChallenges from ...utils import serialize_user_flag, simple_tar, random_home_path, module_challenges_visible, user_ipv4 from ...utils.dojo import dojo_accessible, get_current_dojo_challenge @@ -91,18 +91,7 @@ def start_container(user, dojo_challenge, practice): "bind", propagation="shared", ) - ] - + ( - [ - docker.types.Mount( - target="/run/media/windows", - source="pwncollege_windows", - read_only=True, - ) - ] - if WINDOWS_VM_ENABLED - else [] - ), + ], devices=devices, network=None, extra_hosts={ diff --git a/dojo_plugin/config.py b/dojo_plugin/config.py index 364598332..64dea5597 100644 --- a/dojo_plugin/config.py +++ b/dojo_plugin/config.py @@ -87,7 +87,6 @@ def create_seccomp(): HOST_DATA_PATH = os.getenv("HOST_DATA_PATH") BINARY_NINJA_API_KEY = os.getenv("BINARY_NINJA_API_KEY") INTERNET_FOR_ALL = bool(ast.literal_eval(os.getenv("INTERNET_FOR_ALL") or "False")) -WINDOWS_VM_ENABLED = os.getenv("WINDOWS_VM") == "full" missing_errors = ["DOJO_HOST", "HOST_DATA_PATH"] missing_warnings = ["BINARY_NINJA_API_KEY"] diff --git a/dojo_plugin/pages/workspace.py b/dojo_plugin/pages/workspace.py index 41f70b0fe..56b9601a2 100644 --- a/dojo_plugin/pages/workspace.py +++ b/dojo_plugin/pages/workspace.py @@ -17,9 +17,8 @@ "challenge": 80, "vscode": 6080, "desktop": 6081, - "desktop-windows": 6082, } -ondemand_services = { "vscode", "desktop", "desktop-windows" } +ondemand_services = { "vscode", "desktop"} def container_password(container, *args): key = container.labels["dojo.auth_token"].encode() diff --git a/script/container-setup.sh b/script/container-setup.sh index 5e4968759..f9495786a 100755 --- a/script/container-setup.sh +++ b/script/container-setup.sh @@ -17,7 +17,6 @@ define () { define DOJO_HOST localhost.pwn.hust.college define DOJO_ENV development define DOJO_CHALLENGE challenge-mini -define WINDOWS_VM none define SECRET_KEY $(openssl rand -hex 16) define DOCKER_PSLR $(openssl rand -hex 16) define UBUNTU_VERSION 20.04 diff --git a/windows/Autounattend.xml b/windows/Autounattend.xml deleted file mode 100644 index bdbfabec5..000000000 --- a/windows/Autounattend.xml +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - en-US - - en-US - en-US - en-US - en-US - en-US - - - - - E:\virtio-win\NetKVM\2k16\amd64\ - - - E:\virtio-win\viostor\2k16\amd64\ - - - - - - - 0 - true - - - Primary - 1 - 350 - - - 2 - Primary - true - - - - - true - NTFS - - 0x27 - 1 - 1 - - - NTFS - - C - 2 - 2 - - - - - - - - - /IMAGE/NAME - - Windows Server 2022 SERVERDATACENTER - - - - 0 - 2 - - - - - - - - - - OnError - - true - - Dojo - Dojo - - - - - - - false - - win2022 - UTC - - - - true - - - false - false - - - - - true - Google - Google - http://www.google.com/search?q={searchTerms} - - - true - true - about:blank - - - false - - - 0 - - - true - - - true - - - - - - - hacker - true</PlainText> - </Password> - <Enabled>true</Enabled> - <Username>hacker</Username> - </AutoLogon> - <FirstLogonCommands> - <!-- Run this first to attempt to pre-empt the propmt --> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c reg add "HKLM\System\CurrentControlSet\Control\Network\NewNetworkWindowOff"</CommandLine> - <Description>Network prompt</Description> - <Order>1</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <!-- Ensure we can run our scripts --> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine> - <Description>Set Execution Policy 64 Bit</Description> - <Order>2</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c powershell -File A:\setup.ps1</CommandLine> - <Description>Run setup script</Description> - <Order>3</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - </FirstLogonCommands> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Home</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>hacker</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - <LocalAccounts> - <LocalAccount wcm:action="add"> - <Password> - <Value>hacker</Value> - <PlainText>true</PlainText> - </Password> - <!-- This is for setup. It will be removed before the container is made accessible. --> - <Group>administrators</Group> - <DisplayName>Hacker</DisplayName> - <Name>hacker</Name> - <Description>Hacker User</Description> - </LocalAccount> - </LocalAccounts> - </UserAccounts> - <RegisteredOwner/> - </component> - </settings> - <settings pass="offlineServicing"> - <component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" language="neutral" name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS"> - <EnableLUA>false</EnableLUA> - </component> - </settings> -</unattend> diff --git a/windows/Dockerfile b/windows/Dockerfile deleted file mode 100644 index fe7f4f4c4..000000000 --- a/windows/Dockerfile +++ /dev/null @@ -1,110 +0,0 @@ -FROM ubuntu:20.04 AS full - -RUN sed -i.bak 's|https\?://archive.ubuntu.com|http://mirrors.hust.edu.cn|g' /etc/apt/sources.list -RUN echo 'APT::Install-Recommends 0;' >> /etc/apt/apt.conf.d/01norecommends \ - && echo 'APT::Install-Suggests 0;' >> /etc/apt/apt.conf.d/01norecommends \ - && apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y \ - ca-certificates apt-transport-https curl \ - xorriso mtools dosfstools qemu-utils qemu-kvm python3 openssh-client \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /app - -# IDA Freeware: only permissible for free and open deployments of the dojo! -ARG INSTALL_IDA_FREE=no - -# we create a floppy disk that will hold our Autounattend.xml in the root which will -# allow windows install to proceed automatically. -# We require privileges to create a loop device -COPY ./Autounattend.xml ./setup.ps1 ./startup.ps1 ./sshd_config ./ -COPY ./challenge-proxy ./challenge-proxy -RUN sed -i 's/{INSTALLIDA}/'"$INSTALL_IDA_FREE"'/g' ./setup.ps1 \ - && touch ./practice-mode-enabled \ - && mkfs.fat -F 12 -C ./floppy.img 1440 \ - && mcopy -si ./floppy.img \ - ./Autounattend.xml ./setup.ps1 ./startup.ps1 ./practice-mode-enabled ./sshd_config ./challenge-proxy/ :: \ - && rm -rf ./Autounattend.xml ./setup.ps1 ./startup.ps1 ./practice-mode-enabled ./sshd_config ./challenge-proxy/ - -VOLUME /app/build - -COPY ./shutdown.py . -# we have to repackage the ISO file into the correct format for windows to accept it -# we create a virtio-win directory in the root of the ISO here. This isn't *strictly* -# necessary but it has to correspond with the paths in the Autounattend.xml -# careful... if the drivers can't load for some reason, install will fail with the -# cryptic error "Failed to applay DriveConfiguration". This is because the drivers -# are required to write to the qcow2 image. -CMD \ - ( [ -f ./build/virtio-win-processed.iso ] || ( \ - echo "Building virtio drivers disk" \ - && curl -Lo virtio-win-raw.iso \ - 'https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso' \ - && WORKDIR="$(mktemp -d --suffix=.img-extract)" \ - && EXTRACT_DIR="$WORKDIR/virtio-win" \ - && mkdir -p "$EXTRACT_DIR" \ - && xorriso -report_about SORRY -osirrox on -indev ./virtio-win-raw.iso -extract / "$EXTRACT_DIR" \ - && rm ./virtio-win-raw.iso \ - && xorriso \ - -as genisoimage -rock -joliet -volid VIRTIO \ - -output ./build/virtio-win-processed.iso \ - "$WORKDIR" \ - && rm -rf "$WORKDIR" virtio-win-raw.iso \ - ) ) \ - && ( [ -f ./build/server-2022.iso ] || ( \ - echo "Downloading Windows Server ISO" \ - && curl -Lo ./build/server-2022.iso \ - 'https://software-static.download.prss.microsoft.com/sg/download/888969d5-f34g-4e03-ac9d-1f9786c66749/SERVER_EVAL_x64FRE_en-us.iso' \ - ) ) \ - && ( [ -f ./build/image-stage1-complete ] || ( \ - echo "Creating VM image" \ - && rm -rf ./build/clean.qcow2 ./build/image-built \ - && qemu-img create -f qcow2 ./build/clean.qcow2 51200M \ - && echo "Installing and configuring windows (this will take a while)" \ - && qemu-system-x86_64 \ - -name dojo \ - -boot once=d \ - -machine type=pc,accel=kvm \ - -m 4096M \ - -smp "$(nproc)" \ - -display vnc=:12 \ - -nographic \ - -device virtio-net,netdev=user.0 \ - -netdev user,id=user.0,hostfwd=tcp::5985-:5985,hostfwd=tcp::2222-:22 \ - -serial null \ - `#-monitor unix:./build/monitor.sock,server,nowait` \ - -drive file=./floppy.img,format=raw,index=0,if=floppy \ - -drive "file=./build/server-2022.iso,media=cdrom" \ - -drive "file=./build/virtio-win-processed.iso,media=cdrom" \ - -drive file=./build/clean.qcow2,if=virtio,cache=writeback,discard=ignore,format=qcow2 \ - && rm -rf ./build/monitor.sock \ - && touch ./build/image-stage1-complete \ - ) ) \ - && ( [ -f ./build/image-built ] || ( \ - echo "Performing initial bootup" \ - && ( \ - qemu-system-x86_64 \ - -name dojo \ - -boot once=d \ - -machine type=pc,accel=kvm \ - -m 4096M \ - -smp "$(nproc)" \ - -display vnc=:12 \ - -nographic \ - -device virtio-net,netdev=user.0 \ - -netdev user,id=user.0,hostfwd=tcp::5985-:5985,hostfwd=tcp::2222-:22 \ - -serial null \ - `#-monitor unix:./build/monitor.sock,server,nowait` \ - -drive file=./floppy.img,format=raw,index=0,if=floppy \ - -drive "file=./build/server-2022.iso,media=cdrom" \ - -drive "file=./build/virtio-win-processed.iso,media=cdrom" \ - -drive file=./build/clean.qcow2,if=virtio,cache=writeback,discard=ignore,format=qcow2 \ - & python3 ./shutdown.py \ - ) && rm -f ./build/monitor.sock \ - && touch ./build/image-built \ - && echo "Windows image built" \ - ) ) - -FROM ubuntu:20.04 AS none - -CMD true diff --git a/windows/README.md b/windows/README.md deleted file mode 100644 index 37b063aef..000000000 --- a/windows/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# Dojo Windows Infrastructure - -## Requirements - -The windows environment requires KVM. -It is possible to run without KVM, although this would be extremely slow and is not implemented. -If KVM is enabled, the device `/dev/kvm` will exist in the host operating system. - -## Enabling - -KVM is already passed through to the dojo container due to the `--privileged` flag. -The windows environment is gated behind the `WINDOWS_VM` environment variable, which can have the values `none` (default) and `full`. -This variable functions similarly to the `DOJO_CHALLENGE` environment variable: it can be modified using either `-e WINDOWS_VM=full` on the docker command-line, or by editing `data/config.env`. - -## Basic architecture - -The `WINDOWS_VM` environment variable is read by the `docker-compose.yml` file and used to conditionally pick between a no-op service and a builder service. -This is done so that the KVM-requiring full service is swapped with one that does not require KVM when the windows VM in not in use. -`docker-compose` also creates a windows volume which will be shared between the builder service and the challenge container. - -The builder service is a docker image located in the `windows/` directory of the source tree. -This docker image contains the tools needed to run a QEMU VM and a floppy disk with files for the install. - -Once the VM is built, the resulting image is stored the windows volume. -When a new challenge container is spun up, this volume will be read-only mounted into the container image. -This shared clean image will server as the base for every new copy-on-write image created by a user container. -The read-only mount ensures that the shared image file cannot be modified, even with `root` permissions in the challenge container. -The user can then interact with the VM using the `windows` setuid script within the challenge container. -The script manages the creation and interfacing with the VM image. - -Users can interact with the VM over both SSH on port `22` and VNC on port `5912`. -Both of these ports are forwarded by QEMU, and connect to running servers inside the VM image. -QEMU VNC is not used because its limited integration with the operating system prevents the use of important features like copy-and-paste. -Instead, a tightVNC server is installed and configured within the VM. -The windows VNC desktop can be accessed in a similar manner to the linux desktop. - -Two `virtio-fs` mounts are forwarded to the VM: one for `/challenge` and one for `/home`. -These are mounted as `Y:` and `Z:` respectively, although they can be configured to be mounted anywhere on the filesystem, including a subdirectory of the `C:\` drive. -The challenge mount is also used to pass the flag and information about whether practice mode is enabled to the VM. -The startup script will secure the flag in `C:\flag` prior to starting SSH. - -## Builder service - -The VM is not built by the Dockerfile due to a couple factors. -First, docker builders do not have access to devices, like the `/dev/kvm` device needed for the install, by default. -This can be sidestepped by enabling some newer docker features that allow you to define the "build container", allowing you to give this container access to devices and remove isolation from certain build steps. -This however comes at a performance cost, because the resulting image has to be exported as a tar file and transferred into the host docker daemon. -This process is extremely slow for large images. -At the size the VM will be, 10-15GB, this process can take 10-20 minutes for this transfer alone. -Due to this consideration, the image is instead built in the builder service's entrypoint. - -The builder first repackages Red Hat's `virtio-win-tools` CDROM ISO, which contains needed drivers and executables, in the format that windows expects. -The repackaged ISO is stored in the volume for later use. -(The command for doing so was extracted from the source code of `hashicorp/packer`, which is used by `hashicorp/vagrant` internally.) -It then downloads a Windows Server 2022 Evaluation Image from Microsoft servers. -(As far as legal issues with this step, I am not a lawyer, but it seems like the evaluation image works fine and does not need to be activated for the dojo's use case.) -It will then check for an `image-built` file in the windows volume. -If this file is present, the builder will exit. -Otherwise it will rebuild the VM image into the `clean.qcow2` file in the windows volume. - -## Building process - -The builder boots with the server ISO, floppy disk, and virtio CDROM attached. -Users can monitor the building process by connecting via VNC to the top-level dojo container's port `5912`. -First, the VM will boot the windows server ISO. -The server ISO will read the `Autounattend.xml` file from the floppy disk. -This file is known as an answer file, it allows the setup to process completely unattended. -After the operating system is installed, it will reboot into the operating system and automatically log in to the hacker user. -The hacker user is chosen because the administrator account needs to be disabled by the install process for security reasons. -The hacker user has administrator in order to perform this setup. -Once hacker is logged in, it will run the first logon commands defined by the answer file. -These commands will disable the new network prompt pop-up, make the powershell execution policy more permissive, and then run the `setup.ps1` file. - -The setup script does a few things to configure the image: - -- Set the virtual network to be "private" to ensure windows trusts it -- Enable the SSH service, set the default shell to be PowerShell, and whitelist it in the firewall -- Install the required drivers for the filesystem bridging -- Setup the ChallengeProxy service -- Setup the startup script as a scheduled task -- Install the chocolately package manager -- Install and configure the TightVNC server -- Deactivate the administrator account - -Finally, it shuts down the computer. -This automatic shutdown is convienient because it means we don't have to use a separate, potentially fragile script to wait for SSH or WinRM to come up and allow us to shut down the machine to end the build service. -Once the machine boots, control is handed to the startup service. - -## Startup service - -The startup service: - -- mounts the filesystem bridges -- copies the flag out of the bridge (which doesn't support permissions and is therefore world readable) into the C drive, and sets up its permissions -- removes admin unless practice mode is enabled -- starts the SSH daemon and VNC server. - These are set to manual startup mode so that users cannot connect before the startup script has properly configured permissions. - -## Filesystem Sharing - -The filesystem sharing has a component on each side of the VM. -The host side has a `virtiofsd` process running for each virtual filesystem that listens on a UNIX socket for connection from QEMU. -The guest side has a filesystem driver that connects to the virtual PCI device, and a userspace process that uses WinFsp, the windows equivalent of FUSE, to mount the filesystem and talks to the driver. - -### Host - -The biggest concern on the host side is sandboxing. -We don't want users to be able to abuse the filesystem daemon to access files outside of the directories we want to mount in (such as the flag) or escalate privileges. -The typical sandboxing approach with user namespaces is not available to us because of the constraints of the docker container security model. -Instead we can either use chroot sandboxing, which requires root access, or run as hacker and use no sandboxing. -Currently the chroot sandbox is used, however this may be changed in the future. - -### Guest - -Information about the guest side software can be found on [the virtio-win virtiofs wiki page](https://github.com/virtio-win/kvm-guest-drivers-windows/wiki/Virtiofs). -The userspace process defaults to mounting the first filesystem, unless command-line arguments specify a mount tag to select filesystem. -The mountpoint also defaults to `Z:\` unless overriden. -The userspace process can be started as a service, but, for some reason, windows has no way to persist service command-line arguments across boots, so this can only be used if the defaults are acceptable. -We want to have two filesystems, so our only option is to use the registry to store configuration. -WinFsp, the user filesystem driver library similar to linux's FUSE that the virtiofs service uses, has it's own scripts that can be used to define an FS service in the registry that can then be started by a launcher binary. -We first use the filesystem register script to add an entry to the registry for the virtiofs service, with a template for the command-line arguments. -Later, we can start up this service in the startup script with the launcher, specifying the command-line arguments to substitute into the template. - -## Rebuilding the VM image - -This can be done by removing the `image-stage1-complete` marker file and updating the dojo: - -```sh -sudo rm ./data/docker/volumes/pwncollege_windows/_data/image-stage1-complete -sudo docker exec -it dojo dojo update -``` - -The existing `virtio-win` ISO and Windows Server ISO stored in the volume will be reused. diff --git a/windows/challenge-proxy/Cargo.lock b/windows/challenge-proxy/Cargo.lock deleted file mode 100644 index 6b03e61a7..000000000 --- a/windows/challenge-proxy/Cargo.lock +++ /dev/null @@ -1,732 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" -dependencies = [ - "memchr", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "challenge-proxy" -version = "0.1.0" -dependencies = [ - "env_logger", - "eyre", - "log", - "once_cell", - "tokio", - "windows-service", - "winlog", -] - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "errno" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "eyre" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "is-terminal" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "linux-raw-sys" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf14a7a466ce88b5eac3da815b53aefc208ce7e74d1c263aabb04d88c4abeb1" -dependencies = [ - "bitflags 2.4.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" - -[[package]] -name = "socket2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "syn" -version = "2.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "tokio" -version = "1.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "widestring" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-service" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9db37ecb5b13762d95468a2fc6009d4b2c62801243223aabd44fca13ad13c8" -dependencies = [ - "bitflags 1.3.2", - "widestring", - "windows-sys 0.45.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "winlog" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b651e150c151f8feee1c3df5cd5d2c9f5c02d921e34ca309df247ef9c555f919" -dependencies = [ - "log", - "regex", - "sha2", - "winapi", - "winreg", -] - -[[package]] -name = "winreg" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a" -dependencies = [ - "winapi", -] diff --git a/windows/challenge-proxy/Cargo.toml b/windows/challenge-proxy/Cargo.toml deleted file mode 100644 index 26295e2b9..000000000 --- a/windows/challenge-proxy/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "challenge-proxy" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -env_logger = "0.10.0" -eyre = "0.6.8" -log = "0.4.20" -once_cell = "1.18.0" -tokio = { version = "1.32.0", features = ["full"] } -windows-service = "0.6.0" - -[target.'cfg(windows)'.dependencies] -winlog = "0.2.6" diff --git a/windows/challenge-proxy/src/main.rs b/windows/challenge-proxy/src/main.rs deleted file mode 100644 index 717669922..000000000 --- a/windows/challenge-proxy/src/main.rs +++ /dev/null @@ -1,227 +0,0 @@ -use std::ffi::OsString; -use std::path::PathBuf; -use std::process::Stdio; -use std::sync::{Arc, Mutex}; -use std::time::Duration; - -use eyre::WrapErr; -use log::{debug, error, info}; -use once_cell::sync::Lazy; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::{TcpListener, TcpStream}; -use tokio::sync::oneshot; -use windows_service::{ - define_windows_service, - service::{ - ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, - ServiceType, - }, - service_control_handler::{self, ServiceControlHandlerResult, ServiceStatusHandle}, - service_dispatcher, -}; - -const CHALLENGE_DIR: &'static str = "Y:\\"; - -fn find_challenge_binary() -> eyre::Result<PathBuf> { - let dir = PathBuf::from(CHALLENGE_DIR); - for entry in dir - .read_dir() - .wrap_err_with(|| format!("Failed to read directory {:?}", CHALLENGE_DIR))? - { - let entry = - entry.wrap_err_with(|| format!("Failed to read directory {:?}", CHALLENGE_DIR))?; - match entry.path().extension() { - Some(ext) if ext == "exe" => { - return Ok(entry.path()); - } - _ => {} - } - } - Err(eyre::eyre!( - "Failed to find a .exe file in {:?}", - CHALLENGE_DIR - )) -} - -async fn client_handler(mut socket: TcpStream) -> eyre::Result<()> { - const BUFSIZE: usize = 4096; - let mut stdin_buf = vec![0; BUFSIZE]; - let mut stdout_buf = vec![0; BUFSIZE]; - let mut stderr_buf = vec![0; BUFSIZE]; - - info!("Handling connection"); - let challenge_binary = find_challenge_binary()?; - let mut child = tokio::process::Command::new(&challenge_binary) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .wrap_err_with(|| format!("Failed to spawn child process {:?}", &challenge_binary))?; - let mut stdin = child.stdin.take().unwrap(); - let mut stdout = child.stdout.take().unwrap(); - let mut stderr = child.stderr.take().unwrap(); - - loop { - tokio::select! { - n = socket.read(&mut stdin_buf) => { - let n = n.wrap_err("Failed to read from socket")?; - if n == 0 { - info!("client disconnect"); - return Ok(()); - } - debug!("stdin: read {} bytes", n); - stdin.write_all(&stdin_buf[0..n]).await.wrap_err("Failed to write to child stdin")?; - } - n = stdout.read(&mut stdout_buf) => { - let n = n.wrap_err("Failed to read from child stdout")?; - if n == 0 { - info!("stdout: process exit"); - return Ok(()); - } - debug!("stdout: read {} bytes", n); - socket.write_all(&stdout_buf[0..n]).await.wrap_err("Failed to write to socket")?; - } - n = stderr.read(&mut stderr_buf) => { - let n = n.wrap_err("Failed to read from child stderr")?; - if n == 0 { - info!("stderr: process exit"); - return Ok(()); - } - debug!("stderr: read {} bytes", n); - socket.write_all(&stderr_buf[0..n]).await.wrap_err("Failed to write to socket")?; - } - status = child.wait() => { - let status = status.wrap_err("Failed to wait for process")?; - info!("child exited with status {}", status); - return Ok(()); - } - } - } -} - -async fn server_entry(mut stop_channel: oneshot::Receiver<()>) -> eyre::Result<()> { - let addr = "0.0.0.0:4001"; - let listener = TcpListener::bind(addr).await?; - info!("listening on {addr}"); - - loop { - tokio::select! { - _ = &mut stop_channel => { - break Ok(()) - } - r = listener.accept() => { - let (socket, _) = r?; - tokio::spawn(async move { - match client_handler(socket).await { - Ok(_) => {} - Err(e) => error!("Error handling connection: {:?}", e), - } - }); - } - } - } -} - -const SERVICE_NAME: &'static str = "ChallengeProxy"; -static SERVICE_HANDLE: Lazy<Arc<Mutex<Option<ServiceStatusHandle>>>> = - Lazy::new(|| Arc::new(Mutex::new(None))); -static STOP_CHANNEL: Lazy<Arc<Mutex<Option<oneshot::Sender<()>>>>> = - Lazy::new(|| Arc::new(Mutex::new(None))); - -fn windows_service_main(_arguments: Vec<OsString>) { - let next_status = ServiceStatus { - // Should match the one from system service registry - service_type: ServiceType::OWN_PROCESS, - // The new state - current_state: ServiceState::Running, - // Accept stop events when running - controls_accepted: ServiceControlAccept::STOP, - // Used to report an error when starting or stopping only, otherwise must be zero - exit_code: ServiceExitCode::Win32(0), - // Only used for pending states, otherwise must be zero - checkpoint: 0, - // Only used for pending states, otherwise must be zero - wait_hint: Duration::default(), - // process ID retrieved when querying service status - process_id: Some(std::process::id()), - }; - let (tx, rx) = oneshot::channel(); - *STOP_CHANNEL.lock().unwrap() = Some(tx); - let event_handler = { - let mut next_status = next_status.clone(); - move |control_event: ServiceControl| -> ServiceControlHandlerResult { - match control_event { - ServiceControl::Stop => { - if let Some(tx) = STOP_CHANNEL.lock().unwrap().take() { - let _ = tx.send(()); - } - next_status.current_state = ServiceState::StopPending; - let _ = SERVICE_HANDLE - .lock() - .unwrap() - .unwrap() - .set_service_status(next_status.clone()); - ServiceControlHandlerResult::NoError - } - ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, - _ => ServiceControlHandlerResult::NotImplemented, - } - } - }; - *SERVICE_HANDLE.lock().unwrap() = - Option::Some(service_control_handler::register(SERVICE_NAME, event_handler).unwrap()); - - SERVICE_HANDLE - .lock() - .unwrap() - .unwrap() - .set_service_status(next_status.clone()) - .unwrap(); - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(async move { - let mut next_status = next_status.clone(); - let r = server_entry(rx).await; - next_status.current_state = ServiceState::Stopped; - match r { - Ok(()) => { - info!("Server exiting gracefully"); - } - Err(err) => { - error!("Server fatal error: {:?}", err); - next_status.exit_code = ServiceExitCode::Win32(1); - } - }; - let _ = SERVICE_HANDLE - .lock() - .unwrap() - .unwrap() - .set_service_status(next_status.clone()); - }); -} - -define_windows_service!(ffi_service_main, windows_service_main); - -fn main() -> eyre::Result<()> { - #[cfg(target_os = "windows")] - { - winlog::try_register(SERVICE_NAME).unwrap(); - winlog::init(SERVICE_NAME).expect("failed to initialize windows log"); - // init sets level to debug, so set it back afterwards - log::set_max_level(log::LevelFilter::Info); - service_dispatcher::start(SERVICE_NAME, ffi_service_main).unwrap(); - Ok(()) - } - #[cfg(not(target_os = "windows"))] - { - env_logger::init(); - let (tx, rx) = oneshot::channel(); - tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap() - .block_on(async move { server_entry(rx).await }) - } -} diff --git a/windows/full.yml b/windows/full.yml deleted file mode 100644 index 31dc1e428..000000000 --- a/windows/full.yml +++ /dev/null @@ -1,15 +0,0 @@ -services: - windows: - build: - context: ./ - target: ${WINDOWS_VM} - args: - - INSTALL_IDA_FREE=${INSTALL_IDA_FREE} - platform: linux/amd64 - devices: - - /dev/kvm - volumes: - - windows:/app/build - ports: - - "5912:5912" - stop_signal: SIGKILL diff --git a/windows/none.yml b/windows/none.yml deleted file mode 100644 index b8c8205f6..000000000 --- a/windows/none.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - windows: - build: - context: ./ - target: none - platform: linux/amd64 diff --git a/windows/setup.ps1 b/windows/setup.ps1 deleted file mode 100644 index 9baf71951..000000000 --- a/windows/setup.ps1 +++ /dev/null @@ -1,198 +0,0 @@ -# -- fixnetwork -- - -# You cannot enable Windows PowerShell Remoting on network connections that are set to Public -# Spin through all the network locations and if they are set to Public, set them to Private -# using the INetwork interface: -# http://msdn.microsoft.com/en-us/library/windows/desktop/aa370750(v=vs.85).aspx -# For more info, see: -# http://blogs.msdn.com/b/powershell/archive/2009/04/03/setting-network-location-to-private.aspx - -# Network location feature was only introduced in Windows Vista - no need to bother with this -# if the operating system is older than Vista -if([environment]::OSVersion.version.Major -lt 6) { return } - -# You cannot change the network location if you are joined to a domain, so abort -if(1,3,4,5 -contains (Get-WmiObject win32_computersystem).DomainRole) { return } - -# Get network connections -$networkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")) -$connections = $networkListManager.GetNetworkConnections() - -$connections |foreach { - Write-Host $_.GetNetwork().GetName()"category was previously set to"$_.GetNetwork().GetCategory() - $_.GetNetwork().SetCategory(1) - Write-Host $_.GetNetwork().GetName()"changed to category"$_.GetNetwork().GetCategory() -} - -# -- setup powershell profile -- -if (!(Test-Path -Path $PROFILE)) { - New-Item -ItemType File -Path $PROFILE -Force -} - -# -- disable windows defender -- -Uninstall-WindowsFeature -Name Windows-Defender - -# -- enable SSH -- -Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 -# Start the sshd service -#Start-Service sshd -# This will be done later when the service actually exists -#Set-Service -Name sshd -StartupType 'Manual' - -# set default shell to powershell -New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force - -# Confirm the Firewall rule is configured. It should be created automatically by setup. -if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) { - Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..." - New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 -} else { - Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists." -} - -# -- virtfs -- -(New-Object Net.WebClient).DownloadFile("https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi", "C:\winfsp.msi") -Start-Process msiexec -ArgumentList "/i C:\winfsp.msi /qn" -Wait -Remove-Item -Force -Path C:\winfsp.msi -# while the server ISO is plugged in, the virtio drivers are in the 2nd CDROM slot, E: -# ...but when we boot up later without the server ISO it will be in D: -pnputil.exe /add-driver E:\virtio-win\viofs\2k22\amd64\viofs.inf /install -# ...but when we boot up later without the server ISO it will be in D: -& "C:\Program Files (x86)\WinFsp\bin\fsreg.bat" virtiofs "D:\virtio-win\viofs\2k22\amd64\virtiofs.exe" "-t %1 -m %2" - -Copy-Item A:\startup.ps1 -Destination "C:\Program Files\Common Files\" -& schtasks /create /tn "dojoinit" /sc onstart /delay 0000:00 /rl highest /ru system /tr "powershell.exe -file 'C:\Program Files\Common Files\startup.ps1'" /f - -# -- install chocolately -- -Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) - -# -- install windbg -- -(New-Object Net.WebClient).DownloadFile("https://windbg.download.prss.microsoft.com/dbazure/prod/1-2308-2002-0/windbg.msixbundle", "C:\windbg.msixbundle") -add-appxpackage -Path C:\windbg.msixbundle -Remove-Item -Force -Path C:\windbg.msixbundle - -# -- install IDA -- -$InstallIDA = "{INSTALLIDA}"; -if ($InstallIDA -eq "yes") { - (New-Object Net.WebClient).DownloadFile("https://out7.hex-rays.com/files/idafree82_windows.exe", "C:\idafree.exe") - Start-Process "C:\idafree.exe" -ArgumentList "--unattendedmodeui minimal --mode unattended --installpassword freeware" -Wait - Remove-Item -Force -Path "C:\idafree.exe" -} - -# -- install telnet -- -Enable-WindowsOptionalFeature -Online -NoRestart -FeatureName "TelnetClient" - -# -- install tools -- -choco install --ignore-detected-reboot -y visualstudio2022community -choco install --ignore-detected-reboot -y visualstudio2022-workload-nativedesktop -choco install --ignore-detected-reboot -y git -choco install --ignore-detected-reboot -y python311 --params "CompileAll=1" -# git requires a reboot to work, so we can't install git python packages right now... -py -m pip install --user pwntools - -# -- install VNC server -- -# install options reference: https://www.tightvnc.com/doc/win/TightVNC_2.7_for_Windows_Installing_from_MSI_Packages.pdf -choco install --ignore-detected-reboot tightvnc -y --installArguments 'ADDLOCAL=Server SET_RFBPORT=1 VALUE_OF_RFBPORT=5912 SET_USEVNCAUTHENTICATION=1 VALUE_OF_USEVNCAUTHENTICATION=1 SET_PASSWORD=1 VALUE_OF_PASSWORD=abcd' -# this will be done later when the service actually exists -#Set-Service -Name tvnserver -StartupType 'Manual' - -# -- install rust through rustup (this must be done after MSVC is installed) -- -# WARNING: I learned this the hard way. this binary behaves differently based on argv[0]. -# It must be saved as rustup-init.exe and not rustup.exe. -(New-Object Net.WebClient).DownloadFile("https://win.rustup.rs/x86_64", "C:\rustup-init.exe") -& C:\rustup-init.exe --profile minimal -y -Remove-Item "C:\rustup-init.exe" - -Copy-Item -Recurse "A:\challenge-proxy" "C:\Windows\Temp\" -Push-Location "C:\Windows\Temp\challenge-proxy\" -& $env:USERPROFILE\.cargo\bin\cargo build --release -Copy-Item ".\target\release\challenge-proxy.exe" -Destination "C:\Program Files\Common Files\" -Pop-Location -Remove-Item -Force -Recurse "C:\Windows\Temp\challenge-proxy\" -& sc.exe create ChallengeProxy binPath= "C:\Program Files\Common Files\challenge-proxy.exe" displayname= "Challenge Proxy" depend= TcpIp start= auto - -if (!(Get-NetFirewallRule -Name "ChallengeProxy-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) { - Write-Output "Firewall Rule 'ChallengeProxy-In-TCP' does not exist, creating it..." - New-NetFirewallRule -Name 'ChallengeProxy-In-TCP' -DisplayName 'ChallengeProxy' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 4001 -} else { - Write-Output "Firewall rule 'ChallengeProxy-In-TCP' has been created and exists." -} - -# -- disable admin account -- -net user administrator /active:no - -# Based on https://gist.github.com/Tras2/06670c93199b5621ce2076a36e86f41e -function EnableWmiRemoting($namespace) { - $invokeparams = @{Namespace=$namespace;Path="__systemsecurity=@"} - $output = Invoke-WmiMethod -Name GetSecurityDescriptor @invokeparams - if ($output.ReturnValue -ne 0) { - throw "GetSecurityDescriptor failed: $($output.ReturnValue)" - } - $acl = $output.Descriptor - - $computerName = (Get-WmiObject Win32_ComputerSystem).Name - $acc = Get-WmiObject -Class Win32_Group -Filter "Domain='$computerName' and Name='Users'" - - $WBEM_ENABLE = 0x00001 # Enable - $WBEM_METHOD_EXECUTE = 0x00002 # MethodExecute - $WBEM_FULL_WRITE_REP = 0x00004 # FullWrite - $WBEM_PARTIAL_WRITE_REP = 0x00008 # PartialWrite - $WBEM_WRITE_PROVIDER = 0x00010 # ProviderWrite - $WBEM_REMOTE_ACCESS = 0x00020 # RemoteAccess - $WBEM_RIGHT_SUBSCRIBE = 0x00040 - $WBEM_RIGHT_PUBLISH = 0x00080 - $READ_CONTROL = 0x20000 # ReadSecurity - $WRITE_DAC = 0x40000 # WriteSecurity - - # Execute Methods | Enable Account | ProviderWrite - $defaultMask = $WBEM_METHOD_EXECUTE + $WBEM_ENABLE + $WBEM_WRITE_PROVIDER - # Remote Enable - $accessMask = $defaultMask + $WBEM_REMOTE_ACCESS - - $ace = (New-Object System.Management.ManagementClass("win32_Ace")).CreateInstance() - $ace.AccessMask = $accessMask - $ace.AceFlags = 0 - - $trustee = (New-Object System.Management.ManagementClass("win32_Trustee")).CreateInstance() - $trustee.SidString = $acc.Sid - $ace.Trustee = $trustee - - $ACCESS_ALLOWED_ACE_TYPE = 0x0 - $ACCESS_DENIED_ACE_TYPE = 0x1 - $ace.AceType = $ACCESS_ALLOWED_ACE_TYPE - - $acl.DACL += $ace.psobject.immediateBaseObject - $output = Invoke-WmiMethod -Name SetSecurityDescriptor -ArgumentList $acl.psobject.immediateBaseObject @invokeparams - if ($output.ReturnValue -ne 0) { - throw "SetSecurityDescriptor failed: $($output.ReturnValue)" - } -} - -EnableWmiRemoting "Root/WMI" -EnableWmiRemoting "Root/CIMV2" -EnableWmiRemoting "Root/StandardCimv2" - -# -- edit password policy & shutdown policy -- -& secedit /export /cfg C:\Windows\Temp\policy-edit.inf -(Get-Content -Path C:\Windows\Temp\policy-edit.inf) ` - -replace "PasswordComplexity = 1", "PasswordComplexity = 0" ` - -replace "SeShutdownPrivilege .+", "`$0,hacker" ` - -replace "SeRemoteShutdownPrivilege .+", "`$0,hacker" | - Set-Content -Path C:\Windows\Temp\policy-edit.inf -& secedit /configure /db C:\windows\security\local.sdb /cfg C:\Windows\Temp\policy-edit.inf -Remove-Item -Force C:\Windows\Temp\policy-edit.inf -Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "LimitBlankPasswordUse" -Value 0 - -# -- set empty password for hacker user -- -$SecureString = New-Object System.Security.SecureString -Get-LocalUser -Name hacker | Set-LocalUser -Password $SecureString -PasswordNeverExpires $true - -# -- edit SSH config -- -# to support empty passwords, we require the following settings: -# PasswordAuthentication yes -# PermitEmptyPasswords yes -Copy-Item "A:\sshd_config" -Destination "$env:programdata\ssh\sshd_config" - -# -- shutdown -- -Stop-Computer -computername localhost -force - diff --git a/windows/shutdown.py b/windows/shutdown.py deleted file mode 100644 index 02b1cd96f..000000000 --- a/windows/shutdown.py +++ /dev/null @@ -1,66 +0,0 @@ -import socket -import time -import os -import subprocess -from pathlib import Path - -vm_hostname = "127.0.0.1" -port = 2222 - - -def wait(): - start = time.time() - while time.time() - start < 5 * 60: - try: - connection = socket.create_connection((vm_hostname, port), timeout=10) - data = connection.recv(3) - connection.close() - if data == b"SSH": - return - except (ConnectionRefusedError, socket.timeout): - pass - time.sleep(0.1) - print("Timeout expired") - - -def shutdown(): - subprocess.check_call( - [ - "ssh", - "-o", - "StrictHostKeyChecking=no", - "-p", - str(port), - f"hacker@{vm_hostname}", - "--", - "Set-Service -Name sshd -StartupType Manual; " - + "Set-Service -Name tvnserver -StartupType Manual; " - + "Stop-Computer -Force", - ] - ) - - -def qemu_running(): - procfs = Path("/proc") - pid_dirs = [d for d in procfs.iterdir() if d.name.isdigit()] - for pid in pid_dirs: - try: - exe_link = Path("/proc") / str(pid) / "exe" - if "qemu" in os.readlink(str(exe_link)): - return True - except FileNotFoundError: - pass - return False - - -def wait_qemu_exit(): - start = time.time() - while time.time() - start < 2 * 60 and qemu_running(): - time.sleep(1) - - -if __name__ == "__main__": - wait() - time.sleep(30) - shutdown() - wait_qemu_exit() diff --git a/windows/sshd_config b/windows/sshd_config deleted file mode 100644 index 97b614da4..000000000 --- a/windows/sshd_config +++ /dev/null @@ -1,88 +0,0 @@ -# This is the sshd server system-wide configuration file. See -# sshd_config(5) for more information. - -# The strategy used for options in the default sshd_config shipped with -# OpenSSH is to specify options with their default value where -# possible, but leave them commented. Uncommented options override the -# default value. - -#Port 22 -#AddressFamily any -#ListenAddress 0.0.0.0 -#ListenAddress :: - -#HostKey __PROGRAMDATA__/ssh/ssh_host_rsa_key -#HostKey __PROGRAMDATA__/ssh/ssh_host_dsa_key -#HostKey __PROGRAMDATA__/ssh/ssh_host_ecdsa_key -#HostKey __PROGRAMDATA__/ssh/ssh_host_ed25519_key - -# Ciphers and keying -#RekeyLimit default none - -# Logging -#SyslogFacility AUTH -#LogLevel INFO - -# Authentication: - -#LoginGraceTime 2m -#PermitRootLogin prohibit-password -#StrictModes yes -#MaxAuthTries 6 -#MaxSessions 10 - -#PubkeyAuthentication yes - -# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 -# but this is overridden so installations will only check .ssh/authorized_keys -AuthorizedKeysFile .ssh/authorized_keys - -#AuthorizedPrincipalsFile none - -# For this to work you will also need host keys in %programData%/ssh/ssh_known_hosts -#HostbasedAuthentication no -# Change to yes if you don't trust ~/.ssh/known_hosts for -# HostbasedAuthentication -#IgnoreUserKnownHosts no -# Don't read the user's ~/.rhosts and ~/.shosts files -#IgnoreRhosts yes - -# To disable tunneled clear text passwords, change to no here! -PasswordAuthentication yes -PermitEmptyPasswords yes - -# GSSAPI options -#GSSAPIAuthentication no - -#AllowAgentForwarding yes -#AllowTcpForwarding yes -#GatewayPorts no -#PermitTTY yes -#PrintMotd yes -#PrintLastLog yes -#TCPKeepAlive yes -#UseLogin no -#PermitUserEnvironment no -#ClientAliveInterval 0 -#ClientAliveCountMax 3 -#UseDNS no -#PidFile /var/run/sshd.pid -#MaxStartups 10:30:100 -#PermitTunnel no -#ChrootDirectory none -#VersionAddendum none - -# no default banner path -#Banner none - -# override default of no subsystems -Subsystem sftp sftp-server.exe - -# Example of overriding settings on a per-user basis -#Match User anoncvs -# AllowTcpForwarding no -# PermitTTY no -# ForceCommand cvs server - -Match Group administrators - AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys diff --git a/windows/startup.ps1 b/windows/startup.ps1 deleted file mode 100644 index c841e61c9..000000000 --- a/windows/startup.ps1 +++ /dev/null @@ -1,40 +0,0 @@ -Remove-LocalGroupMember -Group "Administrators" -Member hacker -(Get-Service WinFsp.Launcher).WaitForStatus('Running') -& "C:\Program Files (x86)\WinFsp\bin\fsreg.bat" virtiofs "D:\virtio-win\viofs\2k22\amd64\virtiofs.exe" "-t %1 -m %2" -& "C:\Program Files (x86)\WinFsp\bin\launchctl-x64.exe" start virtiofs viofsX flag X: -& "C:\Program Files (x86)\WinFsp\bin\launchctl-x64.exe" start virtiofs viofsY challenge Y: -& "C:\Program Files (x86)\WinFsp\bin\launchctl-x64.exe" start virtiofs viofsZ home Z: - -Remove-iTem -Path C:\flag -Force -echo 'pwn.college{uninitialized}' > C:\flag - -# crash course in the footguns of NTFS's ACL based permissions system that I learned -# the hard way: -# - a "Deny" rule will always take precedence over an "Allow" rule. -# For example: Admins Allow Read + Users Deny Read -# This will result in no one being able to read the flag because they all fall under -# the "Users" rule. -# - ACLs inherit from the parent directory by default unless explicitly disabled. -# Combined with the previous rule, this means that if an "Allow" rule is inherited -# from the parent directory, there is no way to counteract it with a "Deny" rule. -# You have to disable inheritance instead. - -$flagAcl = New-Object System.Security.AccessControl.FileSecurity -# important: do not inherit from the parent directory. -$flagAcl.SetAccessRuleProtection($true, $false) -$rule = New-Object System.Security.AccessControl.FileSystemAccessRule( - "Administrators", - "FullControl", - "Allow" -) -$flagAcl.AddAccessRule($rule) -Set-Acl -Path C:\flag -AclObject $flagAcl -Set-Content -Path C:\flag -Value (Get-Content X:\flag) -Remove-Item -Path X:\flag -Force - -if (Test-Path X:\practice-mode-enabled) { - Add-LocalGroupMember -Group "Administrators" -Member hacker -} - -Start-Service sshd -Start-Service tvnserver