Skip to content

Commit

Permalink
Merge pull request #19 from RhinoSecurityLabs/update-dependencies
Browse files Browse the repository at this point in the history
Update dependencies
  • Loading branch information
DaveYesland authored Apr 13, 2021
2 parents b2ffe70 + 6047354 commit a3319bc
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 876 deletions.
18 changes: 2 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ Cleaning up snapshot: snap-0543a8681adce0086
```

### Mounting in Vagrant
Note: Vagrant does not offer any guarantee's of seperation between the guest and the host. It shouldn't considered a security boundry like most VM's.

This requires virtualbox to be installed. dsnap init will write a Vagrantfile to the current directory that can be used to mount a specific downloaded snapshot. Conversion to a VDI disk is handled in the Vagrantfile, it will look for the disk file specified in the IMAGE environment variable, convert it to a VDI using `VBoxManage convertdd`. The resulting VDI is destroyed when the Vagrant box is, however the original raw .img file will remain and can be reused as needed.

```shell
Expand All @@ -117,22 +119,6 @@ This requires virtualbox to be installed. dsnap init will write a Vagrantfile to
% vagrant ssh
```

#### Trusted Mode

By default, we treat the guest as untrusted within reason. This means that by default there is no mount between the
guest and the host and external networking is disabled. SSH access from the host is still allowed for usability.

If you trust the downloaded image you can enable both of these features by using `vagrant init --trusted` to write out
the Vagrantfile. This will enable networking and the host to guest vagrant share.

Improtant: Keep in mind trusted mode will allow access to the hosts loopback adapter. This is due to how VirtualBox's
NAT adapter works which is both default and heavily relied on by vagrant. You can find more information on this in this
[blog post](https://blog.ryanjarv.sh/2020/11/13/virtual-box-networking.html).

Another common vagrant escape is related to the default share mounting the directory containing the executable
Vagrantfile. This *is* prevented even in the trusted mode. This is done by mounting a subdirectory instead of the
default.

### Mounting With Docker

This uses libguestfs to work directly with the downloaded img file.
Expand Down
38 changes: 1 addition & 37 deletions dsnap/files/Vagrantfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
config.vm.box = "bento/ubuntu-20.04"

# Prevents RCE from guest to host.
# https://blog.ryanjarv.sh/2019/06/08/malicious-vagrant-boxes.html
Dir.mkdir 'vagrant' unless File.exists? 'vagrant'
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder "vagrant", "/vagrant"


if ['up', 'reload'].member? ARGV[0]
Expand All @@ -32,40 +30,6 @@ Vagrant.configure("2") do |config|
vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', vdi]
end

config.vm.network "private_network", type: "dhcp", adapter: 1
config.vm.network :forwarded_port, id: 'ssh', guest: 22, host: 2222, disabled: true

# Used because most the information about the vm isn't available when this config get's parsed.
# We can't use a lazy object here because config.ssh.host is used too early on to print to the console
# and we end up getting the wrong IP. So instead call out to `VBoxManager dhcpserver` each time we need
# the IP. This should result in the correct IP by the time it's actually needed.
class GuestIP
def ip_address
vm_id = File.read(File.dirname(__FILE__) + '/.vagrant/machines/default/virtualbox/id')

@vminfo ||= `VBoxManage showvminfo #{vm_id} --details --machinereadable`
interface = @vminfo.lines.grep(/hostonlyadapter1/)[0].match('\w+="(\w+)"')[1]
mac_addr = @vminfo.lines.grep(/macaddress1/)[0].match('\w+="(\w+)"')[1]

resp=`VBoxManage dhcpserver findlease --interface='#{interface}' --mac-address='#{mac_addr}'`
ip_address=resp.lines.grep(/IP Address/)[0].match('([0-9.]+)')[1]
end

def to_s
self.ip_address
end

def to_str
self.ip_address
end
end


# Vagrant isn't meant to work without the NAT network adapter so work around this by scraping
# the the IP address from the networks dhcpserver and using the returned ip address as the
# guest ssh ip.
config.ssh.host = GuestIP.new

config.vm.provision "shell", inline: <<-SHELL
sudo mkdir /mnt/snapshot
sudo mount -o ro /dev/sdb1 /mnt/snapshot
Expand Down
41 changes: 0 additions & 41 deletions dsnap/files/Vagrantfile.trusted

This file was deleted.

5 changes: 1 addition & 4 deletions dsnap/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,12 @@ def session(

@app.command()
def init(
trusted: bool = typer.Option(False, help='Enable network access and host share.'),
out_dir: Path = typer.Option(Path('.'), help='Output directory to write Vagrantfile'),
force: bool = typer.Option(False, help='Overwrite any existing Vagrantfile.')
):
"""
Write out a Vagrantfile template to explore downloaded snapshots.
If --trusted is used external guest VM networking and the shared mount will be enabled.
Warning: Due to how Vagrant and VirtualBox work's this will allow access to the host's loopback adapter.
If --out-dir is used the given directory will be used instead.
If --force is used we will overwrite an already present Vagrantfile
Expand All @@ -51,7 +48,7 @@ def init(
% IMAGE=snap-0543a8681adce0086.img vagrant up
% vagrant ssh
"""
output = utils.init_vagrant(out_dir, force, trusted)
output = utils.init_vagrant(out_dir, force)
if output:
print(f"Wrote Vagrantfile to {style('./'+str(output), bold=True)}")
else:
Expand Down
9 changes: 2 additions & 7 deletions dsnap/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,9 @@ def sha256_check(data: bytes, digest: str) -> bool:
return result


def init_vagrant(out_dir: Path = Path('.'), force=False, trusted=False) -> Optional[Path]:
def init_vagrant(out_dir: Path = Path('.'), force=False) -> Optional[Path]:
"""Initializes out_dir directory with a templated Vagrantfile for mounting downloaded images"""
if trusted:
vagrant_path = 'files/Vagrantfile.trusted'
else:
vagrant_path = 'files/Vagrantfile'

template = Path(__file__).parent.joinpath(Path(vagrant_path))
template = Path(__file__).parent.joinpath(Path('files/Vagrantfile'))
out = out_dir.joinpath(Path('Vagrantfile').name)
if out.exists() and not force:
return None
Expand Down
Loading

0 comments on commit a3319bc

Please sign in to comment.