From da75559e3a029c7c8ddbd4a5cb05bfc2a01a370e Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Wed, 30 Jun 2021 16:21:40 -0700 Subject: [PATCH] Start working on ssh reverse tunnel stuff --- dangerzone/gui/vm.py | 121 ++++++++++++++++++++- install/vm-builder/README.md | 28 +++++ install/vm-builder/genapkovl-dangerzone.sh | 51 ++++++++- install/vm-builder/mkimg.dangerzone.sh | 2 +- install/vm-builder/run-vm.sh | 4 + install/vm-builder/ssh-key/README.md | 7 -- install/vm-builder/ssh-key/id_ed25519 | 7 -- install/vm-builder/ssh-key/id_ed25519.pub | 1 - 8 files changed, 193 insertions(+), 28 deletions(-) delete mode 100644 install/vm-builder/ssh-key/README.md delete mode 100644 install/vm-builder/ssh-key/id_ed25519 delete mode 100644 install/vm-builder/ssh-key/id_ed25519.pub diff --git a/dangerzone/gui/vm.py b/dangerzone/gui/vm.py index aeeafeb..9b70500 100644 --- a/dangerzone/gui/vm.py +++ b/dangerzone/gui/vm.py @@ -4,6 +4,10 @@ import subprocess import uuid import pipes import tempfile +import socket +import random +import getpass +import json from PySide2 import QtCore @@ -34,10 +38,19 @@ class Vm(QtCore.QObject): "vm/initramfs.img" ) - # Folder to hold files related to the VM + # Folder to hold temporary files related to the VM self.state_dir = tempfile.TemporaryDirectory() self.vpnkit_sock_path = os.path.join(self.state_dir.name, "vpnkit.eth.sock") self.hyperkit_pid_path = os.path.join(self.state_dir.name, "hyperkit.pid") + self.ssh_host_key_path = os.path.join(self.state_dir.name, "host_ed25519") + self.ssh_host_pubkey_path = os.path.join( + self.state_dir.name, "host_ed25519.pub" + ) + self.ssh_client_key_path = os.path.join(self.state_dir.name, "client_ed25519") + self.ssh_client_pubkey_path = os.path.join( + self.state_dir.name, "client_ed25519.pub" + ) + self.vm_disk_img_path = os.path.join(self.state_dir.name, "disk.img") # UDID for VM self.vm_uuid = str(uuid.uuid4()) @@ -49,6 +62,92 @@ class Vm(QtCore.QObject): self.state = self.STATE_STARTING self.vm_state_change.emit(self.state) + # Delete keys if they already exist + for filename in [ + self.ssh_host_key_path, + self.ssh_host_pubkey_path, + self.ssh_client_key_path, + self.ssh_client_pubkey_path, + ]: + if os.path.exists(filename): + os.remove(filename) + + # Generate new keys + subprocess.run( + [ + "/usr/bin/ssh-keygen", + "-t", + "ed25519", + "-C", + "dangerzone-host", + "-N", + "", + "-f", + self.ssh_host_key_path, + ] + ) + subprocess.run( + [ + "/usr/bin/ssh-keygen", + "-t", + "ed25519", + "-C", + "dangerzone-client", + "-N", + "", + "-f", + self.ssh_client_key_path, + ] + ) + with open(self.ssh_client_key_path) as f: + ssh_client_key = f.read() + with open(self.ssh_client_pubkey_path) as f: + ssh_client_pubkey = f.read() + + # Find an open port + sshd_port = self.find_open_port() + sshd_tunnel_port = self.find_open_port() + + # Start an sshd service on this port + subprocess.run( + [ + "/usr/sbin/sshd", + "-4", + "-o", + f"HostKey={self.ssh_host_key_path}", + "-o", + f"ListenAddress=127.0.0.1:{sshd_port}", + "-o", + f"AllowUsers={getpass.getuser()}", + "-o", + "PasswordAuthentication=no", + "-o", + "PubkeyAuthentication=yes", + "-o", + "Compression=yes", + "-o", + "ForceCommand=/usr/bin/whoami", + "-o", + "UseDNS=no", + "-o", + f"AuthorizedKeysFile={self.ssh_client_pubkey_path}", + ] + ) + + # Create a JSON object to pass into the VM + # This is a 512kb file that starts with a JSON object, followed by null bytes + vm_info = { + "id_ed25519": ssh_client_key, + "id_ed25519.pub": ssh_client_pubkey, + "ssh_target": f"{getpass.getuser()}@192.168.65.2", + "sshd_port": sshd_port, + "sshd_tunnel_port": sshd_tunnel_port, + } + with open(self.vm_disk_img_path, "wb") as f: + vm_info_bytes = json.dumps(vm_info).encode() + f.write(vm_info_bytes) + f.write(b"\x00" * (512 * 1024 - len(vm_info_bytes))) + # Run VPNKit args = [ self.vpnkit_path, @@ -65,11 +164,7 @@ class Vm(QtCore.QObject): ] args_str = " ".join(pipes.quote(s) for s in args) print("> " + args_str) - self.vpnkit_p = subprocess.Popen( - args, - stdout=sys.stdout, - stderr=subprocess.STDOUT, - ) + self.vpnkit_p = subprocess.Popen(args) # Run Hyperkit args = [ @@ -92,6 +187,8 @@ class Vm(QtCore.QObject): f"1:0,ahci-cd,{self.vm_iso_path}", "-s", f"2:0,virtio-vpnkit,path={self.vpnkit_sock_path}", + "-s", + f"3:0,virtio-blk,{self.vm_disk_img_path}", "-U", self.vm_uuid, "-f", @@ -117,3 +214,15 @@ class Vm(QtCore.QObject): if self.hyperkit_p is not None: self.hyperkit_p.terminate() self.hyperkit_p = None + + def find_open_port(self): + with socket.socket() as tmpsock: + while True: + try: + tmpsock.bind(("127.0.0.1", random.randint(1024, 65535))) + break + except OSError: + pass + _, port = tmpsock.getsockname() + + return port diff --git a/install/vm-builder/README.md b/install/vm-builder/README.md index 32952c0..9d9653e 100644 --- a/install/vm-builder/README.md +++ b/install/vm-builder/README.md @@ -37,3 +37,31 @@ ssh -i ./ssh-key/id_ed25519 \ ``` (doesn't work yet) + + +Notes on sshd: + +``` +# Generate keys +rm -r state +mkdir state +ssh-keygen -t ed25519 -C dangerzone-vm-key -N "" -f state/host_ed25519 +ssh-keygen -t ed25519 -C dangerzone-vm-key -N "" -f state/client_ed25519 + +# start sshd service +/usr/sbin/sshd -4 \ + -o HostKey=$(pwd)/state/host_ed25519 \ + -o ListenAddress=127.0.0.1:4444 \ + -o AllowUsers=$(whoami) \ + -o PasswordAuthentication=no \ + -o PubkeyAuthentication=yes \ + -o Compression=yes \ + -o ForceCommand=/usr/bin/whoami \ + -o UseDNS=no \ + -o AuthorizedKeysFile=$(pwd)/state/client_ed25519.pub + +# in the vm, making an ssh tunnel + + ssh -o StrictHostKeyChecking=no -N -R 52038:127.0.0.1:22 -p 52039 user@192.168.65.2 + +``` \ No newline at end of file diff --git a/install/vm-builder/genapkovl-dangerzone.sh b/install/vm-builder/genapkovl-dangerzone.sh index 2013d5c..7071838 100644 --- a/install/vm-builder/genapkovl-dangerzone.sh +++ b/install/vm-builder/genapkovl-dangerzone.sh @@ -46,6 +46,39 @@ UseDNS no PasswordAuthentication no EOF +# Script to read info from host +makefile root:root 0755 "$tmp"/etc/read-info-from-host < /home/user/.ssh/authorized_keys - chown -R user:user /home/user/.ssh - chmod 700 /home/user/.ssh - chmod 600 /home/user/.ssh/authorized_keys # Move containers into home dir mkdir -p /home/user/.local/share @@ -87,6 +115,17 @@ start_pre() { # Allow podman containers to run echo "user:100000:65536" >> /etc/subuid echo "user:100000:65536" >> /etc/subgid + + # Get info from the host + /etc/read-info-from-host + chmod 700 /home/user/.ssh + chmod 600 /home/user/.ssh/* + + # Start the ssh reverse tunnel + SSH_TARGET=$(cat /home/user/.ssh/env_ssh_target) + SSHD_PORT=$(cat /home/user/.ssh/env_sshd_port) + SSHD_TUNNEL_PORT=$(cat /home/user/.ssh/sshd_tunnel_port) + /usr/bin/ssh -o StrictHostKeyChecking=no -N -R $SSHD_TUNNEL_PORT:127.0.0.1:22 -p $SSHD_PORT $SSH_TARGET & } EOF diff --git a/install/vm-builder/mkimg.dangerzone.sh b/install/vm-builder/mkimg.dangerzone.sh index 2ff10b5..b3bed50 100644 --- a/install/vm-builder/mkimg.dangerzone.sh +++ b/install/vm-builder/mkimg.dangerzone.sh @@ -9,5 +9,5 @@ profile_dangerzone() { kernel_cmdline="console=tty0 console=ttyS0,115200" syslinux_serial="0 115200" apkovl="genapkovl-dangerzone.sh" - apks="$apks podman openssh" + apks="$apks podman openssh sshfs python3" } diff --git a/install/vm-builder/run-vm.sh b/install/vm-builder/run-vm.sh index b58c264..c0d76db 100755 --- a/install/vm-builder/run-vm.sh +++ b/install/vm-builder/run-vm.sh @@ -15,6 +15,9 @@ $VPNKIT \ echo $! > $PIDFILE trap 'test -f $PIDFILE && kill `cat $PIDFILE` && rm $PIDFILE' EXIT +cd $ROOT +python3 -c 's="this is a test"; open("disk.img", "wb").write(s.encode()+b"\x00"*(512*1024-len(s)))' + $HYPERKIT \ -F $ROOT/hyperkit.pid \ -A -u \ @@ -24,5 +27,6 @@ $HYPERKIT \ -l com1,stdio \ -s 1:0,ahci-cd,$ROOT/dangerzone.iso \ -s 2:0,virtio-vpnkit,path=$VPNKIT_SOCK \ + -s 3:0,virtio-blk,$ROOT/disk.img \ -U 9efa82d7-ebd5-4287-b1cc-ac4160a39fa7 \ -f kexec,$ROOT/kernel,$ROOT/initramfs.img,"earlyprintk=serial console=ttyS0 modules=loop,squashfs,sd-mod" diff --git a/install/vm-builder/ssh-key/README.md b/install/vm-builder/ssh-key/README.md deleted file mode 100644 index 4cbf52f..0000000 --- a/install/vm-builder/ssh-key/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Dangerzone VM key - -This is an insecure hard-coded SSH key that's built-in to allow ssh access to the VM's `user` account. It was generated like this: - -```sh -ssh-keygen -t ed25519 -C dangerzone-vm-key -N "" -f id_ed25519 -``` diff --git a/install/vm-builder/ssh-key/id_ed25519 b/install/vm-builder/ssh-key/id_ed25519 deleted file mode 100644 index 2b2d5af..0000000 --- a/install/vm-builder/ssh-key/id_ed25519 +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACC5sSMNnrYNiMWO+xjhXv+rbjB/yuXNYLM96j2P7O62RQAAAJhcTPZgXEz2 -YAAAAAtzc2gtZWQyNTUxOQAAACC5sSMNnrYNiMWO+xjhXv+rbjB/yuXNYLM96j2P7O62RQ -AAAEBCvhorS+9SPDNqhyxAPvFMnzkbUoc6HcM6Ll2W8F5krrmxIw2etg2IxY77GOFe/6tu -MH/K5c1gsz3qPY/s7rZFAAAAEWRhbmdlcnpvbmUtdm0ta2V5AQIDBA== ------END OPENSSH PRIVATE KEY----- diff --git a/install/vm-builder/ssh-key/id_ed25519.pub b/install/vm-builder/ssh-key/id_ed25519.pub deleted file mode 100644 index 4d7a185..0000000 --- a/install/vm-builder/ssh-key/id_ed25519.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILmxIw2etg2IxY77GOFe/6tuMH/K5c1gsz3qPY/s7rZF dangerzone-vm-key