Skip to content

Commit

Permalink
Add SSRF integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
estringana committed Jan 22, 2025
1 parent b514593 commit 2593774
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ trait CommonTests {
assert exploit.frames[2].line == 15
}

static Stream<Arguments> getTestData() {
static Stream<Arguments> getTestLfiData() {
return Arrays.stream(new Arguments[]{
Arguments.of("file_put_contents", "/tmp/dummy", 9),
Arguments.of("readfile", "/tmp/dummy", 15),
Expand All @@ -285,8 +285,8 @@ trait CommonTests {
}

@ParameterizedTest
@MethodSource("getTestData")
void 'file_put_contents generates LFI signal'(String target_function, String path, Integer line) {
@MethodSource("getTestLfiData")
void 'filesystem functions generate LFI signal'(String target_function, String path, Integer line) {
HttpRequest req = container.buildReq('/filesystem.php?function='+target_function+"&path="+path).GET().build()
def trace = container.traceFromRequest(req, ofString()) { HttpResponse<String> re ->
assert re.statusCode() == 200
Expand Down Expand Up @@ -528,4 +528,52 @@ trait CommonTests {
throw new AssertionError("Module has STATIC_TLS flag: $res.stdout")
}
}

static Stream<Arguments> getTestSsrfData() {
return Arrays.stream(new Arguments[]{
Arguments.of("file_get_contents", 12),
Arguments.of("fopen", 9),
});
}

@ParameterizedTest
@MethodSource("getTestSsrfData")
void 'filesystem functions generate SSRF signal'(String target_function, Integer line) {
HttpRequest req = container.buildReq('/ssrf.php?function='+target_function+"&domain=169.254.169.254").GET().build()
def trace = container.traceFromRequest(req, ofString()) { HttpResponse<String> re ->
assert re.statusCode() == 200
assert re.body().contains('OK')
}

Span span = trace.first()

assert span.metrics."_dd.appsec.enabled" == 1.0d
assert span.metrics."_dd.appsec.waf.duration" > 0.0d
assert span.meta."_dd.appsec.event_rules.version" != ''

InputStream stream = new ByteArrayInputStream( span.meta_struct."_dd.stack".decodeBase64() )
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(stream)
List<Object> stacks = []
stacks << MsgpackHelper.unpackSingle(unpacker)
Object exploit = stacks.first().exploit.first()

assert exploit.language == "php"
assert exploit.id ==~ /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/
assert exploit.frames[0].file == "ssrf.php"
assert exploit.frames[0].function == target_function
assert exploit.frames[0].id == 1
assert exploit.frames[0].line == line
assert exploit.frames[1].file == "ssrf.php"
assert exploit.frames[1].function == "one"
assert exploit.frames[1].id == 2
assert exploit.frames[1].line == 18
assert exploit.frames[2].file == "ssrf.php"
assert exploit.frames[2].function == "two"
assert exploit.frames[2].id == 3
assert exploit.frames[2].line == 22
assert exploit.frames[3].file == "ssrf.php"
assert exploit.frames[3].function == "three"
assert exploit.frames[3].id == 4
assert exploit.frames[3].line == 25
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class RemoteConfigTests {
Capability.ASM_CUSTOM_RULES,
Capability.ASM_CUSTOM_BLOCKING_RESPONSE,
Capability.ASM_TRUSTED_IPS,
Capability.ASM_RASP_LFI,
Capability.ASM_RASP_SSRF,
].each { assert it in capSet }

doReq.call(403)
Expand Down
48 changes: 48 additions & 0 deletions appsec/tests/integration/src/test/waf/recommended.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,54 @@
"stack_trace"
]
},
{
"id": "rasp-934-100",
"name": "Server-side request forgery exploit",
"tags": {
"type": "ssrf",
"category": "vulnerability_trigger",
"cwe": "918",
"capec": "1000/225/115/664",
"confidence": "1",
"module": "rasp"
},
"conditions": [
{
"parameters": {
"resource": [
{
"address": "server.io.net.url"
}
],
"params": [
{
"address": "server.request.query"
},
{
"address": "server.request.body"
},
{
"address": "server.request.path_params"
},
{
"address": "grpc.server.request.message"
},
{
"address": "graphql.server.all_resolvers"
},
{
"address": "graphql.server.resolver"
}
]
},
"operator": "ssrf_detector"
}
],
"transformers": [],
"on_match": [
"stack_trace"
]
},
{
"id": "blk-001-003",
"name": "Block User Addresses",
Expand Down
28 changes: 28 additions & 0 deletions appsec/tests/integration/src/test/www/base/public/ssrf.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

function one() {
$function = $_GET['function'];
$path = 'http://'. $_GET['domain'] .'/somewhere/in/the/app';

switch ($function) {
case 'fopen':
fopen($path, 'r');
break;
default:
$function($path);
break;
}
}

function two() {
one();
}

function three() {
two();
}

three();


echo "OK";

0 comments on commit 2593774

Please sign in to comment.