From 5355e9532f7c71ede7a5f5be6709f1b55b65e943 Mon Sep 17 00:00:00 2001 From: zinjacoder Date: Mon, 23 Sep 2024 17:05:18 +0530 Subject: [PATCH] 2024.10:Release --- ReportExplorer.py | 41 ++++++++++++++++-- modules/misc_functions/print_banner.py | 2 +- .../show_data/show_request_response.py | 19 ++++++--- modules/reporting/final_report.py | 2 +- .../reporting/write_single_fuzz_traffic.py | 42 ++++++++++++++++++- 5 files changed, 93 insertions(+), 13 deletions(-) diff --git a/ReportExplorer.py b/ReportExplorer.py index 894ffa9..387d6b3 100644 --- a/ReportExplorer.py +++ b/ReportExplorer.py @@ -104,13 +104,17 @@ def update_font_size(delta): response_text.configure(font=new_font) web_page_before_text.configure(font=new_font) web_page_after_text.configure(font=new_font) + request_text_base64.configure(font=new_font) + response_text_base64.configure(font=new_font) # Adjust Text widget height and width request_text.config(height=int(font_size * 1.5), width=int(font_size * 8)) response_text.config(height=int(font_size * 1.5), width=int(font_size * 8)) web_page_before_text.config(height=int(font_size * 1.5), width=int(font_size * 4)) web_page_after_text.config(height=int(font_size * 1.5), width=int(font_size * 4)) - + request_text_base64.config(height=int(font_size * 1.5), width=int(font_size * 8)) + response_text_base64.config(height=int(font_size * 1.5), width=int(font_size * 8)) + # Update font size for Treeview style.configure('Treeview', font=new_font) @@ -244,24 +248,53 @@ def update_font_size(delta): response_body_length_label = ttk.Label(web_page_after_tab, text="") response_body_length_label.pack() + # Create tab for Request/Response details base64 + request_response_tab_base64 = ttk.Frame(notebook) + notebook.add(request_response_tab_base64, text='Base64') + + # Create Panedwindow for Request/Response tabs base64 + request_response_paned_window_base64 = ttk.Panedwindow(request_response_tab_base64, orient=tk.HORIZONTAL) + request_response_paned_window_base64.pack(expand=True, fill='both') + + # Create frame for Request tab base64 + request_tab_base64 = ttk.Frame(request_response_paned_window_base64) + request_response_paned_window_base64.add(request_tab_base64, weight=1) + + # Create Text widget for displaying request details base64 + request_text_base64 = tk.Text(request_tab_base64, wrap='word', width=80, height=20) + request_text_base64.pack(fill='both', expand=True) + + # Create frame for Response tab base64 + response_tab_base64 = ttk.Frame(request_response_paned_window_base64) + request_response_paned_window_base64.add(response_tab_base64, weight=1) + + # Create Text widget for displaying response details base64 + response_text_base64 = tk.Text(response_tab_base64, wrap='word', width=80, height=20) + response_text_base64.pack(fill='both', expand=True) + # Bind keyboard events to notebook request_text.bind("", lambda event: ignore_keyboard(event, request_text, root, tk)) response_text.bind("", lambda event: ignore_keyboard(event, response_text, root, tk)) web_page_before_text.bind("", lambda event: ignore_keyboard(event, web_page_before_text, root, tk)) web_page_after_text.bind("", lambda event: ignore_keyboard(event, web_page_after_text, root, tk)) + response_text_base64.bind("", lambda event: ignore_keyboard(event, response_text_base64, root, tk)) + request_text_base64.bind("", lambda event: ignore_keyboard(event, request_text_base64, root, tk)) # Bind Right mouse click to copy selection request_text.bind("", lambda event: show_context_menu_notebook(event, request_text, root, tk)) response_text.bind("", lambda event: show_context_menu_notebook(event, response_text, root, tk)) web_page_before_text.bind("", lambda event: show_context_menu_notebook(event, web_page_before_text, root, tk)) web_page_after_text.bind("", lambda event: show_context_menu_notebook(event, web_page_after_text, root, tk)) + response_text_base64.bind("", lambda event: show_context_menu_notebook(event, response_text_base64, root, tk)) + request_text_base64.bind("", lambda event: show_context_menu_notebook(event, request_text_base64, root, tk)) + # Bind Treeview click event to show_request_response function - tree.bind('', lambda event: show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, messagebox)) + tree.bind('', lambda event: show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, request_text_base64, response_text_base64, messagebox)) # Bind Treeview up and down arrow keys to show_request_response function - tree.bind('', lambda event: show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, messagebox)) - tree.bind('', lambda event: show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, messagebox)) + tree.bind('', lambda event: show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, request_text_base64, response_text_base64, messagebox)) + tree.bind('', lambda event: show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, request_text_base64, response_text_base64, messagebox)) # Bind the right-click event to the show_request_response function tree.bind("", lambda event: show_context_menu(event, tree, tk, root)) diff --git a/modules/misc_functions/print_banner.py b/modules/misc_functions/print_banner.py index 54eda8f..39285f4 100644 --- a/modules/misc_functions/print_banner.py +++ b/modules/misc_functions/print_banner.py @@ -28,7 +28,7 @@ def print_banner(): {global_variable.GREEN}### {global_variable.GREEN}### {global_variable.GREEN}### {global_variable.GREEN}### {global_variable.GREEN}### {global_variable.YELLOW}The First-Ever! Advance Browser Based Automated Web Form Fuzzing Tool {global_variable.GREEN}### - {global_variable.GREEN}### {global_variable.YELLOW}Version : {global_variable.BLUE}v2024.5 {global_variable.GREEN}### + {global_variable.GREEN}### {global_variable.YELLOW}Version : {global_variable.BLUE}v2024.10 {global_variable.GREEN}### {global_variable.GREEN}### {global_variable.YELLOW}Github : {global_variable.BLUE}https://github.com/netsquare/BrowserBruter {global_variable.GREEN}### {global_variable.GREEN}### {global_variable.YELLOW}Copyright : {global_variable.BLUE}Net-Square Solutions PVT LTD. (https://net-square.com) {global_variable.GREEN}### {global_variable.GREEN}### {global_variable.YELLOW}Documentation: {global_variable.BLUE}https://net-square.com/browserbruter {global_variable.GREEN}### diff --git a/modules/report_explorer/show_data/show_request_response.py b/modules/report_explorer/show_data/show_request_response.py index ee050d3..e9de58b 100644 --- a/modules/report_explorer/show_data/show_request_response.py +++ b/modules/report_explorer/show_data/show_request_response.py @@ -30,11 +30,11 @@ """ ################################################################## -def show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, messagebox): +def show_request_response(event, tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, request_text_base64, response_text_base64, messagebox): # Allow time for selection to change - tree.after(1, lambda: _process_selection(tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, messagebox)) + tree.after(1, lambda: _process_selection(tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, request_text_base64, response_text_base64, messagebox)) -def _process_selection(tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, messagebox): +def _process_selection(tree, tk, request_text, response_text, web_page_before_text, web_page_after_text, request_text_base64, response_text_base64, messagebox): # Get the newly selected item from the Treeview selected_item = tree.selection() if selected_item: @@ -42,7 +42,7 @@ def _process_selection(tree, tk, request_text, response_text, web_page_before_te index = tree.index(iid) # Define required columns for request/response details - required_columns = ['Method', 'URL', 'Request Headers', 'Response Status Code', 'Web Page Before', 'Web Page After', 'Response Body', 'Request Body'] + required_columns = ['Method', 'URL', 'Request Headers', 'Response Status Code', 'Web Page Before', 'Web Page After', 'Response Body', 'Request Body', 'Base64 Request', 'Base64 Response'] # Check if required columns are present in the DataFrame if all(col in re_global_variable.df.columns for col in required_columns): @@ -61,6 +61,9 @@ def _process_selection(tree, tk, request_text, response_text, web_page_before_te web_page_before = re_global_variable.df.at[index, 'Web Page Before'] web_page_after = re_global_variable.df.at[index, 'Web Page After'] + request_base64 = re_global_variable.df.at[index, 'Base64 Request'] + response_base64 = re_global_variable.df.at[index, 'Base64 Response'] + # Build full request and response strings full_request = f"{method} {url}\n{request_headers}\n{request_body}" full_response = f"HTTP/1.1 {response_status} {response_reason}\n{response_headers}\n{response_body}" @@ -70,7 +73,13 @@ def _process_selection(tree, tk, request_text, response_text, web_page_before_te response_text.delete(1.0, tk.END) request_text.insert(tk.END, full_request) response_text.insert(tk.END, full_response) - + + # Display the base64 data + request_text_base64.delete(1.0, tk.END) + response_text_base64.delete(1.0, tk.END) + request_text_base64.insert(tk.END, request_base64) + response_text_base64.insert(tk.END, response_base64) + # Display web page before and after details in the respective Text widgets web_page_before_text.delete(1.0, tk.END) web_page_after_text.delete(1.0, tk.END) diff --git a/modules/reporting/final_report.py b/modules/reporting/final_report.py index a781377..32dfa70 100644 --- a/modules/reporting/final_report.py +++ b/modules/reporting/final_report.py @@ -79,7 +79,7 @@ def generate_final_report(): # Algorithm step: 9 get the csv writer object which writes csv data into report writer = csv.writer(final) # Algorithm step: 10 Insert column names or, in other words, headings - writer.writerow(['Index', 'Request Time', 'Fuzzing', 'Payload', 'Method', 'URL', 'Request Headers', 'Request Body', 'Response Time', 'Cycle Time MilliSeconds', 'Response Status Code', 'Response Reason', 'Response Headers', 'Response Body', 'Response Length', 'Web Page Before', 'Web Page After']) + writer.writerow(['Index', 'Request Time', 'Fuzzing', 'Payload', 'Method', 'URL', 'Request Headers', 'Request Body', 'Response Time', 'Cycle Time MilliSeconds', 'Response Status Code', 'Response Reason', 'Response Headers', 'Response Body', 'Response Length', 'Web Page Before', 'Web Page After', 'Base64 Request', 'Base64 Response']) # Algorithm step: 11 Iterate over each CSV file for csv_file in all_threads_files: # Algorithm step: 11.a get the temporary file diff --git a/modules/reporting/write_single_fuzz_traffic.py b/modules/reporting/write_single_fuzz_traffic.py index 02ba998..eb87e30 100644 --- a/modules/reporting/write_single_fuzz_traffic.py +++ b/modules/reporting/write_single_fuzz_traffic.py @@ -22,6 +22,7 @@ import zlib # used for zlib decompression of http response import brotli # used for brotli decompression of http response import zstandard # used for zstd decompression of http response +import base64 # used to encode the raw http request and response from traceback import format_exc from bs4 import BeautifulSoup as bs # used to make html into pretty format from urllib.parse import urlparse # used to parse the url @@ -75,11 +76,48 @@ def write_http_request_response(element, this_threads_file, driver, payload, web writer = csv.writer(report) # Algorithm step: 6. for request in filtered_requests: # For each request + try: + base64_request = None + base64_response = None + # Converting request into base64 + request_headers_for_bs64 = "\r\n".join(f"{header}: {value}" for header, value in request.headers.items()) + + # Combine headers and raw body + if request.body: + raw_data_request = f"{request.method} {request.path} HTTP/1.1\r\n{request_headers_for_bs64}\r\n\r\n".encode('utf-8') + request.body + else: + raw_data_request = f"{request.method} {request.path} HTTP/1.1\r\n{request_headers_for_bs64}\r\n\r\n".encode('utf-8') + + # Encode the raw data in Base64 + base64_request = base64.b64encode(raw_data_request).decode('utf-8') + + # Converting response into base64 + response_headers_for_bs64 = "\r\n".join(f"{header}: {value}" for header, value in request.response.headers.items()) + # Combine headers and raw body + if request.response.body: + raw_data_response = f"HTTP/1.1 {request.response.status_code} {request.response.reason}\r\n{response_headers_for_bs64}\r\n\r\n".encode('utf-8') + request.response.body + else: + raw_data_response = f"HTTP/1.1 {request.response.status_code} {request.response.reason}\r\n{response_headers_for_bs64}\r\n\r\n".encode('utf-8') + # Encode the raw data in Base64 + base64_response = base64.b64encode(raw_data_response).decode('utf-8') + except Exception as e: + log_error(format_exc()) + if global_variable.args.debug: + print(e) + pass + else: + pass + try: # Algorithm step: 6.a decode the request body request_body = request.body.decode("UTF-8") except UnicodeDecodeError: request_body = request.body try: + # Check if the base64 request or base64 response are not none + if base64_response is None: + base64_response = "N/A" + if base64_request is None: + base64_request = "N/A" # Algorithm step: 6.b Get request response time request_time = request.date response_time = request.response.date @@ -115,7 +153,7 @@ def write_http_request_response(element, this_threads_file, driver, payload, web [request_time.strftime('%Y-%m-%d %H:%M:%S'), str(element), str(payload), request.method, urllib.parse.unquote(request.url), request.headers, request_body, response_time.strftime('%Y-%m-%d %H:%M:%S'), cycle_time_in_milliseconds, request.response.status_code, request.response.reason, request.response.headers, response_body, len(request.response.body), bs(webpage_before,features="html.parser").prettify(), - bs(webpage_after,features="html.parser").prettify()]] + bs(webpage_after,features="html.parser").prettify(), base64_request, base64_response]] # Algorithm step: 6.i write the row in report writer.writerow(row) # Algorithm step: 6.j Check whether the output should be printed on the console or not @@ -149,6 +187,6 @@ def write_http_request_response(element, this_threads_file, driver, payload, web [request_time.strftime('%Y-%m-%d %H:%M:%S'), str(element), str(payload), request.method, urllib.parse.unquote(request.url), request.headers, request_body, request_time.strftime('%Y-%m-%d %H:%M:%S'), '0', '0', "N/A", "N/A", "N/A", '0', bs(webpage_before,features="html.parser").prettify(), - bs(webpage_after,features="html.parser").prettify()]] + bs(webpage_after,features="html.parser").prettify(), base64_request, base64_response]] # write the row to report writer.writerow(row) \ No newline at end of file