def test_render_with_unicode_control_chars(self): _id = 2 desc = ('This is a long description that contains some special' ' unicode control characters such as \f and \x09') vuln = MockVuln(_id=_id) vuln.set_desc(desc) url = URL('http://w3af.com/a/b/c.php') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() x = xml_file() finding = Finding(x._get_jinja2_env(), vuln) xml = finding.to_string() self.assertNotIn('unicode control characters such as \f and \x09', xml) self.assertIn('unicode control characters such as <character code="000c"/> and <character code="0009"/>', xml) self.assertValidXML(xml)
def get_traffic_details(scan_id, traffic_id): """ The HTTP request and response associated with a vulnerability, usually the user will first get /scans/1/kb/3 and from there (if needed) browse to this resource where the HTTP traffic is available :param scan_id: The scan ID :param traffic_id: The ID of the request/response :return: HTTP request and response in base64 format """ scan_info = get_scan_info_from_id(scan_id) if scan_info is None: abort(404, 'Scan not found') history_db = HistoryItem() try: details = history_db.read(traffic_id) except DBException: msg = 'Failed to retrieve request with id %s from DB.' abort(404, msg) return data = {'request': b64encode(details.request.dump()), 'response': b64encode(details.response.dump())} return jsonify(data)
def toggle_bookmark(self, cell, path, model): """Toggle bookmark.""" model[path][1] = not model[path][1] historyItem = HistoryItem() historyItem.load(model[path][0]) historyItem.toggle_mark(True) return
def edit_tag(self, cell, path, new_text, model): """Edit tag.""" model[path][4] = new_text historyItem = HistoryItem() historyItem.load(model[path][0]) historyItem.update_tag(new_text, True) return
def __init__(self, w3af, request_id, enableWidget=None, withManual=True, withFuzzy=True, withCompare=True, withAudit=True, editableRequest=False, editableResponse=False, widgname="default"): # Create the window RememberingWindow.__init__(self, w3af, "reqResWin", _("w3af - HTTP Request/Response"), "Browsing_the_Knowledge_Base") # Create the request response viewer rrViewer = reqResViewer(w3af, enableWidget, withManual, withFuzzy, withCompare, withAudit, editableRequest, editableResponse, widgname) # Search the id in the DB historyItem = HistoryItem() historyItem.load(request_id) # Set rrViewer.request.show_object(historyItem.request) rrViewer.response.show_object(historyItem.response) rrViewer.show() self.vbox.pack_start(rrViewer) # Show the window self.show()
def _get_request_response_from_work_unit(self, work_unit): """ In some cases the work unit is a tuple with request / response instances. In other cases it is an ID, which needs to be queried from the History DB to get the request / response. :param work_unit: One of the options explained above :return: A request / response tuple """ if not isinstance(work_unit, int): request, response = work_unit else: # Before we sent requests and responses as work units, # but since we changed from Queue to CachedQueue for BaseConsumer # the database was growing really big (1GB) for storing that traffic # and I decided to migrate to using just the response.id and querying # the SQLite one extra time. history = HistoryItem() request, response = history.load_from_file(work_unit) # Create a fuzzable request based on the urllib2 request object headers_inst = Headers(request.header_items()) request = FuzzableRequest.from_parts(request.url_object, request.get_method(), request.get_data() or '', headers_inst) return request, response
def test_render_with_special_chars(self): _id = 2 desc = ('This is a long description that contains some special' ' characters such as <, & and > which MUST be encoded' ' by jinja2.') vuln = MockVuln(_id=_id) vuln.set_desc(desc) url = URL('http://w3af.com/a/b/c.php') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() x = xml_file() finding = Finding(x._get_jinja2_env(), vuln) xml = finding.to_string() self.assertNotIn('such as <, & and > which MUST', xml) self.assertIn('such as <, & and > which MUST', xml) self.assertValidXML(xml)
def setUp(self): super(TestHTMLRendering, self).setUp() self.plugin = self.w3afcore.plugins.get_plugin_inst('output', 'html_file') HistoryItem().init() url = URL('http://w3af.com/a/b/c.php') request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(1) h1.response = res h1.save() url = URL('http://w3af.com/foo.py') request = HTTPRequest(url, data='text=xss') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>empty</html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(4) h1.response = res h1.save()
def test_render_attr_with_special_chars(self): _id = 2 name = 'A long description with special characters: <&">' vuln = MockVuln(_id=_id) vuln.set_name(name) url = URL('http://w3af.com/a/b/c.php') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() x = xml_file() finding = Finding(x._get_jinja2_env(), vuln) xml = finding.to_string() self.assertNotIn(name, xml) self.assertIn('A long description with special characters: <&">', xml) self.assertValidXML(xml)
def test_history_access(self): self.count_plugin.loops = 1 self.w3afcore.start() history_item = HistoryItem() self.assertTrue(history_item.load(1)) self.assertEqual(history_item.id, 1) self.assertEqual(history_item.get_request().get_uri().url_string, get_moth_http()) self.assertEqual(history_item.get_response().get_uri().url_string, get_moth_http())
def response_dump(_id): """ :param _id: The ID to query in the database :return: The response as unicode """ _history = HistoryItem() try: details = _history.read(_id) except DBException: return None return smart_unicode(details.response.dump().strip())
def test_cache(self): url = URL('http://w3af.com/a/b/c.php') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) _id = 2 h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() x = xml_file() http_transaction = HTTPTransaction(x._get_jinja2_env(), _id) self.assertIsNone(http_transaction.get_node_from_cache()) # Writes to cache xml = http_transaction.to_string() expected = (u'<http-transaction id="2">\n\n' u' <http-request>\n' u' <status>POST http://w3af.com/a/b/c.php HTTP/1.1</status>\n' u' <headers>\n' u' <header field="User-agent" content="w3af" />\n' u' </headers>\n' u' <body content-encoding="base64">YT0x\n</body>\n' u' </http-request>\n\n' u' <http-response>\n' u' <status>HTTP/1.1 200 OK</status>\n' u' <headers>\n' u' <header field="Content-Type" content="text/html" />\n' u' </headers>\n' u' <body content-encoding="base64">PGh0bWw+\n</body>\n' u' </http-response>\n\n</http-transaction>') self.assertEqual(expected, xml) # Yup, we're cached self.assertIsNotNone(http_transaction.get_node_from_cache()) # Make sure they are all the same cached_xml = http_transaction.get_node_from_cache() self.assertEqual(cached_xml, expected) xml = http_transaction.to_string() self.assertEqual(expected, xml)
def test_render_simple(self): _id = 2 vuln = MockVuln(_id=_id) url = URL('http://w3af.com/a/b/c.php') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() x = xml_file() finding = Finding(x._get_jinja2_env(), vuln) xml = finding.to_string() expected = (u'<vulnerability id="[2]" method="GET" name="TestCase" plugin="plugin_name" severity="High" url="None" var="None">\n' u' <description>Foo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggs</description>\n\n\n' u' <http-transactions>\n' u' <http-transaction id="2">\n\n' u' <http-request>\n' u' <status>POST http://w3af.com/a/b/c.php HTTP/1.1</status>\n' u' <headers>\n' u' <header field="User-agent" content="w3af" />\n' u' </headers>\n' u' <body content-encoding="base64">YT0x\n</body>\n' u' </http-request>\n\n' u' <http-response>\n' u' <status>HTTP/1.1 200 OK</status>\n' u' <headers>\n' u' <header field="Content-Type" content="text/html" />\n' u' </headers>\n' u' <body content-encoding="base64">PGh0bWw+\n</body>\n' u' </http-response>\n\n' u'</http-transaction>\n' u' </http-transactions>\n' u'</vulnerability>') self.assertEqual(xml, expected) self.assertValidXML(xml)
def test_no_duplicate_vuln_reports(self): # The xml_file plugin had a bug where vulnerabilities were written to # disk multiple times, this test makes sure I fixed that vulnerability # Write the HTTP request / response to the DB url = URL('http://w3af.com/a/b/c.php') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>syntax error near', hdr, url, url) _id = 1 h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() # Create one vulnerability in the KB pointing to the request- # response we just created desc = 'Just a test for the XML file output plugin.' v = Vuln('SQL injection', desc, severity.HIGH, _id, 'sqli') kb.kb.append('sqli', 'sqli', v) self.assertEqual(len(kb.kb.get_all_vulns()), 1) # Setup the plugin plugin_instance = xml_file() # Set the output file for the unittest ol = OptionList() d = 'Output file name where to write the XML data' o = opt_factory('output_file', self.FILENAME, d, OUTPUT_FILE) ol.add(o) # Then we flush() twice to disk, this reproduced the issue plugin_instance.set_options(ol) plugin_instance.flush() plugin_instance.flush() plugin_instance.flush() # Now we parse the vulnerabilities from disk and confirm only one # is there file_vulns = get_vulns_from_xml(self.FILENAME) self.assertEqual(len(file_vulns), 1, file_vulns)
def __init__(self, w3af, kbbrowser, ifilter): super(FullKBTree, self).__init__(w3af, ifilter, 'Knowledge Base', strict=False) self._historyItem = HistoryItem() self.kbbrowser = kbbrowser self.connect('cursor-changed', self._showDesc) self.show()
def test_clear(self): url = URL('http://w3af.com/a/b/c.php') request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(1) h1.response = res h1.save() table_name = h1.get_table_name() db = get_default_temp_db_instance() self.assertTrue(db.table_exists(table_name)) clear_result = h1.clear() self.assertTrue(clear_result) self.assertFalse(os.path.exists(h1._session_dir), '%s exists.' % h1._session_dir) # Changed the meaning of clear a little bit... now it simply removes # all rows from the table, not the table itself self.assertTrue(db.table_exists(table_name))
def test_tag(self): tag_id = random.randint(501, 999) tag_value = rand_alnum(10) url = URL('http://w3af.org/a/b/c.php') for i in xrange(501, 1000): request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(i) h1.response = res if i == tag_id: h1.update_tag(tag_value) h1.save() h2 = HistoryItem() h2.load(tag_id) self.assertEqual(h2.tag, tag_value)
def __init__(self, w3af): super(KBBrowser, self).__init__(w3af, "pane-kbbrowser", 250) # Internal variables: # Save the request and response ids to be used in the page control self.req_res_ids = [] # This is to search the DB and print the different request and responses # as they are requested from the page control, "page_change" method. self._historyItem = HistoryItem() # the filter to the tree filterbox = gtk.HBox() self.filters = {} def make_but(label, signal, initial): but = gtk.CheckButton(label) but.set_active(initial) but.connect('clicked', self.type_filter, signal) self.filters[signal] = initial but.show() filterbox.pack_start(but, expand=False, fill=False, padding=2) make_but('Vulnerability', 'vuln', True) make_but('Information', 'info', True) filterbox.show() # the kb tree self.kbtree = FullKBTree(w3af, self, self.filters) # all in the first pane kbtree_scrollwin = gtk.ScrolledWindow() kbtree_scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) kbtree_scrollwin.add(self.kbtree) kbtree_scrollwin.show() # the filter and tree box treebox = gtk.VBox() treebox.pack_start(filterbox, expand=False, fill=False) treebox.pack_start(kbtree_scrollwin) treebox.show() # the vulnerability information summary = self.get_notebook_summary(w3af) description = self.get_notebook_description() self.vuln_notebook = gtk.Notebook() self.vuln_notebook.append_page(summary, gtk.Label('Summary')) self.vuln_notebook.append_page(description, gtk.Label('Description')) self.vuln_notebook.set_current_page(0) self.vuln_notebook.show() # pack & show self.pack1(treebox) self.pack2(self.vuln_notebook) self.show()
def store_in_cache(request, response): # Create the http response object resp = HTTPResponse.from_httplib_resp(response, original_url=request.url_object) resp.set_id(response.id) resp.set_alias(gen_hash(request)) hi = HistoryItem() hi.request = request hi.response = resp # Now save them try: hi.save() except sqlite3.Error, e: msg = 'A sqlite3 error was raised: "%s".' % e if 'disk' in str(e).lower(): msg += ' Please check if your disk is full.' raise ScanMustStopException(msg)
def test_render_simple(self): url = URL('http://w3af.com/a/b/c.php') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) _id = 1 h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() x = xml_file() http_transaction = HTTPTransaction(x._get_jinja2_env(), _id) xml = http_transaction.to_string() expected = (u'<http-transaction id="1">\n\n' u' <http-request>\n' u' <status>POST http://w3af.com/a/b/c.php HTTP/1.1</status>\n' u' <headers>\n' u' <header field="User-agent" content="w3af" />\n' u' </headers>\n' u' <body content-encoding="base64">YT0x\n</body>\n' u' </http-request>\n\n' u' <http-response>\n' u' <status>HTTP/1.1 200 OK</status>\n' u' <headers>\n' u' <header field="Content-Type" content="text/html" />\n' u' </headers>\n' u' <body content-encoding="base64">PGh0bWw+\n</body>\n' u' </http-response>\n\n</http-transaction>') self.assertEqual(expected, xml) self.assertValidXML(xml)
def test_save_load(self): i = random.randint(1, 499) url = URL('http://w3af.com/a/b/c.php') request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(i) h1.response = res h1.save() h2 = HistoryItem() h2.load(i) self.assertEqual(h1.request, h2.request) self.assertEqual(h1.response.body, h2.response.body)
def _impact_done(self, event, impact): # Keep calling this from timeout_add until isSet if not event.isSet(): return True # We stop the throbber, and hide it self.throbber.hide() self.throbber.running(False) # Analyze the impact if impact.ok: # Lets check if we found any vulnerabilities # # TODO: I should actually show ALL THE REQUESTS generated by audit plugins... # not just the ones with vulnerabilities. # for result in impact.result: # TODO: I'm not sure when this is None bug it appeared in Trac bug #167736 if result.get_id() is not None: for itemId in result.get_id(): historyItem = HistoryItem() historyItem.load(itemId) historyItem.update_tag(historyItem.tag + result.plugin_name) historyItem.info = result.get_desc() historyItem.save() else: if impact.exception.__class__ == BaseFrameworkException: msg = str(impact.exception) elif impact.exception.__class__ == ScanMustStopException: msg = "Stopped sending requests because " + \ str(impact.exception) elif impact.exception.__class__ == ScanMustStopOnUrlError: msg = "Not sending requests because " + str(impact.exception) else: raise impact.exception # We stop the throbber, and hide it self.throbber.hide() self.throbber.running(False) gtk.gdk.threads_enter() helpers.FriendlyExceptionDlg(msg) gtk.gdk.threads_leave() return False
def test_delete(self): i = random.randint(1, 499) url = URL('http://w3af.com/a/b/c.php') request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) res.set_id(i) h1 = HistoryItem() h1.request = request h1.response = res h1.save() fname = h1._get_trace_filename_for_id(i) self.assertTrue(os.path.exists(fname)) h1.delete(i) self.assertRaises(DBException, h1.read, i) self.assertFalse(os.path.exists(fname))
def _impact_done(self, event, impact): # Keep calling this from timeout_add until isSet if not event.isSet(): return True # We stop the throbber, and hide it self.throbber.hide() self.throbber.running(False) # Analyze the impact if impact.ok: # Lets check if we found any vulnerabilities # # TODO: I should actually show ALL THE REQUESTS generated by # audit plugins... not just the ones with vulnerabilities. # for result in impact.result: if result.get_id() is None: continue for itemId in result.get_id(): history_item = HistoryItem() history_item.load(itemId) history_item.update_tag(history_item.tag + result.plugin_name) history_item.info = result.get_desc() history_item.save() else: if isinstance(impact.exception, HTTPRequestException): msg = 'Exception found while sending HTTP request. Original' \ ' exception is: "%s"' % impact.exception elif isinstance(impact.exception, ScanMustStopException): msg = 'Multiple exceptions found while sending HTTP requests.' \ ' Exception: "%s"' % impact.exception elif isinstance(impact.exception, BaseFrameworkException): msg = str(impact.exception) else: raise impact.exception # We stop the throbber, and hide it self.throbber.hide() self.throbber.running(False) gtk.gdk.threads_enter() helpers.FriendlyExceptionDlg(msg) gtk.gdk.threads_leave() return False
def __init__(self, w3af, kbbrowser, ifilter): """A tree showing all the info. This also gives a long description of the element when clicked. :param kbbrowser: The KB Browser :param filter: The filter to show which elements :author: Facundo Batista <facundobatista =at= taniquetil.com.ar> """ super(FullKBTree, self).__init__(w3af, ifilter, 'Knowledge Base', strict=False) self._historyItem = HistoryItem() self.kbbrowser = kbbrowser self.connect('cursor-changed', self._showDesc) self.show()
def test_clear_clear(self): url = URL('http://w3af.com/a/b/c.php') request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(1) h1.response = res h1.save() h1.clear() h1.clear()
def test_render_url_special_chars(self): self.maxDiff = None _id = 2 vuln = MockVuln(_id=_id) url = URL( u'https://w3af.com/._basebind/node_modules/lodash._basecreate/' u'LICENSE.txt\x00=ڞ') hdr = Headers([('User-Agent', 'w3af')]) request = HTTPRequest(url, data='a=1') request.set_headers(hdr) vuln.set_uri(url) hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(_id) h1.response = res h1.save() x = xml_file() finding = Finding(x._get_jinja2_env(), vuln) xml = finding.to_string() expected = ( u'<vulnerability id="[2]" method="GET" name="TestCase" plugin="plugin_name" severity="High" url="https://w3af.com/._basebind/node_modules/lodash._basecreate/LICENSE.txt<character code="0000"/>=\u069e" var="None">\n' u' <description>Foo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggsFoo bar spam eggs</description>\n\n\n' u' <http-transactions>\n' u' <http-transaction id="2">\n\n' u' <http-request>\n' u' <status>POST https://w3af.com/._basebind/node_modules/lodash._basecreate/LICENSE.txt%00=%DA%9E HTTP/1.1</status>\n' u' <headers>\n' u' <header field="User-agent" content="w3af" />\n' u' </headers>\n' u' <body content-encoding="base64">YT0x\n</body>\n' u' </http-request>\n\n' u' <http-response>\n' u' <status>HTTP/1.1 200 OK</status>\n' u' <headers>\n' u' <header field="Content-Type" content="text/html" />\n' u' </headers>\n' u' <body content-encoding="base64">PGh0bWw+\n</body>\n' u' </http-response>\n\n' u'</http-transaction>\n' u' </http-transactions>\n' u'</vulnerability>') self.assertEqual(xml, expected) self.assertValidXML(xml)
def test_save_load_unicode_decode_error(self): url = URL('http://w3af.com/a/b/é.php?x=á') request = HTTPRequest(url, data='a=1') headers = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', headers, url, url) res.set_id(1) h1 = HistoryItem() h1.request = request h1.response = res h1.save() h2 = HistoryItem() h2.load(1) self.assertEqual(h1.request, h2.request) self.assertEqual(h1.response.body, h2.response.body) self.assertEqual(h1.request.url_object, h2.request.url_object)
def __init__(self): OutputPlugin.__init__(self) # These attributes hold the file pointers self._file = None # User configured parameters self._file_name = '/tmp/f5_asm_import.xml' self._timeFormat = '%a %b %d %H:%M:%S %Y' self._longTimestampString = str( time.strftime(self._timeFormat, time.localtime())) self._timestampString = str(int(time.time())) # List with additional xml elements # xml # HistoryItem to get requests/responses self._history = HistoryItem() self._attack_type = {} # attack type matrix self._attack_type["US Social Security"] = "Information Leakage - SSN" self._attack_type["XPATH"] = "XPath Injection" self._attack_type["Response splitting"] = "HTTP Response Splitting" self._attack_type["path disclosure"] = "Path Traversal" self._attack_type[ "Cross Site Request Forgery"] = "Cross-site Request Forgery" self._attack_type["SQL injection"] = "SQL-Injection" self._attack_type[ "credit card number"] = "Information Leakage - Credit Card" self._attack_type[ "Cross Site Scripting"] = "Cross Site Scripting (XSS)" self._attack_type["OS Commanding"] = "Command Execution" self._attack_type["SSI"] = "Server Side Code Injection" self._attack_type["input injection"] = "Injection Attempt" self._attack_type["LDAP injection"] = "LDAP Injection" self._attack_type["remote file inclusion"] = "Remote File Include" self._attack_type["file upload"] = "Malicious File Upload" self._attack_type["authentication cred"] = "Brute Force Attack" self._attack_type[ "requires authentication"] = "Authentication/Authorization Attacks" self._attack_type["buffer-overflow"] = "Buffer Overflow" # start xml file self._asmfile = xml.dom.minidom.Document() self._topElement = self._asmfile.createElement( "scanner_vulnerabilities") self._topElement.setAttribute("version", self._timestampString)
def _impact_done(self, event, impact): # Keep calling this from timeout_add until isSet if not event.isSet(): return True # We stop the throbber, and hide it self.throbber.hide() self.throbber.running(False) # Analyze the impact if impact.ok: # Lets check if we found any vulnerabilities # # TODO: I should actually show ALL THE REQUESTS generated by audit plugins... # not just the ones with vulnerabilities. # for result in impact.result: # TODO: I'm not sure when this is None bug it appeared in Trac bug #167736 if result.get_id() is not None: for itemId in result.get_id(): historyItem = HistoryItem() historyItem.load(itemId) historyItem.update_tag( historyItem.tag + result.plugin_name) historyItem.info = result.get_desc() historyItem.save() else: if impact.exception.__class__ == BaseFrameworkException: msg = str(impact.exception) elif impact.exception.__class__ == ScanMustStopException: msg = "Stopped sending requests because " + \ str(impact.exception) elif impact.exception.__class__ == ScanMustStopOnUrlError: msg = "Not sending requests because " + str(impact.exception) else: raise impact.exception # We stop the throbber, and hide it self.throbber.hide() self.throbber.running(False) gtk.gdk.threads_enter() helpers.FriendlyExceptionDlg(msg) gtk.gdk.threads_leave() return False
def test_delete(self): i = random.randint(1, 499) url = URL('http://w3af.com/a/b/c.php') request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) res.set_id(i) h1 = HistoryItem() h1.request = request h1.response = res h1.save() fname = h1._get_fname_for_id(i) self.assertTrue(os.path.exists(fname)) h1.delete(i) self.assertRaises(DBException, h1.read, i) self.assertFalse(os.path.exists(fname))
def __init__(self, w3af, padding=10, time_refresh=False): """Init object.""" super(httpLogTab, self).__init__(w3af, "pane-httplogtab", 300) self.w3af = w3af self._padding = padding self._lastId = 0 self._historyItem = HistoryItem() if time_refresh: gobject.timeout_add(1000, self.refresh_results) # Create the main container mainvbox = gtk.VBox() mainvbox.set_spacing(self._padding) # Add the menuHbox, Req/Res viewer and the R/R selector on the bottom self._initSearchBox(mainvbox) self._initFilterBox(mainvbox) self._initReqResViewer(mainvbox) mainvbox.show() # Add everything self.add(mainvbox) self.show()
def test_load_not_exists(self): h = HistoryItem() self.assertRaises(DBException, h.load, 1)
def _get_hist_obj(self): hist_obj = self._hist_obj if hist_obj is None: historyobjs = HistoryItem().find([('alias', self._hash_id, "=")]) self._hist_obj = hist_obj = historyobjs[0] if historyobjs else None return hist_obj
def test_single_db(self): h1 = HistoryItem() h2 = HistoryItem() self.assertEqual(h1._db, h2._db)
def setUp(self): kb.kb.cleanup() create_temp_dir() HistoryItem().init()
def test_init_init(self): # No exceptions should be raised HistoryItem().init() HistoryItem().init()
def test_save_load_compressed(self): force_compression_count = HistoryItem._UNCOMPRESSED_FILES + HistoryItem._COMPRESSED_FILE_BATCH force_compression_count += 150 url = URL('http://w3af.com/a/b/c.php') headers = Headers([('Content-Type', 'text/html')]) body = '<html>' + LOREM * 20 for i in xrange(1, force_compression_count): request = HTTPRequest(url, data='a=%s' % i) response = HTTPResponse(200, body, headers, url, url) response.set_id(i) h = HistoryItem() h.request = request h.response = response h.save() compressed_file = os.path.join(h.get_session_dir(), '1-150.zip') self.assertTrue(os.path.exists(compressed_file)) expected_files = [ '%s.trace' % i for i in range(1, HistoryItem._COMPRESSED_FILE_BATCH + 1) ] _zip = zipfile.ZipFile(compressed_file, mode='r') self.assertEqual(_zip.namelist(), expected_files) for i in xrange(1, 100): h = HistoryItem() h.load(i) self.assertEqual(h.request.get_uri(), url) self.assertEqual(h.response.get_headers(), headers) self.assertEqual(h.response.get_body(), body)
def init(): create_temp_dir() HistoryItem().init()
class FuzzyRequests(entries.RememberingWindow): """Infrastructure to generate fuzzy HTTP requests. :author: Facundo Batista <facundobatista =at= taniquetil.com.ar> """ def __init__(self, w3af, initial_request=None): super(FuzzyRequests, self).__init__(w3af, "fuzzyreq", "w3af - Fuzzy Requests", "Fuzzy_Requests") self.w3af = w3af self.historyItem = HistoryItem() mainhbox = gtk.HBox() # To store the responses self.responses = [] # ---- left pane ---- vbox = gtk.VBox() mainhbox.pack_start(vbox, False, False) # we create the buttons first, to pass them analyzBut = gtk.Button("Analyze") self.sendPlayBut = entries.SemiStockButton( "", gtk.STOCK_MEDIA_PLAY, "Sends the pending requests") self.sendStopBut = entries.SemiStockButton( "", gtk.STOCK_MEDIA_STOP, "Stops the request being sent") self.sSB_state = helpers.PropagateBuffer( self.sendStopBut.set_sensitive) self.sSB_state.change(self, False) # Fix content length checkbox self._fix_content_lengthCB = gtk.CheckButton('Fix content length header') self._fix_content_lengthCB.set_active(True) self._fix_content_lengthCB.show() # request self.originalReq = RequestPart(self, w3af, [analyzBut.set_sensitive, self.sendPlayBut.set_sensitive, functools.partial(self.sSB_state.change, "rRV")], editable=True, widgname="fuzzyrequest") if initial_request is None: self.originalReq.show_raw(FUZZY_REQUEST_EXAMPLE, '') else: (initialUp, initialDn) = initial_request self.originalReq.show_raw(initialUp, initialDn) # Add the right button popup menu to the text widgets rawTextView = self.originalReq.get_view_by_id('HttpRawView') rawTextView.textView.connect("populate-popup", self._populate_popup) # help helplabel = gtk.Label() helplabel.set_selectable(True) helplabel.set_markup(FUZZYHELP) self.originalReq.append_page(helplabel, gtk.Label("Syntax help")) helplabel.show() self.originalReq.show() vbox.pack_start(self.originalReq, True, True, padding=5) vbox.show() # the commands t = gtk.Table(2, 4) analyzBut.connect("clicked", self._analyze) t.attach(analyzBut, 0, 2, 0, 1) self.analyzefb = gtk.Label("0 requests") self.analyzefb.set_sensitive(False) t.attach(self.analyzefb, 2, 3, 0, 1) self.preview = gtk.CheckButton("Preview") t.attach(self.preview, 3, 4, 0, 1) self.sPB_signal = self.sendPlayBut.connect("clicked", self._send_start) t.attach(self.sendPlayBut, 0, 1, 1, 2) self.sendStopBut.connect("clicked", self._send_stop) t.attach(self.sendStopBut, 1, 2, 1, 2) self.sendfb = gtk.Label("0 ok, 0 errors") self.sendfb.set_sensitive(False) t.attach(self.sendfb, 2, 3, 1, 2) t.attach(self._fix_content_lengthCB, 3, 4, 1, 2) t.show_all() vbox.pack_start(t, False, False, padding=5) # ---- throbber pane ---- vbox = gtk.VBox() self.throbber = helpers.Throbber() self.throbber.set_sensitive(False) vbox.pack_start(self.throbber, False, False) vbox.show() mainhbox.pack_start(vbox, False, False) # ---- right pane ---- vbox = gtk.VBox() mainhbox.pack_start(vbox) # A label to show the id of the response self.title0 = gtk.Label() self.title0.show() vbox.pack_start(self.title0, False, True) # result itself self.resultReqResp = ReqResViewer(w3af, withFuzzy=False, editableRequest=False, editableResponse=False) self.resultReqResp.set_sensitive(False) vbox.pack_start(self.resultReqResp, True, True, padding=5) vbox.show() # result control centerbox = gtk.HBox() self.pagesControl = entries.PagesControl(w3af, self._pageChange) centerbox.pack_start(self.pagesControl, True, False) centerbox.show() # cluster responses button image = gtk.Image() image.set_from_file(os.path.join(ROOT_PATH, 'core', 'ui', 'gui', 'data', 'cluster_data.png')) image.show() self.clusterButton = gtk.Button(label='Cluster responses') self.clusterButton.connect("clicked", self._clusterData) self.clusterButton.set_sensitive(False) self.clusterButton.set_image(image) self.clusterButton.show() centerbox.pack_start(self.clusterButton, True, False) # clear responses button self.clearButton = entries.SemiStockButton( 'Clear Responses', gtk.STOCK_CLEAR, tooltip='Clear all HTTP responses from fuzzer window') self.clearButton.connect("clicked", self._clearResponses) self.clearButton.set_sensitive(False) self.clearButton.show() centerbox.pack_start(self.clearButton, True, False) vbox.pack_start(centerbox, False, False, padding=5) # Show all! self._sendPaused = True self.vbox.pack_start(mainhbox) self.vbox.show() mainhbox.show() self.show() def _populate_popup(self, textview, menu): """Populates the menu with the fuzzing items.""" menu.append(gtk.SeparatorMenuItem()) main_generator_menu = gtk.MenuItem(_("Generators")) main_generator_menu.set_submenu(create_generator_menu(self)) menu.append(main_generator_menu) menu.show_all() def _clearResponses(self, widg): """Clears all the responses from the fuzzy window.""" self.responses = [] self.resultReqResp.request.clear_panes() self.resultReqResp.response.clear_panes() self.resultReqResp.set_sensitive(False) self.clusterButton.set_sensitive(False) self.clearButton.set_sensitive(False) self.pagesControl.deactivate() def _clusterData(self, widg): """Analyze if we can cluster the responses and do it.""" data = [] for resp in self.responses: if resp[0]: reqid = resp[1] historyItem = self.historyItem.read(reqid) data.append(historyItem.response) if data: distance_function_selector(self.w3af, data) else: # Let the user know ahout the problem msg = "There are no HTTP responses available to cluster." dlg = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, msg) opt = dlg.run() dlg.destroy() def _analyze(self, widg): """Handles the Analyze part.""" (request, postbody) = self.originalReq.get_both_texts_raw() try: fg = helpers.coreWrap(fuzzygen.FuzzyGenerator, request, postbody) except fuzzygen.FuzzyError: return self.analyzefb.set_text("%d requests" % fg.calculate_quantity()) self.analyzefb.set_sensitive(True) # raise the window only if preview is active if self.preview.get_active(): PreviewWindow(self.w3af, self, fg) def _send_stop(self, widg=None): """Stop the requests being sent.""" self._sendStopped = True self.sendPlayBut.change_internals( "", gtk.STOCK_MEDIA_PLAY, "Sends the pending requests") self.sendPlayBut.disconnect(self.sPB_signal) self.sPB_signal = self.sendPlayBut.connect("clicked", self._send_start) self.sSB_state.change(self, False) self.throbber.running(False) def _send_pause(self, widg): """Pause the requests being sent.""" self._sendPaused = True self.sendPlayBut.change_internals("", gtk.STOCK_MEDIA_PLAY, "Sends the pending requests") self.sendPlayBut.disconnect(self.sPB_signal) self.sPB_signal = self.sendPlayBut.connect("clicked", self._send_play) self.throbber.running(False) def _send_play(self, widg): """Continue sending the requests.""" self._sendPaused = False self.sendPlayBut.change_internals("", gtk.STOCK_MEDIA_PAUSE, "Sends the pending requests") self.sendPlayBut.disconnect(self.sPB_signal) self.sPB_signal = self.sendPlayBut.connect("clicked", self._send_pause) self.throbber.running(True) def _send_start(self, widg): """Start sending the requests.""" (request, postbody) = self.originalReq.get_both_texts_raw() try: fg = helpers.coreWrap(fuzzygen.FuzzyGenerator, request, postbody) except fuzzygen.FuzzyError: return quant = fg.calculate_quantity() if quant > 20: msg = "Are you sure you want to send %d requests?" % quant dlg = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO, msg) opt = dlg.run() dlg.destroy() if opt != gtk.RESPONSE_YES: return # Get the fix content length value fixContentLength = self._fix_content_lengthCB.get_active() # initial state self.result_ok = 0 self.result_err = 0 self._sendPaused = False self._sendStopped = False requestGenerator = fg.generate() # change the buttons self.sendPlayBut.change_internals("", gtk.STOCK_MEDIA_PAUSE, "Pauses the requests sending") self.sendPlayBut.disconnect(self.sPB_signal) self.sPB_signal = self.sendPlayBut.connect("clicked", self._send_pause) self.sSB_state.change(self, True) self.throbber.running(True) # let's send the requests! gobject.timeout_add(100, self._real_send, fixContentLength, requestGenerator) def _real_send(self, fixContentLength, requestGenerator): """This is the one that actually sends the requests, if corresponds. :param fixContentLength: if the lenght should be fixed by the core. :param requestGenerator: where to ask for the requests """ if self._sendStopped: return False if self._sendPaused: return True try: realreq, realbody = requestGenerator.next() except StopIteration: # finished with all the requests! self._send_stop() return False try: http_resp = self.w3af.uri_opener.send_raw_request(realreq, realbody, fixContentLength) error_msg = None self.result_ok += 1 except HTTPRequestException, e: # One HTTP request failed error_msg = str(e) http_resp = None self.result_err += 1 except ScanMustStopException, e: # Many HTTP requests failed and the URL library wants to stop error_msg = str(e) self.result_err += 1 # Let the user know about the problem msg = "Stopped sending requests because of the following"\ " unexpected error:\n\n%s" helpers.FriendlyExceptionDlg(msg % error_msg) return False
def clear(): """ Clear the cache (remove all files and directories associated with it). """ return HistoryItem().clear()
def _write_findings_to_xml(self): """ Write all the findings to the XML file :return: None, we write the data to the XML """ # HistoryItem to get requests/responses req_history = HistoryItem() for i in kb.kb.get_all_findings(): message_node = self._xml.createElement('vulnerability') message_node.setAttribute('severity', xml_str(i.get_severity())) message_node.setAttribute('method', xml_str(i.get_method())) message_node.setAttribute('url', xml_str(i.get_url())) message_node.setAttribute('var', xml_str(i.get_token_name())) message_node.setAttribute('name', xml_str(i.get_name())) message_node.setAttribute('plugin', xml_str(i.get_plugin_name())) # Wrap description in a <description> element and put it above the # request/response elements desc_str = xml_str(i.get_desc(with_id=False)) description_node = self._xml.createElement('description') description = self._xml.createTextNode(desc_str) description_node.appendChild(description) message_node.appendChild(description_node) # If there is information from the vulndb, then we should write it if i.has_db_details(): desc_str = xml_str(i.get_long_description()) description_node = self._xml.createElement('long-description') description = self._xml.createTextNode(desc_str) description_node.appendChild(description) message_node.appendChild(description_node) fix_str = xml_str(i.get_fix_guidance()) fix_node = self._xml.createElement('fix-guidance') fix = self._xml.createTextNode(fix_str) fix_node.appendChild(fix) message_node.appendChild(fix_node) fix_effort_str = xml_str(i.get_fix_effort()) fix_node = self._xml.createElement('fix-effort') fix = self._xml.createTextNode(fix_effort_str) fix_node.appendChild(fix) message_node.appendChild(fix_node) if i.get_references(): references_node = self._xml.createElement('references') for ref in i.get_references(): ref_node = self._xml.createElement('reference') ref_node.setAttribute('title', xml_str(ref.title)) ref_node.setAttribute('url', xml_str(ref.url)) references_node.appendChild(ref_node) message_node.appendChild(references_node) if i.get_id(): message_node.setAttribute('id', str(i.get_id())) # Wrap all transactions in a http-transactions node transaction_set = self._xml.createElement('http-transactions') message_node.appendChild(transaction_set) for request_id in i.get_id(): try: details = req_history.read(request_id) except DBException: msg = 'Failed to retrieve request with id %s from DB.' print(msg % request_id) continue # Wrap the entire http transaction in a single block action_set = self._xml.createElement('http-transaction') action_set.setAttribute('id', str(request_id)) transaction_set.appendChild(action_set) request_node = self._xml.createElement('http-request') self.report_http_action(request_node, details.request) action_set.appendChild(request_node) response_node = self._xml.createElement('http-response') self.report_http_action(response_node, details.response) action_set.appendChild(response_node) self._top_elem.appendChild(message_node)
def test_find(self): find_id = random.randint(1, 499) url = URL('http://w3af.org/a/b/foobar.php?foo=123') tag_value = rand_alnum(10) for i in xrange(0, 500): request = HTTPRequest(url, data='a=1') code = 200 if i == find_id: code = 302 hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(code, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(i) h1.response = res if i == find_id: h1.toggle_mark() h1.update_tag(tag_value) h1.save() h2 = HistoryItem() self.assertEqual( len(h2.find([('tag', "%" + tag_value + "%", 'like')])), 1) self.assertEqual(len(h2.find([('code', 302, '=')])), 1) self.assertEqual(len(h2.find([('mark', 1, '=')])), 1) self.assertEqual(len(h2.find([('has_qs', 1, '=')])), 500) self.assertEqual(len(h2.find([('has_qs', 1, '=')], result_limit=10)), 10) results = h2.find([('has_qs', 1, '=')], result_limit=1, order_data=[('id', 'desc')]) self.assertEqual(results[0].id, 499) search_data = [('id', find_id + 1, "<"), ('id', find_id - 1, ">")] self.assertEqual(len(h2.find(search_data)), 1)
class httpLogTab(RememberingHPaned): """ A tab that shows all HTTP requests and responses made by the framework. :author: Andres Riancho ([email protected]) """ def __init__(self, w3af, padding=10, time_refresh=False): """Init object.""" super(httpLogTab, self).__init__(w3af, "pane-httplogtab", 300) self.w3af = w3af self._padding = padding self._lastId = 0 self._historyItem = HistoryItem() if time_refresh: gobject.timeout_add(1000, self.refresh_results) # Create the main container mainvbox = gtk.VBox() mainvbox.set_spacing(self._padding) # Add the menuHbox, Req/Res viewer and the R/R selector on the bottom self._initSearchBox(mainvbox) self._initFilterBox(mainvbox) self._initReqResViewer(mainvbox) mainvbox.show() # Add everything self.add(mainvbox) self.show() def _initReqResViewer(self, mainvbox): """Create the req/res viewer.""" self._req_res_viewer = ReqResViewer(self.w3af, editableRequest=False, editableResponse=False) self._req_res_viewer.set_sensitive(False) # Create the req/res selector (when a search with more # than one result is done, this window appears) self._sw = gtk.ScrolledWindow() self._sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self._lstore = gtk.ListStore(gobject.TYPE_UINT, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_UINT, gobject.TYPE_STRING, gobject.TYPE_UINT, gobject.TYPE_STRING, gobject.TYPE_FLOAT) # Create tree view self._lstoreTreeview = gtk.TreeView(self._lstore) self._lstoreTreeview.set_rules_hint(True) self._lstoreTreeview.set_search_column(0) self.__add_columns(self._lstoreTreeview) self._lstoreTreeview.show() self._lstoreTreeview.connect('cursor-changed', self._view_in_req_res_viewer) # Popup menu self._rightButtonMenu = None self._lstoreTreeview.connect('button-press-event', self._popupMenu) # # # Selection # treeselection = self._lstoreTreeview.get_selection() treeselection.set_mode(gtk.SELECTION_MULTIPLE) self._sw.add(self._lstoreTreeview) #self._sw.set_sensitive(False) self._sw.show_all() # I want all sections to be resizable self._vpan = RememberingVPaned(self.w3af, "pane-swandrRV", 100) self._vpan.pack1(self._sw) self._vpan.pack2(self._req_res_viewer) self._vpan.show() mainvbox.pack_start(self._vpan) def _popupMenu(self, tv, event): """Generate and show popup menu.""" if event.button != 3: return # creates the whole menu only once if self._rightButtonMenu is None: gm = gtk.Menu() self._rightButtonMenu = gm # the items e = gtk.MenuItem(_("Delete selected items")) e.connect('activate', self._deleteSelected) gm.append(e) gm.show_all() else: gm = self._rightButtonMenu gm.popup(None, None, None, event.button, event.time) return True def _deleteSelected(self, widg=None): """Delete selected transactions.""" ids = [] iters = [] sel = self._lstoreTreeview.get_selection() (model, pathlist) = sel.get_selected_rows() for path in pathlist: iters.append(self._lstore.get_iter(path)) itemNumber = path[0] iid = self._lstore[itemNumber][0] ids.append(iid) for i in iters: self._lstore.remove(i) # TODO Move this action to separate thread for iid in ids: self._historyItem.delete(iid) def _initSearchBox(self, mainvbox): """Init Search box.""" # The search entry self._searchText = gtk.Entry() self._searchText.connect("activate", self.find_request_response) # The button that is used to advanced search filterBtn = gtk.ToggleButton(label=_("_Filter Options")) filterBtn.connect("toggled", self._showHideFilterBox) filterImg = gtk.Image() filterImg.set_from_stock(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU) filterBtn.set_image(filterImg) # Clear button close = gtk.Image() close.set_from_stock(gtk.STOCK_CLEAR, gtk.ICON_SIZE_MENU) clearBox = gtk.EventBox() clearBox.add(close) clearBox.connect("button-release-event", self._showAllRequestResponses) # Create the container that has the menu menuHbox = gtk.HBox() menuHbox.set_spacing(self._padding) menuHbox.pack_start(gtk.Label(_("Search:")), False) menuHbox.pack_start(self._searchText) menuHbox.pack_start(clearBox, False) menuHbox.pack_start(filterBtn, False) menuHbox.show_all() mainvbox.pack_start(menuHbox, False, True) def _initFilterBox(self, mainvbox): """Init advanced search options.""" self._advSearchBox = gtk.HBox() self._advSearchBox.set_spacing(self._padding) self.pref = FilterOptions(self) # Filter options self._filterMethods = [ ('GET', 'GET', False), ('POST', 'POST', False), ] filterMethods = OptionList() for method in self._filterMethods: filterMethods.add( opt_factory(method[0], method[2], method[1], "boolean")) self.pref.add_section('methods', _('Request Method'), filterMethods) filterId = OptionList() filterId.add(opt_factory("min", "0", "Min ID", "string")) filterId.add(opt_factory("max", "0", "Max ID", "string")) self.pref.add_section('trans_id', _('Transaction ID'), filterId) filterCodes = OptionList() codes = [ ("1xx", "1xx", False), ("2xx", "2xx", False), ("3xx", "3xx", False), ("4xx", "4xx", False), ("5xx", "5xx", False), ] for code in codes: filterCodes.add(opt_factory(code[0], code[2], code[1], "boolean")) self.pref.add_section('codes', _('Response Code'), filterCodes) filterMisc = OptionList() filterMisc.add(opt_factory("tag", False, "Tag", "boolean")) filterMisc.add( opt_factory("has_qs", False, "Request has Query String", "boolean")) self.pref.add_section('misc', _('Misc'), filterMisc) filterTypes = OptionList() self._filterTypes = [ ('html', 'HTML', False), ('javascript', 'JavaScript', False), ('image', 'Images', False), ('flash', 'Flash', False), ('css', 'CSS', False), ('text', 'Text', False), ] for filterType in self._filterTypes: filterTypes.add( opt_factory(filterType[0], filterType[2], filterType[1], "boolean")) self.pref.add_section('types', _('Response Content Type'), filterTypes) filterSize = OptionList() filterSize.add(opt_factory("resp_size", False, "Not Null", "boolean")) self.pref.add_section('sizes', _('Response Size'), filterSize) self.pref.show() self._advSearchBox.pack_start(self.pref, False, False) self._advSearchBox.hide_all() mainvbox.pack_start(self._advSearchBox, False, False) def __add_columns(self, treeview): """Add columns to main log table.""" model = treeview.get_model() # Column for id's column = gtk.TreeViewColumn(_('ID'), gtk.CellRendererText(), text=0) column.set_sort_column_id(0) treeview.append_column(column) # Column for bookmark #TODO: Find a better way to do this. The "B" and the checkbox aren't nice #what we aim for is something like the stars in gmail. """ renderer = gtk.CellRendererToggle() renderer.set_property('activatable', True) renderer.connect('toggled', self.toggle_bookmark, model) column = gtk.TreeViewColumn(_('B'), renderer) column.add_attribute(renderer, "active", 1) column.set_sort_column_id(1) treeview.append_column(column) """ # Column for METHOD column = gtk.TreeViewColumn(_('Method'), gtk.CellRendererText(), text=2) column.set_sort_column_id(2) treeview.append_column(column) # Column for URI renderer = gtk.CellRendererText() renderer.set_property('ellipsize', pango.ELLIPSIZE_END) column = gtk.TreeViewColumn('URI', renderer, text=3) column.set_sort_column_id(3) column.set_expand(True) column.set_resizable(True) treeview.append_column(column) # Column for Tag renderer = gtk.CellRendererText() #renderer.set_property('ellipsize', pango.ELLIPSIZE_END) renderer.set_property('editable', True) renderer.connect('edited', self.edit_tag, model) column = gtk.TreeViewColumn(_('Tag'), renderer, text=4) column.set_sort_column_id(4) column.set_resizable(True) column.set_sizing(gtk.TREE_VIEW_COLUMN_GROW_ONLY) treeview.append_column(column) extColumns = [ (5, _('Code')), (6, _('Message')), (7, _('Content-Length')), (8, _('Content-Type')), (9, _('Time (ms)')), ] for n, title in extColumns: column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=n) column.set_sort_column_id(n) treeview.append_column(column) def toggle_bookmark(self, cell, path, model): """Toggle bookmark.""" model[path][1] = not model[path][1] historyItem = HistoryItem() historyItem.load(model[path][0]) historyItem.toggle_mark(True) return def edit_tag(self, cell, path, new_text, model): """Edit tag.""" model[path][4] = new_text historyItem = HistoryItem() historyItem.load(model[path][0]) historyItem.update_tag(new_text, True) return def _showHideFilterBox(self, widget): """Show/hide advanced options.""" if not widget.get_active(): self._advSearchBox.hide_all() else: self._advSearchBox.show_all() def _showAllRequestResponses(self, widget=None, event=None): """Show all results.""" self._searchText.set_text("") try: self.find_request_response() except BaseFrameworkException as w3: self._empty_results() return def refresh_results(self): """ TODO: IMPROVEMENT: The find_request_response will read all items from the DB again. If there are no new requests BUT we're already showing 1K of them, all will be read. Not good for performance. """ self.find_request_response(refresh=True) return True def find_request_response(self, widget=None, refresh=False): """Find entries (req/res).""" searchText = self._searchText.get_text() searchText = searchText.strip() search_data = [] # # Search part # if searchText: likePieces = [('url', "%" + searchText + "%", 'like'), ('tag', "%" + searchText + "%", 'like')] search_data.append((likePieces, 'OR')) # # Filter part # # Codes codes = self.pref.get_options('codes') filterCodes = [] for opt in codes: if opt.get_value(): codef = opt.get_name() filterCodes.append(('codef', int(codef[0]), '=')) search_data.append((filterCodes, 'OR')) # IDs try: minId = int(self.pref.get_value('trans_id', 'min')) except: minId = 0 try: maxId = int(self.pref.get_value('trans_id', 'max')) except: maxId = 0 if maxId > 0: search_data.append(('id', maxId, "<")) if minId > 0: search_data.append(('id', minId, ">")) if refresh: search_data.append(('id', self._lastId, ">")) # Sizes if self.pref.get_value('sizes', 'resp_size'): search_data.append(('response_size', 0, ">")) # Tags if self.pref.get_value('misc', 'tag'): search_data.append(('tag', '', "!=")) # has_query_string if self.pref.get_value('misc', 'has_qs'): search_data.append(('has_qs', 0, ">")) # Content type filterTypes = [] for filterType in self._filterTypes: if self.pref.get_value('types', filterType[0]): filterTypes.append( ('content_type', "%" + filterType[0] + "%", 'like')) search_data.append((filterTypes, 'OR')) # Method filterMethods = [] for method in self._filterMethods: if self.pref.get_value('methods', method[0]): filterTypes.append(('method', method[0], '=')) search_data.append((filterMethods, 'OR')) try: # Please see the 5000 below searchResultObjects = self._historyItem.find(search_data, result_limit=5001, order_data=[("id", "") ]) except BaseFrameworkException, w3: self._empty_results() return if len(searchResultObjects) == 0: if not refresh: self._empty_results() return # Please see the 5001 above elif len(searchResultObjects) > 5000: self._empty_results() msg = _('The search you performed returned too many results (') +\ str(len(searchResultObjects)) + ').\n' msg += _('Please refine your search and try again.') self._show_message('Too many results', msg) return else: # show the results in the list view (when first row is selected # that just triggers the req/resp filling. lastItem = searchResultObjects[-1] self._lastId = int(lastItem.id) self._show_list_view(searchResultObjects, appendMode=refresh) self._sw.set_sensitive(True) self._req_res_viewer.set_sensitive(True) if not refresh: self._lstoreTreeview.set_cursor((0, )) return
def test_mark(self): mark_id = 3 url = URL('http://w3af.org/a/b/c.php') for i in xrange(0, 500): request = HTTPRequest(url, data='a=1') hdr = Headers([('Content-Type', 'text/html')]) res = HTTPResponse(200, '<html>', hdr, url, url) h1 = HistoryItem() h1.request = request res.set_id(i) h1.response = res if i == mark_id: h1.toggle_mark() h1.save() h2 = HistoryItem() h2.load(mark_id) self.assertTrue(h2.mark) h3 = HistoryItem() h3.load(mark_id - 1) self.assertFalse(h3.mark)
class FullKBTree(KBTree): def __init__(self, w3af, kbbrowser, ifilter): """A tree showing all the info. This also gives a long description of the element when clicked. :param kbbrowser: The KB Browser :param filter: The filter to show which elements :author: Facundo Batista <facundobatista =at= taniquetil.com.ar> """ super(FullKBTree, self).__init__(w3af, ifilter, 'Knowledge Base', strict=False) self._historyItem = HistoryItem() self.kbbrowser = kbbrowser self.connect('cursor-changed', self._showDesc) self.show() def _showDesc(self, tv): """Shows the description at the right :param tv: the treeview. """ (path, column) = tv.get_cursor() if path is None: return instance = self.get_instance(path) if not isinstance(instance, Info): return longdesc = instance.get_desc() self.kbbrowser.explanation.set_text(longdesc) if not instance.get_id(): self.clear_request_response_viewer() return # # We have two different cases: # # 1) The object is related to ONLY ONE request / response # 2) The object is related to MORE THAN ONE request / response # # For 1), we show the classic view, and for 2) we show the classic # view with a "page control" # # Work: # if len(instance.get_id()) == 1: # There is ONLY ONE id related to the object # This is 1) self.kbbrowser.pagesControl.deactivate() self.kbbrowser._pageChange(0) self.kbbrowser.pagesControl.hide() self.kbbrowser.title0.hide() search_id = instance.get_id()[0] try: history_item = self._historyItem.read(search_id) except DBException: msg = _('The HTTP data with id %s is not inside the database.') self._show_message(_('Error'), msg % search_id) self.clear_request_response_viewer() return # Error handling for .trace file problems # https://github.com/andresriancho/w3af/issues/1174 try: # These lines will trigger the code that reads the .trace file # from disk and if they aren't there an exception will rise history_item.request history_item.response except IOError, ioe: self._show_message(_('Error'), str(ioe)) return # Now we know that these two lines will work and we won't trigger # https://github.com/andresriancho/w3af/issues/1174 self.kbbrowser.rrV.request.show_object(history_item.request) self.kbbrowser.rrV.response.show_object(history_item.response) # Don't forget to highlight if necessary severity = instance.get_severity() for s in instance.get_to_highlight(): self.kbbrowser.rrV.response.highlight(s, severity) else:
def __init__(self, w3af, initial_request=None): super(FuzzyRequests, self).__init__(w3af, "fuzzyreq", "w3af - Fuzzy Requests", "Fuzzy_Requests") self.w3af = w3af self.historyItem = HistoryItem() mainhbox = gtk.HBox() # To store the responses self.responses = [] # ---- left pane ---- vbox = gtk.VBox() mainhbox.pack_start(vbox, False, False) # we create the buttons first, to pass them analyzBut = gtk.Button("Analyze") self.sendPlayBut = entries.SemiStockButton( "", gtk.STOCK_MEDIA_PLAY, "Sends the pending requests") self.sendStopBut = entries.SemiStockButton( "", gtk.STOCK_MEDIA_STOP, "Stops the request being sent") self.sSB_state = helpers.PropagateBuffer( self.sendStopBut.set_sensitive) self.sSB_state.change(self, False) # Fix content length checkbox self._fix_content_lengthCB = gtk.CheckButton('Fix content length header') self._fix_content_lengthCB.set_active(True) self._fix_content_lengthCB.show() # request self.originalReq = RequestPart(self, w3af, [analyzBut.set_sensitive, self.sendPlayBut.set_sensitive, functools.partial(self.sSB_state.change, "rRV")], editable=True, widgname="fuzzyrequest") if initial_request is None: self.originalReq.show_raw(FUZZY_REQUEST_EXAMPLE, '') else: (initialUp, initialDn) = initial_request self.originalReq.show_raw(initialUp, initialDn) # Add the right button popup menu to the text widgets rawTextView = self.originalReq.get_view_by_id('HttpRawView') rawTextView.textView.connect("populate-popup", self._populate_popup) # help helplabel = gtk.Label() helplabel.set_selectable(True) helplabel.set_markup(FUZZYHELP) self.originalReq.append_page(helplabel, gtk.Label("Syntax help")) helplabel.show() self.originalReq.show() vbox.pack_start(self.originalReq, True, True, padding=5) vbox.show() # the commands t = gtk.Table(2, 4) analyzBut.connect("clicked", self._analyze) t.attach(analyzBut, 0, 2, 0, 1) self.analyzefb = gtk.Label("0 requests") self.analyzefb.set_sensitive(False) t.attach(self.analyzefb, 2, 3, 0, 1) self.preview = gtk.CheckButton("Preview") t.attach(self.preview, 3, 4, 0, 1) self.sPB_signal = self.sendPlayBut.connect("clicked", self._send_start) t.attach(self.sendPlayBut, 0, 1, 1, 2) self.sendStopBut.connect("clicked", self._send_stop) t.attach(self.sendStopBut, 1, 2, 1, 2) self.sendfb = gtk.Label("0 ok, 0 errors") self.sendfb.set_sensitive(False) t.attach(self.sendfb, 2, 3, 1, 2) t.attach(self._fix_content_lengthCB, 3, 4, 1, 2) t.show_all() vbox.pack_start(t, False, False, padding=5) # ---- throbber pane ---- vbox = gtk.VBox() self.throbber = helpers.Throbber() self.throbber.set_sensitive(False) vbox.pack_start(self.throbber, False, False) vbox.show() mainhbox.pack_start(vbox, False, False) # ---- right pane ---- vbox = gtk.VBox() mainhbox.pack_start(vbox) # A label to show the id of the response self.title0 = gtk.Label() self.title0.show() vbox.pack_start(self.title0, False, True) # result itself self.resultReqResp = ReqResViewer(w3af, withFuzzy=False, editableRequest=False, editableResponse=False) self.resultReqResp.set_sensitive(False) vbox.pack_start(self.resultReqResp, True, True, padding=5) vbox.show() # result control centerbox = gtk.HBox() self.pagesControl = entries.PagesControl(w3af, self._pageChange) centerbox.pack_start(self.pagesControl, True, False) centerbox.show() # cluster responses button image = gtk.Image() image.set_from_file(os.path.join(ROOT_PATH, 'core', 'ui', 'gui', 'data', 'cluster_data.png')) image.show() self.clusterButton = gtk.Button(label='Cluster responses') self.clusterButton.connect("clicked", self._clusterData) self.clusterButton.set_sensitive(False) self.clusterButton.set_image(image) self.clusterButton.show() centerbox.pack_start(self.clusterButton, True, False) # clear responses button self.clearButton = entries.SemiStockButton( 'Clear Responses', gtk.STOCK_CLEAR, tooltip='Clear all HTTP responses from fuzzer window') self.clearButton.connect("clicked", self._clearResponses) self.clearButton.set_sensitive(False) self.clearButton.show() centerbox.pack_start(self.clearButton, True, False) vbox.pack_start(centerbox, False, False, padding=5) # Show all! self._sendPaused = True self.vbox.pack_start(mainhbox) self.vbox.show() mainhbox.show() self.show()
def to_string(self): """ :return: An xml node (as a string) representing the HTTP request / response. <http-transaction id="..."> <http-request> <status></status> <headers> <header> <field></field> <content></content> </header> </headers> <body content-encoding="base64"></body> </http-request> <http-response> <status></status> <headers> <header> <field></field> <content></content> </header> </headers> <body content-encoding="base64"></body> </http-response> </http-transaction> One of the differences this class has with the previous implementation is that the body is always encoded, no matter the content-type. This helps prevent encoding issues. """ # Get the data from the cache node = self.get_node_from_cache() if node is not None: return node # HistoryItem to get requests/responses req_history = HistoryItem() # This might raise a DBException in some cases (which I still # need to identify and fix). When an exception is raised here # the caller needs to handle it by ignoring this part of the # HTTP transaction request, response = req_history.load_from_file(self._id) data = request.get_data() or '' b64_encoded_request_body = base64.encodestring(smart_str_ignore(data)) body = response.get_body() or '' b64_encoded_response_body = base64.encodestring(smart_str_ignore(body)) context = { 'id': self._id, 'request': { 'status': request.get_request_line().strip(), 'headers': request.get_headers(), 'body': b64_encoded_request_body }, 'response': { 'status': response.get_status_line().strip(), 'headers': response.get_headers(), 'body': b64_encoded_response_body } } context = dotdict(context) template = self.get_template(self.TEMPLATE) transaction = template.render(context) self.save_node_to_cache(transaction) return transaction