from burp import IBurpExtender, ITab
from java.awt import BorderLayout
from javax.swing import JPanel, JTable, JScrollPane, JTextArea, JSplitPane, JButton, JComboBox
from javax.swing.table import DefaultTableModel
from java.util import Date
from java.text import SimpleDateFormat
from java.net import URL
class BurpExtender(IBurpExtender, ITab):
def registerExtenderCallbacks(self, callbacks):
self.callbacks = callbacks
self.helpers = callbacks.getHelpers()
self.callbacks.setExtensionName("Dir Index Checker with Request/Response List (Jython)")
self._request_responses = []
# UI 패널 구성
self._panel = JPanel(BorderLayout())
# 테이블에 URL, Status, Indexed, Time, Request, Response 컬럼을 추가
self._table_model = DefaultTableModel(["URL", "Status", "Indexed", "Time", "Request", "Response"], 0)
self._table = JTable(self._table_model)
self._panel.add(JScrollPane(self._table), BorderLayout.CENTER)
# 추가 상세 정보용 텍스트 영역 (클릭 시 상세하게 볼 수 있음)
self._request_viewer = JTextArea()
self._response_viewer = JTextArea()
self._request_viewer.setEditable(False)
self._response_viewer.setEditable(False)
split = JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
JScrollPane(self._request_viewer),
JScrollPane(self._response_viewer))
split.setDividerLocation(400)
self._panel.add(split, BorderLayout.SOUTH)
self._table.getSelectionModel().addListSelectionListener(lambda e: self.onRowSelect())
# 도메인 선택 드롭다운 및 스캔 버튼
self._host_selector = JComboBox()
self._scan_button = JButton("Scan Selected Host", actionPerformed=self.scanSelectedHost)
top_panel = JPanel()
top_panel.add(self._host_selector)
top_panel.add(self._scan_button)
self._panel.add(top_panel, BorderLayout.NORTH)
# 탭 등록
callbacks.addSuiteTab(self)
# 초기 호스트 목록 로딩
self.updateHostList()
def getTabCaption(self):
return "Dir Index Checker"
def getUiComponent(self):
return self._panel
def updateHostList(self):
hosts = set()
for item in self.callbacks.getSiteMap(None):
try:
url = self.helpers.analyzeRequest(item).getUrl()
hosts.add(url.getHost())
except Exception as e:
print("Error updating host list: %s" % e)
continue
self._host_selector.removeAllItems()
for host in sorted(hosts):
self._host_selector.addItem(host)
def scanSelectedHost(self, event):
selected_host = self._host_selector.getSelectedItem()
if selected_host is None:
return
# 초기화
self._table_model.setRowCount(0)
self._request_responses = []
items = self.callbacks.getSiteMap(None)
seen = set()
for item in items:
try:
req_info = self.helpers.analyzeRequest(item)
url = req_info.getUrl()
if url.getHost() != selected_host:
continue
service = item.getHttpService()
# 원본 URL 스캔
self.scan_url(url, service, seen)
# 경로가 "/"로 끝나지 않으면, "/"를 추가한 URL도 스캔
if not url.getPath().endswith("/"):
appended = url.toString() + "/"
new_url = URL(appended)
self.scan_url(new_url, service, seen)
except Exception as e:
print("Error scanning host: %s" % e)
def scan_url(self, url, service, seen):
url_str = url.toString()
if url_str in seen:
return
seen.add(url_str)
try:
request = self.helpers.buildHttpRequest(url)
new_response = self.callbacks.makeHttpRequest(service, request)
resp_bytes = new_response.getResponse()
if resp_bytes is None:
return
analyzed_response = self.helpers.analyzeResponse(resp_bytes)
# 응답 본문 추출
body_offset = analyzed_response.getBodyOffset()
body = self.helpers.bytesToString(resp_bytes)[body_offset:].lower()
# 디렉토리 리스팅 판별 (예: "index of"와 "parent directory" 포함 여부)
if "index of" in body and "parent directory" in body:
indexed = "YES"
else:
indexed = "NO"
status = analyzed_response.getStatusCode()
time_str = SimpleDateFormat("HH:mm:ss").format(Date())
# 요청과 응답 내용을 문자열로 변환
req_str = self.helpers.bytesToString(new_response.getRequest())
res_str = self.helpers.bytesToString(new_response.getResponse())
self._table_model.addRow([url_str, status, indexed, time_str, req_str, res_str])
self._request_responses.append(new_response)
except Exception as e:
print("Error scanning URL %s: %s" % (url_str, e))
def onRowSelect(self):
row = self._table.getSelectedRow()
if 0 <= row < len(self._request_responses):
rr = self._request_responses[row]
self._request_viewer.setText(self.helpers.bytesToString(rr.getRequest()))
self._response_viewer.setText(self.helpers.bytesToString(rr.getResponse()))