diff --git a/README.md b/README.md index dcce738..3ea07cf 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,66 @@ Secure import for python modules using dtrace under the hood.
# Quick Start +`secimport` can be used out of the box in the following ways: +1. Inside your code using `module = secimport.secure_import('module_name', ...)`. + - Replacing the regular `import` statement with `secure_import` + - Only modules that were imported with `secure_import` will be traced. +2. As a sandbox, by specifying the modules and their policies. + - Use this repository to: + - Generate a YAML policy from your code + - Compile that YAML to dscript. + - Use `dtrace` command to run your main python application, with your tailor-made sandbox. + - No need for `secure_import`, you can keep using regular `import`s + For the full list of examples, see EXAMPLES.md. +# Pickle Example +### How pickle can be exploited in your 3rd party packages: +```python +>>> import pickle +>>> class Demo: +... def __reduce__(self): +... return (eval, ("__import__('os').system('echo Exploited!')",)) +... +>>> pickle.dumps(Demo()) +b"\x80\x04\x95F\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x04eval\x94\x93\x94\x8c*__import__('os').system('echo Exploited!')\x94\x85\x94R\x94." +>>> pickle.loads(b"\x80\x04\x95F\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x04eval\x94\x93\x94\x8c*__import__('os').system('echo Exploited!')\x94\x85\x94R\x94.") +Exploited! +0 +``` +With `secimport`, you can control such action to do whatever you want: +```python +In [1]: import secimport +In [2]: pickle = secimport.secure_import("pickle") +In [3]: pickle.loads(b"\x80\x04\x95F\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x04eval\x94\x93\x94\x8c*__import__('os').system('echo Exploited!')\x94\x85\x94R\x94.") + +[1] 28027 killed ipython +``` +A log file is automatically created, containing everything you need to know: +``` +$ less /tmp/.secimport/sandbox_pickle.log + + @posix_spawn from /Users/avilumelsky/Downloads/Python-3.10.0/Lib/threading.py + DETECTED SHELL: + depth=8 + sandboxed_depth=0 + sandboxed_module=/Users/avilumelsky/Downloads/Python-3.10.0/Lib/pickle.py + + TERMINATING SHELL: + libsystem_kernel.dylib`__posix_spawn+0xa + ... + libsystem_kernel.dylib`__posix_spawn+0xa + libsystem_c.dylib`system+0x18b + python.exe`os_system+0xb3 + KILLED +: +``` + ## YAML Template Example +For a full tutorial, see YAML Profiles Usage ```shell +# An example yaml template for a sandbox. + modules: requests: destructive: true @@ -45,9 +101,8 @@ modules: - stat64 ``` -See YAML Profiles Usage -## Python Shell Interactive Example +## Python Processing Example ```python Python 3.10.0 (default, May 2 2022, 21:43:20) [Clang 13.0.0 (clang-1300.0.27.3)] on darwin Type "help", "copyright", "credits" or "license" for more information. @@ -93,7 +148,7 @@ Type "help", "copyright", "credits" or "license" for more information. killed. ``` -## Shell blocking +## Shell Blocking Example ```python # example.py - Executes code upon import; import os; @@ -117,7 +172,7 @@ Killed: 9 - If a syscall like `spawn/exec/fork/forkexec` will be executed - The process will be `kill`ed with `-9` signal. -## Network blocking +## Network Blocking Example ``` >>> import requests >>> requests.get('https://google.com') @@ -166,11 +221,11 @@ Not related for python, but for the sake of explanation (Equivilant Demo soon).

## TODO: +- ✔️ Allow/Block list configuration +- ✔️ Create a .yaml configuration per module in the code + - ✔️ Use secimport to compile that yml + - ✔️ Create a single dcript policy + - ✔️ Run an application with that policy using dtrace, without using `secure_import` - Node support (dtrace hooks) - Go support (dtrace hooks) -- Allow/Block list configuration - Use current_module_str together with thread ID -- Create a .yaml configuration per module in the code - - Use secimport to compile that yml - - Create a single dcript policy - - Run an application with that policy using dtrace, without using `secure_import` diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index aaca369..73fac5e 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -9,7 +9,7 @@ To understand how to trace you process and create custom profiles for modules or - YAML to Sandbox Example - `examples/create_profile_from_yaml.sh` - Create a sandbox template code for your app from a single YAML file. - - See YAML Profiles Usage + - See YAML Profiles Usage - Python (import inline): - `requests` example - secure import vs regular import (Killed because of socket related syscall) - `python examples/http_request.py` diff --git a/docs/TRACING_PROCESSES.md b/docs/TRACING_PROCESSES.md index 14b5b7b..34b28c4 100644 --- a/docs/TRACING_PROCESSES.md +++ b/docs/TRACING_PROCESSES.md @@ -1,7 +1,7 @@ # Tracing processes for syscalls There are several ways to create a secimport profile for your modules. - - Using a YAML template - - See YAML Profiles Usage + - Using a YAML build + - See YAML Profiles Usage - Using `secure_import` from python: - `secimport.secure_import(..., log_syscalls=True, destructive=False)` - The log output will contain all the syscalls made by your process. diff --git a/pyproject.toml b/pyproject.toml index a6c3636..952e4ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "secimport" -version = "0.4.1" +version = "0.4.2" description = "A sandbox/supervisor for python modules." authors = ["Avi Lumelsky"] license = "MIT" diff --git a/src/secimport/templates/actions/kill_on_processing.d b/src/secimport/templates/actions/kill_on_processing.d index f5c2a90..40bbfd9 100644 --- a/src/secimport/templates/actions/kill_on_processing.d +++ b/src/secimport/templates/actions/kill_on_processing.d @@ -1,10 +1,8 @@ - printf("\t\t\t\tDETECTED SHELL, depth=%d sandboxed_depth=%d\r\n", self->depth, depth_matrix["###MODULE_NAME###"]); - if(depth_matrix["###MODULE_NAME###"] != 0 && self->depth >= depth_matrix["###MODULE_NAME###"]){ - printf("\t\tTERMINATING shell...\r\n"); - ustack(); - stop(); - printf("\t\tKILLING...\r\n"); - system("\t\tkill -9 %d", pid); - printf("\t\tKILLED.\r\n"); - exit(-1); - } \ No newline at end of file + printf("\t\t\t\tDETECTED SHELL, depth=%d sandboxed_depth=%d sandboxed_module=%s current_module=%s\r\n", self->depth, depth_matrix["###MODULE_NAME###"], "###MODULE_NAME###", _current_module_str); + printf("\t\tTERMINATING shell...\r\n"); + ustack(); + stop(); + printf("\t\tKILLING...\r\n"); + system("\t\tkill -9 %d", pid); + printf("\t\tKILLED.\r\n"); + exit(-1); \ No newline at end of file diff --git a/src/secimport/templates/actions/log_syscall.d b/src/secimport/templates/actions/log_syscall.d index f03cd59..63d40b4 100644 --- a/src/secimport/templates/actions/log_syscall.d +++ b/src/secimport/templates/actions/log_syscall.d @@ -1 +1 @@ - printf("\n@%s", probefunc); \ No newline at end of file + printf("\n@%s from %s", probefunc, current_module_str); \ No newline at end of file diff --git a/tests/test_sandbox_helper.py b/tests/test_sandbox_helper.py index 515dbb5..e16c6ec 100644 --- a/tests/test_sandbox_helper.py +++ b/tests/test_sandbox_helper.py @@ -243,3 +243,7 @@ def test_build_module_sandbox_from_yaml_template(self): self.assertIsInstance(module_sandbox_code, str) self.assertFalse("###SUPERVISED_MODULES_PROBES###" in module_sandbox_code) + + +if __name__ == '__main__': + \ No newline at end of file