mirror of
https://github.com/lunchcat/sif.git
synced 2026-06-12 19:11:25 -07:00
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:
+26
-28
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user