Skip to content

Commit d73e82e

Browse files
committed
fixed/improved SQLi construction
1 parent 36a437e commit d73e82e

File tree

3 files changed

+32
-24
lines changed

3 files changed

+32
-24
lines changed

core/src/main/kotlin/org/evomaster/core/EMConfig.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,10 +2650,9 @@ class EMConfig {
26502650
@Cfg("Maximum allowed baseline response time (in milliseconds) before the malicious payload is applied.")
26512651
var sqliBaselineMaxResponseTimeMs = 2000
26522652

2653-
26542653
@Regex(faultCodeRegex)
26552654
@Cfg("Disable oracles. Provide a comma-separated list of codes to disable. " +
2656-
"By default, all oracles are enabled."
2655+
"By default, all oracles are enabled. Codes are based on WFC (Web Fuzzing Commons)."
26572656
)
26582657
var disabledOracleCodes = ""
26592658

core/src/main/kotlin/org/evomaster/core/problem/rest/service/SecurityRest.kt

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.evomaster.core.problem.enterprise.SampleType
1212
import org.evomaster.core.problem.enterprise.auth.AuthSettings
1313
import org.evomaster.core.problem.enterprise.auth.NoAuth
1414
import org.evomaster.core.problem.externalservice.HostnameResolutionAction
15+
import org.evomaster.core.problem.httpws.HttpWsCallResult
1516
import org.evomaster.core.problem.httpws.auth.HttpWsAuthenticationInfo
1617
import org.evomaster.core.problem.httpws.auth.HttpWsNoAuth
1718
import org.evomaster.core.problem.rest.*
@@ -341,8 +342,9 @@ class SecurityRest {
341342

342343
private fun handleSqlICheck(){
343344

344-
mainloop@ for(action in actionDefinitions){
345+
val K = config.sqliBaselineMaxResponseTimeMs
345346

347+
mainloop@ for(action in actionDefinitions){
346348

347349
// Find individuals with 2xx response for this endpoint
348350
val successfulIndividuals = RestIndividualSelectorUtils.findIndividuals(
@@ -356,41 +358,49 @@ class SecurityRest {
356358
continue
357359
}
358360

359-
// Take the smallest successful individual
360-
val target = successfulIndividuals.minBy { it.individual.size() }
361-
362-
val actionIndex = RestIndividualSelectorUtils.findIndexOfAction(
363-
target,
364-
action.verb,
365-
action.path,
366-
statusGroup = StatusGroup.G_2xx
367-
)
361+
val candidates = successfulIndividuals.mapNotNull { ei ->
362+
val actionIndex = RestIndividualSelectorUtils.findIndexOfAction(
363+
ei,
364+
action.verb,
365+
action.path,
366+
statusGroup = StatusGroup.G_2xx
367+
)
368368

369-
if(actionIndex < 0){
370-
continue
369+
if(actionIndex < 0){
370+
null
371+
} else {
372+
val action = ei.individual.seeMainExecutableActions()[actionIndex]
373+
val result = ei.seeResult(action.getLocalId()) as HttpWsCallResult
374+
val time = result.getResponseTimeMs()
375+
if(time == null || time >= K ){
376+
//make sure the call didn't take too long
377+
null
378+
} else {
379+
// Slice to keep only up to the target action
380+
RestIndividualBuilder.sliceAllCallsInIndividualAfterAction(ei.individual, actionIndex)
381+
}
382+
}
371383
}
372384

373-
// Slice to keep only up to the target action
374-
val sliced = RestIndividualBuilder.sliceAllCallsInIndividualAfterAction(
375-
target.individual,
376-
actionIndex
377-
)
385+
// Take the smallest successful individual
386+
val target = candidates.minBy { it.size() }
378387

379388
// Try each sqli payload (but only add one test per endpoint)
380389
for(payload in SQLI_PAYLOADS){
381390

382391
// Create a copy of the individual
383-
var copy = sliced.copy() as RestIndividual
392+
val copy = target.copy() as RestIndividual
384393
val actionCopy = copy.seeMainExecutableActions().last() as RestCallAction
385394

386395
val genes = GeneUtils.getAllStringFields(actionCopy.parameters)
387396
.filter { it.staticCheckIfImpactPhenotype() }
388397

389398
if(genes.isEmpty()){
390-
continue
399+
continue@mainloop
391400
}
392401
var anySuccess = false
393402

403+
//here we try to modify ALL potential genes
394404
genes.forEach {
395405
gene ->
396406
val leafGene = gene.getLeafGene().getPhenotype()
@@ -413,7 +423,7 @@ class SecurityRest {
413423
continue
414424
}
415425

416-
val newInd = builder.merge(sliced, copy)
426+
val newInd = builder.merge(target, copy)
417427

418428
newInd.modifySampleType(SampleType.SECURITY)
419429
newInd.ensureFlattenedStructure()
@@ -432,7 +442,6 @@ class SecurityRest {
432442
assert(added)
433443
continue@mainloop
434444
}
435-
436445
}
437446
}
438447
}

docs/options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ There are 3 types of options:
9191
|`customNaming`| __Boolean__. Enable custom naming and sorting criteria. *Default value*: `true`.|
9292
|`d`| __Double__. When weight-based mutation rate is enabled, specify a percentage of calculating mutation rate based on a number of candidate genes to mutate. For instance, d = 1.0 means that the mutation rate fully depends on a number of candidate genes to mutate, and d = 0.0 means that the mutation rate fully depends on weights of candidates genes to mutate. *Constraints*: `probability 0.0-1.0`. *Default value*: `0.8`.|
9393
|`dependencyFile`| __String__. Specify a file that saves derived dependencies. *DEBUG option*. *Default value*: `dependencies.csv`.|
94-
|`disabledOracleCodes`| __String__. Disable oracles. Provide a comma-separated list of codes to disable. By default, all oracles are enabled. *Constraints*: `regex (\s*\d{3}\s*(,\s*\d{3}\s*)*)?`. *Default value*: `""`.|
94+
|`disabledOracleCodes`| __String__. Disable oracles. Provide a comma-separated list of codes to disable. By default, all oracles are enabled. Codes are based on WFC (Web Fuzzing Commons). *Constraints*: `regex (\s*\d{3}\s*(,\s*\d{3}\s*)*)?`. *Default value*: `""`.|
9595
|`doCollectImpact`| __Boolean__. Specify whether to collect impact info that provides an option to enable of collecting impact info when archive-based gene selection is disable. *DEBUG option*. *Default value*: `false`.|
9696
|`doesApplyNameMatching`| __Boolean__. Whether to apply text/name analysis to derive relationships between name entities, e.g., a resource identifier with a name of table. *Default value*: `true`.|
9797
|`e_u1f984`| __Boolean__. QWN0aXZhdGUgdGhlIFVuaWNvcm4gTW9kZQ==. *Default value*: `false`.|

0 commit comments

Comments
 (0)