Trafficanalyse und -modifikation mit IMP

Trafficanalyse und
-modifikation
mit IMP
Steffen Ullrich, genua mbH
Deutscher Perl-Workshop 2013, Berlin

who am I

Übersicht Talk

Firewalls

Firewalls

Funktionsweise

Vielfalt von Analysen

Vielfalt von Datenquellen

Trennung Datenquellen und Analyse

Trennung Datenquellen und Analyse

warum

Anforderungen an API

was heisst performant

existente Lösungen

IMP

IMP

was ist IMP

IMP vs. ICAP

Funktionsweise

Funktionsweise im Bild

Funktionsweise im Bild (static)

IMP Callbacks

IMP Callbacks

Durchlassen

Beispiel PASS dir,inside

Beispiel PASS dir,future

Beispiel PASS dir,infinite

Ersetzen

Beispiel Ersetzen

Beispiel Löschen

Beispiel Einfügen

Verbieten

Vorab durchlassen

Beispiel PREPASS infinite - SessionLog

Beispiel PREPASS Window - RTP Stream

sonst noch

IMP input

IMP input

Daten füttern

Datentypen

Stream vs. Packet

IMP Implementierungen

IMP Implementierungen

Implementierungen

existierende IMP Plugins

Beispiel 1: SSL Analyse

Beispiel: SSL Analyse

Funktionsweise

Basics

package Net::IMP::Example::LogServerCertificate;
use base 'Net::IMP::Base';
use Net::IMP qw(:log :DEFAULT); # import IMP_ constants
use Net::IMP::Debug;
use fields (
     'done',  # set after Server Hello or if no SSL
     'sbuf',  # buffer data for processing Server Hello
);

Interface deklarieren

sub INTERFACE {
    return ([
        IMP_DATA_STREAM,                    # what we accept
        [ IMP_PASS, IMP_PREPASS, IMP_LOG ]  # what we return
    ])
}

Initialisierung

sub new_analyzer {
    my ($factory,%args) = @_;
    my $self = $factory->SUPER::new_analyzer(%args);

    $self->run_callback(
        # we are not interested in data from client
        [ IMP_PASS, 0, IMP_MAXOFFSET ],
        # and we will not change data from server, only inspect
        [ IMP_PREPASS, 1, IMP_MAXOFFSET ],
    );

    $self->{sbuf} = '';
    return $self;
}

Daten füttern (1)

sub data {
    my ($self,$dir,$data) = @_;
    return if $dir == 0; # should not happen
    return if $self->{done}; # done or no SSL
    return if $data eq ''; # eof from server

    my $buf = $self->{sbuf} .= $data;
    ....

Daten füttern (2)

...
if ( _read_ssl_handshake($self,\$buf,2)                  # Server Hello
    and my $certs = _read_ssl_handshake($self,\$buf,11)  # Certificates
) {
    $self->{done} = 1;

    # find OID 2.5.4.3 (common name) the quick and dirty way
    if ( $certs =~m{\x06\x03\x55\x04\x03.}g
        and my $name = _get_asn1_string(substr($certs,pos($certs)))) {
        $self->run_callback([ IMP_LOG,1,0,0,IMP_LOG_INFO,"cn=$name" ]);
    }
}

$self->run_callback([ IMP_PASS,1,IMP_MAXOFFSET ])
    if $self->{done};

Testen

$ imp-pcap-filter.pl \
   -MNet::IMP::Example::LogServerCertificate \
   -r rsasnakeoil2.cap \
   -w x.pcap
[info] cn=Snake Oil CA

Variationen

Beispiel 2 - IRC Shout

Beispiel: IRC Shout

Funktionsweise

Basics

package IRCShout;
use Net::IMP; # import IMP_ constants
use base 'Net::IMP::Base';
use fields (
    'pos',   # current position in stream
    'line',  # buffer for unfinished lines
);

Interface

sub INTERFACE {
    return ([
        IMP_DATA_STREAM,
        [ IMP_PASS, IMP_REPLACE ]
    ])
}

Initialisierung

sub new_analyzer {
    my ($factory,%args) = @_;
    my $self = $factory->SUPER::new_analyzer(%args);

    $self->run_callback(
        # we are not interested in data from server
        [ IMP_PASS, 1, IMP_MAXOFFSET ],
    );

    $self->{line} = '';
    $self->{pos} = 0;
    return $self;
}

Daten verändern

sub data {
    my ($self,$dir,$data) = @_;
    return if $dir == 1; # should not happen
    return if $data eq ''; # eof from client
    $self->{line} .= $data;

    my @rv; # collect callbacks
    while ( $self->{line} =~s{\A([^\n]*\n)}{} ) {
        my $line = $1;
        $self->{pos} += length($line);
        ....

REPLACE

if ( shout(\$line)) {
   if ( @rv and $rv[-1][0] == IMP_REPLACE ) {
       # merge into last replacement
       $rv[-1][2] = $self->{pos};
       $rv[-1][3].= $line;
   } else {
       # add new replacement
       push @rv, [ IMP_REPLACE,0,$self->{pos},$line ];
   }

oder PASS

} else {
   if ( @rv and $rv[-1][0] == IMP_PASS ) {
       # merge into last pass
       $rv[-1][2] = $self->{pos};
   } else {
       # add new pass
       push @rv, [ IMP_PASS,0,$self->{pos} ];
   }
}

Callback am Ende

    }
    $self->run_callback(@rv) if @rv;
}

howto shout

sub shout {
    my $line = shift;
    return $$line =~s{\A
        (
            (?: :\S+\x20+ )?      # opt msg prefix
            PRIVMSG\x20+\S+\x20+  # privmsg rcpt
        )
        (.+)                      # message
    }{$1\U$2}x                    # shout message
}

Fragen

Fragen ?