Coder Social home page Coder Social logo

avilum / secimport Goto Github PK

View Code? Open in Web Editor NEW
171.0 6.0 12.0 349 KB

eBPF Python runtime sandbox with seccomp (Blocks RCE).

Home Page: https://avilum.github.io/secimport/

License: MIT License

Python 76.11% Shell 3.75% Dockerfile 2.50% DTrace 16.23% D 1.38% Makefile 0.03%
ebpf python bpftrace linux security-tools sandbox import dtrace tracing profiling security seccomp 3rd-party rce

secimport's Introduction

secimport

Upload Python Package

A Tailor-Made Sandbox for Your Python Applications.
secimport is eBPF-based sandbox toolkit for Python, that enforces specific syscalls per module in your code.

  1. It traces your python code
  2. It creates a security profile for your application
  3. Use the profile by applying it to running processes, or to run a new python process with supervision.

secimport for python is like seccomp-bpf for linux but per module in your code.

Table of Contents generated with DocToc

Background

Technical Blogs

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

  1. secimport is able to trace which syscalls each module in your code uses (by package name).
  2. After tracing, secimport creates a JSON/YAML policy for your code. It compiles it into a high-performance eBPF instrumentation script (smaller then 512 bytes overall), that looks like this.
    modules:
      requests:
        destructive: true     # when true, secimport will kill on vilation instead of logging.
        syscall_allowlist:
          - fchmod
          - getentropy
          - getpgrp
          - getrlimit
    ...
    
    You can also use JSON instaead of YAML, and even confine builtin python modules.
  3. Finally, you convert this policy into an sandbox (eBPF instrumentation script) to run the python process in production. Running the sandbox will enfore python to obey any given policy.

Who is it for?

secimport is great for...

  • Preventing Code Execution: reduce the risk of supply chain attacks.
    • Trace the syscalls flow of your application at the user-space/os/kernel level and per module.
    • Run your application while enforcing syscalls per module.
      • Upon violation of the policy, it can log, stop, or kill the process.
  • Protect yourself from RCE:
    • secimport makes 1day attacks less of an issue, because it prevents the code form running. If you are using a vulnerable package and someone exploited it, your policy will not allow this exploit's syscalls and it will be handled as you wish.
    • Avoid incidents like log4shell. A logging library requires very few syscalls, and it should never run command using fork, execve or spawn.
      • The syscalls that "fastapi", "numpy" or "requests" use are very different.
  • Load AI Models from Insecure Sources
    • Models from unsafe source (huggingface, torch hub, and pytorch pickled models) can be limited to run only a set of syscalls. RCE like 'import os;os.system(...)' somewhere deep in the code will be catched by secimport.
  • Minimal Performance Impact
    • Has negligible performance impact and is production-ready thanks to eBPF. Check out the Performance benchmarks.
  • Trace which syscalls are called by each module in your code.
    • secimport uses USDT (Userland Statically Defined Tracing) together with kernel probes in the runtime using eBPF or dtrace instrumentation scripts.

Getting Started

Example Sandboxes

The Sandbox Examples page contains basic and advanced real-world examples.

Using Docker

The quickest way to evaluate secimport is to use our Docker container, which includes bpftrace (ebpf) and other plug-and-play examples. For quicker evaluation, we recommend using the Secimport Docker Image instead of self-installing.

  • Build and run the Docker container with a custom kernel that matches your existing OS kernel version:
    cd docker/ && ./build.sh && ./run.sh
    
    A temporary container will be created, and you will be logged in as the root user.

Without Docker

Tested on Ubuntu, Debian, Rocky (Linux x86/AMD/ARM) and MacOS in (x86/M1). If you run on MacOS you will need to disable SIP for dtrace.

  1. Install python with USDT probes by configuring it with '--dtrace'
  2. Install one of the backends: eBPF or DTrace.
  3. Install secimport
  • Install from pypi
    • python3 -m pip install secimport
      
  • Install from source
    • git clone https://github.com/avilum/secimport.git && cd secimport
      python3 -m pip install poetry && python3 -m poetry install
      

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.

NAME
    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.

SYNOPSIS
    secimport COMMAND

DESCRIPTION
    https://github.com/avilum/secimport/wiki/Command-Line-Usage

    WORKFLOW:
            1. secimport trace / secimport shell
            2. secimport build
            3. secimport run

    QUICKSTART:
            $ secimport interactive

    EXAMPLES:
        1. trace:
            $  secimport trace
            $  secimport trace -h
            $  secimport trace_pid 123
            $  secimport trace_pid -h
        2. build:
            # secimport build
            $ secimport build -h
        3. run:
            $  secimport run
            $  secimport run --entrypoint my_custom_main.py
            $  secimport run --entrypoint my_custom_main.py --stop_on_violation=true
            $  secimport run --entrypoint my_custom_main.py --kill_on_violation=true
            $  secimport run --sandbox_executable /path/to/my_sandbox.bt --pid 2884
            $  secimport run --sandbox_executable /path/to/my_sandbox.bt --sandbox_logfile my_log.log
            $  secimport run -h

COMMANDS
    COMMAND is one of the following:

     build
       Compiles a trace log (trace.log). Creates the sandbox executable (instrumentation script) for each supported backend It uses `create_profile_from_trace ...` and `sandbox_from_profile`.

     compile_sandbox_from_profile
       Generates a tailor-made sandbox that will enforce a given yaml profile/policy in runtime.

     interactive

     run
       Run a python process inside the sandbox.

     shell
       Alternative syntax for secimport "trace".

     trace
       Traces a python process using an entrypoint or interactive interpreter. It might require sudo privilleges on some hosts.

     trace_pid
       Traces a running process by pid. It might require sudo privilleges on some hosts.

Stop on violation

root@1bc0531d91d0:/workspace# secimport run  --stop_on_violation=true
 >>> secimport run
[WARNING]: This sandbox will send SIGSTOP to the program upon violation.
 RUNNING SANDBOX... ['./sandbox.bt', '--unsafe', ' -c ', '/workspace/Python-3.11.8/python', 'STOP']
Attaching 4 probes...
Python 3.11.8 (default, Apr 28 2023, 11:32:40) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system('ps')
[SECURITY PROFILE VIOLATED]: <stdin> called syscall 56 at depth 8022

^^^ STOPPING PROCESS 85918 DUE TO SYSCALL VIOLATION ^^^
		PROCESS 85918 STOPPED.

Kill on violation

root@ee4bc99bb011:/workspace# secimport run --kill_on_violation
 >>> secimport run
[WARNING]: This sandbox will send SIGKILL to the program upon violation.
 RUNNING SANDBOX... ['./sandbox.bt', '--unsafe', ' -c ', '/workspace/Python-3.11.8/python', 'KILL']
import os
oAttaching 4 probes...
sPython 3.11.8 (default, Apr 28 2023, 11:32:40) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system('ps')
[SECURITY PROFILE VIOLATED]: <stdin> called syscall 56 at depth 8022

^^^ KILLING PROCESS 86466 DUE TO SYSCALL VIOLATION ^^^
		KILLED.
 SANDBOX EXITED;

Quickstart: trace, build, run.

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!

- 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]: <stdin> called syscall ioctl at depth 0
[SECIMPORT VIOLATION]: <stdin> called syscall ioctl at depth 0

For more detailed usage instructions, see the Command-Line Usage page.

Advanced

Python API

See the 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

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

See the Changelog for development progress and existing features.

Contributing

For information on how to contribute to secimport, see the Contributing guide.

secimport's People

Contributors

avilum avatar dependabot[bot] avatar manuels avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

secimport's Issues

Create a .yaml configuration per module in the code

Enable running out of band - without replacing the imports in the code.

  • Design the configuration file for modules in the code (firejail/nsjail/gvisor profiles are a good place to start with).
  • Use secimport to create a single dcript policy, based on that configuration file.
  • Run the application with that policy using dtrace, without using secure_import in the code.
  • Add poetry scripts for compilation on demand

Not working in ubuntu container

Describe the bug
`secimport interactive
Welcome to secimport!

  1. A python code can be traced using "secimport trace" or using "secimport shell"
  2. All the function calls and system calls will be recorded to ./trace.log.

Continue? (y): y

Tracing using ['/home/lukas/venv/lib/python3.10/site-packages/secimport/profiles/trace.bt', '-c', '/home/lukas/venv/bin/python', '-o', 'trace.log', '/home/lukas/venv/bin/python']
Press CTRL+D or CTRL+C to stop the trace gracefully.

ERROR: Unknown error -1: couldn't set RLIMIT_MEMLOCK for bpftrace. If your program is not loading, you can try "ulimit -l 8192" to fix the problem
/home/lukas/venv/lib/python3.10/site-packages/secimport/profiles/trace.bt:703-705: ERROR: tracepoint not found: raw_syscalls:sys_enter
The trace log is at ./trace.log

Running "secimport build"; it compiles ./trace.log which is the trace log to ./sandbox.bt

syscalls:
nsjail sandbox: nsjail -Ml -Mo --chroot / --port 8000 --user 99999 --group 99999 --seccomp_string 'ALLOW { } DEFAULT KILL' -- /home/lukas/venv/bin/python -i
Policy is ready: policy.yaml policy.json

[info] Creating profile for general_requirements
[debug] adding syscall vfork to blocklist for module general_requirements
[debug] adding syscall clone to blocklist for module general_requirements
[debug] adding syscall access to blocklist for module general_requirements
[debug] adding syscall chdir to blocklist for module general_requirements
[debug] adding syscall creat to blocklist for module general_requirements
[debug] adding syscall dup to blocklist for module general_requirements
[debug] adding syscall dup2 to blocklist for module general_requirements
[debug] adding syscall execve to blocklist for module general_requirements
[debug] adding syscall faccessat to blocklist for module general_requirements
[debug] adding syscall fcntl to blocklist for module general_requirements
[debug] adding syscall fdatasync to blocklist for module general_requirements
[debug] adding syscall fork to blocklist for module general_requirements
[debug] adding syscall fstat to blocklist for module general_requirements
[debug] adding syscall fsync to blocklist for module general_requirements
[debug] adding syscall getegid to blocklist for module general_requirements
[debug] adding syscall geteuid to blocklist for module general_requirements
[debug] adding syscall getgid to blocklist for module general_requirements
[debug] adding syscall getgroups to blocklist for module general_requirements
[debug] adding syscall getpid to blocklist for module general_requirements
[debug] adding syscall getppid to blocklist for module general_requirements
[debug] adding syscall getrlimit to blocklist for module general_requirements
[debug] adding syscall getsockname to blocklist for module general_requirements
[debug] adding syscall getsid to blocklist for module general_requirements
[debug] adding syscall getuid to blocklist for module general_requirements
[debug] adding syscall ioctl to blocklist for module general_requirements
[debug] adding syscall link to blocklist for module general_requirements
[debug] adding syscall lseek to blocklist for module general_requirements
[debug] adding syscall lstat to blocklist for module general_requirements
[debug] adding syscall mkdir to blocklist for module general_requirements
[debug] adding syscall mknod to blocklist for module general_requirements
[debug] adding syscall open to blocklist for module general_requirements
[debug] adding syscall openat to blocklist for module general_requirements
[debug] adding syscall pipe to blocklist for module general_requirements
[debug] adding syscall poll to blocklist for module general_requirements
[debug] adding syscall read to blocklist for module general_requirements
[debug] adding syscall readlink to blocklist for module general_requirements
[debug] adding syscall readv to blocklist for module general_requirements
[debug] adding syscall recvfrom to blocklist for module general_requirements
[debug] adding syscall recvmsg to blocklist for module general_requirements
[debug] adding syscall rename to blocklist for module general_requirements
[debug] adding syscall rmdir to blocklist for module general_requirements
[debug] adding syscall select to blocklist for module general_requirements
[debug] adding syscall sendmsg to blocklist for module general_requirements
[debug] adding syscall sendto to blocklist for module general_requirements
[debug] adding syscall setgid to blocklist for module general_requirements
[debug] adding syscall setgroups to blocklist for module general_requirements
[debug] adding syscall setpgid to blocklist for module general_requirements
[debug] adding syscall setpriority to blocklist for module general_requirements
[debug] adding syscall setregid to blocklist for module general_requirements
[debug] adding syscall setreuid to blocklist for module general_requirements
[debug] adding syscall setrlimit to blocklist for module general_requirements
[debug] adding syscall setsid to blocklist for module general_requirements
[debug] adding syscall setsockopt to blocklist for module general_requirements
[debug] adding syscall stat to blocklist for module general_requirements
[debug] adding syscall symlink to blocklist for module general_requirements
[debug] adding syscall truncate to blocklist for module general_requirements
[debug] adding syscall umask to blocklist for module general_requirements
[debug] adding syscall utime to blocklist for module general_requirements
[debug] adding syscall utimes to blocklist for module general_requirements
[debug] adding syscall write to blocklist for module general_requirements
[debug] adding syscall writev to blocklist for module general_requirements
The profile does not contain any modules: policy.yaml
Traceback (most recent call last):
File "/home/lukas/venv/bin/secimport", line 8, in
sys.exit(main())
File "/home/lukas/venv/lib/python3.10/site-packages/secimport/cli.py", line 424, in main
fire.Fire(SecImportCLI())
File "/home/lukas/venv/lib/python3.10/site-packages/fire/core.py", line 141, in Fire
component_trace = _Fire(component, args, parsed_flag_args, context, name)
File "/home/lukas/venv/lib/python3.10/site-packages/fire/core.py", line 475, in _Fire
component, remaining_args = _CallAndUpdateTrace(
File "/home/lukas/venv/lib/python3.10/site-packages/fire/core.py", line 691, in _CallAndUpdateTrace
component = fn(*varargs, **kwargs)
File "/home/lukas/venv/lib/python3.10/site-packages/secimport/cli.py", line 399, in interactive
SecImportCLI.build()
File "/home/lukas/venv/lib/python3.10/site-packages/secimport/cli.py", line 292, in build
bpftrace_sandbox_filename = SecImportCLI.compile_sandbox_from_profile(
File "/home/lukas/venv/lib/python3.10/site-packages/secimport/cli.py", line 165, in compile_sandbox_from_profile
raise AssertionError(
AssertionError: The trace file 'policy.yaml' has 0 modules. A valid policy should include at least 1 module.`

To Reproduce
Steps to reproduce the behavior:

  1. build a docker container
    `FROM ubuntu:latest

RUN apt update
&& apt -y upgrade

RUN apt -y install build-essential git bpftrace vim python3.10-venv`

  1. in the container, as root, build and activate venv
    python3 -m venv venv
    source venv/bin/activate

  2. install secimport
    python -m pip install secimport

  3. verify --with-dtrace, success
    readelf -n $(which python) | grep -i function__entry
    output: Name: function__entry

  4. run secimport
    secimport interactive

Allow/Block list configuration

DOD: Enable users to import modules with only specific syscalls.
e.g:

  • secure_import(..., allow_syscalls=['read', 'select', ...])
  • secure_import(..., disallow_syscalls=['forkexec', 'chroot', ...])
  • secure_import(..., allow_syscalls=[('read', '/tmp/'), ...]

Make destructive flag optional

Make the dtrace destructive attribute optional.

it can be done by crating a variable in the for “PRAGMA destructive” header in the template.

Usage on Debian based systems

Hello,

I don't understand the following since the documentation show that the attribute exists: https://docs.python.org/3.9/library/importlib.html

>>> os = secure_import('os', allow_shells=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/dev/secimport_testing/venv/lib/python3.9/site-packages/secimport/sandbox_helper.py", line 50, in secure_import
    assert run_dtrace_script_for_module(
  File "dev/secimport_testing/venv/lib/python3.9/site-packages/secimport/sandbox_helper.py", line 81, in run_dtrace_script_for_module
    module_file_path = create_dtrace_script_for_module(
  File "dev/secimport_testing/venv/lib/python3.9/site-packages/secimport/sandbox_helper.py", line 128, in create_dtrace_script_for_module
    module = importlib.machinery.PathFinder().find_spec(module_name)
AttributeError: module 'importlib' has no attribute 'machinery'

UPDATE: This is not the issue of concern, see comments.

ModuleNotFoundError: No module named 'numpy'

Describe the bug
ModuleNotFoundError: No module named 'numpy'

To Reproduce
Steps to reproduce the behavior:

>>> import secimport
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".venv/lib/python3.10/site-packages/secimport/__init__.py", line 1, in <module>
    from secimport.sandbox_helper import secure_import
  File ".venv/lib/python3.10/site-packages/secimport/sandbox_helper.py", line 13, in <module>
    from numpy import isin
ModuleNotFoundError: No module named 'numpy'

Desktop (please complete the following information):

  • OS: MacOS M1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.