Skip to content

Commit e2ff162

Browse files
[python] add support for SHi and CMDi tests for python (#3791)
1 parent 2d8d3da commit e2ff162

File tree

5 files changed

+94
-13
lines changed

5 files changed

+94
-13
lines changed

manifests/python.yml

+11-11
Original file line numberDiff line numberDiff line change
@@ -245,17 +245,17 @@ tests/:
245245
TestURI: missing_feature
246246
rasp/:
247247
test_cmdi.py:
248-
Test_Cmdi_BodyJson: missing_feature
249-
Test_Cmdi_BodyUrlEncoded: missing_feature
250-
Test_Cmdi_BodyXml: missing_feature
251-
Test_Cmdi_Capability: missing_feature
252-
Test_Cmdi_Mandatory_SpanTags: missing_feature
253-
Test_Cmdi_Optional_SpanTags: missing_feature
248+
Test_Cmdi_BodyJson: v2.20.0.dev
249+
Test_Cmdi_BodyUrlEncoded: v2.20.0.dev
250+
Test_Cmdi_BodyXml: v2.20.0.dev
251+
Test_Cmdi_Capability: v2.20.0.dev
252+
Test_Cmdi_Mandatory_SpanTags: v2.20.0.dev
253+
Test_Cmdi_Optional_SpanTags: v2.20.0.dev
254254
Test_Cmdi_Rules_Version: v2.18.0.dev
255-
Test_Cmdi_StackTrace: missing_feature
256-
Test_Cmdi_Telemetry: missing_feature
257-
Test_Cmdi_Telemetry_Variant_Tag: missing_feature
258-
Test_Cmdi_UrlQuery: missing_feature
255+
Test_Cmdi_StackTrace: v2.20.0.dev
256+
Test_Cmdi_Telemetry: v2.20.0.dev
257+
Test_Cmdi_Telemetry_Variant_Tag: v2.20.0.dev
258+
Test_Cmdi_UrlQuery: v2.20.0.dev
259259
Test_Cmdi_Waf_Version: v2.18.0.dev
260260
test_lfi.py:
261261
Test_Lfi_BodyJson: v2.10.0
@@ -280,7 +280,7 @@ tests/:
280280
Test_Shi_Rules_Version: v2.15.0
281281
Test_Shi_StackTrace: v2.11.0-rc2
282282
Test_Shi_Telemetry: v2.11.0-rc2
283-
Test_Shi_Telemetry_Variant_Tag: missing_feature
283+
Test_Shi_Telemetry_Variant_Tag: v2.20.0.dev
284284
Test_Shi_UrlQuery: v2.11.0-rc2
285285
Test_Shi_Waf_Version: v2.15.0
286286
test_sqli.py:

utils/build/docker/python/django/app/urls.py

+27
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,32 @@ def rasp_shi(request, *args, **kwargs):
257257
return HttpResponse(f"Shell command failure: {e!r}", status=201)
258258

259259

260+
@csrf_exempt
261+
def rasp_cmdi(request, *args, **kwargs):
262+
cmd = None
263+
if request.method == "GET":
264+
cmd = request.GET.get("command")
265+
elif request.method == "POST":
266+
try:
267+
cmd = (request.POST or json.loads(request.body)).get("command")
268+
except Exception as e:
269+
print(repr(e), file=sys.stderr)
270+
try:
271+
if cmd is None:
272+
cmd = xmltodict.parse(request.body).get("command").get("cmd")
273+
except Exception as e:
274+
print(repr(e), file=sys.stderr)
275+
pass
276+
277+
if cmd is None:
278+
return HttpResponse("missing command parameter", status=400)
279+
try:
280+
res = subprocess.run(cmd, capture_output=True)
281+
return HttpResponse(f"Exec command [{cmd}] with result: {res}")
282+
except Exception as e:
283+
return HttpResponse(f"Shell command [{cmd}] failure: {e!r}", status=201)
284+
285+
260286
### END EXPLOIT PREVENTION
261287

262288

@@ -853,6 +879,7 @@ def s3_multipart_upload(request):
853879
path("returnheaders", return_headers),
854880
path("returnheaders/", return_headers),
855881
path("set_cookie", set_cookie),
882+
path("rasp/cmdi", rasp_cmdi),
856883
path("rasp/lfi", rasp_lfi),
857884
path("rasp/shi", rasp_shi),
858885
path("rasp/sqli", rasp_sqli),

utils/build/docker/python/fastapi/main.py

+28
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,34 @@ async def rasp_shi(request: Request):
291291
return PlainTextResponse(f"Shell command failure: {e!r}", status_code=201)
292292

293293

294+
@app.get("/rasp/cmdi")
295+
@app.post("/rasp/cmdi")
296+
async def rasp_cmdi(request: Request):
297+
cmd = None
298+
if request.method == "GET":
299+
cmd = request.query_params.get("command")
300+
elif request.method == "POST":
301+
body = await request.body()
302+
try:
303+
cmd = ((await request.form()) or json.loads(body) or {}).get("command")
304+
except Exception as e:
305+
print(repr(e), file=sys.stderr)
306+
try:
307+
if cmd is None:
308+
cmd = xmltodict.parse(body).get("command").get("cmd")
309+
except Exception as e:
310+
print(repr(e), file=sys.stderr)
311+
pass
312+
313+
if cmd is None:
314+
return PlainTextResponse("missing command parameter", status_code=400)
315+
try:
316+
res = subprocess.run(cmd, capture_output=True)
317+
return PlainTextResponse(f"Exec command [{cmd}] with result: {res}")
318+
except Exception as e:
319+
return PlainTextResponse(f"Exec command [{cmd}] failure: {e!r}", status_code=201)
320+
321+
294322
### END EXPLOIT PREVENTION
295323

296324

utils/build/docker/python/flask/app.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ def rasp_shi(*args, **kwargs):
345345
pass
346346

347347
if list_dir is None:
348-
return "missing user_id parameter", 400
348+
return "missing list_dir parameter", 400
349349
try:
350350
command = f"ls {list_dir}"
351351
res = os.system(command)
@@ -355,6 +355,32 @@ def rasp_shi(*args, **kwargs):
355355
return f"Shell command failure: {e!r}", 201
356356

357357

358+
@app.route("/rasp/cmdi", methods=["GET", "POST"])
359+
def rasp_cmdi(*args, **kwargs):
360+
cmd = None
361+
if request.method == "GET":
362+
cmd = flask_request.args.get("command")
363+
elif request.method == "POST":
364+
try:
365+
cmd = (request.form or request.json or {}).get("command")
366+
except Exception as e:
367+
print(repr(e), file=sys.stderr)
368+
try:
369+
if cmd is None:
370+
cmd = xmltodict.parse(flask_request.data).get("command").get("cmd")
371+
except Exception as e:
372+
print(repr(e), file=sys.stderr)
373+
pass
374+
375+
if cmd is None:
376+
return "missing cmd parameter", 400
377+
try:
378+
res = subprocess.run(cmd, capture_output=True)
379+
return f"Exec command [{cmd}] with result: [{res.returncode}]: {res.stdout}", 200
380+
except Exception as e:
381+
return f"Exec command [{cmd}] yfailure: {e!r}", 201
382+
383+
358384
### END EXPLOIT PREVENTION
359385

360386

utils/interfaces/_library/core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ def validator(_, appsec_data):
452452

453453
trigger = triggers[0]
454454
obtained_rule_id = trigger["rule"]["id"]
455-
assert obtained_rule_id == rule, f"incorrect rule id, expected {rule}"
455+
assert obtained_rule_id == rule, f"incorrect rule id, expected {rule}, got {obtained_rule_id}"
456456

457457
if parameters is not None:
458458
rule_matches = trigger["rule_matches"]

0 commit comments

Comments
 (0)