Changeset 5518

Show
Ignore:
Timestamp:
02/08/10 15:00:14 (6 months ago)
Author:
nopper
Message:

Readapting injector audit to respect the new engine.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pm/trunk/audits/active/injector/sources/main.py

    r5435 r5518  
    11#!/usr/bin/env python 
    22# -*- coding: utf-8 -*- 
    3 # Copyright (C) 2008 Adriano Monteiro Marques 
     3# Copyright (C) 2008, 2010 Adriano Monteiro Marques 
    44# 
    55# Author: Francesco Piccinno <stack.box@gmail.com> 
     
    2020 
    2121import gtk 
     22import pango 
    2223import gobject 
    2324 
     
    3637 
    3738from umit.pm.manager.auditmanager import * 
     39from umit.pm.manager.sessionmanager import TCPIdent, SessionManager 
    3840 
    3941from umit.pm.backend import MetaPacket 
     
    4850COLUMN_OBJECT = range(8) 
    4951 
    50 # Special constant to track idle connections 
    51 CONN_IDLE = CONN_TIMED_OUT + 1 
    52  
    5352escape_table = '.........\t\n\x0b\x0c\r..................' \ 
    5453               ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFG' \ 
     
    6160escape_raw = lambda x: string.translate(x, escape_table) 
    6261 
    63 def _kill_stream_seq(ctx, stream, seqoff): 
    64     pkt = MetaPacket.new('ip') / MetaPacket.new('tcp') 
    65     pkt.set_field('ip.src', stream.get_source()) 
    66     pkt.set_field('ip.dst', stream.get_dest()) 
    67     pkt.set_field('tcp.sport', stream.sport) 
    68     pkt.set_field('tcp.dport', stream.dport) 
    69     pkt.set_field('tcp.seq', stream.client.first_data_seq + \ 
    70                   stream.server.count + stream.server.urg_count + \ 
    71                   (seqoff and stream.server.window / 2 or 0)) 
    72     pkt.set_field('tcp.flags', TH_RST) 
    73  
    74     ctx.si_l3(pkt) 
    75  
    76     pkt = MetaPacket.new('ip') / MetaPacket.new('tcp') 
    77     pkt.set_field('ip.src', stream.get_dest()) 
    78     pkt.set_field('ip.dst', stream.get_source()) 
    79     pkt.set_field('tcp.sport', stream.dport) 
    80     pkt.set_field('tcp.dport', stream.sport) 
    81     pkt.set_field('tcp.seq', stream.server.first_data_seq + \ 
    82                   stream.client.count + stream.client.urg_count + \ 
    83                   (seqoff and stream.client.window / 2 or 0)) 
    84     pkt.set_field('tcp.flags', TH_RST) 
    85  
    86     ctx.si_l3(pkt) 
    87  
    88 def kill_stream(ctx, stream): 
    89     _kill_stream_seq(ctx, stream, False) 
    90     _kill_stream_seq(ctx, stream, True) 
     62def inject_buffer(ctx, conn, index, buff): 
     63    if conn.l4_proto == NL_TYPE_TCP: 
     64        proto = 'tcp' 
     65    elif conn.l4_proto == NL_TYPE_UDP: 
     66        proto = 'udp' 
     67    else: 
     68        return False 
     69 
     70    mpkt = MetaPacket.new('ip') / MetaPacket.new(proto) 
     71 
     72    if index == 0: 
     73        mpkt.l3_src = conn.l3_addr1 
     74        mpkt.l3_dst = conn.l3_addr2 
     75 
     76        mpkt.l4_src = conn.l4_addr1 
     77        mpkt.l4_dst = conn.l4_addr2 
     78    else: 
     79        mpkt.l3_src = conn.l3_addr2 
     80        mpkt.l3_dst = conn.l3_addr1 
     81 
     82        mpkt.l4_src = conn.l4_addr2 
     83        mpkt.l4_dst = conn.l4_addr1 
     84 
     85    mpkt.l4_proto = conn.l4_proto 
     86 
     87    mpkt.set_fields('ip', { 
     88        'src' : mpkt.l3_src, 
     89        'dst' : mpkt.l3_dst}) 
     90    mpkt.set_fields(proto, { 
     91        'sport' : mpkt.l4_src, 
     92        'dport' : mpkt.l4_dst}) 
     93 
     94    mpkt.inject = buff 
     95    mpkt.inject_len = len(buff) 
     96 
     97    index += 2 
     98    conn.flags = CN_INJECTED 
     99    conn.buffers.append((index, buff)) 
     100 
     101    ctx.inject_buffer(mpkt) 
     102 
     103    return True 
     104 
     105def send_tcpkill(ctx, src, dst, sport, dport, seq): 
     106    mpkt = MetaPacket.new('ip') / MetaPacket.new('tcp') 
     107 
     108    mpkt.set_fields('ip', { 
     109        'src' : src, 
     110        'dst' : dst}) 
     111 
     112    mpkt.set_fields('tcp', { 
     113        'sport' : sport, 
     114        'dport' : dport, 
     115        'seq' : seq, 
     116        'ack' : 0, 
     117        'flags' : TH_RST}) 
     118 
     119    ctx.si_l3(mpkt) 
     120 
     121def kill_connection(ctx, conn): 
     122    if conn.l4_proto != NL_TYPE_TCP: 
     123        log.debug('I can kill only TCP connections') 
     124        return False 
     125 
     126    ident = TCPIdent(conn.l3_addr1, conn.l3_addr2, 
     127                     conn.l4_addr1, conn.l4_addr2) 
     128 
     129    sess = SessionManager().get_session(ident) 
     130 
     131    if not sess: 
     132        log.debug('Cannot find the TCP session') 
     133        return False 
     134 
     135    if ident.l3_src == sess.ident.l3_src: 
     136        status = sess.data[1] 
     137        ostatus = sess.data[0] 
     138    else: 
     139        status = sess.data[0] 
     140        ostatus = sess.data[1] 
     141 
     142    send_tcpkill(ctx, conn.l3_addr1, conn.l3_addr2, 
     143                 conn.l4_addr1, conn.l4_addr2, ostatus.last_ack) 
     144    send_tcpkill(ctx, conn.l3_addr2, conn.l3_addr1, 
     145                 conn.l4_addr2, conn.l4_addr1, status.last_ack) 
     146 
     147    return True 
    91148 
    92149class InjectDialog(gtk.Dialog): 
    93     def __init__(self, stream, inj_file=False): 
     150    def __init__(self, conn, inj_file=False): 
    94151        gtk.Dialog.__init__(self, _('Active connections'), PMApp().main_window, 
    95152                            gtk.DIALOG_DESTROY_WITH_PARENT, 
     
    99156        tbl = gtk.Table(2, 2, False) 
    100157 
    101         self.rsrc = gtk.RadioButton(None, '%s:%d' % (stream.get_source(), 
    102                                                      stream.sport)) 
    103         self.rdst = gtk.RadioButton(self.rsrc, '%s:%d' % (stream.get_dest(), 
    104                                                           stream.dport)) 
     158        self.rsrc = gtk.RadioButton(None, '%s:%d' % (conn.l3_addr1, 
     159                                                     conn.l4_addr1)) 
     160        self.rdst = gtk.RadioButton(self.rsrc, '%s:%d' % (conn.l3_addr2, 
     161                                                          conn.l4_addr2)) 
    105162        self.rdst.set_active(True) 
    106163 
     
    147204 
    148205    def get_inject_data(self): 
    149         is_client = self.rsrc.get_active() 
     206        if self.rsrc.get_active(): 
     207            index = 1 
     208        else: 
     209            index = 0 
    150210 
    151211        if hasattr(self, 'entry'): 
     
    153213 
    154214            try: 
    155                 return is_client, open(fname, 'r').read() 
     215                return index, open(fname, 'r').read() 
    156216            except: 
    157                 return is_client, None 
     217                return index, None 
    158218        else: 
    159             return is_client, self.view.get_buffer().get_text( 
     219            return index, self.view.get_buffer().get_text( 
    160220                *self.view.get_buffer().get_bounds() 
    161221            ) 
     
    164224    tagtable = None 
    165225 
    166     def __init__(self, connw, stream): 
     226    def __init__(self, connw, conn): 
    167227        gtk.VBox.__init__(self, False, 2) 
    168228 
    169         self.stream = stream 
    170229        self.connw = connw 
    171  
    172         # This is for data collected 
    173         # Everything is saved in the form (is_client : bool, data : str) 
    174         self.data_frags = [] 
    175  
    176         # This is for data to inject 
    177         self.client_inj_frags = [] 
    178         self.server_inj_frags = [ 
    179             #'USER test injection test :Tester\r\n', 
    180             #'PING :pingthis\r\n' 
    181         ] 
     230        self.conn = conn 
     231        self.conn.flags |= CN_VIEWING 
     232        self.index = 0 
    182233 
    183234        if not self.tagtable: 
     235            # Create tag table if not yet allocated 
    184236            self.tagtable = gtk.TextTagTable() 
    185237 
    186238            tag = gtk.TextTag('src') 
    187239            tag.set_property('foreground', 'blue') 
    188             tag.set_property('font', 'Monospace 9') 
    189240            self.tagtable.add(tag) 
    190241 
    191242            tag = gtk.TextTag('dst') 
    192243            tag.set_property('foreground', 'red') 
    193             tag.set_property('font', 'Monospace 9') 
     244            self.tagtable.add(tag) 
     245 
     246            tag = gtk.TextTag('srcinj') 
     247            tag.set_property('weight', pango.WEIGHT_BOLD) 
     248            tag.set_property('foreground', 'blue') 
     249            self.tagtable.add(tag) 
     250 
     251            tag = gtk.TextTag('dstinj') 
     252            tag.set_property('weight', pango.WEIGHT_BOLD) 
     253            tag.set_property('foreground', 'red') 
    194254            self.tagtable.add(tag) 
    195255 
     
    198258        self.view.set_wrap_mode(gtk.WRAP_CHAR) 
    199259        self.view.set_editable(False) 
     260        self.view.modify_font(pango.FontDescription('Monospace 9')) 
    200261 
    201262        sw = gtk.ScrolledWindow() 
     
    240301 
    241302    def __on_kill(self, btn): 
    242         kill_stream(self.connw.session.context, self.stream) 
     303        kill_connection(self.connw.session.context, self.conn) 
    243304 
    244305    def __on_inject(self, btn, is_file): 
    245         dialog = InjectDialog(self.stream, is_file) 
     306        dialog = InjectDialog(self.conn, is_file) 
    246307 
    247308        if dialog.run() == gtk.RESPONSE_ACCEPT: 
    248             is_client, data = dialog.get_inject_data() 
     309            index, data = dialog.get_inject_data() 
    249310 
    250311            if data: 
    251                 if is_client: 
    252                     self.client_inj_frags.append(data) 
    253                 else: 
    254                     self.server_inj_frags.append(data) 
     312                inject_buffer(self.connw.session.context, self.conn, index, data) 
    255313 
    256314        dialog.hide() 
    257315        dialog.destroy() 
    258316 
     317    def update(self): 
     318        if not self.conn: 
     319            return 
     320 
     321        tags = ('src', 'dst', 'dstinj', 'srcinj') 
     322 
     323        if self.index > len(self.conn.buffers): 
     324            self.index = 0 
     325            self.buff.set_text('') 
     326 
     327        while self.index < len(self.conn.buffers): 
     328            is_client, buff = self.conn.buffers[self.index] 
     329            self.buff.insert_with_tags(self.buff.get_end_iter(), 
     330                                       escape_raw(buff), 
     331                                       self.tagtable.lookup(tags[is_client])) 
     332 
     333            self.index += 1 
     334 
    259335class ConnectionsWindow(gtk.Dialog): 
    260     def __init__(self, reassembler): 
    261         self.session = None 
    262         self.reassembler = reassembler 
    263  
    264         self.stream_dict = {} 
     336    def __init__(self, session): 
     337        self.session = session 
     338 
    265339        self.following = {} 
    266  
    267         self.status_string = (_('established'), _('active'), _('reset'), 
    268                               _('closed'), _('timed out'), _('idle')) 
    269340 
    270341        gtk.Dialog.__init__(self, _('Active connections'), PMApp().main_window, 
     
    330401 
    331402        self.update_id = None 
     403        self.last_conn = None 
    332404        self.set_size_request(400, 200) 
    333405 
     
    336408            gobject.timeout_add(1000, self.__on_update_tree) 
    337409 
    338     def add_connection(self, stream): 
    339         if stream in self.stream_dict and self.stream_dict[stream][0] is stream: 
    340             self.remove_connection(stream) 
    341  
     410    def add_connection(self, conn): 
    342411        self.store.append( 
    343             [stream.get_source(), stream.sport, stream.get_dest(), stream.dport, 
    344              'TCP', stream.state, stream.get_bytes(), stream] 
     412            [conn.l3_addr1, conn.l4_addr1, 
     413             conn.l3_addr2, conn.l4_addr2, 
     414             conn.l4_proto == NL_TYPE_TCP and 'TCP' or 'UDP', 
     415             conn.status, conn.xferred, conn] 
    345416        ) 
    346  
    347         path = self.store.iter_n_children(None) - 1 
    348         self.stream_dict[stream] = (stream, path) 
    349  
    350         # DEBUG: remove me after injection is complete 
    351         #if stream.sport in (6667, 80) or stream.dport in (6667, 80): 
    352             #details = TabDetails(self.session, stream) 
    353             #details.show_all() 
    354  
    355             #self.following[stream] = details 
    356  
    357             #self.notebook.append_page(details, gtk.Label('%s:%d <-> %s:%d' \ 
    358                 #% (stream.get_source(), stream.sport, 
    359                    #stream.get_dest(), stream.dport))) 
    360  
    361         log.debug('Connection added') 
    362  
    363     def remove_connection(self, stream): 
    364         if stream in self.stream_dict: 
    365             return 
    366  
    367         idx = self.stream_dict[stream][1] 
    368  
    369         del self.stream_dict[stream] 
    370  
    371         self.store[idx][COLUMN_OBJECT] = (stream.get_bytes(), stream.state) 
    372  
    373         log.debug('Reference removed') 
     417        self.last_conn = conn 
    374418 
    375419    def remove_tab_details(self, tab): 
     
    379423        self.notebook.remove_page(pagenum) 
    380424 
    381         if tab.stream in self.following: 
    382             del self.following[tab.stream] 
     425        if tab.conn in self.following: 
     426            tab.conn &= ~CN_VIEWING 
     427            del self.following[tab.conn] 
    383428 
    384429    def get_extern_iter(self, top=True): 
     
    406451 
    407452        if iter: 
    408             stream = self.store.get_value(iter, COLUMN_OBJECT) 
    409  
    410             if stream and not isinstance(stream, (tuple, int)): 
    411                 details = TabDetails(self, stream) 
     453            conn = self.store.get_value(iter, COLUMN_OBJECT) 
     454 
     455            if conn and not isinstance(conn, (tuple, int)): 
     456                details = TabDetails(self, conn) 
    412457                details.show_all() 
    413458 
    414                 self.following[stream] = details 
     459                self.following[conn] = details 
    415460 
    416461                self.notebook.append_page(details, gtk.Label('%s:%d <-> %s:%d' \ 
    417                     % (stream.get_source(), stream.sport, 
    418                        stream.get_dest(), stream.dport))) 
     462                    % (conn.l3_addr1, conn.l4_addr1, 
     463                       conn.l3_addr2, conn.l4_addr2))) 
    419464 
    420465    def __on_kill(self, action): 
     
    423468 
    424469        if iter: 
    425             stream = self.store.get_value(iter, COLUMN_OBJECT) 
    426  
    427             if stream and not isinstance(stream, (tuple, int)): 
    428                 kill_stream(self.session.context, stream) 
     470            conn = self.store.get_value(iter, COLUMN_OBJECT) 
     471 
     472            if conn and not isinstance(conn, (tuple, int)): 
     473                kill_connection(self.session.context, conn) 
    429474 
    430475    def __on_clear(self, action): 
    431         self.stream_dict.clear() 
    432476        self.store.clear() 
     477        self.last_conn = None 
    433478 
    434479    def __on_button_pressed(self, widget, evt): 
     
    440485 
    441486        if iter: 
    442             stream = self.store.get_value(iter, COLUMN_OBJECT) 
    443  
    444             if stream and not isinstance(stream, (tuple, int)): 
     487            conn = self.store.get_value(iter, COLUMN_OBJECT) 
     488 
     489            if conn and not isinstance(conn, (tuple, int)): 
    445490                self.menu.show() 
    446491                self.menu.popup(None, None, None, evt.button, evt.time, None) 
     
    450495 
    451496        if page == 0: 
    452             #log.debug('Updating tree view (%d connections)' % \ 
    453             #          self.store.iter_n_children(None)) 
     497            log.debug('Updating tree view (%d connections)' % \ 
     498                      self.store.iter_n_children(None)) 
     499 
     500            for row in self.store: 
     501                if row[COLUMN_OBJECT] is None: 
     502                    self.store.remove(row.iter) 
    454503 
    455504            start, end = self.get_extern_iter(), self.get_extern_iter(False) 
    456505 
    457             if not start: 
    458                 return True 
    459  
    460             while start != end: 
     506            while start and start != end: 
    461507                try: 
    462                     stream = self.store.get_value(start, COLUMN_OBJECT) 
     508                    conn = self.store.get_value(start, COLUMN_OBJECT) 
    463509                except Exception, err: 
    464                     return True 
    465  
    466                 if isinstance(stream, tuple): 
    467                     self.store.set_value(start, COLUMN_BYTES, stream[0]) 
    468                     self.store.set_value(start, COLUMN_STATUS, stream[1]) 
     510                    break 
     511 
     512                if isinstance(conn, tuple): 
     513                    self.store.set_value(start, COLUMN_BYTES, conn[0]) 
     514                    self.store.set_value(start, COLUMN_STATUS, conn[1]) 
    469515                    self.store.set_value(start, COLUMN_OBJECT, None) 
    470                 elif stream is not None: 
    471                     old_bytes = self.store.get_value(start, COLUMN_BYTES) 
    472                     new_bytes = stream.get_bytes() 
    473  
    474                     if old_bytes == new_bytes: 
    475                         self.store.set_value(start, COLUMN_STATUS, CONN_IDLE) 
    476                     else: 
    477                         self.store.set_value(start, COLUMN_STATUS, stream.state) 
    478                         self.store.set_value(start, COLUMN_BYTES, new_bytes) 
     516                elif conn is not None: 
     517                    self.store.set_value(start, COLUMN_BYTES, conn.xferred) 
     518                    self.store.set_value(start, COLUMN_STATUS, conn.status) 
    479519 
    480520                start = self.store.iter_next(start) 
     521 
     522            # Ok now let's add newer connections 
     523            conn_man = self.session.context.audit_dispatcher.\ 
     524                     get_connection_manager() 
     525 
     526            try: 
     527                idx = conn_man.conn_list.index(self.last_conn) + 1 
     528            except ValueError, exc: 
     529                idx = 0 
     530 
     531            while idx < len(conn_man.conn_list): 
     532                self.add_connection(conn_man.conn_list[idx]) 
     533                idx += 1 
     534 
    481535        else: 
    482536            page = self.notebook.get_nth_page(page) 
     
    485539                return True 
    486540 
    487             #log.debug('Adding missing fragments %s' % page.data_frags) 
    488  
    489             while page.data_frags: 
    490                 is_client, data = page.data_frags.pop(0) 
    491  
    492                 page.buff.insert_with_tags( 
    493                     page.buff.get_end_iter(), escape_raw(data), 
    494                     page.tagtable.lookup((is_client and 'src' or 'dst')), 
    495                 ) 
     541            page.update() 
    496542 
    497543        return True 
     
    500546        idx = model.get_value(iter, COLUMN_STATUS) 
    501547 
    502         assert idx >= 0 and idx <= 5, 'Status id cannot be %d' % idx 
    503  
    504         cell.set_property('text', self.status_string[idx]) 
     548        if idx == CN_IDLE:      out = 'idle' 
     549        elif idx == CN_OPENING: out = 'opening' 
     550        elif idx == CN_OPEN:    out = 'open' 
     551        elif idx == CN_ACTIVE:  out = 'active' 
     552        elif idx == CN_CLOSING: out = 'closing' 
     553        elif idx == CN_CLOSED:  out = 'closed' 
     554        elif idx == CN_KILLED:  out = 'killed' 
     555 
     556        cell.set_property('text', out) 
    505557 
    506558    def __on_response(self, dialog, rid): 
     
    513565class Injector(Plugin, ActiveAudit): 
    514566    def start(self, reader): 
    515         tcpdecoder = Core().get_need(reader, 'TCPDecoder') 
    516  
    517         if not tcpdecoder: 
    518             raise PMErrorException('TCPDecoder plugin not loaded.') 
    519  
    520         if not tcpdecoder.reassembler: 
    521             raise PMErrorException('TCP segments reassembling disabled ' 
    522                                    'in TCPDecoder.') 
    523  
    524         tcpdecoder.reassembler.analyzers.insert(0, self.__tcp_callback) 
    525  
    526567        self.item = self.add_menu_entry('Injector', _('Active connections'), 
    527568                                        _('View active connections or inject ' 
    528569                                          'data in active one'), 
    529570                                        gtk.STOCK_INDEX) 
    530  
    531         self.window = ConnectionsWindow(tcpdecoder.reassembler) 
    532         # DEBUG: 
    533         #self.window.show() 
    534         #self.window.start_update() 
     571        self.window = None 
    535572 
    536573    def stop(self): 
     
    539576 
    540577    def execute_audit(self, sess, inp_dict): 
    541         self.window.session = sess 
     578        if self.window is None: 
     579            self.window = ConnectionsWindow(sess) 
    542580 
    543581        if not self.window.flags() & gtk.VISIBLE: 
    544582            self.window.show() 
    545583            self.window.start_update() 
    546  
    547     def __tcp_callback(self, stream, mpkt): 
    548         # DEBUG: remove me 
    549         #if stream.sport in (6667, 80) or stream.dport in (6667, 80): 
    550         self.window.add_connection(stream) 
    551         stream.listeners.append(self.__follow_connection) 
    552  
    553     def __follow_connection(self, stream, mpkt, rcv): 
    554         if stream.state != CONN_DATA: 
    555             self.window.remove_connection(stream) 
    556  
    557         elif stream in self.window.following: 
    558             page = self.window.following[stream] 
    559  
    560             log.debug('Collecting data for %s' % stream) 
    561  
    562             if rcv is stream.server: 
    563                 data = stream.server.data[-stream.server.count_new:] 
    564  
    565                 if data: 
    566                     page.data_frags.append((0, data)) 
    567  
    568                 if page.server_inj_frags: 
    569                     inj_data = page.server_inj_frags.pop(0) 
    570                     mpkt.set_cfield('inj::payload', inj_data) 
    571  
    572                     return INJ_MODIFIED 
    573             else: 
    574                 data = stream.client.data[-stream.client.count_new:] 
    575  
    576                 if data: 
    577                     page.data_frags.append((1, data)) 
    578  
    579                 if page.client_inj_frags: 
    580                     inj_data = page.client_inj_frags.pop(0) 
    581                     mpkt.set_cfield('inj::payload', inj_data) 
    582  
    583                     return INJ_MODIFIED 
    584  
    585             return INJ_COLLECT_DATA 
    586  
    587         return INJ_COLLECT_STATS 
    588584 
    589585__plugins__ = [Injector]