Skip to content

Commit 21363bd

Browse files
9.9.0 fixes
1 parent e2817a9 commit 21363bd

5 files changed

Lines changed: 209 additions & 29 deletions

File tree

src/ptk/background/dast/dastEngine.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2309,6 +2309,7 @@ export class dastEngine {
23092309
id: attack.id || null,
23102310
findingId: attack.findingId || null,
23112311
success: !!attack.success,
2312+
confidence: Number.isFinite(Number(attack.confidence)) ? Number(attack.confidence) : null,
23122313
proof: attack.proof || null,
23132314
payload: attack.payload || null,
23142315
param: attack.param || null,
@@ -2615,6 +2616,9 @@ export class dastEngine {
26152616
presentationAggregate: reconMeta?.presentation?.aggregate || classification.presentationAggregate || null,
26162617
uiSurface: reconMeta.uiSurface || classification.uiSurface || null
26172618
}
2619+
const persistedConfidenceDetails = attackResult?.success
2620+
? this._resolveAttackConfidenceDetails(attackResult, classification)
2621+
: null
26182622
if (requestData) attackMeta.request = requestData
26192623
if (responseData) attackMeta.response = responseData
26202624
const followupRequestData = this._compactRequestForStorage(attackResult?.renderFollowup?.request, {
@@ -2635,6 +2639,9 @@ export class dastEngine {
26352639
}
26362640
if (Number.isFinite(attackResult?.confidence)) attackMeta.confidence = attackResult.confidence
26372641
if (Number.isFinite(attackResult?.metadata?.confidence)) attackMeta.confidence = attackResult.metadata.confidence
2642+
if (!Number.isFinite(attackMeta.confidence) && Number.isFinite(persistedConfidenceDetails?.confidence)) {
2643+
attackMeta.confidence = persistedConfidenceDetails.confidence
2644+
}
26382645
if (actionToken) {
26392646
attackMeta.actionToken = actionToken
26402647
}
@@ -7781,6 +7788,8 @@ export class dastEngine {
77817788
if (String(classification.outputKind || '').toLowerCase() !== 'recon') {
77827789
return
77837790
}
7791+
const confidenceDetails = this._resolveAttackConfidenceDetails(attack, classification)
7792+
const confidence = Number.isFinite(confidenceDetails?.confidence) ? confidenceDetails.confidence : null
77847793
const ptkMeta = this._resolveAttackPtkMeta(attack)
77857794
const reqSchema = attack.request && attack.request.request ? attack.request.request : attack.request
77867795
const originalReq = requestRecord?.original?.request || requestRecord?.original || {}
@@ -7826,6 +7835,7 @@ export class dastEngine {
78267835
ruleName: classification.ruleName,
78277836
category: classification.category || 'recon',
78287837
severity: classification.severity || null,
7838+
confidence,
78297839
outputKind: "recon",
78307840
reconKind: ptkMeta.reconKind || classification.reconKind || null,
78317841
presentationAggregate: ptkMeta?.presentation?.aggregate || classification.presentationAggregate || null,
@@ -7846,7 +7856,8 @@ export class dastEngine {
78467856
resolverKey,
78477857
param: location.param || null,
78487858
payload: payloadValue || null,
7849-
proof: attack?.proof || null
7859+
proof: attack?.proof || null,
7860+
confidenceSignals: Array.isArray(confidenceDetails?.signals) ? confidenceDetails.signals : []
78507861
}
78517862
}
78527863
})

src/ptk/background/dast/modules/modules.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11305,7 +11305,13 @@
1130511305
"constants": {
1130611306
"regex": "/(admin|administrator|manage|management|console|cpanel|superadmin)(/|\\b)"
1130711307
},
11308-
"extensions": {}
11308+
"extensions": {
11309+
"ptk": {
11310+
"presentation": {
11311+
"aggregate": "scan"
11312+
}
11313+
}
11314+
}
1130911315
}
1131011316
},
1131111317
{

src/ptk/background/dast/services/dastResultProjector.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export class DastResultProjector {
148148
success: !!attack.success
149149
}
150150
const scalarKeys = [
151+
"confidence",
151152
"proof",
152153
"param",
153154
"name",

src/ptk/browser/assets/js/dast.js

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4330,9 +4330,27 @@ function ensureGroupedReconObservation(map, attack, original, requestId) {
43304330
return map.get(key)
43314331
}
43324332

4333+
function scoreGroupedReconSampleAttack(attack = null) {
4334+
if (!attack || typeof attack !== 'object') return 0
4335+
let score = 0
4336+
if (attack.findingId || attack?.finding?.id) score += 8
4337+
if (Number.isFinite(Number(attack?.confidence)) || Number.isFinite(Number(attack?.finding?.confidence)) || Number.isFinite(Number(attack?.metadata?.confidence))) score += 4
4338+
if (attack?.finding?.presentationAggregate || attack?.presentationAggregate) score += 2
4339+
if (Array.isArray(attack?.finding?.evidence?.dast?.samples) && attack.finding.evidence.dast.samples.length) score += 3
4340+
if (attack?.finding?.description || attack?.description || attack?.metadata?.description || attack?.metadata?.docs?.description) score += 1
4341+
if (attack?.finding?.links || attack?.links || attack?.metadata?.links || attack?.metadata?.docs?.links) score += 1
4342+
return score
4343+
}
4344+
4345+
function selectPreferredGroupedReconSampleAttack(current = null, incoming = null) {
4346+
return scoreGroupedReconSampleAttack(incoming) >= scoreGroupedReconSampleAttack(current) ? incoming : current
4347+
}
4348+
43334349
function collectGroupedReconObservation(map, attack, original, requestId) {
43344350
const entry = ensureGroupedReconObservation(map, attack, original, requestId)
43354351
if (!entry) return
4352+
entry.sampleAttack = selectPreferredGroupedReconSampleAttack(entry.sampleAttack, attack)
4353+
entry.sampleRequest = entry.sampleAttack?.request || attack?.request || original?.request || original || entry.sampleRequest
43364354
const request = attack?.request || original?.request || original || {}
43374355
const method = String(request?.method || '').trim().toUpperCase() || 'GET'
43384356
const path = normalizeObservationRoutePath(request?.url || request?.ui_url || request?.target || '')
@@ -4360,8 +4378,8 @@ function renderGroupedReconRoutes(entry) {
43604378
</div>
43614379
`
43624380
}
4363-
const previewRoutes = routes.slice(0, 6)
4364-
const remainingRoutes = routes.slice(6)
4381+
const previewRoutes = routes.slice(0, 3)
4382+
const remainingRoutes = routes.slice(3)
43654383
const renderRouteItem = (route) => {
43664384
const label = `${route.method} ${route.path}`
43674385
if (route.url) {
@@ -4370,19 +4388,18 @@ function renderGroupedReconRoutes(entry) {
43704388
return `<li>${ptk_utils.escapeHtml(label)}</li>`
43714389
}
43724390
const preview = previewRoutes.map(renderRouteItem).join('')
4373-
const remaining = remainingRoutes.length
43744391
const allRoutes = remainingRoutes.map(renderRouteItem).join('')
43754392
const toggleKey = ptk_utils.escapeHtml(String(entry?.key || ''))
43764393
return `
43774394
<div class="description">
4378-
<p>Affected routes: <b>${routes.length}</b>${entry.rawCount > routes.length ? `</p><p>Matched requests: <b>${entry.rawCount}</b>` : ''}</p>
4395+
<p>Affected routes: <b>${routes.length}</b>${entry.rawCount > routes.length ? ` | Matched responses: <b>${entry.rawCount}</b>` : ''}</p>
43794396
<ul style="margin: 6px 0 0 16px;">${preview}</ul>
4380-
${remaining > 0 ? `
4397+
${remainingRoutes.length > 0 ? `
43814398
<div class="grouped_recon_routes_all" data-grouped-routes-key="${toggleKey}" style="display:none;">
43824399
<ul style="margin: 6px 0 0 16px;">${allRoutes}</ul>
43834400
</div>
43844401
<p style="margin-top:6px;">
4385-
<a href="#" class="toggle_grouped_recon_routes" data-grouped-routes-key="${toggleKey}" data-expanded="0">Show all routes</a>
4402+
<a href="#" class="toggle_grouped_recon_routes" data-grouped-routes-key="${toggleKey}" data-expanded="0">More</a>
43864403
</p>
43874404
` : ''}
43884405
</div>
@@ -4420,6 +4437,7 @@ function buildGroupedReconDetailsPayload(entry, resolvedAttack = null) {
44204437
function buildGroupedReconCardHtml(entry) {
44214438
if (!entry?.sampleAttack) return null
44224439
const meta = rutils.getMiscMeta(entry.sampleAttack)
4440+
const confidence = rutils.resolveConfidence(entry.sampleAttack)
44234441
const severityAttr = meta.severity || ''
44244442
const safeRequestId = entry.requestId === null || entry.requestId === undefined || entry.requestId === ''
44254443
? '__ptk_grouped_recon__'
@@ -4439,12 +4457,7 @@ function buildGroupedReconCardHtml(entry) {
44394457
data-severity="${ptk_utils.escapeHtml(severityAttr)}"
44404458
data-request-id="${ptk_utils.escapeHtml(safeRequestId)}"
44414459
data-grouped-recon-key="${keyAttr}">
4442-
<div class="ptk-finding-header">
4443-
<div class="ptk-finding-header-main">${titleHtml}</div>
4444-
</div>
4445-
<div class="description">
4446-
<p>Grouped posture observation to reduce repeated low-signal route cards.</p>
4447-
</div>
4460+
${rutils.renderFindingHeader(titleHtml, confidence)}
44484461
${targetUrl ? `<div class="description"><p>Sample URL: <a href="${safeTarget}" target="_blank">${safeTarget}</a></p></div>` : ''}
44494462
${routesHtml}
44504463
<div class="ui left floated">
@@ -5838,7 +5851,7 @@ jQuery(function () {
58385851
const expanded = String($(this).attr("data-expanded") || "0") === "1"
58395852
$allRoutes.toggle(!expanded)
58405853
$(this).attr("data-expanded", expanded ? "0" : "1")
5841-
$(this).text(expanded ? "Show all routes" : "Hide routes")
5854+
$(this).text(expanded ? "More" : "Less")
58425855
return false
58435856
})
58445857

@@ -6568,7 +6581,9 @@ function bindScanResult(result) {
65686581
const aggregateKey = getPassiveHeadersAggregateFindingKey(enrichedAttack, original)
65696582
if (aggregateKey) {
65706583
const attrValue = (window.CSS && typeof CSS.escape === 'function') ? CSS.escape(aggregateKey) : escAttrValue(aggregateKey)
6571-
if ($(`#attacks_info .attack_info[data-aggregate-key="${attrValue}"]`).length) {
6584+
const $existing = $(`#attacks_info .attack_info[data-aggregate-key="${attrValue}"]`)
6585+
if ($existing.length) {
6586+
$existing.replaceWith(rutils.bindAttack(enrichedAttack, original, attackKey, requestKey))
65726587
return
65736588
}
65746589
}
@@ -7142,7 +7157,9 @@ function flushDastQueue() {
71427157
const aggregateKey = getPassiveHeadersAggregateFindingKey(enrichedAttack, original)
71437158
if (aggregateKey) {
71447159
const attrValue = (window.CSS && typeof CSS.escape === 'function') ? CSS.escape(aggregateKey) : escAttrValue(aggregateKey)
7145-
if ($(`#attacks_info .attack_info[data-aggregate-key="${attrValue}"]`).length) {
7160+
const $existing = $(`#attacks_info .attack_info[data-aggregate-key="${attrValue}"]`)
7161+
if ($existing.length) {
7162+
$existing.replaceWith(rutils.bindAttack(enrichedAttack, original, attackId, requestId))
71467163
return
71477164
}
71487165
}

0 commit comments

Comments
 (0)