Skip to content

Commit fdcce14

Browse files
committed
feat: Burp插件任务创建后自动保存历史配置,优化历史去重逻辑
1 parent 48a334b commit fdcce14

4 files changed

Lines changed: 113 additions & 17 deletions

File tree

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# 使用标准库的logging模块
22
import logging
33
from datetime import datetime
4+
from urllib.parse import urlparse
45

56
from fastapi import HTTPException
67
from fastapi import APIRouter, Depends, Request, Query
@@ -9,6 +10,7 @@
910
from model.BaseResponseMsg import BaseResponseMsg
1011
from model.requestModel.TaskRequest import TaskAddRequest
1112
from service.taskService import taskService
13+
from service.scanPresetService import scanPresetService
1214
from utils.auth import get_current_user
1315

1416
logger = logging.getLogger(__name__)
@@ -19,19 +21,42 @@
1921
async def add_task(taskAddRequest: TaskAddRequest, request: Request, current_user: dict = Depends(get_current_user)):
2022
try:
2123
if request.client:
22-
# pdb.set_trace()
2324
task_dict = taskAddRequest.model_dump()
2425
if 'options' not in task_dict or task_dict['options'] is None:
2526
return BaseResponseMsg(success=False, msg="options is required", code=status.HTTP_400_BAD_REQUEST, data=None)
26-
logger.info(f"request.client: {request.client}")
27+
logger.info(f"[Burp] request.client: {request.client}")
2728
remote_ip = request.client.host
28-
# pdb.set_trace()
29-
res = await taskService.star_task(remote_addr=remote_ip, scanUrl=taskAddRequest.scanUrl, host=taskAddRequest.host, method=taskAddRequest.method, headers=taskAddRequest.headers, body=taskAddRequest.body, options=taskAddRequest.options)
29+
30+
res = await taskService.star_task(
31+
remote_addr=remote_ip,
32+
scanUrl=taskAddRequest.scanUrl,
33+
host=taskAddRequest.host,
34+
method=taskAddRequest.method,
35+
headers=taskAddRequest.headers,
36+
body=taskAddRequest.body,
37+
options=taskAddRequest.options
38+
)
39+
40+
# 任务创建成功后,保存到历史配置
41+
if res.success and taskAddRequest.options:
42+
try:
43+
# 生成历史配置名称(与 Web 端格式一致)
44+
parsed_url = urlparse(taskAddRequest.scanUrl)
45+
path = parsed_url.path or '/'
46+
history_name = f"{taskAddRequest.method} {taskAddRequest.host}{path}"
47+
history_name = history_name[:50] # 限制长度
48+
49+
scanPresetService.add_to_history(history_name, taskAddRequest.options)
50+
logger.info(f"[Burp] Saved scan config to history: {history_name}")
51+
except Exception as e:
52+
logger.warning(f"[Burp] Failed to save history config: {e}")
53+
# 不影响任务创建结果
54+
3055
return res
3156
else:
3257
remote_ip = None
33-
logger.warning("request.client is None")
34-
return BaseResponseMsg(success=False, msg="options is required", code=status.HTTP_400_BAD_REQUEST, data=None)
58+
logger.warning("[Burp] request.client is None")
59+
return BaseResponseMsg(success=False, msg="Unable to determine client address", code=status.HTTP_400_BAD_REQUEST, data=None)
3560
except Exception as e:
36-
logger.error(f"Error: {e}")
61+
logger.error(f"[Burp] Error: {e}")
3762
raise HTTPException(status_code=500, detail="Error accessing request.client")

src/backEnd/model/ScanPresetDatabase.py

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,20 +377,29 @@ def record_preset_usage(self, preset_id: int):
377377
def add_to_history(self, name: str, options: dict, max_history: int = 20) -> Optional[ScanPreset]:
378378
"""添加到历史记录"""
379379
try:
380-
# 检查是否已存在相同名称的历史记录
380+
# 生成 parameter_string
381+
parameter_string = self._generate_parameter_string(options)
382+
383+
# 检查是否已存在相同名称且相同参数的历史记录
384+
# 只有名称和参数都相同才更新,否则创建新记录
381385
existing = self.get_preset_by_name(name)
382386
if existing and existing.preset_type == PresetType.HISTORY:
383-
# 更新现有记录
384-
return self.update_preset(existing.id, ScanPresetUpdate(
385-
options=options
386-
))
387+
# 比较参数是否相同(通过 parameter_string)
388+
existing_params = existing.parameter_string or ""
389+
if existing_params == parameter_string:
390+
# 参数相同,只更新使用时间
391+
self.record_preset_usage(existing.id)
392+
return existing
393+
# 参数不同,创建新记录(名称添加时间戳避免重复)
394+
name = f"{name} ({datetime.now().strftime('%H:%M:%S')})"
387395

388396
# 创建新历史记录
389397
preset = self.create_preset(ScanPresetCreate(
390398
name=name,
391399
description=f"历史配置 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
392400
preset_type=PresetType.HISTORY,
393-
options=options
401+
options=options,
402+
parameter_string=parameter_string
394403
))
395404

396405
if preset:
@@ -406,6 +415,60 @@ def add_to_history(self, name: str, options: dict, max_history: int = 20) -> Opt
406415
logger.error(f"Failed to add to history: {getSafeExString(e)}")
407416
return None
408417

418+
def _generate_parameter_string(self, options: dict) -> str:
419+
"""从 options 生成命令行参数字符串"""
420+
if not options:
421+
return ""
422+
423+
# 默认值定义(与前端保持一致)
424+
defaults = {
425+
'level': 1, 'risk': 1, 'technique': 'BEUSTQ', 'timeSec': 5,
426+
'timeout': 30, 'retries': 3, 'delay': 0, 'threads': 1,
427+
'verbose': 1, 'batch': True, 'crawlDepth': 0
428+
}
429+
430+
# 参数名到 CLI 选项的映射
431+
param_map = {
432+
'level': 'level', 'risk': 'risk', 'technique': 'technique',
433+
'timeSec': 'time-sec', 'timeout': 'timeout', 'retries': 'retries',
434+
'delay': 'delay', 'threads': 'threads', 'verbose': 'v',
435+
'dbms': 'dbms', 'os': 'os', 'prefix': 'prefix', 'suffix': 'suffix',
436+
'tamper': 'tamper', 'proxy': 'proxy', 'testParameter': 'p',
437+
'string': 'string', 'notString': 'not-string', 'regexp': 'regexp',
438+
'randomAgent': 'random-agent', 'tor': 'tor', 'smart': 'smart',
439+
'textOnly': 'text-only', 'titles': 'titles', 'forms': 'forms',
440+
'flushSession': 'flush-session', 'freshQueries': 'fresh-queries',
441+
'getBanner': 'banner', 'getCurrentUser': 'current-user',
442+
'getCurrentDb': 'current-db', 'getDbs': 'dbs', 'getTables': 'tables',
443+
'getColumns': 'columns', 'dumpTable': 'dump', 'dumpAll': 'dump-all',
444+
'db': 'D', 'tbl': 'T', 'col': 'C', 'answers': 'answers'
445+
}
446+
447+
parts = []
448+
for key, value in options.items():
449+
if value is None or value == '':
450+
continue
451+
452+
# 跳过默认值
453+
if key in defaults and value == defaults[key]:
454+
continue
455+
456+
cli_opt = param_map.get(key, key)
457+
458+
# 布尔值处理
459+
if isinstance(value, bool):
460+
if value:
461+
parts.append(f"--{cli_opt}")
462+
# 字符串/数字处理
463+
else:
464+
# 短选项使用不同格式
465+
if len(cli_opt) == 1:
466+
parts.append(f"-{cli_opt}={value}")
467+
else:
468+
parts.append(f"--{cli_opt}={value}")
469+
470+
return ' '.join(parts)
471+
409472
def _cleanup_old_history(self, max_history: int):
410473
"""清理旧的历史记录"""
411474
try:

src/frontEnd/src/stores/scanPreset.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,14 @@ export const useScanPresetStore = defineStore('scanPreset', () => {
227227

228228
/**
229229
* 添加到历史记录
230+
* @param name 历史记录名称
231+
* @param options 可选的扫描配置,未提供则使用当前 Store 状态
230232
*/
231-
async function addToHistory(name: string): Promise<ScanPreset | null> {
233+
async function addToHistory(name: string, options?: ScanOptions): Promise<ScanPreset | null> {
232234
try {
233-
const result = await scanPresetApi.addToHistory(name, currentOptions.value)
235+
// 使用传入的配置,或回退到 Store 状态
236+
const effectiveOptions = options ?? currentOptions.value
237+
const result = await scanPresetApi.addToHistory(name, effectiveOptions)
234238
if (result) {
235239
await loadConfigOptions()
236240
}

src/frontEnd/src/views/AddTask/index.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,21 +308,25 @@ async function submitTask() {
308308
submitting.value = true
309309
310310
try {
311+
// 获取实际使用的配置
312+
const taskOptions = getEffectiveOptions()
313+
311314
const taskData = {
312315
scanUrl: requestInfo.url,
313316
host: requestInfo.host,
314317
method: requestInfo.method,
315318
headers: requestInfo.headers,
316319
body: requestInfo.body,
317-
options: getEffectiveOptions()
320+
options: taskOptions
318321
}
319322
320323
await apiRequest.post('/web/admin/task/add', taskData)
321324
322325
const urlPath = requestInfo.url.split('?')[0] || ''
323326
const hostPart = requestInfo.host && urlPath ? urlPath.split(requestInfo.host)[1] : ''
324327
const historyName = `${requestInfo.method} ${requestInfo.host}${hostPart || '/'}`
325-
await presetStore.addToHistory(historyName.substring(0, 50))
328+
// 传递实际使用的配置到历史记录
329+
await presetStore.addToHistory(historyName.substring(0, 50), taskOptions as ScanOptions)
326330
327331
toast.add({
328332
severity: 'success',

0 commit comments

Comments
 (0)