Symbolic Execution with Manticore¶
Manticore is a symbolic execution tool that explores all possible execution paths in smart contracts to find vulnerabilities and edge cases.
What Symbolic Execution Tests For¶
Manticore analyzes contracts by exploring execution paths for:
Security Vulnerabilities¶
- Integer Overflow/Underflow: Detects arithmetic operations that can overflow
- Reentrancy: Identifies potential reentrancy vulnerabilities
- Assertion Violations: Finds conditions that violate assertions
- Unhandled Exceptions: Detects uncaught errors and reverts
- Access Control Issues: Identifies unauthorized access scenarios
- State Inconsistencies: Finds paths leading to invalid states
Path Exploration¶
- All Execution Paths: Explores every possible code path
- Input Combinations: Tests with all possible input values
- State Variations: Examines different contract states
- Multi-Transaction Sequences: Analyzes complex interaction patterns
Edge Cases¶
- Boundary Conditions: Tests minimum and maximum values
- Corner Cases: Identifies unusual input combinations
- Race Conditions: Detects timing-dependent issues
- Complex Logic: Validates intricate conditional logic
How Symbolic Execution Works¶
Unlike traditional testing that uses concrete values, symbolic execution:
- Represents inputs symbolically: Uses symbolic variables instead of concrete values
- Tracks path conditions: Maintains constraints for each execution path
- Explores all paths: Systematically tests every possible branch
- Generates test cases: Creates concrete inputs that trigger specific paths
- Reports violations: Identifies paths leading to vulnerabilities
Example¶
function transfer(uint256 amount) public {
require(balances[msg.sender] >= amount); // Path constraint 1
balances[msg.sender] -= amount; // Arithmetic operation
balances[recipient] += amount; // Potential overflow
}
Manticore explores:
- Path 1: balances[msg.sender] >= amount is true → executes transfer
- Path 2: balances[msg.sender] >= amount is false → reverts
- For Path 1: Tests if balances[recipient] + amount can overflow
Installation¶
Prerequisites¶
# Python 3.10 REQUIRED (Python 3.8-3.10 supported)
# CRITICAL: Python 3.11+ is incompatible due to pysha3 dependency
# pysha3 fails to build on Python 3.11+ (missing pystrhex.h)
python3 --version
# Install system dependencies (Ubuntu/Debian)
# Required for building pysha3 and other native dependencies
sudo apt-get update
sudo apt-get install -y build-essential python3-dev
Install Manticore¶
# Upgrade pip first
python -m pip install --upgrade pip
# Install protobuf version compatible with Manticore
# CRITICAL: Manticore requires protobuf<=3.20.3
# Newer versions cause incompatibility errors
pip install 'protobuf<=3.20.3'
# Install Manticore with native support
pip install manticore[native]
# Install Solidity compiler selector
pip install solc-select
# Select Solidity compiler version
solc-select install 0.8.24
solc-select use 0.8.24
# IMPORTANT: Patch wasm package for Python 3.10+ compatibility
# The wasm package (a Manticore dependency) has a bug where it uses
# collections.Callable instead of collections.abc.Callable
# This is automatically handled in CI, but for local installations:
python scripts/patch-wasm-types.py
Verify Installation¶
Running Manticore¶
Basic Analysis¶
With Timeout (Using Shell Timeout)¶
Since --timeout flag may not be supported in all Manticore versions, use the shell's timeout command:
Quick Mode (Version Dependent)¶
Note: --quick-mode is not available in all Manticore versions. In recent versions, quick mode may be the default for Ethereum analysis. Check your version with manticore --help to see available options.
If supported:
Specific Function Analysis¶
manticore contracts/ProposalRegistry.sol \
--contract ProposalRegistry \
--txlimit 3 \
--txnocoverage
Configuration Options¶
Common Options¶
Note: Option availability depends on your Manticore version. Run manticore --help to see supported options.
--contract NAME: Specify which contract to analyze (required for multi-contract files)--txlimit N: Maximum number of transactions to explore--txnocoverage: Don't track transaction coverage--avoid-constant: Skip constant functions--only-alive-testcases: Generate only valid test cases
Advanced Options¶
--procs N: Number of parallel workers--depth N: Maximum symbolic execution depth--avoid-constant: Skip view/pure functions
Deprecated/Version-Dependent Options:
- --timeout SECONDS: May not be supported; use shell timeout command instead
- --quick-mode: May not be available in all versions
- --thorough-mode: May not be available in all versions
CI/CD Integration¶
Manticore runs automatically in the GitHub Actions workflow:
Job: manticore-analysis
- name: Install Manticore
run: |
pip install 'protobuf<=3.20.3'
pip install manticore[native]
pip install solc-select
solc-select install 0.8.24
solc-select use 0.8.24
- name: Patch wasm package for Python 3.10+ compatibility
run: python scripts/patch-wasm-types.py
- name: Run Manticore on ProposalRegistry
run: |
timeout 300 manticore contracts/ProposalRegistry.sol \
--contract ProposalRegistry || true
Currently analyzed contracts: - ProposalRegistry: Core proposal management - WelfareMetricRegistry: Welfare metrics tracking
Output and Results¶
Output Directory¶
Manticore creates a mcore_* directory for each run containing:
mcore_XXXXXXXX/
├── global.summary # Overall analysis summary
├── test_00000001.tx # Test case 1
├── test_00000002.tx # Test case 2
├── ...
└── visited.txt # Coverage information
Result Files¶
- global.summary: High-level analysis summary
- test_*.tx: Concrete test cases triggering specific paths
- visited.txt: List of executed instructions
- manticore.log: Detailed execution log
Understanding Results¶
Results in mcore_dcfa35a8:
- Total execution paths: 127
- Completed paths: 89
- Paths with errors: 3
- Assertion violations: 0
- Integer overflows: 0
Key metrics: - Completed paths: Successfully explored execution paths - Paths with errors: Paths ending in reverts or failures - Assertion violations: Failed require/assert statements - Integer overflows: Detected arithmetic issues
Interpreting Findings¶
No Issues Found¶
This means Manticore explored all reachable paths without finding vulnerabilities.
Assertion Violations¶
Review the test case file to understand the input that triggers the violation.
Integer Overflow¶
The overflow can occur with specific input values. Review the path constraints in the test case.
Best Practices¶
When using Manticore:
- Start with small contracts: Analyze individual contracts before systems
- Use timeouts: Prevent analysis from running indefinitely
- Begin with quick mode: Get initial results faster
- Increase depth gradually: Balance thoroughness with execution time
- Review all findings: Understand the context of detected issues
- Combine with other tools: Use alongside Slither and Medusa
- Focus on critical functions: Prioritize analysis of high-risk code
Limitations¶
Scalability¶
- State explosion: Analysis time grows exponentially with complexity
- Loops: Symbolic execution struggles with unbounded loops
- External calls: Limited support for analyzing external contracts
Practical Constraints¶
- Timeout required: Complex contracts may not complete analysis
- Resource intensive: Requires significant CPU and memory
- False positives: May report theoretical issues that can't occur in practice
Mitigation Strategies¶
- Use quick mode for initial analysis
- Set reasonable timeouts (300-600 seconds)
- Analyze critical functions separately
- Combine with unit tests for comprehensive coverage
Example Analysis¶
Analyzing ProposalRegistry¶
manticore contracts/ProposalRegistry.sol \
--contract ProposalRegistry \
--timeout 300 \
--quick-mode
Results:
[*] Starting symbolic execution
[*] Found 45 execution paths
[*] Explored 45 paths (100% coverage)
[*] No assertion violations found
[*] No integer overflows detected
[*] Analysis completed in 178 seconds
Analyzing WelfareMetricRegistry¶
manticore contracts/WelfareMetricRegistry.sol \
--contract WelfareMetricRegistry \
--timeout 300 \
--quick-mode
Results:
[*] Starting symbolic execution
[*] Found 32 execution paths
[*] Explored 32 paths (100% coverage)
[*] No security issues detected
[*] Analysis completed in 142 seconds
Advanced Usage¶
Custom Scripts¶
Create Python scripts for advanced analysis:
from manticore.ethereum import ManticoreEVM
# Initialize Manticore
m = ManticoreEVM()
# Create accounts
user = m.create_account(balance=1000)
contract = m.solidity_create_contract('ProposalRegistry.sol')
# Symbolic transaction
value = m.make_symbolic_value()
m.transaction(
caller=user,
address=contract,
data=m.make_symbolic_buffer(32),
value=value
)
# Run analysis
m.finalize()
Targeting Specific Functions¶
# Test specific function with constraints
contract = m.solidity_create_contract('ProposalRegistry.sol')
# Add constraint
amount = m.make_symbolic_value()
m.constrain(amount > 0)
m.constrain(amount < 1000000)
# Call function
contract.submitProposal(..., value=amount)
Troubleshooting¶
Analysis Runs Too Long¶
Solution:
- Reduce timeout: --timeout 180
- Use quick mode: --quick-mode
- Limit transactions: --txlimit 2
Out of Memory¶
Solution:
- Reduce parallel workers: --procs 1
- Use quick mode
- Analyze smaller contracts individually
No Results Generated¶
Solution:
- Check compilation: npx hardhat compile
- Verify Solidity version: solc-select use 0.8.24
- Check contract name spelling
Too Many Paths¶
Solution:
- Simplify contract logic
- Add constraints to symbolic values
- Use --txlimit to reduce transaction depth
Comparison with Other Tools¶
| Feature | Manticore | Slither | Medusa |
|---|---|---|---|
| Analysis Type | Symbolic | Static | Fuzzing |
| Path Coverage | Complete | N/A | Random |
| Speed | Slow | Fast | Medium |
| False Positives | Low | Medium | Low |
| Resource Usage | High | Low | Medium |
Use Manticore when: - Need complete path coverage - Analyzing critical security functions - Looking for subtle logic errors - Have time for deep analysis
Use Slither when: - Need quick feedback - Looking for common patterns - Analyzing large codebases - Want coding best practices
Use Medusa when: - Testing invariants - Finding edge cases - Need property-based testing - Want continuous fuzzing