Tag Archive for 'bash'

Howto: Virtual Isolated Network Using VMWare

February 15th, 2008 by peasleer

I enjoy computer security. There aren’t a lot of opportunities to study it formally within computer science, so my education in this field is entirely from what I read and practice in my own time.

Most recently, I’ve been feeling the itch to write a worm. The idea is attractive because a worm can be developed modularly with reusable components. Each individual component will increase my knowledge substantially in a different area of security, making the development a measurable goal with incremental positive feedback.

However, before development could begin, I wanted to ensure that I wouldn’t end up in court for an accidental release of one of the components gone awry. I love virtual machines as a tool to aid in the development process, so the solution was immediately obvious - create a multi-host virtual network that is isolated from the world. Further, I wanted each machine on this isolated network to occasionally be able to access the Internet to retrieve updates or tools, so the isolation needed to be complete but /controllable./ The final requirements of the virtual network ended up looking like this:

  • Isolated network except when explicitly given access to the Internet
  • Multiple hosts with different operating systems
  • Must be able to easily add and remove hosts
  • All hosts on the network must both default and fail to isolation

The way to implement this using VMWare Workstation (and I’m sure other products in their virtualization line) is to utilize teams. Teams are a ‘wrapper’ of a sort that encompass multiple VMs with additional configuration. When you start a team, each virtual machine included in the team’s configuration is also started. The team can be configured to also provide a virtual network segment for the virtual machines to use, which when paired with each VM in the team being configured with ‘host only’ network access, results in a virtual isolated network.

The team doesn’t provide DHCP though, which means the network has to be maintained with static address and modifications to each machine’s host file. This hardly met my requirement for easily adding and removing hosts from the network. Creating a host that would act as the network server fulfills this requirement, and will also facilitate network control access. As we continue on, please note that I’m using Debian Linux with a 2.6.x kernel, and all of the commands I give below and edits to configuration files *must be done as a superuser.*

Enough setup: time for implementation. To speed the process, I created two base images, one Windows XP SP2 install, and one Debian Lenny netinstall with a 2.6.x kernel. Each image was updated to include the latest patches, user accounts were created, and standard tools were installed. Once these base images were created, they were set aside to never be modified. Clones of the base images are created for each of the expendable hosts, and one clone of the Debian base image was used as the only ‘permanent’ member of the team. All members of the team share one virtual network segment, and have one interface. The only exception to this is the network server VM, which is dual-homed to be connected to both the virtual network and the Internet via NAT.

All hosts default to DHCP, so cloned images have no need for additional configuration when added. The network server is the only machine that had be set up specially. The bind9 and dhcp3-server packages were obtained (for DNS and DHCP, respectively) using Debian’s awesome package manager:

apt-get install bind9 dhcp3-server

Configuring bind is trivial, it defaults to forwarding DNS requests, so nothing is required as far as configuration unless you want to. dhcpd, provided by dhcp3-server, is a little more complicated. First, the interface connected to the isolated network must be set up to have a static address in the subnet in which you will be offering IP addresses, like 10.10.10.1 for the 10.10.10.x subnet or 192.168.30.1 for the 192.168.x.x subnet. It would be wise to modify your interface configuration to make this change survive rebooting.

/etc/network/interfaces:

auto lo eth0 ethiface lo inet loopback
iface eth0 inet static
 	address 10.10.10.1
 	netmask 255.255.255.0iface eth1 inet dhcp

The external interface is eth1, and is configured with DHCP since it is NAT routed. The internal interface is eth0, and is given an ip of 10.10.10.1 with a subnet mask of 255.255.255.0. (This means that the last quartet of the IP address is variable and available for use.) Next comes the configuration for dhcpd:

/etc/dhcp3/dhcpd.conf:

default-lease-time 600;max-lease-time 7200;
authoritative;option domain-name-servers 10.10.1.1 192.168.30.1

subnet 10.10.10.0 netmask 255.255.255.0 {
 range 10.10.10.2 10.10.10.254;
 option routers 10.10.10.1;
 option ip-forwarding off;
 option broadcast address 10.10.10.255;
 option subnet-mask 255.255.255.0;
}

Here we are saying that the subnet is 10.10.10.*, and that we will assign addresses from 10.10.10.2 - 10.10.10.254. The other options should be self-explanatory - read up on networking if you have questions. As it stands, when the interfaces are brought down and back up and dhcpd is started, addresses will be assigned to all virtual machines sharing that network segment. If this is all you want, just issue:

ifdown eth1 eth0
ifup eth1 eth0
/etc/init.d/dhcpd3-server start

And you are done! The machine now will serve DHCP to the isolated subnet, while maintaining separate access for itself to the Internet.

However, if you want to continue on to enable Internet access for other hosts on the isolated network, we still have some work to do.

My solution for this involves iptables and masquerading. Before we do anything, we’ll need to enable IP forwarding. This can be done in multiple ways, but the most reliable for me has been the following simple command:

echo 1 > /proc/sys/net/ipv4/ip_forward

With IP forwarding enabled, we can now utilize the masquerading features of iptables, the Linux firewall. By creating rules that will take packets coming in from our internal network’s interface and sending them out on our external interface, in addition to creating a complementing rule that will accept return packets coming in from the external interface headed for the isolated host, we can accomplish this. The individual rules for my setup are:

iptables -t nat -A POSTROUTING -s  -o eth1 -j MASQUERADE
iptables -A FORWARD -d  -i eth0 -j ACCEPT

Since these are annoying to have to type in each time I want to enable access for a host, I wrote a set of scripts. The first two enable and disable access for a host or multiple hosts respectively. The third script is my emergency “oh crap” failsafe, with which a simple command I can disable all isolated hosts’s access immediately followed by bringing down the network server’s interfaces for complete assurance that whatever is going on won’t get out of the virtual network. Here they are:

enableInternet.sh

#!/bin/bash
if [ $UID -ne 0 ]; then
        echo
        echo "Must be root to run this program."
        echo
        exit 1
fi

if [[ -z $* ]]; then
        echo
        echo "  Usage: ./enableInternet.sh <ipaddress [ipaddress2...ipaddressN]>"
        echo
        exit 1
fi

for ip in $@; do
        # Will match an address of type 10.10.1.2, which matches our subnet
        # definition
        check=`echo $ip | grep -E "^([[:digit:]]{2}[.]){2}[[:digit:]][.][[:digit:]]+$"`
        # If it doesn't match, print a warning and skip it
        if [ -z $check ]; then
                echo "Improperly formatted address $ip, skipping..."
                continue
        fi

        # Enable Internet access for the address
        iptables -t nat -A POSTROUTING -s $ip -o eth1 -j MASQUERADE
        iptables -A FORWARD -d $ip -i eth0 -j ACCEPT
        echo "$ip's internet access enabled..."

done

echo "Done."

blockInternet.sh

#!/bin/bash
if [ $UID -ne 0 ]; then
        echo
        echo "Must be root to run this program."
        echo
        exit 1
fi

if [[ -z $* ]]; then
        echo
        echo "  Usage: ./blockInternet.sh <ipaddress [ipaddress2...ipaddressN]>"
        echo
        exit 1
fi

for ip in $@; do
        # Will match an address of type 10.10.1.2, which matches our subnet definition
        check=`echo $ip | grep -E "^([[:digit:]]{2}[.]){2}[[:digit:]][.][[:digit:]]+$"`
        # If it doesn't match, print a warning and skip it
        if [ -z $check ]; then
                echo "Improperly formatted address $ip, skipping..."
                continue
        fi

        # Disable Internet access for the address
        iptables -t nat -D POSTROUTING -s $ip -o eth1 -j MASQUERADE
        iptables -D FORWARD -d $ip -i eth0 -j ACCEPT
        echo "$ip's internet access disabled..."
done

echo "Done."

blockAll.sh

#!/bin/bash
if [ $UID -ne 0 ]; then
        echo
        echo "Must be root to run this program."
        echo
        exit 1
fi

echo "Disabling Internet access for all hosts on 10.10.1.0/255.255.255.0..."

iptables --flush
iptables --delete-chain
iptables -t nat --flush
iptables -t nat --delete-chain
ifdown eth0 eth1

echo "Done."

I alias’d all the commands in my shell’s configuration scripts and prefixed them with sudo so they may be executed quickly and from anywhere on the system. If you’ve read this far, you should too - at least for the blockAll script. You don’t want to be fumbling around trying to remember where you put the script when you need complete isolation 30 seconds ago :)

I know this post was long, but there was a lot to cover. With this setup, hosts can now be easily added thanks to DHCP, Internet access is manually granted and defaults to none, and the environment is completely homogeneous. Perfect for worm development, malware analysis, or what have you. If you replicate this environment, let me know how it works out for you and what improvements you make. I’m always interested in making better systems!

Converting a Relative Path to an Absolute Path in Bash

September 29th, 2007 by peasleer

This really shouldn’t have taken me as long as it did to figure this out, but it was a big enough of an annoyance that I decided to share it.

How to convert a relative path to an absolute path in linux/unix/bash script:

#!/bin/bash
# Assume parameter passed in is a relative path to a directory.
# For brevity, we won't do argument type or length checking.
echo "Absolute path: `cd $1; pwd`"

For those unaware, you don’t have to ‘cd -’ because the backticks perform command substitution and don’t modify the working directory of the script.

EDIT: Anonymous poster ‘foo’ left a comment mentioning that this only works if the path destination already exists, which is indeed the case. This isn’t at all elegant, but it is the ‘two minute hack’ version I could immediately come up with. The result only works if you have permission to write where the path should go, meaning *yes,* there will be a version three of this script when I have more time:

#!/bin/bash
# Alright, this time we'll do parameter checking.

if [ $# -eq 0 ]; then
	echo "Usage: $0 "
	exit 1
fi

if [ -d $1 ]; then
	# Paramater is an existing directory. Print it using the method in the script above.
	echo "Absolute path: `cd $1; pwd`"

elif [[ -e $1 && ! -d $1 ]]; then
	# File already exists and isn't a directory. Be more safe with the conversion.
	mkdir $1$$ 2> /dev/null
	if[ $? -ne 0 ]; then
		echo "We cannot conver this path without write permissions to the path's destination."
		exit 1
	fi
	# I don't want to escape the quotes. This is already ugly, anyway.
	dirName=`cd $1$$; pwd | awk -F"$$" {'print $1'}`
	echo "Absolute path: $dirName"
	rm -r $1$$
else
	# File doesn't exist, begin unelegant conversion
	mkdir $1 2> /dev/null
	if [ $? -ne 0 ]; then
		echo "We cannot convert this path without write permissions to the path's destination."
		exit 1
	fi
	echo "Absolute path: `cd $1; pwd`"
	rm -r $1
fi

Secondary notes: I really wrote this on the spot in a couple minutes, directly into this blog post. It is untested, and very ugly. I promise to post something better soon!