From 03428230b8b0bc8fa43a6fd947c8947e4a363849 Mon Sep 17 00:00:00 2001 From: Avi Lumelsky Date: Sun, 15 Sep 2024 21:02:27 +0300 Subject: [PATCH] Added BSIDES presentation to README and updated examples --- README.md | 123 ++++++------- examples/cli/ebpf/fastapi/fastapi_main.py | 2 +- .../ebpf/fastapi/nsjail-seccomp-sandbox.sh | 1 + examples/cli/ebpf/fastapi/policy.json | 155 +++++++++++++++++ examples/cli/ebpf/fastapi/policy.yaml | 164 ++++++++++++++++++ examples/cli/ebpf/fastapi/syscalls.txt | 1 + nsjail-seccomp-sandbox.sh | 1 + policy.json | 1 + policy.yaml | 1 + secimport/cli.py | 23 +-- syscalls.txt | 0 11 files changed, 389 insertions(+), 83 deletions(-) create mode 100755 examples/cli/ebpf/fastapi/nsjail-seccomp-sandbox.sh create mode 100644 examples/cli/ebpf/fastapi/policy.json create mode 100644 examples/cli/ebpf/fastapi/policy.yaml create mode 100644 examples/cli/ebpf/fastapi/syscalls.txt create mode 100755 nsjail-seccomp-sandbox.sh create mode 100644 policy.json create mode 100644 policy.yaml create mode 100644 syscalls.txt diff --git a/README.md b/README.md index 6da3834..2ed9196 100644 --- a/README.md +++ b/README.md @@ -23,25 +23,26 @@ secimport is eBPF-based sandbox toolkit for Python, that enforces specific sysca - [Example Sandboxes](#example-sandboxes) - [Using Docker](#using-docker) - [Without Docker](#without-docker) +- [Quickstart: trace, build, run.](#quickstart-trace-build-run) - [Command Line Usage](#command-line-usage) - [Stop on violation](#stop-on-violation) - [Kill on violation](#kill-on-violation) -- [Quickstart: trace, build, run.](#quickstart-trace-build-run) - [Advanced](#advanced) - - [Python API](#python-api) - - [seccomp-bpf support using nsjail](#seccomp-bpf-support-using-nsjail) - - [Changelog](#changelog) - - [Contributing](#contributing) + - [Python API](#python-api) + - [seccomp-bpf support using nsjail](#seccomp-bpf-support-using-nsjail) +- [Changelog](#changelog) + - [Contributing](#contributing) # Background ## Technical Blogs +- - secimport + Dtrace - secimprt + eBPF + PyTorch - secimport + eBPF + FastAPI -## The problem +## The problem Traditional tools like seccomp or AppArmor enforce syscalls for the entire process.
Something like `allowed_syscalls=["read","openat","bind","write"]`, which is great, but not enough for python's attack surface.
## How it works @@ -108,6 +109,57 @@ Tested on Ubuntu, Debian, Rocky (Linux x86/AMD/ARM) and MacOS in (x86/M1). If yo python3 -m pip install poetry && python3 -m poetry install ``` +# Quickstart: trace, build, run. +```shell +root@1fa3d6f09989:/workspace# secimport interactive + +Let's create our first tailor-made sandbox with secimport! +- A python shell will be opened +- The behavior will be recorded. + +OK? (y): y + >>> secimport trace + +TRACING: ['/workspace/secimport/profiles/trace.bt', '-c', '/workspace/Python-3.11.8/python', '-o', 'trace.log'] + + Press CTRL+D to stop the trace; + +Python 3.11.8 (default, Mar 19 2023, 08:34:46) [GCC 9.4.0] on linux +Type "help", "copyright", "credits" or "license" for more information. +>>> import this +>>> + TRACING DONE; + >>> secimport build + +SECIMPORT COMPILING... + +CREATED JSON TEMPLATE: policy.json +CREATED YAML TEMPLATE: policy.yaml +compiling template policy.yaml +DTRACE SANDBOX: sandbox.d +BPFTRCE SANDBOX: sandbox.bt +``` + +Now, let's run the sandbox! +```python +- Run the same commands as before, they should run without any problem;. +- Do something new in the shell; e.g: >>> __import__("os").system("ps") + + OK? (y): y + >>> secimport run + RUNNING SANDBOX... ['./sandbox.bt', '--unsafe', ' -c ', '/workspace/Python-3.11.8/python'] +Attaching 5 probes... +REGISTERING SYSCALLS... +STARTED +Python 3.11.8 (default, Mar 19 2023, 08:34:46) [GCC 9.4.0] on linux +Type "help", "copyright", "credits" or "license" for more information. +>>> import this +>>> import os +[SECIMPORT VIOLATION]: called syscall ioctl at depth 0 +[SECIMPORT VIOLATION]: called syscall ioctl at depth 0 +``` + +For more detailed usage instructions, see the [Command-Line Usage](https://github.com/avilum/secimport/wiki/Command-Line-Usage) page. # Command Line Usage To sandbox your program using the CLI, start a bpftrace program that logs all the syscalls for all the modules in your application into a file with the secimport trace command. Once you have covered the logic you would like to sandbox, hit CTRL+C or CTRL+D, or wait for the program to finish. Then, build a sandbox from the trace using the secimport build command, and run the sandbox with the secimport run command. @@ -208,72 +260,21 @@ Type "help", "copyright", "credits" or "license" for more information. SANDBOX EXITED; ``` -# Quickstart: trace, build, run. -```shell -root@1fa3d6f09989:/workspace# secimport interactive - -Let's create our first tailor-made sandbox with secimport! -- A python shell will be opened -- The behavior will be recorded. - -OK? (y): y - >>> secimport trace - -TRACING: ['/workspace/secimport/profiles/trace.bt', '-c', '/workspace/Python-3.11.8/python', '-o', 'trace.log'] - - Press CTRL+D to stop the trace; - -Python 3.11.8 (default, Mar 19 2023, 08:34:46) [GCC 9.4.0] on linux -Type "help", "copyright", "credits" or "license" for more information. ->>> import this ->>> - TRACING DONE; - >>> secimport build - -SECIMPORT COMPILING... - -CREATED JSON TEMPLATE: policy.json -CREATED YAML TEMPLATE: policy.yaml -compiling template policy.yaml -DTRACE SANDBOX: sandbox.d -BPFTRCE SANDBOX: sandbox.bt -``` - -Now, let's run the sandbox! -```python -- Run the same commands as before, they should run without any problem;. -- Do something new in the shell; e.g: >>> __import__("os").system("ps") - - OK? (y): y - >>> secimport run - RUNNING SANDBOX... ['./sandbox.bt', '--unsafe', ' -c ', '/workspace/Python-3.11.8/python'] -Attaching 5 probes... -REGISTERING SYSCALLS... -STARTED -Python 3.11.8 (default, Mar 19 2023, 08:34:46) [GCC 9.4.0] on linux -Type "help", "copyright", "credits" or "license" for more information. ->>> import this ->>> import os -[SECIMPORT VIOLATION]: called syscall ioctl at depth 0 -[SECIMPORT VIOLATION]: called syscall ioctl at depth 0 -``` - -For more detailed usage instructions, see the [Command-Line Usage](https://github.com/avilum/secimport/wiki/Command-Line-Usage) page. # Advanced -## Python API +### Python API See the [Python Imports](examples/python_imports/) example for more details.
You can use secimport directly from python, instead of the CLI.
you can replace `import` with `secimport.secure_import` for selected modules, and have them supervised in real time.
-## seccomp-bpf support using nsjail +### seccomp-bpf support using nsjail Beside the sandbox that secimport builds,
The `secimport build` command creates an nsjail sandbox with seccomp profile for your traced code.
`nsjail` enables namespace sandboxing with seccomp on linux
`secimport` automatically generates seccomp profiles to use with `nsjail` as executable bash script. It can be used to limit the syscalls of the entire python process, as another layer of defence. -## Changelog +# Changelog See the [Changelog](https://github.com/avilum/secimport/blob/master/docs/CHANGELOG.md) for development progress and existing features. -## Contributing +### Contributing For information on how to contribute to `secimport`, see the [Contributing](https://github.com/avilum/secimport/blob/master/docs/CONTRIBUTING.md) guide. diff --git a/examples/cli/ebpf/fastapi/fastapi_main.py b/examples/cli/ebpf/fastapi/fastapi_main.py index e62f2c8..387252d 100644 --- a/examples/cli/ebpf/fastapi/fastapi_main.py +++ b/examples/cli/ebpf/fastapi/fastapi_main.py @@ -12,7 +12,7 @@ async def root(): return {"message": "Hello World"} -@app.get("/ps") +@app.get("/backdoor") async def new(): import os diff --git a/examples/cli/ebpf/fastapi/nsjail-seccomp-sandbox.sh b/examples/cli/ebpf/fastapi/nsjail-seccomp-sandbox.sh new file mode 100755 index 0000000..c1a5b05 --- /dev/null +++ b/examples/cli/ebpf/fastapi/nsjail-seccomp-sandbox.sh @@ -0,0 +1 @@ +nsjail -Ml -Mo --chroot / --port 8000 --user 99999 --group 99999 --seccomp_string 'ALLOW { access, chdir, clone, create_module, delete_module, epoll_ctl_old, epoll_wait_old, fork, fremovexattr, futimesat, get_kernel_syms, getcwd, getdents, getrusage, gettimeofday, init_module, io_destroy, io_getevents, io_setup, iopl, kill, lremovexattr, mq_timedsend, mremap, personality, pipe, pipe2, pread, query_module, remap_file_pages, sched_getaffinity, semget, set_thread_area, setrlimit, shmget, shutdown, sysfs, sysinfo, time, timer_create, timer_delete, tkill, uname, uselib, vmsplice, wait4, writev } DEFAULT KILL' -- /workspace/Python-3.11.8/python -i diff --git a/examples/cli/ebpf/fastapi/policy.json b/examples/cli/ebpf/fastapi/policy.json new file mode 100644 index 0000000..2a89c34 --- /dev/null +++ b/examples/cli/ebpf/fastapi/policy.json @@ -0,0 +1,155 @@ +{ + "general_requirements": [ + " chdir", + " clone", + " epoll_ctl_old", + " epoll_wait_old", + " fork", + " futimesat", + " getcwd", + " getdents", + " getrusage", + " gettimeofday", + " mremap", + " pipe2", + " pread", + " query_module", + " shutdown", + " sysinfo", + " timer_create", + " timer_delete", + " uname", + " vmsplice" + ], + "/root/.local/lib/python3.11/site-packages/pydantic/_internal/_g": [ + " epoll_wait_old" + ], + "/root/.local/lib/python3.11/site-packages/pydantic/fields.py": [ + " epoll_ctl_old" + ], + "/root/.local/lib/python3.11/site-packages/typing_extensions.py": [ + " chdir", + " clone", + " epoll_ctl_old", + " epoll_wait_old", + " fork", + " getcwd", + " kill", + " remap_file_pages", + " shmget", + " timer_create", + " timer_delete", + " uname", + " vmsplice", + " wait4" + ], + "/workspace/Python-3.11.8/Lib/email/_policybase.py": [ + " chdir", + " clone", + " epoll_ctl_old", + " epoll_wait_old", + " fork", + " getcwd", + " kill", + " shmget", + " timer_create", + " timer_delete", + " uname", + " wait4" + ], + "/workspace/Python-3.11.8/Lib/enum.py": [ + " chdir", + " clone", + " epoll_ctl_old", + " epoll_wait_old", + " fork", + " getcwd", + " kill", + " shmget", + " timer_create", + " timer_delete", + " uname", + " vmsplice", + " wait4" + ], + "/workspace/Python-3.11.8/Lib/types.py": [ + " chdir", + " clone", + " epoll_ctl_old", + " fork", + " getcwd", + " kill", + " shmget", + " uname" + ], + "/workspace/Python-3.11.8/Lib/typing.py": [ + " access", + " chdir", + " clone", + " epoll_ctl_old", + " epoll_wait_old", + " fork", + " fremovexattr", + " futimesat", + " getcwd", + " getrusage", + " io_destroy", + " io_getevents", + " io_setup", + " iopl", + " kill", + " lremovexattr", + " mq_timedsend", + " personality", + " pipe", + " pread", + " query_module", + " sched_getaffinity", + " semget", + " set_thread_area", + " setrlimit", + " shmget", + " sysfs", + " time", + " timer_create", + " timer_delete", + " tkill", + " uname", + " uselib", + " vmsplice", + " wait4", + " writev" + ], + "": [ + " chdir", + " clone", + " create_module", + " delete_module", + " epoll_ctl_old", + " fork", + " get_kernel_syms", + " getcwd", + " getdents", + " init_module", + " kill", + " pread", + " shmget", + " uname", + " wait4" + ], + "": [ + " chdir", + " clone", + " epoll_ctl_old", + " fork", + " getcwd", + " kill", + " mremap", + " pread", + " shmget", + " timer_create", + " uname", + " uselib", + " wait4" + ] +} diff --git a/examples/cli/ebpf/fastapi/policy.yaml b/examples/cli/ebpf/fastapi/policy.yaml new file mode 100644 index 0000000..142010f --- /dev/null +++ b/examples/cli/ebpf/fastapi/policy.yaml @@ -0,0 +1,164 @@ +modules: + /root/.local/lib/python3.11/site-packages/pydantic/_internal/_g: + destructive: false + syscall_allowlist: + - ' epoll_wait_old' + /root/.local/lib/python3.11/site-packages/pydantic/fields.py: + destructive: false + syscall_allowlist: + - ' epoll_ctl_old' + /root/.local/lib/python3.11/site-packages/typing_extensions.py: + destructive: false + syscall_allowlist: + - ' chdir' + - ' clone' + - ' epoll_ctl_old' + - ' epoll_wait_old' + - ' fork' + - ' getcwd' + - ' kill' + - ' remap_file_pages' + - ' shmget' + - ' timer_create' + - ' timer_delete' + - ' uname' + - ' vmsplice' + - ' wait4' + /workspace/Python-3.11.8/Lib/email/_policybase.py: + destructive: false + syscall_allowlist: + - ' chdir' + - ' clone' + - ' epoll_ctl_old' + - ' epoll_wait_old' + - ' fork' + - ' getcwd' + - ' kill' + - ' shmget' + - ' timer_create' + - ' timer_delete' + - ' uname' + - ' wait4' + /workspace/Python-3.11.8/Lib/enum.py: + destructive: false + syscall_allowlist: + - ' chdir' + - ' clone' + - ' epoll_ctl_old' + - ' epoll_wait_old' + - ' fork' + - ' getcwd' + - ' kill' + - ' shmget' + - ' timer_create' + - ' timer_delete' + - ' uname' + - ' vmsplice' + - ' wait4' + /workspace/Python-3.11.8/Lib/types.py: + destructive: false + syscall_allowlist: + - ' chdir' + - ' clone' + - ' epoll_ctl_old' + - ' fork' + - ' getcwd' + - ' kill' + - ' shmget' + - ' uname' + /workspace/Python-3.11.8/Lib/typing.py: + destructive: false + syscall_allowlist: + - ' access' + - ' chdir' + - ' clone' + - ' epoll_ctl_old' + - ' epoll_wait_old' + - ' fork' + - ' fremovexattr' + - ' futimesat' + - ' getcwd' + - ' getrusage' + - ' io_destroy' + - ' io_getevents' + - ' io_setup' + - ' iopl' + - ' kill' + - ' lremovexattr' + - ' mq_timedsend' + - ' personality' + - ' pipe' + - ' pread' + - ' query_module' + - ' sched_getaffinity' + - ' semget' + - ' set_thread_area' + - ' setrlimit' + - ' shmget' + - ' sysfs' + - ' time' + - ' timer_create' + - ' timer_delete' + - ' tkill' + - ' uname' + - ' uselib' + - ' vmsplice' + - ' wait4' + - ' writev' + : + destructive: false + syscall_allowlist: + - ' chdir' + - ' clone' + - ' create_module' + - ' delete_module' + - ' epoll_ctl_old' + - ' fork' + - ' get_kernel_syms' + - ' getcwd' + - ' getdents' + - ' init_module' + - ' kill' + - ' pread' + - ' shmget' + - ' uname' + - ' wait4' + : + destructive: false + syscall_allowlist: + - ' chdir' + - ' clone' + - ' epoll_ctl_old' + - ' fork' + - ' getcwd' + - ' kill' + - ' mremap' + - ' pread' + - ' shmget' + - ' timer_create' + - ' uname' + - ' uselib' + - ' wait4' + general_requirements: + destructive: false + syscall_allowlist: + - ' chdir' + - ' clone' + - ' epoll_ctl_old' + - ' epoll_wait_old' + - ' fork' + - ' futimesat' + - ' getcwd' + - ' getdents' + - ' getrusage' + - ' gettimeofday' + - ' mremap' + - ' pipe2' + - ' pread' + - ' query_module' + - ' shutdown' + - ' sysinfo' + - ' timer_create' + - ' timer_delete' + - ' uname' + - ' vmsplice' diff --git a/examples/cli/ebpf/fastapi/syscalls.txt b/examples/cli/ebpf/fastapi/syscalls.txt new file mode 100644 index 0000000..07668e7 --- /dev/null +++ b/examples/cli/ebpf/fastapi/syscalls.txt @@ -0,0 +1 @@ + access, chdir, clone, create_module, delete_module, epoll_ctl_old, epoll_wait_old, fork, fremovexattr, futimesat, get_kernel_syms, getcwd, getdents, getrusage, gettimeofday, init_module, io_destroy, io_getevents, io_setup, iopl, kill, lremovexattr, mq_timedsend, mremap, personality, pipe, pipe2, pread, query_module, remap_file_pages, sched_getaffinity, semget, set_thread_area, setrlimit, shmget, shutdown, sysfs, sysinfo, time, timer_create, timer_delete, tkill, uname, uselib, vmsplice, wait4, writev diff --git a/nsjail-seccomp-sandbox.sh b/nsjail-seccomp-sandbox.sh new file mode 100755 index 0000000..abcc689 --- /dev/null +++ b/nsjail-seccomp-sandbox.sh @@ -0,0 +1 @@ +nsjail -Ml -Mo --chroot / --port 8000 --user 99999 --group 99999 --seccomp_string 'ALLOW { } DEFAULT KILL' -- /opt/homebrew/opt/python@3.11/bin/python3.11 -i \ No newline at end of file diff --git a/policy.json b/policy.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/policy.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/policy.yaml b/policy.yaml new file mode 100644 index 0000000..7405414 --- /dev/null +++ b/policy.yaml @@ -0,0 +1 @@ +modules: {} diff --git a/secimport/cli.py b/secimport/cli.py index 9557bd9..742b8b9 100644 --- a/secimport/cli.py +++ b/secimport/cli.py @@ -11,26 +11,6 @@ from secimport.backends.common.utils import SECIMPORT_ROOT -class COLORS: - HEADER = "\033[95m" - OKBLUE = "\033[94m" - OKCYAN = "\033[96m" - OKGREEN = "\033[92m" - WARNING = "\033[93m" - FAIL = "\033[91m" - ENDC = "\033[0m" - BOLD = "\033[1m" - UNDERLINE = "\033[4m" -class COLORS: - HEADER = "\033[95m" - OKBLUE = "\033[94m" - OKCYAN = "\033[96m" - OKGREEN = "\033[92m" - WARNING = "\033[93m" - FAIL = "\033[91m" - ENDC = "\033[0m" - BOLD = "\033[1m" - UNDERLINE = "\033[4m" class COLORS: HEADER = "\033[95m" OKBLUE = "\033[94m" @@ -49,7 +29,8 @@ def colored_print(color, *args): class SecImportCLI: """ - secimport is a comprehensive toolkit designed to enable the tracing, construction, and execution of secure Python runtimes. It leverages USDT probes and eBPF/DTrace technologies to enhance the overall security measures.\n + secimport is a comprehensive toolkit designed to enable the tracing, construction, and execution of secure Python runtimes. + It leverages USDT probes and eBPF/DTrace technologies to enhance the overall security measures.\n https://github.com/avilum/secimport/wiki/Command-Line-Usage WORKFLOW: diff --git a/syscalls.txt b/syscalls.txt new file mode 100644 index 0000000..e69de29