Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save SafeEval/31cae3d6916dbd00b0b2ba9fa2692799 to your computer and use it in GitHub Desktop.
Save SafeEval/31cae3d6916dbd00b0b2ba9fa2692799 to your computer and use it in GitHub Desktop.
PoC: Automatic commenting from Burp Turbo Intruder scripts
"""
poc-turbo-intruder-messageinfo-comment.py
Jack Sullivan <jack@divergent.codes>
This is a Burp Turbo Intruder PoC that shows how to automatically set the comment
field from a Turbo Intruder script. Each comment will be persisted across other
Burp plugins, like Logger++.
The approach is to register a IHttpListener class that captures and exposes
each IHttpRequestResponse object in a way that can be called from other
portions of a Turbo Intruder script, like `queueRequests` and `handleResponse`.
Yes, it might be over-engineered, but it works! ;)
"""
#############################################################################
# HTTP listener class and functions for Turbo Intruder messageInfo modification
#############################################################################
class TurboIntruderMessageInfoHttpListener(burp.IHttpListener):
name = 'TurboIntruderMessageInfoHttpListener'
_callbacks = None
_call_count = 0
request_messages = []
response_messages = []
comment = 'Default Comment'
def set_callbacks_reference(self, callbacks_ref):
self._callbacks = callbacks_ref
def console_log(self, message):
if not self._callbacks:
return
self._callbacks.printOutput('[%s] %s' % (self.name, message))
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
self._call_count += 1
if not self._callbacks:
return
tool_name = self._callbacks.getToolName(toolFlag)
if tool_name != 'Extender':
return
#### Requests ####
# Setting comments on requests can be done from here.
if messageIsRequest:
self.request_messages.append(messageInfo)
messageInfo.setComment(self.comment)
#### Responses ####
# Setting a response comment from here results in something like "$LPP:47:f20286db-2b3a-4a6d-8ae5-6d15e406f5b7$"
# Let the handleResponse() handler use it via HTTP_LISTENER.response_messages[]
if not messageIsRequest:
self.response_messages.append(messageInfo)
def get_matching_http_listeners():
# Collect existing listeners registered by this extension.
http_listeners = callbacks.getHttpListeners()
# Find matching listeners.
matches = []
for hl in http_listeners:
if TurboIntruderMessageInfoHttpListener.name in str(type(hl)):
matches.append(hl)
return matches
def clear_http_listeners():
matches = get_matching_http_listeners()
callbacks.printOutput('Removing %s existing HTTP listener(s)' % len(matches))
[callbacks.removeHttpListener(hl) for hl in matches]
def create_http_listener():
callbacks.printOutput('Creating HTTP listener')
http_listener = TurboIntruderMessageInfoHttpListener()
http_listener.set_callbacks_reference(callbacks)
callbacks.registerHttpListener(http_listener)
return http_listener
def initialize_http_listener():
matches = get_matching_http_listeners()
if not matches:
return create_http_listener()
return matches[-1]
#############################################################################
# Standard Turbo Intruder code
#############################################################################
#clear_http_listeners()
HTTP_LISTENER = initialize_http_listener()
def queueRequests(target, wordlists):
engine = RequestEngine(
endpoint=target.endpoint,
concurrentConnections=1, # Single concurrent connection to force sequential order.
engine=Engine.BURP, # Use Burp's network stack, so state is persisted across tools.
)
for i in range(0, 3):
# Can set persisted label per request here, and use it to
# set the comment on the response in handleResponse.
label = '#%s' % i
engine.queue(target.req, i, learn=1, label=label)
# Only a single comment value can be applied in queueRequests().
# The comment set here will be applied to all queued requests in the Turbo Intruder run.
# Setting the response comment in handleResponse() will override it.
#HTTP_LISTENER.comment = 'queueRequests Comment'
def handleResponse(req, interesting):
# Commenting on the most recent request has no effect. Default comment will be used.
#last_request = HTTP_LISTENER.request_messages[-1]
#last_request.setComment('[Request] %s' % req.label)
# Commenting on the most recent response will be set.
last_response = HTTP_LISTENER.response_messages[-1]
last_response.setComment('[Response] %s' % req.label)
table.add(req)
@SafeEval
Copy link
Author

SafeEval commented Mar 7, 2021

loggerpp_result

@Rufan0
Copy link

Rufan0 commented Aug 14, 2022

I was looking for this for a long time, thank you very much

@SafeEval
Copy link
Author

Sure thing. Glad you found it useful.

@SCParrot
Copy link

I use this gist but the output panel show requestsPerConnection has been forced to 1 and pipelining has been disabled due to Burp engine limitations, is this gist can't be used now?

@SafeEval
Copy link
Author

I might have some time over the weekend to see if this needs any tweaks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment