Skip to content

Commit

Permalink
Test LFi functions
Browse files Browse the repository at this point in the history
  • Loading branch information
estringana committed Aug 21, 2024
1 parent bb3e3d5 commit b431a34
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 2 deletions.
3 changes: 2 additions & 1 deletion appsec/tests/integration/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ dependencies {

implementation platform('org.testcontainers:testcontainers-bom:1.19.8')
implementation "org.testcontainers:junit-jupiter"
implementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
implementation 'com.flipkart.zjsonpatch:zjsonpatch:0.4.16'
implementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
implementation 'org.junit.jupiter:junit-jupiter-params:5.9.2'
}

test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ import com.datadog.appsec.php.mock_agent.MsgpackHelper
import com.datadog.appsec.php.model.Span
import com.datadog.appsec.php.model.Trace
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.containers.Container

import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.util.stream.Stream;
import org.msgpack.core.MessageUnpacker
import org.msgpack.core.MessagePack

Expand Down Expand Up @@ -208,6 +212,58 @@ trait CommonTests {
assert exploit.frames[2].line == 15
}

static Stream<Arguments> getTestData() {
return Arrays.stream(new Arguments[]{
Arguments.of("file_put_contents", "/tmp/dummy", 9),
Arguments.of("readfile", "/tmp/dummy", 15),
Arguments.of("file_get_contents", "/tmp/dummy", 15),
Arguments.of("fopen", "/tmp/dummy", 12),
Arguments.of("stat", "/tmp/dummy", 15),
Arguments.of("lstat", "/tmp/dummy", 15),
});
}

@ParameterizedTest
@MethodSource("getTestData")
void 'file_put_contents generates 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
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 == "filesystem.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 == "filesystem.php"
assert exploit.frames[1].function == "one"
assert exploit.frames[1].id == 2
assert exploit.frames[1].line == 21
assert exploit.frames[2].file == "filesystem.php"
assert exploit.frames[2].function == "two"
assert exploit.frames[2].id == 3
assert exploit.frames[2].line == 25
assert exploit.frames[3].file == "filesystem.php"
assert exploit.frames[3].function == "three"
assert exploit.frames[3].id == 4
assert exploit.frames[3].line == 28
}

@Test
void 'user blocking'() {
def trace = container.traceFromRequest('/user_id.php?id=user2020') { HttpResponse<InputStream> resp ->
Expand Down
30 changes: 30 additions & 0 deletions appsec/tests/integration/src/test/waf/recommended.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,36 @@
"block"
]
},
{
"id": "rasp-001-001",
"name": "Path traversal attack",
"tags": {
"type": "lfi",
"category": "vulnerability_trigger",
"module": "rasp"
},
"conditions": [
{
"parameters": {
"params": [
{
"address": "server.request.query"
}
],
"resource": [
{
"address": "server.io.fs.file"
}
]
},
"operator": "lfi_detector"
}
],
"transformers": [],
"on_match": [
"stack_trace"
]
},
{
"id": "blk-001-003",
"name": "Block User Addresses",
Expand Down
31 changes: 31 additions & 0 deletions appsec/tests/integration/src/test/www/base/public/filesystem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

function one() {
$function = $_GET['function'];
$path = $_GET['path'];

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

function two() {
one();
}

function three() {
two();
}

three();


echo "OK";
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ public function init(): int
null
);


\DDTrace\install_hook(
'lstat',
self::preHook('lstat'),
Expand Down

0 comments on commit b431a34

Please sign in to comment.