Automated Deployment and Compilation of National Security Agency’s Ghidra

The following vagrantfile describes a host configured to bring up the NSA’s Ghidra interactive debugger featuring disassembly tooling for a variety of processors. Using this vagrantfile to establish a remote session to the host will allow for the use of an SSH tunneled connection to an X11 session, and via session forwarding allow the use of the GUI application presented locally.

While the usefulness is not immediately apparent, it is of immense value when remotely debugging an embedded device implant.

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.
 
  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
 

    # Default false
  config.ssh.forward_agent = true
  config.ssh.forward_x11 = true
   
    # Default true
  config.ssh.keep_alive = true
 
  config.vm.define :kaliserver do |kaliserver|
    kaliserver.vm.box = "kalilinux/rolling"
    kaliserver.vm.provider :libvirt do |libvirt|
      libvirt.id_ssh_key_file = "/home/jason/projects/kali_remote/id_ssh.key"
      #libvirt.uri = "qemu+ssh://10.130.10.50/system"
      libvirt.host = '10.130.10.50'
      libvirt.connect_via_ssh = true
      libvirt.username = "jason"
      libvirt.password = ''
      libvirt.memory = 8192
      libvirt.cpus = 8
      # Required for virtiofs
      # libvirt.memorybacking :access, :mode => "shared"
    end
  end

  #config.vm.provision "shell", inline: <<-'SHELL'
  #  curl -s -S -o ./get-sdkman.sh "https://get.sdkman.io?rcupdate=false" \
  #  && chmod +x ./get-sdkman.sh \
  #  && ./get-sdkman.sh \
  #  && rm ./get-sdkman.sh \
  #  # Change SDKMAN's config to be suitable for a CI pipeline execution
  #  && sed -i 's/sdkman_auto_answer=false/sdkman_auto_answer=true/g'                $HOME/.sdkman/etc/config \
  #  && sed -i 's/sdkman_selfupdate_feature=true/sdkman_selfupdate_feature=false/g'  $HOME/.sdkman/etc/config \
  #  && sed -i 's/sdkman_colour_enable=true/sdkman_colour_enable=false/g' 
  #SHELL

  # Configure host for transparent proxy
  config.vm.provision "file", source: "~/projects/crt.pem", destination: "~/"
  config.vm.provision "shell", privileged: "yes", inline: <<-'SHELL'
    echo foo

    #rm -rf /etc/skel/.zshrc
    #rm -rf /etc/skel/.bashrc
    #rm -rf /root/.bashrc
    #rm -rf /root/.zshrc
    sudo chsh -s /bin/bash root
    sudo chsh -s /bin/bash vagrant
    exit
  SHELL

  config.vm.provision "shell", privileged: "false", inline: <<-SHELL
    echo bar
    sudo cp /home/vagrant/crt.pem /usr/local/share/ca-certificates/crt.crt
    sudo update-ca-certificates
    sudo apt-get update
    sudo apt-get upgrade
    git clone https://github.com/NationalSecurityAgency/ghidra.git
    #unzip -qq /vagrant/ghidr.zip
    sudo apt-get install -y openjdk-21-jdk
    sudo apt-get install -y openjdk-21-jre
    sudo apt-get install -y gdb ddd
    #sudo mkdir /usr/local/sdkman
    #chown vagrant /usr/local/sdkman
    #export SDKMAN_DIR=/usr/local/sdkman
    #curl -s "https://get.sdkman.io" | zsh
    #sudo curl -s "https://get.sdkman.io" | zsh
    #export $PATH=/usr/local/sdkman:$PATH
    #source "/home/vagrant/.sdkman/bin/sdkman-init.sh"
    #sudo apt-get install -y gradle
  SHELL

  config.vm.provision "shell", privileged: "false", path: "sdkman.sh"

  config.vm.provision "shell", privileged: "true", inline: <<-'SHELL'
    #!/bin/bash
    echo fooby
    echo $SHELL
    su vagrant bash -c whoami
    su vagrant /vagrant/sdkman.sh
    su vagrant source "/home/vagrant/.sdkman/bin/sdkman-init.sh"
    source "/root/.sdkman/bin/sdkman-init.sh"
    su vagrant sdk
    sdk
    sdk install gradle 8.9
    sudo sdk install gradle 8.9
    cd ghidra
    gradle prepDev
    gradle -I gradle/support/fetchDependencies.gradle
    gradle buildGhidra
    cd $HOME/ghidra/build/dist/
    #sudo apt-get install -y binutils-dev-dev
    #sudo apt-get install -y texinfo
    #wget https://ftp.gnu.org/gnu/binutils/binutils-2.41.tar.bz2 
    #mv binutils-2.41.tar.bz2 /home/vagrant/ghidr/build/dist/ghidra.bin/GPL/GnuDisassembler/binutils-2.41.tar.bz2
    #sudo unzip ghidra_11.2_DEV_20240722_linux_x86_64.zip
    #sudo unzip ghidra_11.2_DEV_20240722_GnuDisassembler.zip 
    #sudo unzip /home/vagrant/ghidr/build/dist/ghidra_11.2_DEV/Extensions/Ghidra/ghidra_11.2_DEV_20240722_GnuDisassembler.zip -d /home/vagrant/ghidr/build/dist/ghidra_11.2_DEV/GPL
    echo Enter the host with: vagrant ssh
    echo Run Ghidra by entering the following: ./ghidr/Ghidra/RuntimeScripts/Linux/ghidraRun
  SHELL

  

  ### To access services running within remote host, use the following pattern:
  # ssh -L8080:192.168.121.148:80 [email protected]
  # To accept license:
  # ssh -L5901:127.0.0.1:5901 [email protected]
  # ncviewer 127.0.0.1:5901
  ### This describes a website running on port 80 on 192.168.121.148 
  ### made available via local port 8080 
  #onfig.vm.network "forwarded_port", guest: 80, host: 8080
  
  
  # Default false
  config.ssh.forward_agent = true
  config.ssh.forward_x11 = true
 
  # Default true
  config.ssh.keep_alive = false
 
  # Default 300s
  config.vm.boot_timeout = 900

  #config.vm.provision "shell", inline: <<-SHELL
    #sudo apt install -y x11vnc
      # run interactively 
      # sudo x11vnc -storepasswd
      #    - or -
      #  /etc/vncserver.pass
      # sudo x11vnc
      # sudo vi /etc/systemd/system/vncserver.service
      # [Unit]
      # Description=start vnc at boot
      # After=multi-user.target
      # 
      # [Service]
      # Type=simple
      # ExecStart=/usr/bin/x11vnc -display :0 -auth guess -forever -loop -noxdamage -repeat -rfbauth /etc/vncserver.pass -rfbport 5900 -shared
      # 
      # [Install]
      # WantedBy=multi-user.target
      #
      # sudo systemctl enable vncserver
      # sudo systemctl start vncserver
      # systemctl status vncserver
  #SHELL
    
  config.vm.provision "shell", inline: <<-SHELL
    echo barby
    # Base requirements for installing X11
    #sudo dnf update -y
    #sudo dnf install -y git
    # Add desktop environment
    #sudo dnf install -y xorg-x11-xauth
    #sudo dnf install -y xclock
    #sudo dnf install -y gnome-shell
    #sudo dnf install xorg-x11-apps
    #sudo dnf install -y xorg*
    #sudo dnf install -y @xfce-desktop-environment
    unzip -qq /vagrant/asmsbs3e.zip
    unzip -qq /vagrant/x64ASMSBS.zip
    sudo sed -i '/#X11Forwarding no/s//X11Forwarding yes/' /etc/ssh/sshd_config
    sudo rm -rf /root/.Xauthority
    sudo rm -rf /root/.serverauth.*  
    
  SHELL
  config.vm.synced_folder ".", "/vagrant", type: "rsync",
    rsync__exclude: ".git/, ./vagrant"
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end