perf: optimize deduplication with map-based o(1) lookups in lfi and sql

replace o(n) slice iteration with map lookups for checking duplicates,
preallocate result slices, reduce lock hold time by separating map check
from result append
This commit is contained in:
vmfunc
2026-01-02 22:58:21 -08:00
parent 582baf2d33
commit aba8c410a6
2 changed files with 50 additions and 54 deletions
+26 -28
View File
@@ -131,8 +131,9 @@ func LFI(targetURL string, timeout time.Duration, threads int, logdir string) (*
lfilog.Infof("Starting LFI reconnaissance...")
result := &LFIResult{
Vulnerabilities: []LFIVulnerability{},
Vulnerabilities: make([]LFIVulnerability, 0, 16),
}
seen := make(map[string]bool)
var mu sync.Mutex
var wg sync.WaitGroup
@@ -232,38 +233,35 @@ func LFI(targetURL string, timeout time.Duration, threads int, logdir string) (*
// check for evidence patterns
for _, evidence := range lfiEvidencePatterns {
if evidence.pattern.MatchString(bodyStr) {
key := item.param + "|" + item.payload.payload
mu.Lock()
// check for duplicates
duplicate := false
for _, v := range result.Vulnerabilities {
if v.Parameter == item.param && v.Payload == item.payload.payload {
duplicate = true
break
}
if seen[key] {
mu.Unlock()
break
}
if !duplicate {
vuln := LFIVulnerability{
URL: testURL,
Parameter: item.param,
Payload: item.payload.payload,
Evidence: evidence.description,
Severity: item.payload.severity,
FileIncluded: item.payload.target,
}
result.Vulnerabilities = append(result.Vulnerabilities, vuln)
seen[key] = true
lfilog.Warnf("LFI vulnerability found: %s in param [%s] - %s",
styles.SeverityHigh.Render(evidence.description),
styles.Highlight.Render(item.param),
styles.Status.Render(item.payload.target))
if logdir != "" {
logger.Write(sanitizedURL, logdir,
fmt.Sprintf("LFI: %s in param [%s] via payload [%s]\n",
evidence.description, item.param, item.payload.payload))
}
vuln := LFIVulnerability{
URL: testURL,
Parameter: item.param,
Payload: item.payload.payload,
Evidence: evidence.description,
Severity: item.payload.severity,
FileIncluded: item.payload.target,
}
result.Vulnerabilities = append(result.Vulnerabilities, vuln)
mu.Unlock()
lfilog.Warnf("LFI vulnerability found: %s in param [%s] - %s",
styles.SeverityHigh.Render(evidence.description),
styles.Highlight.Render(item.param),
styles.Status.Render(item.payload.target))
if logdir != "" {
logger.Write(sanitizedURL, logdir,
fmt.Sprintf("LFI: %s in param [%s] via payload [%s]\n",
evidence.description, item.param, item.payload.payload))
}
break
}
}
+24 -26
View File
@@ -133,9 +133,10 @@ func SQL(targetURL string, timeout time.Duration, threads int, logdir string) (*
sqllog.Infof("Starting SQL reconnaissance...")
result := &SQLResult{
AdminPanels: []SQLAdminPanel{},
DatabaseErrors: []SQLDatabaseError{},
AdminPanels: make([]SQLAdminPanel, 0, 8),
DatabaseErrors: make([]SQLDatabaseError, 0, 8),
}
seenErrors := make(map[string]bool)
var mu sync.Mutex
var wg sync.WaitGroup
@@ -208,7 +209,7 @@ func SQL(targetURL string, timeout time.Duration, threads int, logdir string) (*
wg.Wait()
// check main URL for database errors
checkDatabaseErrors(client, targetURL, sanitizedURL, result, sqllog, logdir, &mu)
checkDatabaseErrors(client, targetURL, sanitizedURL, result, sqllog, logdir, &mu, seenErrors)
// check common endpoints that might expose database errors
errorCheckPaths := []string{
@@ -223,7 +224,7 @@ func SQL(targetURL string, timeout time.Duration, threads int, logdir string) (*
for _, path := range errorCheckPaths {
checkURL := strings.TrimSuffix(targetURL, "/") + path
checkDatabaseErrors(client, checkURL, sanitizedURL, result, sqllog, logdir, &mu)
checkDatabaseErrors(client, checkURL, sanitizedURL, result, sqllog, logdir, &mu, seenErrors)
}
// summary
@@ -276,7 +277,7 @@ func isAdminPanel(body string, panelType string) bool {
}
}
func checkDatabaseErrors(client *http.Client, checkURL, sanitizedURL string, result *SQLResult, sqllog *log.Logger, logdir string, mu *sync.Mutex) {
func checkDatabaseErrors(client *http.Client, checkURL, sanitizedURL string, result *SQLResult, sqllog *log.Logger, logdir string, mu *sync.Mutex, seen map[string]bool) {
resp, err := client.Get(checkURL)
if err != nil {
return
@@ -291,32 +292,29 @@ func checkDatabaseErrors(client *http.Client, checkURL, sanitizedURL string, res
for _, pattern := range databaseErrorPatterns {
if pattern.pattern.MatchString(bodyStr) {
key := checkURL + "|" + pattern.databaseType
mu.Lock()
// check if we already have this error for this URL
found := false
for _, existing := range result.DatabaseErrors {
if existing.URL == checkURL && existing.DatabaseType == pattern.databaseType {
found = true
break
}
if seen[key] {
mu.Unlock()
break
}
if !found {
dbError := SQLDatabaseError{
URL: checkURL,
DatabaseType: pattern.databaseType,
ErrorPattern: pattern.pattern.String(),
}
result.DatabaseErrors = append(result.DatabaseErrors, dbError)
seen[key] = true
sqllog.Warnf("Database error disclosure: %s at [%s]",
styles.SeverityHigh.Render(pattern.databaseType),
styles.Highlight.Render(checkURL))
if logdir != "" {
logger.Write(sanitizedURL, logdir, fmt.Sprintf("Database error disclosure: %s at [%s]\n", pattern.databaseType, checkURL))
}
dbError := SQLDatabaseError{
URL: checkURL,
DatabaseType: pattern.databaseType,
ErrorPattern: pattern.pattern.String(),
}
result.DatabaseErrors = append(result.DatabaseErrors, dbError)
mu.Unlock()
sqllog.Warnf("Database error disclosure: %s at [%s]",
styles.SeverityHigh.Render(pattern.databaseType),
styles.Highlight.Render(checkURL))
if logdir != "" {
logger.Write(sanitizedURL, logdir, fmt.Sprintf("Database error disclosure: %s at [%s]\n", pattern.databaseType, checkURL))
}
break // only report one database type per URL
}
}