Last active
October 24, 2024 13:53
-
-
Save jonaslejon/7007f001edbdbaabc38b2b47d5a8d39c to your computer and use it in GitHub Desktop.
Burp Suite CSV Log Parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Burp Suite CSV Log Parser | |
This script parses a Burp Suite CSV log file, decodes base64-encoded HTTP requests and responses, | |
and prints them in a human-readable format with colored output for better readability. | |
Usage: | |
python burp_log_parser.py <input_file> --status_code <status_code> --filter_response <filter_response> --negative_filter_response <negative_filter_response> --response_only --json_output | |
Dependencies: | |
- termcolor: Install using `pip install termcolor` | |
""" | |
import csv | |
import base64 | |
import argparse | |
import re | |
import json | |
import sys | |
from termcolor import colored | |
import csv | |
# Increase CSV field size limit to avoid field limit error | |
csv.field_size_limit(sys.maxsize) | |
def decode_burp_log(file_path, filter_status_code, filter_response, negative_filter_response, response_only, json_output): | |
log_entries = [] | |
# Open the CSV file for reading | |
with open(file_path, newline='', encoding='utf-8') as csvfile: | |
reader = csv.DictReader(csvfile) | |
for row in reader: | |
# Filter based on status code if provided | |
if filter_status_code and row['Status code'] != filter_status_code: | |
continue | |
# Decode the base64-encoded HTTP response if it exists | |
if 'Response' in row and row['Response']: | |
response = base64.b64decode(row['Response']).decode('utf-8') | |
# Filter based on response content if provided (supports both text and regex) | |
if filter_response: | |
filter_patterns = filter_response.split(',') | |
if not any(re.search(pattern.strip(), response) for pattern in filter_patterns): | |
continue | |
# Filter out responses that match the negative filter (supports both text and regex) | |
if negative_filter_response: | |
negative_patterns = negative_filter_response.split(',') | |
if any(re.search(pattern.strip(), response) for pattern in negative_patterns): | |
continue | |
# If response_only flag is set, only print the response | |
if response_only: | |
if 'Response' in row and row['Response']: | |
print(colored(response, "yellow")) | |
print("\n") | |
continue | |
# Decode the base64-encoded HTTP request | |
request = row['Request'] | |
decoded_request = base64.b64decode(request).decode('utf-8') | |
# Collect data for JSON output | |
log_entry = { | |
"ID": row['ID'], | |
"Time": row['Time'], | |
"Tool": row['Tool'], | |
"Method": row['Method'], | |
"Protocol": row['Protocol'], | |
"Host": row['Host'], | |
"Port": row['Port'], | |
"URL": row['URL'], | |
"Status Code": row['Status code'], | |
"Length": row['Length'], | |
"MIME Type": row['MIME type'], | |
"Comment": row['Comment'], | |
"Decoded HTTP Request": decoded_request, | |
"Decoded HTTP Response": response if 'Response' in row and row['Response'] else None | |
} | |
log_entries.append(log_entry) | |
# Skip printing if JSON output is selected | |
if json_output: | |
continue | |
# Print general information about the HTTP request/response | |
print(f"ID: {row['ID']}") | |
print(f"Time: {row['Time']}") | |
print(f"Tool: {row['Tool']}") | |
print(f"Method: {row['Method']}") | |
print(f"Protocol: {row['Protocol']}") | |
print(f"Host: {row['Host']}") | |
print(f"Port: {row['Port']}") | |
print(f"URL: {row['URL']}") | |
print(f"Status Code: {row['Status code']}") | |
print(f"Length: {row['Length']}") | |
print(f"MIME Type: {row['MIME type']}") | |
print(f"Comment: {row['Comment']}") | |
print("\n") | |
print(colored("Decoded HTTP Request:", "cyan")) | |
# Print the decoded HTTP request in green color | |
print(colored(decoded_request, "green")) | |
# Print the decoded HTTP response if it exists | |
if 'Response' in row and row['Response']: | |
print("\n") | |
print(colored("Decoded HTTP Response:", "cyan")) | |
# Print the decoded HTTP response in yellow color | |
print(colored(response, "yellow")) | |
print("\n") | |
# Print the output as JSON if the json_output flag is set | |
if json_output: | |
print(json.dumps(log_entries, indent=4)) | |
def main(): | |
# Set up argument parser to take input file, status code, and response filter from command line | |
parser = argparse.ArgumentParser(description='Parse and decode Burp Suite CSV log file.') | |
parser.add_argument('input_file', type=str, help='Path to the Burp Suite CSV log file') | |
parser.add_argument('--status_code', type=str, help='Filter results by HTTP status code', default=None) | |
parser.add_argument('--filter_response', type=str, help='Filter results by HTTP response content (supports text and regex, multiple patterns separated by commas)', default=None) | |
parser.add_argument('--negative_filter_response', type=str, help='Exclude results by HTTP response content (supports text and regex, multiple patterns separated by commas)', default=None) | |
parser.add_argument('--response_only', action='store_true', help='Only print the HTTP response data') | |
parser.add_argument('--json_output', action='store_true', help='Print the output as JSON') | |
args = parser.parse_args() | |
# Call the function to decode the Burp log with optional filters | |
decode_burp_log(args.input_file, args.status_code, args.filter_response, args.negative_filter_response, args.response_only, args.json_output) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment