diff --git a/Remix/BurpRemix/build.gradle.kts b/Remix/BurpRemix/build.gradle.kts index 1a9c22c..ea66d3c 100644 --- a/Remix/BurpRemix/build.gradle.kts +++ b/Remix/BurpRemix/build.gradle.kts @@ -2,7 +2,7 @@ plugins { kotlin("jvm") version "1.3.72" } -version = "0.0.6" +version = "0.1.0" repositories { mavenCentral() @@ -11,6 +11,8 @@ repositories { dependencies { implementation(kotlin("stdlib-jdk8")) implementation("net.portswigger.burp.extender:burp-extender-api:2.1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") } tasks { diff --git a/Remix/BurpRemix/src/main/kotlin/BurpExtender.kt b/Remix/BurpRemix/src/main/kotlin/BurpExtender.kt index 5b2afba..42ceb54 100644 --- a/Remix/BurpRemix/src/main/kotlin/BurpExtender.kt +++ b/Remix/BurpRemix/src/main/kotlin/BurpExtender.kt @@ -4,7 +4,7 @@ class BurpExtender : IBurpExtender { override fun registerExtenderCallbacks(callbacks: IBurpExtenderCallbacks) { val tab = HuntTab(callbacks) callbacks.registerHttpListener(HuntListener(callbacks, tab)) - callbacks.stdout.write("HUNT Remix - v0.0.6".toByteArray()) + callbacks.stdout.write("HUNT Remix - v0.1.0".toByteArray()) callbacks.stdout.write("\nOriginally by: JP Villanueva, Jason Haddix and team at Bugcrowd".toByteArray()) callbacks.stdout.write("\nRepo: https://github.com/bugcrowd/HUNT".toByteArray()) callbacks.stdout.write("\nRemixed by: Caleb Kinney (derail.io)".toByteArray()) diff --git a/Remix/BurpRemix/src/main/kotlin/HuntListener.kt b/Remix/BurpRemix/src/main/kotlin/HuntListener.kt index de27de7..a8d2d86 100644 --- a/Remix/BurpRemix/src/main/kotlin/HuntListener.kt +++ b/Remix/BurpRemix/src/main/kotlin/HuntListener.kt @@ -15,8 +15,8 @@ class HuntListener(private val callbacks: IBurpExtenderCallbacks, private val hu && (toolFlag == IBurpExtenderCallbacks.TOOL_PROXY || toolFlag == IBurpExtenderCallbacks.TOOL_SPIDER) && (request.method != "OPTIONS" || request.method != "HEAD") ) { - val request = helpers.analyzeRequest(messageInfo) ?: return - val parameters = request.parameters + val requestInfo = helpers.analyzeRequest(messageInfo) ?: return + val parameters = requestInfo.parameters val huntIssues = parameters.asSequence().map { param -> checkParameterName(param.name.toLowerCase()) } .filterNotNull().filter { !it.second.isNullOrEmpty() }.map { @@ -28,8 +28,11 @@ class HuntListener(private val callbacks: IBurpExtenderCallbacks, private val hu }.toList() huntTab.huntTable.addHuntIssue(huntIssues) + if (toolFlag == IBurpExtenderCallbacks.TOOL_PROXY) { + messageInfo.highlight = "cyan" + messageInfo.comment = "HUNT: ${huntIssues.map { it.types }.flatten().toSet().joinToString()}" + } } - } } @@ -61,7 +64,7 @@ class HuntListener(private val callbacks: IBurpExtenderCallbacks, private val hu types = typeNames, parameter = parameter, method = requestInfo?.method ?: "", - statusCode = (response?.statusCode ?: 0).toInt(), + statusCode = response?.statusCode ?: 0, title = getTitle(requestResponse.response), length = requestResponse.response?.size ?: 0, mimeType = response?.inferredMimeType ?: "", @@ -88,7 +91,7 @@ data class HuntIssue( val types: Set, val parameter: String, val method: String, - val statusCode: Int, + val statusCode: Short, val title: String, val length: Int, val mimeType: String, diff --git a/Remix/BurpRemix/src/main/kotlin/HuntTab.kt b/Remix/BurpRemix/src/main/kotlin/HuntTab.kt index 8f27b57..56d869e 100644 --- a/Remix/BurpRemix/src/main/kotlin/HuntTab.kt +++ b/Remix/BurpRemix/src/main/kotlin/HuntTab.kt @@ -1,9 +1,12 @@ package burp -import javax.swing.JScrollPane -import javax.swing.JSplitPane -import javax.swing.JTable -import javax.swing.ListSelectionModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.swing.Swing +import kotlinx.coroutines.withContext +import java.awt.FlowLayout +import javax.swing.* import javax.swing.table.AbstractTableModel import javax.swing.table.TableRowSorter @@ -16,7 +19,7 @@ class HuntTab(callbacks: IBurpExtenderCallbacks) : ITab { override fun getUiComponent() = huntTable.panel } -class HuntPanel(callbacks: IBurpExtenderCallbacks) { +class HuntPanel(private val callbacks: IBurpExtenderCallbacks) { private val huntOptions = HuntOptions(this, callbacks) val model = HuntModel(huntOptions) val table = JTable(model) @@ -60,16 +63,25 @@ class HuntPanel(callbacks: IBurpExtenderCallbacks) { } } + val repeatPanel = JPanel(FlowLayout(FlowLayout.LEFT)) + + val repeatButton = JButton("Repeat Request") + repeatButton.addActionListener { repeatRequest() } + repeatPanel.add(repeatButton) + val huntTable = JScrollPane(table) val reqResSplit = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, requestViewer?.component, responseViewer?.component) reqResSplit.resizeWeight = 0.5 + val repeatReqSplit = + JSplitPane(JSplitPane.VERTICAL_SPLIT, repeatPanel, reqResSplit) + val huntOptSplit = JSplitPane(JSplitPane.VERTICAL_SPLIT, huntOptions.panel, huntTable) panel.topComponent = huntOptSplit - panel.bottomComponent = reqResSplit + panel.bottomComponent = repeatReqSplit panel.resizeWeight = 0.5 callbacks.customizeUiComponent(panel) } @@ -80,8 +92,26 @@ class HuntPanel(callbacks: IBurpExtenderCallbacks) { model.filterOrRefresh() } } + + private fun repeatRequest() { + table.selectionModel.clearSelection() + + GlobalScope.launch(Dispatchers.IO) { + val requestResponse = try { + callbacks.makeHttpRequest(messageEditor.httpService, requestViewer?.message) + } catch (e: java.lang.RuntimeException) { + RequestResponse(requestViewer?.message, null, messageEditor.httpService) + } + withContext(Dispatchers.Swing) { + SwingUtilities.invokeLater { + responseViewer?.setMessage(requestResponse?.response ?: ByteArray(0), false) + } + } + } + } } + class MessageEditor(callbacks: IBurpExtenderCallbacks) : IMessageEditorController { var requestResponse: IHttpRequestResponse? = null @@ -135,7 +165,7 @@ class HuntModel(private val huntOptions: HuntOptions) : AbstractTableModel() { 5 -> String::class.java 6 -> String::class.java 7 -> String::class.java - 8 -> Integer::class.java + 8 -> Short::class.java 9 -> Integer::class.java 10 -> String::class.java 11 -> String::class.java @@ -213,4 +243,33 @@ class HuntModel(private val huntOptions: HuntOptions) : AbstractTableModel() { } } +class RequestResponse(private var req: ByteArray?, private var res: ByteArray?, private var service: IHttpService?) : + IHttpRequestResponse { + + override fun getComment(): String? = null + + override fun setComment(comment: String?) {} + + override fun getRequest(): ByteArray? = req + + override fun getHighlight(): String? = null + + override fun getHttpService(): IHttpService? = service + + override fun getResponse(): ByteArray? = res + + override fun setResponse(message: ByteArray?) { + res = message + } + + override fun setRequest(message: ByteArray?) { + req = message + } + + override fun setHttpService(httpService: IHttpService?) { + service = httpService + } + + override fun setHighlight(color: String?) {} +}