Skip to content

Commit

Permalink
Add Command and Shell injections test for Java (#3691)
Browse files Browse the repository at this point in the history
Motivation
Test Command and Shell injections in Java

Changes
Fix errors in the command injection test file
Add java endpoints
  • Loading branch information
jandro996 authored Dec 20, 2024
1 parent e62d3ec commit 57a2ea5
Show file tree
Hide file tree
Showing 13 changed files with 860 additions and 37 deletions.
103 changes: 101 additions & 2 deletions manifests/java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,59 @@ tests/:
vertx3: missing_feature
vertx4: missing_feature
rasp/:
test_cmdi.py: missing_feature
test_cmdi.py:
Test_Cmdi_BodyJson:
'*': v1.45.0
akka-http: missing_feature (APPSEC-56196)
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
vertx4: missing_feature (APPSEC-55785)
Test_Cmdi_BodyUrlEncoded:
'*': v1.45.0
akka-http: missing_feature (APPSEC-56196)
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Cmdi_BodyXml:
'*': v1.45.0
akka-http: missing_feature (APPSEC-55780)
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
vertx3: missing_feature (APPSEC-55788)
vertx4: missing_feature (APPSEC-55786)
Test_Cmdi_Capability:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Cmdi_Mandatory_SpanTags:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Cmdi_Optional_SpanTags:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Cmdi_Rules_Version:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Cmdi_StackTrace:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Cmdi_Telemetry:
'*': v1.45.0
akka-http: missing_feature (APPSEC-56196)
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Cmdi_Telemetry_Variant_Tag:
'*': v1.45.0
akka-http: missing_feature (APPSEC-56196)
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Cmdi_UrlQuery:
'*': v1.45.0
akka-http: missing_feature (APPSEC-56196)
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Cmdi_Waf_Version:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
test_lfi.py:
Test_Lfi_BodyJson:
'*': v1.40.0
Expand Down Expand Up @@ -610,7 +662,54 @@ tests/:
Test_Lfi_Waf_Version:
'*': v1.40.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
test_shi.py: irrelevant (Not support in Java)
test_shi.py:
Test_Shi_BodyJson:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
vertx4: missing_feature (APPSEC-55785)
Test_Shi_BodyUrlEncoded:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Shi_BodyXml:
'*': v1.45.0
akka-http: missing_feature (APPSEC-55780)
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
vertx3: missing_feature (APPSEC-55788)
vertx4: missing_feature (APPSEC-55786)
Test_Shi_Capability:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Shi_Mandatory_SpanTags:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Shi_Optional_SpanTags:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Shi_Rules_Version:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
Test_Shi_StackTrace:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Shi_Telemetry:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Shi_Telemetry_Variant_Tag:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Shi_UrlQuery:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
spring-boot-payara: missing_feature (APPSEC-54966)
Test_Shi_Waf_Version:
'*': v1.45.0
spring-boot-3-native: missing_feature (GraalVM. Tracing support only)
# SQLi was introduced in v1.38.0 (with RASP disabled by default, but was flaky)
test_sqli.py:
Test_Sqli_BodyJson:
Expand Down
68 changes: 44 additions & 24 deletions tests/appsec/rasp/test_cmdi.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
@features.rasp_command_injection
@scenarios.appsec_rasp
class Test_Cmdi_UrlQuery:
"""Shell Injection through query parameters"""
"""Command Injection through query parameters"""

def setup_cmdi_get(self):
self.r = weblog.get("/rasp/cmdi", params={"command": "/bin/evilCommand"})
self.r = weblog.get("/rasp/cmdi", params={"command": "/usr/bin/touch /tmp/passwd"})

def test_cmdi_get(self):
assert self.r.status_code == 403
Expand All @@ -30,8 +30,14 @@ def test_cmdi_get(self):
self.r,
"rasp-932-110",
{
"resource": {"address": "server.sys.exec.cmd", "value": "/bin/evilCommand"},
"params": {"address": "server.request.query", "value": "/bin/evilCommand"},
"resource": {
"address": "server.sys.exec.cmd",
"value": "/usr/bin/touch /tmp/passwd",
},
"params": {
"address": "server.request.query",
"value": "/usr/bin/touch /tmp/passwd",
},
},
)

Expand All @@ -40,10 +46,10 @@ def test_cmdi_get(self):
@features.rasp_command_injection
@scenarios.appsec_rasp
class Test_Cmdi_BodyUrlEncoded:
"""Shell Injection through a url-encoded body parameter"""
"""Command Injection through a url-encoded body parameter"""

def setup_cmdi_post_urlencoded(self):
self.r = weblog.post("/rasp/cmdi", data={"command": "/bin/evilCommand"})
self.r = weblog.post("/rasp/cmdi", data={"command": "/usr/bin/touch /tmp/passwd"})

def test_cmdi_post_urlencoded(self):
assert self.r.status_code == 403
Expand All @@ -52,8 +58,14 @@ def test_cmdi_post_urlencoded(self):
self.r,
"rasp-932-110",
{
"resource": {"address": "server.sys.exec.cmd", "value": "/bin/evilCommand"},
"params": {"address": "server.request.body", "value": "/bin/evilCommand"},
"resource": {
"address": "server.sys.exec.cmd",
"value": "/usr/bin/touch /tmp/passwd",
},
"params": {
"address": "server.request.body",
"value": "/usr/bin/touch /tmp/passwd",
},
},
)

Expand All @@ -62,10 +74,12 @@ def test_cmdi_post_urlencoded(self):
@features.rasp_command_injection
@scenarios.appsec_rasp
class Test_Cmdi_BodyXml:
"""Shell Injection through an xml body parameter"""
"""Command Injection through an xml body parameter"""

def setup_cmdi_post_xml(self):
data = "<?xml version='1.0' encoding='utf-8'?><command>/bin/evilCommand</command>"
data = (
"<?xml version='1.0' encoding='utf-8'?><command><cmd>/usr/bin/touch</cmd><cmd>/tmp/passwd</cmd></command>"
)
self.r = weblog.post("/rasp/cmdi", data=data, headers={"Content-Type": "application/xml"})

def test_cmdi_post_xml(self):
Expand All @@ -75,8 +89,8 @@ def test_cmdi_post_xml(self):
self.r,
"rasp-932-110",
{
"resource": {"address": "server.sys.exec.cmd", "value": "/bin/evilCommand"},
"params": {"address": "server.request.body", "value": "/bin/evilCommand"},
"resource": {"address": "server.sys.exec.cmd", "value": '/usr/bin/touch "/tmp/passwd"'},
"params": {"address": "server.request.body", "value": "/usr/bin/touch"},
},
)

Expand All @@ -85,11 +99,11 @@ def test_cmdi_post_xml(self):
@features.rasp_command_injection
@scenarios.appsec_rasp
class Test_Cmdi_BodyJson:
"""Shell Injection through a json body parameter"""
"""Command Injection through a json body parameter"""

def setup_cmdi_post_json(self):
"""AppSec detects attacks in JSON body values"""
self.r = weblog.post("/rasp/cmdi", json={"command": "/bin/evilCommand"})
self.r = weblog.post("/rasp/cmdi", json={"command": ["/usr/bin/touch", "/tmp/passwd"]})

def test_cmdi_post_json(self):
assert self.r.status_code == 403
Expand All @@ -98,8 +112,14 @@ def test_cmdi_post_json(self):
self.r,
"rasp-932-110",
{
"resource": {"address": "server.sys.exec.cmd", "value": "/bin/evilCommand"},
"params": {"address": "server.request.body", "value": "/bin/evilCommand"},
"resource": {
"address": "server.sys.exec.cmd",
"value": '/usr/bin/touch "/tmp/passwd"',
},
"params": {
"address": "server.request.body",
"value": "/usr/bin/touch",
},
},
)

Expand All @@ -112,7 +132,7 @@ class Test_Cmdi_Mandatory_SpanTags:
"""Validate span tag generation on exploit attempts"""

def setup_cmdi_span_tags(self):
self.r = weblog.get("/rasp/cmdi", params={"command": "/bin/evilCommand"})
self.r = weblog.get("/rasp/cmdi", params={"command": "/usr/bin/touch /tmp/passwd"})

def test_cmdi_span_tags(self):
validate_span_tags(self.r, expected_metrics=["_dd.appsec.rasp.duration"])
Expand All @@ -126,7 +146,7 @@ class Test_Cmdi_Optional_SpanTags:
"""Validate span tag generation on exploit attempts"""

def setup_cmdi_span_tags(self):
self.r = weblog.get("/rasp/cmdi", params={"command": "/bin/evilCommand"})
self.r = weblog.get("/rasp/cmdi", params={"command": "/usr/bin/touch /tmp/passwd"})

def test_cmdi_span_tags(self):
validate_span_tags(self.r, expected_metrics=["_dd.appsec.rasp.duration_ext", "_dd.appsec.rasp.rule.eval"])
Expand All @@ -140,7 +160,7 @@ class Test_Cmdi_StackTrace:
"""Validate stack trace generation on exploit attempts"""

def setup_cmdi_stack_trace(self):
self.r = weblog.get("/rasp/cmdi", params={"command": "/bin/evilCommand"})
self.r = weblog.get("/rasp/cmdi", params={"command": "/usr/bin/touch /tmp/passwd"})

def test_cmdi_stack_trace(self):
assert self.r.status_code == 403
Expand All @@ -154,7 +174,7 @@ class Test_Cmdi_Telemetry:
"""Validate Telemetry data on exploit attempts"""

def setup_cmdi_telemetry(self):
self.r = weblog.get("/rasp/cmdi", params={"command": "/bin/evilCommand"})
self.r = weblog.get("/rasp/cmdi", params={"command": "/usr/bin/touch /tmp/passwd"})

def test_cmdi_telemetry(self):
assert self.r.status_code == 403
Expand All @@ -173,13 +193,13 @@ def test_cmdi_telemetry(self):


@rfc("https://docs.google.com/document/d/1DDWy3frMXDTAbk-BfnZ1FdRwuPx6Pl7AWyR4zjqRFZw")
@features.rasp_shell_injection
@features.rasp_command_injection
@scenarios.appsec_rasp
class Test_Cmdi_Telemetry_Variant_Tag:
"""Validate Telemetry data variant tag on exploit attempts"""

def setup_cmdi_telemetry(self):
self.r = weblog.get("/rasp/cmdi", params={"command": "/bin/evilCommand"})
self.r = weblog.get("/rasp/cmdi", params={"command": "/usr/bin/touch /tmp/passwd"})

def test_cmdi_telemetry(self):
assert self.r.status_code == 403
Expand All @@ -192,7 +212,7 @@ def test_cmdi_telemetry(self):

series_match = find_series(True, "appsec", "rasp.rule.match")
assert series_match
assert any(validate_metric_variant("rasp.rule.match", "command_injection", "shell", s) for s in series_match), [
assert any(validate_metric_variant("rasp.rule.match", "command_injection", "exec", s) for s in series_match), [
s.get("tags") for s in series_match
]

Expand All @@ -214,7 +234,7 @@ class Test_Cmdi_Rules_Version(Base_Rules_Version):
min_version = "1.13.3"


@features.rasp_local_file_inclusion
@features.rasp_command_injection
class Test_Cmdi_Waf_Version(Base_WAF_Version):
"""Test cmdi WAF version"""

Expand Down
26 changes: 17 additions & 9 deletions tests/appsec/rasp/test_shi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2021 Datadog, Inc.

from utils import features, weblog, interfaces, scenarios, rfc
from utils import features, weblog, interfaces, scenarios, rfc, context
from utils.dd_constants import Capabilities
from tests.appsec.rasp.utils import (
validate_span_tags,
Expand All @@ -15,10 +15,18 @@
)


class Test_Shi_Base:
def get_shell_value(self):
# This is a workaround for java as command injection is not supporting String commands yet, we need to use the shell injection heuristics
if context.library == "java":
return "$(cat /etc/passwd 1>&2 ; echo .)"
return "ls $(cat /etc/passwd 1>&2 ; echo .)"


@rfc("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx")
@features.rasp_shell_injection
@scenarios.appsec_rasp
class Test_Shi_UrlQuery:
class Test_Shi_UrlQuery(Test_Shi_Base):
"""Shell Injection through query parameters"""

def setup_shi_get(self):
Expand All @@ -31,7 +39,7 @@ def test_shi_get(self):
self.r,
"rasp-932-100",
{
"resource": {"address": "server.sys.shell.cmd", "value": "ls $(cat /etc/passwd 1>&2 ; echo .)"},
"resource": {"address": "server.sys.shell.cmd", "value": self.get_shell_value()},
"params": {"address": "server.request.query", "value": "$(cat /etc/passwd 1>&2 ; echo .)"},
},
)
Expand All @@ -40,7 +48,7 @@ def test_shi_get(self):
@rfc("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx")
@features.rasp_shell_injection
@scenarios.appsec_rasp
class Test_Shi_BodyUrlEncoded:
class Test_Shi_BodyUrlEncoded(Test_Shi_Base):
"""Shell Injection through a url-encoded body parameter"""

def setup_shi_post_urlencoded(self):
Expand All @@ -53,7 +61,7 @@ def test_shi_post_urlencoded(self):
self.r,
"rasp-932-100",
{
"resource": {"address": "server.sys.shell.cmd", "value": "ls $(cat /etc/passwd 1>&2 ; echo .)"},
"resource": {"address": "server.sys.shell.cmd", "value": self.get_shell_value()},
"params": {"address": "server.request.body", "value": "$(cat /etc/passwd 1>&2 ; echo .)"},
},
)
Expand All @@ -62,7 +70,7 @@ def test_shi_post_urlencoded(self):
@rfc("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx")
@features.rasp_shell_injection
@scenarios.appsec_rasp
class Test_Shi_BodyXml:
class Test_Shi_BodyXml(Test_Shi_Base):
"""Shell Injection through an xml body parameter"""

def setup_shi_post_xml(self):
Expand All @@ -76,7 +84,7 @@ def test_shi_post_xml(self):
self.r,
"rasp-932-100",
{
"resource": {"address": "server.sys.shell.cmd", "value": "ls $(cat /etc/passwd 1>&2 ; echo .)"},
"resource": {"address": "server.sys.shell.cmd", "value": self.get_shell_value()},
"params": {"address": "server.request.body", "value": "$(cat /etc/passwd 1>&2 ; echo .)"},
},
)
Expand All @@ -85,7 +93,7 @@ def test_shi_post_xml(self):
@rfc("https://docs.google.com/document/d/1gCXU3LvTH9en3Bww0AC2coSJWz1m7HcavZjvMLuDCWg/edit#heading=h.giijrtyn1fdx")
@features.rasp_shell_injection
@scenarios.appsec_rasp
class Test_Shi_BodyJson:
class Test_Shi_BodyJson(Test_Shi_Base):
"""Shell Injection through a json body parameter"""

def setup_shi_post_json(self):
Expand All @@ -99,7 +107,7 @@ def test_shi_post_json(self):
self.r,
"rasp-932-100",
{
"resource": {"address": "server.sys.shell.cmd", "value": "ls $(cat /etc/passwd 1>&2 ; echo .)"},
"resource": {"address": "server.sys.shell.cmd", "value": self.get_shell_value()},
"params": {"address": "server.request.body", "value": "$(cat /etc/passwd 1>&2 ; echo .)"},
},
)
Expand Down
Loading

0 comments on commit 57a2ea5

Please sign in to comment.