Refactor code structure for improved readability and maintainability
This commit is contained in:
270
poc/README.md
Normal file
270
poc/README.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# Security Audit POC Environment
|
||||
|
||||
This directory contains a Docker-based proof-of-concept environment to verify and demonstrate the vulnerabilities identified in the [SECURITY_AUDIT.md](../SECURITY_AUDIT.md).
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Run all POC tests
|
||||
./run_poc.sh
|
||||
|
||||
# Build only (no tests)
|
||||
./run_poc.sh --build-only
|
||||
|
||||
# Include vulnerable dependency tests
|
||||
./run_poc.sh --vulnerable
|
||||
|
||||
# Clean and run fresh
|
||||
./run_poc.sh --clean
|
||||
```
|
||||
|
||||
## Vulnerabilities Demonstrated
|
||||
|
||||
### 1. Shell Command Injection (MEDIUM)
|
||||
|
||||
**File:** `nanobot/agent/tools/shell.py`
|
||||
|
||||
The shell tool uses `create_subprocess_shell()` which is vulnerable to command injection. While a regex pattern blocks some dangerous commands (`rm -rf /`, fork bombs, etc.), many bypasses exist:
|
||||
|
||||
| Bypass Technique | Example |
|
||||
|-----------------|---------|
|
||||
| Command substitution | `echo $(cat /etc/passwd)` |
|
||||
| Backtick substitution | `` echo `id` `` |
|
||||
| Base64 encoding | `echo BASE64 | base64 -d \| bash` |
|
||||
| Alternative interpreters | `python3 -c 'import os; ...'` |
|
||||
| Environment exfiltration | `env \| grep -i key` |
|
||||
|
||||
**Impact:**
|
||||
- Read sensitive files
|
||||
- Execute arbitrary code
|
||||
- Network reconnaissance
|
||||
- Potential container escape
|
||||
|
||||
### 2. Path Traversal (MEDIUM)
|
||||
|
||||
**File:** `nanobot/agent/tools/filesystem.py`
|
||||
|
||||
The `_validate_path()` function supports restricting file access to a base directory, but this parameter is **never passed** by any tool:
|
||||
|
||||
```python
|
||||
# The function signature:
|
||||
def _validate_path(path: str, base_dir: Path | None = None)
|
||||
|
||||
# But all tools call it without base_dir:
|
||||
valid, file_path = _validate_path(path) # No restriction!
|
||||
```
|
||||
|
||||
**Impact:**
|
||||
- Read any file the process can access (`/etc/passwd`, SSH keys, AWS credentials)
|
||||
- Write to any writable location (`/tmp`, home directories)
|
||||
- List any directory for reconnaissance
|
||||
|
||||
### 3. LiteLLM Remote Code Execution (CRITICAL)
|
||||
|
||||
**CVE:** CVE-2024-XXXX (Multiple related CVEs)
|
||||
**Affected Versions:** litellm <= 1.28.11 and < 1.40.16
|
||||
|
||||
Multiple vectors for Remote Code Execution through unsafe `eval()` usage:
|
||||
|
||||
| Vector | Location | Description |
|
||||
|--------|----------|-------------|
|
||||
| Template Injection | `litellm/utils.py` | User input passed to eval() |
|
||||
| Proxy Config | `proxy/ui_sso.py` | Configuration values evaluated |
|
||||
| SSTI | Various | Unsandboxed Jinja2 templates |
|
||||
| Callback Handlers | Callbacks module | Dynamic code execution |
|
||||
|
||||
**Impact:**
|
||||
- Arbitrary code execution on the server
|
||||
- Access to all environment variables (API keys, secrets)
|
||||
- Full file system access
|
||||
- Reverse shell capability
|
||||
- Lateral movement in network
|
||||
|
||||
### 4. Vulnerable Dependencies (CRITICAL - if using old versions)
|
||||
|
||||
**litellm < 1.40.16:**
|
||||
- Remote Code Execution via `eval()`
|
||||
- Server-Side Request Forgery (SSRF)
|
||||
- API Key Leakage
|
||||
|
||||
**ws < 8.17.1:**
|
||||
- Denial of Service via header flooding
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
poc/
|
||||
├── docker-compose.yml # Container orchestration
|
||||
├── Dockerfile.nanobot # Python app container
|
||||
├── Dockerfile.bridge # Node.js bridge container
|
||||
├── Dockerfile.mock-llm # Mock LLM server
|
||||
├── mock_llm_server.py # Simulates LLM responses triggering tools
|
||||
├── run_poc.sh # Test harness script
|
||||
├── config/
|
||||
│ └── config.json # Test configuration
|
||||
├── exploits/
|
||||
│ ├── shell_injection.py # Shell bypass tests
|
||||
│ ├── path_traversal.py # File access tests
|
||||
│ └── litellm_rce.py # LiteLLM RCE vulnerability tests
|
||||
├── sensitive/ # Test sensitive files
|
||||
└── results/ # Test output
|
||||
```
|
||||
|
||||
## Running Individual Tests
|
||||
|
||||
### Shell Injection POC
|
||||
|
||||
```bash
|
||||
# In container
|
||||
docker compose run --rm nanobot python /app/poc/exploits/shell_injection.py
|
||||
|
||||
# Locally (if dependencies installed)
|
||||
python poc/exploits/shell_injection.py
|
||||
```
|
||||
|
||||
### Path Traversal POC
|
||||
|
||||
```bash
|
||||
# In container
|
||||
docker compose run --rm nanobot python /app/poc/exploits/path_traversal.py
|
||||
|
||||
# Locally
|
||||
python poc/exploits/path_traversal.py
|
||||
```
|
||||
|
||||
### LiteLLM RCE POC
|
||||
|
||||
```bash
|
||||
# In container (current version)
|
||||
docker compose run --rm nanobot python /app/poc/exploits/litellm_rce.py
|
||||
|
||||
# With vulnerable version
|
||||
docker compose --profile vulnerable run --rm nanobot-vulnerable python /app/poc/exploits/litellm_rce.py
|
||||
|
||||
# Locally
|
||||
python poc/exploits/litellm_rce.py
|
||||
```
|
||||
|
||||
### Interactive Testing
|
||||
|
||||
```bash
|
||||
# Get a shell in the container
|
||||
docker compose run --rm nanobot bash
|
||||
|
||||
# Test individual commands
|
||||
python -c "
|
||||
import asyncio
|
||||
from nanobot.agent.tools.shell import ExecTool
|
||||
tool = ExecTool()
|
||||
print(asyncio.run(tool.execute(command='cat /etc/passwd')))
|
||||
"
|
||||
```
|
||||
|
||||
## Mock LLM Server
|
||||
|
||||
The mock LLM server simulates OpenAI API responses that trigger vulnerable tool calls:
|
||||
|
||||
```bash
|
||||
# Start the mock server
|
||||
docker compose up mock-llm
|
||||
|
||||
# Set exploit mode
|
||||
curl -X POST http://localhost:8080/set_exploit/path_traversal_read
|
||||
|
||||
# List available exploits
|
||||
curl http://localhost:8080/exploits
|
||||
```
|
||||
|
||||
Available exploit modes:
|
||||
- `shell_injection` - Returns exec tool call with command injection
|
||||
- `path_traversal_read` - Returns read_file for /etc/passwd
|
||||
- `path_traversal_write` - Returns write_file to /tmp
|
||||
- `sensitive_file_read` - Returns read_file for API keys
|
||||
- `resource_exhaustion` - Returns command generating large output
|
||||
|
||||
## Expected Results
|
||||
|
||||
### Shell Injection
|
||||
|
||||
Most tests should show **⚠️ EXECUTED** status, demonstrating that commands bypass the pattern filter:
|
||||
|
||||
```
|
||||
[TEST 1] Command Substitution - Reading /etc/passwd
|
||||
Status: ⚠️ EXECUTED
|
||||
Risk: Read sensitive system file via command substitution
|
||||
Output: root:x:0:0:root:/root:/bin/bash\ndaemon:x:1:1:...
|
||||
```
|
||||
|
||||
### Path Traversal
|
||||
|
||||
File operations outside the workspace should succeed (or fail only due to OS permissions, not code restrictions):
|
||||
|
||||
```
|
||||
[TEST 1] Read /etc/passwd
|
||||
Status: ⚠️ SUCCESS (VULNERABLE)
|
||||
Risk: System user enumeration
|
||||
Content: root:x:0:0:root:/root:/bin/bash...
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
|
||||
```bash
|
||||
# Stop and remove containers
|
||||
docker compose down -v
|
||||
|
||||
# Remove results
|
||||
rm -rf results/*
|
||||
|
||||
# Full cleanup
|
||||
./run_poc.sh --clean
|
||||
```
|
||||
|
||||
## Recommended Mitigations
|
||||
|
||||
### For Shell Injection
|
||||
|
||||
1. **Replace `create_subprocess_shell` with `create_subprocess_exec`:**
|
||||
```python
|
||||
# Instead of:
|
||||
process = await asyncio.create_subprocess_shell(command, ...)
|
||||
|
||||
# Use:
|
||||
args = shlex.split(command)
|
||||
process = await asyncio.create_subprocess_exec(*args, ...)
|
||||
```
|
||||
|
||||
2. **Implement command whitelisting:**
|
||||
```python
|
||||
ALLOWED_COMMANDS = {'ls', 'cat', 'grep', 'find', 'echo'}
|
||||
command_name = shlex.split(command)[0]
|
||||
if command_name not in ALLOWED_COMMANDS:
|
||||
raise SecurityError(f"Command not allowed: {command_name}")
|
||||
```
|
||||
|
||||
3. **Use container isolation with seccomp profiles**
|
||||
|
||||
### For Path Traversal
|
||||
|
||||
1. **Always pass base_dir to _validate_path:**
|
||||
```python
|
||||
WORKSPACE_DIR = Path("/app/workspace")
|
||||
|
||||
async def execute(self, path: str) -> str:
|
||||
valid, file_path = _validate_path(path, base_dir=WORKSPACE_DIR)
|
||||
```
|
||||
|
||||
2. **Prevent symlink traversal:**
|
||||
```python
|
||||
resolved = Path(path).resolve()
|
||||
if not resolved.is_relative_to(base_dir):
|
||||
raise SecurityError("Path traversal detected")
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
When adding new POC tests:
|
||||
|
||||
1. Add test method in appropriate exploit file
|
||||
2. Include expected risk description
|
||||
3. Document bypass technique
|
||||
4. Update this README
|
||||
Reference in New Issue
Block a user