260 likes | 359 Views
EXTREMELY LOW-LEVEL NETWORKING IN PERL (in order to get girls). Samy Kamkar. June 22, 2010. YAPC::NA 2010. Who is Samy?. Co-Founder of Fonality, IP PBX Company Passionate Perl Programmer ”Narcissistic Vulnerability Pimp” (aka Security Researcher for fun) Lady Gaga aficionado.
E N D
EXTREMELY LOW-LEVEL NETWORKING IN PERL(in order to get girls) Samy Kamkar June 22, 2010 YAPC::NA 2010
Who is Samy? • Co-Founder of Fonality, IP PBX Company • Passionate Perl Programmer • ”Narcissistic Vulnerability Pimp” (aka Security Researcher for fun) • Lady Gaga aficionado
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
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
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
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 }; // total = 8 bytes
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
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”}); }
The Basics: C Structures sub bpf_program { my %struct = @_; my $len = length(bpf_insn()); pack(“Ia$len”, $struct{‘bf_len’}, bpf_insn( %{$struct{‘*bf_insns’}} ) ); } sub bpf_insn { my %struct = @_; pack(“SaaI”, @struct{qw/ code jt jf k /} ); } // Use pack()/unpack() // to do these in perl! struct bpf_program { u_int bf_len; struct bpf_insn *bf_insns; }; struct bpf_insn { u_short code; u_char jt; u_char jf; bpf_u_int32 k; };
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);
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! } }
BPF sniffer: continued samy@donttasemebro$ perl bpfsniff.pl # ICMP echo request 001b63f35e42001ec2bf76ee08004500005422180000400147720a00011c040202020800a1530ecd0000cd09174c6b860d0008090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 # ICMP echo reply 001ec2bf76ee001b63f35e420800450000544aad0000380126dd040202020a00011c0000e3460ecd0000cd09174c6b860d0008090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 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
A Portable Packet Sniffer use Packet; my $eth = new Packet::Ethernet; my $ip = new Packet::IP; my $s = Packet::Sniff->new(device => $DEVICE); # start monitoring $s->open() || die $s->{errbuf}; # open our device $s->loop(0, \&callback); # send packets to callback sub callback { my ($ud, $hdr, $pkt, $s) = @_; my ($time, $hi) = Time::HiRes::gettimeofday(); # high-res time $time = $1 if localtime($time) =~ /(\d+:\d+:\d+)/; # 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 } }
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)
ARP Spoofing ARP Spoofing
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();
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”’}; }}}}}
Q&A A gentleman never asks. A lady never tells.
Fin Packet (Perl module suite): samy.pl/packet h2ph: man h2ph pwnat: samy.pl/pwnat Samy Kamkar www.samy.pl samy@samy.pl twitter.com/SamyKamkar