#!/bin/bash # # Simple vm-specific management bash functions and aliases. # Coming with basic functionality of starting, stopping and status checking # routines. Easy to change to manage other type of VMs. # # Providing commands for: # - starting/stopping selected VM # - checking whether selected VM is running # - easily ssh'ing to the selected VM # - scanning for other VMs # - setting selected VM's IP address within /etc/hosts (and alike) file # # Mariusz B. / mgeeky, '16-'19 # v0.7 # # VM_NAME as defined in VirtualBox. Name must not contain any special characters, not # even space. VM_NAME=kali # User's name to be used during ssh. VM_USER=root # Host-only's interface network address and interface HOST_ONLY_NET=192.168.56.1 HOST_ONLY_IFACE=vboxnet0 # Hosts file where to put the VM's host IP address HOSTS_FILE=/etc/hosts # Command to be run to detect proper VM and pattern to be matched then. VM_DETECT_COMMAND="uname -a" VM_DETECT_PATTERN="Linux Kali" # Initial commands one would like to get executed upon VM start. VM_INIT_COMMANDS="dhclient -r eth1 ; dhclient -v eth1" # # Will set the following aliases: # - ssh alias for quick ssh-connection # - get alias for quick vm's ip resolution # - start alias for starting up particular vm # - stop alias for stopping particular vm # - is alias for checking whether the vm is running. # # For instance, when VM_NAME=Kali - the following aliases will be defined: # sshkali, getkali, and so on # function setup_aliases() { name=$VM_NAME if [ -z $name ]; then echo "[!] You must set the VM_NAME variable within that script first!" exit 1 fi alias ssh$name="ssh -o StrictHostKeyChecking=no -Y $VM_USER@$name" alias get$name="cat $HOSTS_FILE | grep -i $name | cut -d' ' -f1" alias start$name="startvm" alias stop$name="stopvm" alias is$name="VBoxManage list runningvms | grep -qi $name && echo '[+] Running' || echo '[-] Not running';" } # # Function for starting particular VM and then detecting it within # user-specified host-only network, in order to setup correct entry in hosts file. # Afterwards some additional actions like sshfs mounting could be deployed. # function startvm() { if [ -n "$1" ] && [[ "$1" == "-h" ]]; then echo "[?] Usage: startvm [mode] - where [mode] is: headless (default) or gui" return fi name=$VM_NAME #hostname=${name,,} hostname=$name mode=$1 if [[ "$mode" == "" ]]; then mode='headless' elif [[ "$mode" == "gui" ]]; then mode='gui' else echo "[?] Usage: startvm [mode] - where [mode] is: headless (default) or gui" return fi echo "[>] Launching $name in $mode" if [[ $(VBoxManage list runningvms | grep -i $name) ]]; then echo "[+] Already running..." else echo "[>] Awaiting for machine to get up..." VBoxManage startvm $name --type $mode if [ $? -ne 0 ]; then echo "[!] Could not get $name started. Bailing out." exit 1 fi found=0 sleep 16 for i in `seq 1 25`; do if [ $found -ne 0 ]; then break fi echo -e "\t$i. Attempting to connect with $name..." sleep 3 if scan_for_vm; then found=1 break fi done if [ $found -ne 1 ]; then echo "[!] Critical - could not locate $name VM machine on network." echo -e "\tYou can always try 'scan_for_vm' command to do a sweep again and retry process." return fi echo "[+] Succeeded. $name found in network." fi } # # Function for stopping particular VM. # function stopvm() { name=$VM_NAME hostname=$name if VBoxManage list runningvms | grep -qi $name then sleep 2 sudo sed -i "/$hostname/d" $HOSTS_FILE echo "[+] Stopping $VM_NAME..." VBoxManage controlvm $name savestate else echo "[-] Not running." return fi sleep 3 if VBoxManage list runningvms | grep -qi $name then echo "[?] Seems that $name do not want to be pasued..." sleep 2 VBoxManage controlvm $name acpipowerbutton if VBoxManage list runningvms | grep -qi $name then echo "[-] Could not pause $name politely. Cut his head!" sleep 3 VBoxManage controlvm $name poweroff else echo "[+] Ok, it had shut itself down." fi fi } # # One can use that very function to enumerate available machines # visible from VMs network interface (under ARP scanning). # function find_vms_netdiscover { sudo netdiscover -i $HOST_ONLY_IFACE -r $HOST_ONLY_NET/24 -N -P | grep ${HOST_ONLY_NET:0:5} | cut -d' ' -f2 | tail -n +2 } function find_vms_nmap { nmap -sn $HOST_ONLY_NET/24 -oG - | grep Up | awk '{print $2}' } function find_vms { sudo ifconfig $HOST_ONLY_IFACE up out="" if [ -x "$(command -v nmap)" ]; then out=$(find_vms_nmap) if test "$out" != ""; then echo "$out" return fi fi if [ -x "$(command -v netdiscover)" ]; then out=$(find_vms_netdiscover) if test "$out" != ""; then echo "$out" return fi fi echo "" } function detect_vm { out=$(timeout 30s ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 $VM_USER@$1 "$VM_DETECT_COMMAND" 2>/dev/null ) if [ $? -eq 124 ] || [ $? -eq 255 ]; then echo "[!] Machine $1 timed out while trying to detect it by ssh probing." return 1 fi if echo "$out" | grep -qi "$VM_DETECT_PATTERN" ; then return 0 else return 1 fi } # # If for some reason `start` command didn't manage to find the VM # that was starting at that moment, one can repeat the scan & set process # manually using the below command. # function scan_for_vm { # Scanning hosts in host-only network made by VirtualBox and then every # found host will be ssh'd to get it's uname and determine whether it is our vm. # Thanks to this loop we will not be failing to connect to our VM in case it's # IP would get assigned differently from VBox dhcp. hosts=$(find_vms) declare -a hostsarray while read -r host do hostsarray+=($host) done <<< "$hosts" sorted_hostsarray=($(echo "${hostsarray[@]}" | tr ' ' '\n' | sort -u)) for host in $sorted_hostsarray[@]; do echo "[.] Testing: $host" detect_vm $host if [ $? -eq 0 ] then # VM found by match in uname's output. echo "[+] Found VM by ssh probing: $host" if [ -n "$VM_INIT_COMMANDS" ]; then echo "[+] Running VM init commands..." timeout 1m ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 $VM_USER@$host "$VM_INIT_COMMANDS" 2>/dev/null if [ $? -eq 124 ]; then echo "[?] Timed out while trying to run VM_INIT_COMMANDS." #return 1 echo "Continuing anyway..." fi detect_vm $host if [ $? -ne 0 ]; then if [ $# -eq 1 ] && [ "$1" == "again" ] ; then echo "[!] After initial commands the connection with VM is lost. Repeat the 'scan_for_vm' process" return 1 else scan_for_vm "again" fi fi fi # Since the shell does output redirection not sudo, we have to write # to the hosts file like so: # cat $HOSTS_FILE | grep -qi $VM_NAME if [ $? -eq 0 ] && [ "$1" != "again" ]; then sudo sed -i -E "s/^[0-9]{1,3}.[0-9]{1,3}+.[0-9]{1,3}+.[0-9]{1,3}+\s+$VM_NAME/$host $VM_NAME/" $HOSTS_FILE echo "[+] Updated /etc/hosts file with '$host $VM_NAME' entry." else echo "$host $hostname" | sudo tee --append $HOSTS_FILE > /dev/null fi return 0 else #echo "[.] Not our target VM: '$host'" continue fi done echo "[!] Could not locate $VM_NAME machine within the network." return 1 } setup_aliases