Changeset 5518
- Timestamp:
- 02/08/10 15:00:14 (6 months ago)
- Files:
-
- 1 modified
-
pm/trunk/audits/active/injector/sources/main.py (modified) (22 diffs)
Legend:
- Unmodified
- Added
- Removed
-
pm/trunk/audits/active/injector/sources/main.py
r5435 r5518 1 1 #!/usr/bin/env python 2 2 # -*- coding: utf-8 -*- 3 # Copyright (C) 2008 Adriano Monteiro Marques3 # Copyright (C) 2008, 2010 Adriano Monteiro Marques 4 4 # 5 5 # Author: Francesco Piccinno <stack.box@gmail.com> … … 20 20 21 21 import gtk 22 import pango 22 23 import gobject 23 24 … … 36 37 37 38 from umit.pm.manager.auditmanager import * 39 from umit.pm.manager.sessionmanager import TCPIdent, SessionManager 38 40 39 41 from umit.pm.backend import MetaPacket … … 48 50 COLUMN_OBJECT = range(8) 49 51 50 # Special constant to track idle connections51 CONN_IDLE = CONN_TIMED_OUT + 152 53 52 escape_table = '.........\t\n\x0b\x0c\r..................' \ 54 53 ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFG' \ … … 61 60 escape_raw = lambda x: string.translate(x, escape_table) 62 61 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) 62 def 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 105 def 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 121 def 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 91 148 92 149 class InjectDialog(gtk.Dialog): 93 def __init__(self, stream, inj_file=False):150 def __init__(self, conn, inj_file=False): 94 151 gtk.Dialog.__init__(self, _('Active connections'), PMApp().main_window, 95 152 gtk.DIALOG_DESTROY_WITH_PARENT, … … 99 156 tbl = gtk.Table(2, 2, False) 100 157 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)) 105 162 self.rdst.set_active(True) 106 163 … … 147 204 148 205 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 150 210 151 211 if hasattr(self, 'entry'): … … 153 213 154 214 try: 155 return i s_client, open(fname, 'r').read()215 return index, open(fname, 'r').read() 156 216 except: 157 return i s_client, None217 return index, None 158 218 else: 159 return i s_client, self.view.get_buffer().get_text(219 return index, self.view.get_buffer().get_text( 160 220 *self.view.get_buffer().get_bounds() 161 221 ) … … 164 224 tagtable = None 165 225 166 def __init__(self, connw, stream):226 def __init__(self, connw, conn): 167 227 gtk.VBox.__init__(self, False, 2) 168 228 169 self.stream = stream170 229 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 182 233 183 234 if not self.tagtable: 235 # Create tag table if not yet allocated 184 236 self.tagtable = gtk.TextTagTable() 185 237 186 238 tag = gtk.TextTag('src') 187 239 tag.set_property('foreground', 'blue') 188 tag.set_property('font', 'Monospace 9')189 240 self.tagtable.add(tag) 190 241 191 242 tag = gtk.TextTag('dst') 192 243 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') 194 254 self.tagtable.add(tag) 195 255 … … 198 258 self.view.set_wrap_mode(gtk.WRAP_CHAR) 199 259 self.view.set_editable(False) 260 self.view.modify_font(pango.FontDescription('Monospace 9')) 200 261 201 262 sw = gtk.ScrolledWindow() … … 240 301 241 302 def __on_kill(self, btn): 242 kill_ stream(self.connw.session.context, self.stream)303 kill_connection(self.connw.session.context, self.conn) 243 304 244 305 def __on_inject(self, btn, is_file): 245 dialog = InjectDialog(self. stream, is_file)306 dialog = InjectDialog(self.conn, is_file) 246 307 247 308 if dialog.run() == gtk.RESPONSE_ACCEPT: 248 i s_client, data = dialog.get_inject_data()309 index, data = dialog.get_inject_data() 249 310 250 311 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) 255 313 256 314 dialog.hide() 257 315 dialog.destroy() 258 316 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 259 335 class 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 265 339 self.following = {} 266 267 self.status_string = (_('established'), _('active'), _('reset'),268 _('closed'), _('timed out'), _('idle'))269 340 270 341 gtk.Dialog.__init__(self, _('Active connections'), PMApp().main_window, … … 330 401 331 402 self.update_id = None 403 self.last_conn = None 332 404 self.set_size_request(400, 200) 333 405 … … 336 408 gobject.timeout_add(1000, self.__on_update_tree) 337 409 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): 342 411 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] 345 416 ) 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 374 418 375 419 def remove_tab_details(self, tab): … … 379 423 self.notebook.remove_page(pagenum) 380 424 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] 383 428 384 429 def get_extern_iter(self, top=True): … … 406 451 407 452 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) 412 457 details.show_all() 413 458 414 self.following[ stream] = details459 self.following[conn] = details 415 460 416 461 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))) 419 464 420 465 def __on_kill(self, action): … … 423 468 424 469 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) 429 474 430 475 def __on_clear(self, action): 431 self.stream_dict.clear()432 476 self.store.clear() 477 self.last_conn = None 433 478 434 479 def __on_button_pressed(self, widget, evt): … … 440 485 441 486 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)): 445 490 self.menu.show() 446 491 self.menu.popup(None, None, None, evt.button, evt.time, None) … … 450 495 451 496 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) 454 503 455 504 start, end = self.get_extern_iter(), self.get_extern_iter(False) 456 505 457 if not start: 458 return True 459 460 while start != end: 506 while start and start != end: 461 507 try: 462 stream= self.store.get_value(start, COLUMN_OBJECT)508 conn = self.store.get_value(start, COLUMN_OBJECT) 463 509 except Exception, err: 464 return True465 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]) 469 515 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) 479 519 480 520 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 481 535 else: 482 536 page = self.notebook.get_nth_page(page) … … 485 539 return True 486 540 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() 496 542 497 543 return True … … 500 546 idx = model.get_value(iter, COLUMN_STATUS) 501 547 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) 505 557 506 558 def __on_response(self, dialog, rid): … … 513 565 class Injector(Plugin, ActiveAudit): 514 566 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 526 567 self.item = self.add_menu_entry('Injector', _('Active connections'), 527 568 _('View active connections or inject ' 528 569 'data in active one'), 529 570 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 535 572 536 573 def stop(self): … … 539 576 540 577 def execute_audit(self, sess, inp_dict): 541 self.window.session = sess 578 if self.window is None: 579 self.window = ConnectionsWindow(sess) 542 580 543 581 if not self.window.flags() & gtk.VISIBLE: 544 582 self.window.show() 545 583 self.window.start_update() 546 547 def __tcp_callback(self, stream, mpkt):548 # DEBUG: remove me549 #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_MODIFIED573 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_MODIFIED584 585 return INJ_COLLECT_DATA586 587 return INJ_COLLECT_STATS588 584 589 585 __plugins__ = [Injector]
