Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SSRFBaseEMTest : SpringTestBase() {
@Test
fun testSSRFEM() {
runTestHandlingFlakyAndCompilation(
"SSRFBaseEMTest",
"SSRFBaseGeneratedTest",
50,
) { args: MutableList<String> ->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SSRFHeaderEMTest: SpringTestBase() {
@Test
fun testSSRFHeader() {
runTestHandlingFlakyAndCompilation(
"SSRFHeaderEMTest",
"SSRFHeaderGeneratedTest",
30,
) { args: MutableList<String> ->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class SSRFPathEMTest: SpringTestBase() {
@Test
fun testSSRFPathVariable() {
runTestHandlingFlakyAndCompilation(
"SSRFPathEMTest",
"SSRFPathGeneratedTest",
200,
) { args: MutableList<String> ->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SSRFQueryEMTest: SpringTestBase() {
@Test
fun testSSRFQuery() {
runTestHandlingFlakyAndCompilation(
"SSRFQueryEMTest",
"SSRFQueryGeneratedTest",
30,
) { args: MutableList<String> ->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.evomaster.core.problem.httpws.HttpWsAction
import org.evomaster.core.problem.httpws.HttpWsCallResult
import org.evomaster.core.problem.rest.param.BodyParam
import org.evomaster.core.problem.rest.param.HeaderParam
import org.evomaster.core.problem.security.data.ActionStubMapping
import org.evomaster.core.problem.security.service.HttpCallbackVerifier
import org.evomaster.core.search.EvaluatedIndividual
import org.evomaster.core.search.FitnessValue
Expand All @@ -29,6 +30,7 @@ import org.evomaster.core.search.gene.wrapper.ChoiceGene
import org.slf4j.LoggerFactory
import java.nio.file.Path
import javax.ws.rs.core.MediaType
import kotlin.collections.filter


abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
Expand Down Expand Up @@ -349,7 +351,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
val res = evaluatedAction.result as HttpWsCallResult

if (config.ssrf && res.getVulnerableForSSRF()) {
handleSSRFFaults(lines, call)
handleSSRFFaultsPrologue(lines, call)
}

if (res.failedCall()) {
Expand All @@ -358,6 +360,10 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
addActionLines(call, index, testCaseName, lines, res, testSuitePath, baseUrlOfSut)
}

if (config.ssrf && res.getVulnerableForSSRF()) {
handleSSRFFaultsEpilogue(lines, call)
}

// reset all used external service action
if (exActions.isNotEmpty()) {
if (!format.isJavaOrKotlin()) {
Expand Down Expand Up @@ -795,7 +801,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
/**
* Method to set up stub for HttpCallbackVerifier to the test case.
*/
private fun handleSSRFFaults(lines: Lines, action: Action) {
private fun handleSSRFFaultsPrologue(lines: Lines, action: Action) {
val verifier = httpCallbackVerifier.getActionVerifierMapping(action.getName())

if (verifier != null) {
Expand All @@ -805,23 +811,60 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
if (format.isKotlin()) {
lines.addStatement("assertNotNull(${verifier.getVerifierName()}.isRunning)")
}

lines.addEmpty(1)

lines.addStatement("${verifier.getVerifierName()}.stubFor(get(\"${verifier.stub}\")")
//Reset verifier before test execution.
lines.addStatement("${verifier.getVerifierName()}.resetAll()")

lines.add("${verifier.getVerifierName()}.stubFor(")
lines.indented {
lines.addStatement(".atPriority(1)")
lines.addStatement(".willReturn(")
lines.add("get(\"${verifier.stub}\")")
lines.indented {
lines.addStatement("aResponse()")
lines.addStatement(".withStatus(${HttpCallbackVerifier.SSRF_RESPONSE_STATUS_CODE})")
lines.addStatement(".withBody(\"${HttpCallbackVerifier.SSRF_RESPONSE_BODY}\")")
lines.add(".withMetadata(Metadata.metadata().attr(\"ssrf\", \"${action.getName()}\"))")
lines.add(".atPriority(1)")
lines.add(".willReturn(")
lines.indented {
lines.add("aResponse()")
lines.indented {
lines.add(".withStatus(${HttpCallbackVerifier.SSRF_RESPONSE_STATUS_CODE})")
lines.add(".withBody(\"${HttpCallbackVerifier.SSRF_RESPONSE_BODY}\")")
}
}
lines.add(")")
}
lines.addStatement(")")
}
lines.addStatement(")")
lines.addEmpty(1)
handleCallbackVerifierRequests(lines, action, verifier, false)
lines.addEmpty(1)
}
}

private fun handleSSRFFaultsEpilogue(lines: Lines, action: Action) {
val verifier = httpCallbackVerifier.getActionVerifierMapping(action.getName())

if (verifier != null) {
lines.addEmpty(1)
handleCallbackVerifierRequests(lines, action, verifier, true)
}
}

private fun handleCallbackVerifierRequests(lines: Lines, action: Action, verifier: ActionStubMapping, assertTrue: Boolean) {
if (assertTrue) {
lines.addSingleCommentLine("Verifying that the request is successfully made to HttpCallbackVerifier after test execution.")
lines.add("assertTrue(${verifier.getVerifierName()}")
} else {
lines.addSingleCommentLine("Verifying that there are no requests made to HttpCallbackVerifier before test execution.")
lines.add("assertFalse(${verifier.getVerifierName()}")
}
lines.indented {
if (format.isKotlin()) {
lines.add(".allServeEvents")
lines.add(".filter { it.wasMatched && it.stubMapping.metadata != null }")
lines.add(".any { it.stubMapping.metadata.getString(\"ssrf\") == \"${action.getName()}\" }")
}
}
lines.add(")")
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.evomaster.core.output.service

import com.google.inject.Inject
import org.evomaster.client.java.controller.api.dto.SqlDtoUtils
import org.evomaster.client.java.controller.api.dto.database.operations.InsertionDto
import org.evomaster.client.java.controller.api.dto.database.operations.MongoInsertionDto
import org.evomaster.client.java.instrumentation.shared.ExternalServiceSharedUtils
Expand All @@ -24,7 +23,6 @@ import org.evomaster.core.remote.service.RemoteController
import org.evomaster.core.search.Solution
import org.evomaster.core.search.service.Sampler
import org.evomaster.core.search.service.SearchTimeController
import org.evomaster.core.sql.schema.Table
import org.evomaster.core.sql.schema.TableId
import org.evomaster.test.utils.EMTestUtils
import org.evomaster.test.utils.SeleniumEMUtils
Expand Down Expand Up @@ -457,6 +455,7 @@ class TestSuiteWriter {
|| (config.ssrf && solution.hasSsrfFaults())) {
addImport("com.github.tomakehurst.wiremock.client.WireMock.*", lines, true)
addImport("com.github.tomakehurst.wiremock.WireMockServer", lines)
addImport("com.github.tomakehurst.wiremock.common.Metadata", lines)
addImport("com.github.tomakehurst.wiremock.core.WireMockConfiguration", lines)
addImport(
"com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class SSRFAnalyser {
// selecting individuals with HTTP 400 and 422 status codes.
val individualsWith4XX = getIndividualsWithStatus4XX()

individualsInSolution = individualsWith2XX + individualsWith4XX
individualsInSolution = individualsWith2XX + individualsWith4XX

if (individualsInSolution.isEmpty()) {
return archive.extractSolution()
Expand All @@ -121,8 +121,8 @@ class SSRFAnalyser {
// Classify endpoints with potential vulnerability classes
classify()

// execute
analyse()
// evaluate
evaluate()

return archive.extractSolution()
}
Expand Down Expand Up @@ -264,7 +264,7 @@ class SSRFAnalyser {
/**
* Run the determined vulnerability class (from the classification) analysers.
*/
private fun analyse() {
private fun evaluate() {
if (config.problemType == EMConfig.ProblemType.REST) {

individualsInSolution.forEach { evaluatedIndividual ->
Expand Down Expand Up @@ -346,7 +346,7 @@ class SSRFAnalyser {
private fun getIndividualsWithStatus4XX(): List<EvaluatedIndividual<RestIndividual>> {
return RestIndividualSelectorUtils.findIndividuals(
this.archive.extractSolution().individuals,
statusCodes = listOf(400, 422)
statusCodes = listOf(422)
)
}
}