Skip to content

Commit e27d1bf

Browse files
authored
feat(golang): add /rasp/cmdi endpoint + enable CMDi RASP tests on net-http-orchestrion (#7251)
1 parent 8ca7d10 commit e27d1bf

7 files changed

Lines changed: 113 additions & 11 deletions

File tree

manifests/golang.yml

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -238,18 +238,51 @@ manifest:
238238
tests/appsec/rasp/test_api10.py::Test_API10_response_status: v2.4.0
239239
tests/appsec/rasp/test_api10.py::Test_API10_without_downstream_body_analysis_using_max: v2.4.0
240240
tests/appsec/rasp/test_api10.py::Test_API10_without_downstream_body_analysis_using_sample_rate: v2.7.0-dev
241-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_BodyJson: missing_feature
242-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_BodyUrlEncoded: missing_feature
243-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_BodyXml: missing_feature
244-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Capability: missing_feature
245-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Mandatory_SpanTags: missing_feature
246-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Optional_SpanTags: missing_feature
241+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_BodyJson:
242+
- weblog_declaration:
243+
"*": irrelevant (CMDi detection requires orchestrion)
244+
net-http-orchestrion: v2.11.0-dev
245+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_BodyUrlEncoded:
246+
- weblog_declaration:
247+
"*": irrelevant (CMDi detection requires orchestrion)
248+
net-http-orchestrion: v2.11.0-dev
249+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_BodyXml:
250+
- weblog_declaration:
251+
"*": irrelevant (CMDi detection requires orchestrion)
252+
net-http-orchestrion: v2.11.0-dev
253+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Capability:
254+
- weblog_declaration:
255+
"*": irrelevant (CMDi detection requires orchestrion)
256+
net-http-orchestrion: v2.11.0-dev
257+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Mandatory_SpanTags:
258+
- weblog_declaration:
259+
"*": irrelevant (CMDi detection requires orchestrion)
260+
net-http-orchestrion: v2.11.0-dev
261+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Optional_SpanTags:
262+
- weblog_declaration:
263+
"*": irrelevant (CMDi detection requires orchestrion)
264+
net-http-orchestrion: v2.11.0-dev
247265
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Rules_Version: v2.3.0-dev # Possibly earlier
248-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_StackTrace: missing_feature
249-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Telemetry: missing_feature
250-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Telemetry_V2: missing_feature
251-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Telemetry_Variant_Tag: missing_feature
252-
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_UrlQuery: missing_feature
266+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_StackTrace:
267+
- weblog_declaration:
268+
"*": irrelevant (CMDi detection requires orchestrion)
269+
net-http-orchestrion: v2.11.0-dev
270+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Telemetry:
271+
- weblog_declaration:
272+
"*": irrelevant (CMDi detection requires orchestrion)
273+
net-http-orchestrion: v2.11.0-dev
274+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Telemetry_V2:
275+
- weblog_declaration:
276+
"*": irrelevant (CMDi detection requires orchestrion)
277+
net-http-orchestrion: v2.11.0-dev
278+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Telemetry_Variant_Tag:
279+
- weblog_declaration:
280+
"*": irrelevant (CMDi detection requires orchestrion)
281+
net-http-orchestrion: v2.11.0-dev
282+
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_UrlQuery:
283+
- weblog_declaration:
284+
"*": irrelevant (CMDi detection requires orchestrion)
285+
net-http-orchestrion: v2.11.0-dev
253286
tests/appsec/rasp/test_cmdi.py::Test_Cmdi_Waf_Version: v2.3.0-dev # Possibly earlier
254287
tests/appsec/rasp/test_lfi.py::Test_Lfi_BodyJson:
255288
- weblog_declaration:

utils/build/docker/golang/app/_shared/rasp/rasp.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"log"
88
"net/http"
99
"os"
10+
"os/exec"
1011

1112
sqltrace "github.com/DataDog/dd-trace-go/contrib/database/sql/v2"
1213
httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2"
@@ -151,3 +152,66 @@ func SQLi(w http.ResponseWriter, r *http.Request) {
151152
log.Println("unknown error during sql call: ", err.Error())
152153
}
153154
}
155+
156+
func parseCommandRASPRequest(r *http.Request) []string {
157+
switch r.Method {
158+
case http.MethodGet:
159+
return []string{r.URL.Query().Get("command")}
160+
case http.MethodPost:
161+
switch r.Header.Get("Content-Type") {
162+
case "application/json":
163+
var body struct {
164+
Command []string `json:"command"`
165+
}
166+
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
167+
log.Fatalf("failed to parse body: %v\n", err)
168+
}
169+
if err := appsec.MonitorParsedHTTPBody(r.Context(), map[string]any{"command": body.Command}); err != nil {
170+
log.Fatalf("Body Monitoring should not block the request: %v\n", err)
171+
}
172+
return body.Command
173+
case "application/xml":
174+
var body struct {
175+
Command []string `xml:"cmd"`
176+
}
177+
if err := xml.NewDecoder(r.Body).Decode(&body); err != nil {
178+
log.Fatalf("failed to parse body: %v\n", err)
179+
}
180+
if err := appsec.MonitorParsedHTTPBody(r.Context(), map[string]any{"command": body.Command}); err != nil {
181+
log.Fatalf("Body Monitoring should not block the request: %v\n", err)
182+
}
183+
return body.Command
184+
case "application/x-www-form-urlencoded":
185+
if err := r.ParseForm(); err != nil {
186+
log.Fatalf("failed to parse body: %v\n", err)
187+
}
188+
command := r.Form.Get("command")
189+
if err := appsec.MonitorParsedHTTPBody(r.Context(), map[string]string{"command": command}); err != nil {
190+
log.Fatalf("Body Monitoring should not block the request: %v\n", err)
191+
}
192+
return []string{command}
193+
default:
194+
log.Fatalln("unsupported content type")
195+
}
196+
default:
197+
log.Fatalln("method not allowed")
198+
}
199+
200+
return nil
201+
}
202+
203+
func CMDI(w http.ResponseWriter, r *http.Request) {
204+
command := parseCommandRASPRequest(r)
205+
if len(command) == 0 {
206+
return
207+
}
208+
209+
err := (&exec.Cmd{Path: command[0], Args: command}).Run()
210+
if events.IsSecurityError(err) {
211+
return
212+
}
213+
214+
if err != nil {
215+
log.Println("unknown error during command execution: ", err.Error())
216+
}
217+
}

utils/build/docker/golang/app/chi/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ func main() {
368368
mux.HandleFunc("/rasp/multiple", rasp.LFIMultiple)
369369
mux.HandleFunc("/rasp/ssrf", rasp.SSRF)
370370
mux.HandleFunc("/rasp/sqli", rasp.SQLi)
371+
mux.HandleFunc("/rasp/cmdi", rasp.CMDI)
371372

372373
mux.HandleFunc("/external_request", rasp.ExternalRequest)
373374
mux.HandleFunc("GET /external_request/redirect", rasp.ExternalRedirectRequest)

utils/build/docker/golang/app/echo/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ func main() {
377377
r.Any("/rasp/multiple", echoHandleFunc(rasp.LFIMultiple))
378378
r.Any("/rasp/ssrf", echoHandleFunc(rasp.SSRF))
379379
r.Any("/rasp/sqli", echoHandleFunc(rasp.SQLi))
380+
r.Any("/rasp/cmdi", echoHandleFunc(rasp.CMDI))
380381

381382
r.Any("/external_request", echoHandleFunc(rasp.ExternalRequest))
382383
r.GET("/external_request/redirect", echoHandleFunc(rasp.ExternalRedirectRequest))

utils/build/docker/golang/app/gin/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ func main() {
363363
r.Any("/rasp/multiple", ginHandleFunc(rasp.LFIMultiple))
364364
r.Any("/rasp/ssrf", ginHandleFunc(rasp.SSRF))
365365
r.Any("/rasp/sqli", ginHandleFunc(rasp.SQLi))
366+
r.Any("/rasp/cmdi", ginHandleFunc(rasp.CMDI))
366367

367368
r.Any("/external_request", ginHandleFunc(rasp.ExternalRequest))
368369
r.GET("/external_request/redirect", ginHandleFunc(rasp.ExternalRedirectRequest))

utils/build/docker/golang/app/net-http-orchestrion/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ func main() {
613613
mux.HandleFunc("/rasp/multiple", rasp.LFIMultiple)
614614
mux.HandleFunc("/rasp/ssrf", rasp.SSRF)
615615
mux.HandleFunc("/rasp/sqli", rasp.SQLi)
616+
mux.HandleFunc("/rasp/cmdi", rasp.CMDI)
616617

617618
mux.HandleFunc("/external_request", rasp.ExternalRequest)
618619
mux.HandleFunc("GET /external_request/redirect", rasp.ExternalRedirectRequest)

utils/build/docker/golang/app/net-http/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ func main() {
753753
mux.HandleFunc("/rasp/multiple", rasp.LFIMultiple)
754754
mux.HandleFunc("/rasp/ssrf", rasp.SSRF)
755755
mux.HandleFunc("/rasp/sqli", rasp.SQLi)
756+
mux.HandleFunc("/rasp/cmdi", rasp.CMDI)
756757

757758
mux.HandleFunc("/add_event", func(w http.ResponseWriter, r *http.Request) {
758759
span, ok := tracer.SpanFromContext(r.Context())

0 commit comments

Comments
 (0)