mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00
Start working on ssh reverse tunnel stuff
This commit is contained in:
parent
9158d02669
commit
da75559e3a
8 changed files with 193 additions and 28 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
```
|
|
@ -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 <<EOF
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
|
||||
# Read data
|
||||
with open("/dev/vda", "rb") as f:
|
||||
s = f.read()
|
||||
|
||||
info = json.loads(s[0:s.find(b"\0")])
|
||||
|
||||
# Create SSH files
|
||||
os.makedirs("/home/user/.ssh", exist_ok=True)
|
||||
|
||||
with open("/home/user/.ssh/id_ed25519") as f:
|
||||
f.write(info["id_ed25519"])
|
||||
|
||||
with open("/home/user/.ssh/id_ed25519.pub") as f:
|
||||
f.write(info["id_ed25519.pub"])
|
||||
|
||||
with open("/home/user/.ssh/authorized_keys") as f:
|
||||
f.write(info["id_ed25519.pub"])
|
||||
|
||||
with open("/home/user/.ssh/env_ssh_target") as f:
|
||||
f.write(info['ssh_target'])
|
||||
|
||||
with open("/home/user/.ssh/env_sshd_port") as f:
|
||||
f.write(info['sshd_port'])
|
||||
|
||||
with open("/home/user/.ssh/env_sshd_tunnel_port") as f:
|
||||
f.write(info['sshd_tunnel_port'])
|
||||
EOF
|
||||
|
||||
# Dangerzone alpine setup
|
||||
makefile root:root 0644 "$tmp"/etc/answers.txt <<EOF
|
||||
KEYMAPOPTS="us us"
|
||||
|
@ -71,13 +104,8 @@ start_pre() {
|
|||
/sbin/setup-alpine -f /etc/answers.txt -e -q
|
||||
rm /etc/answers.txt
|
||||
|
||||
# Create user, give the dangerzone-vm-key ssh access
|
||||
# Create user
|
||||
/usr/sbin/adduser -D -u 1001 user
|
||||
mkdir -p /home/user/.ssh
|
||||
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILmxIw2etg2IxY77GOFe/6tuMH/K5c1gsz3qPY/s7rZF dangerzone-vm-key" > /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
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
```
|
|
@ -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-----
|
|
@ -1 +0,0 @@
|
|||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILmxIw2etg2IxY77GOFe/6tuMH/K5c1gsz3qPY/s7rZF dangerzone-vm-key
|
Loading…
Reference in a new issue