OCI offensive security assessment and enumeration framework.
Project description
OCInferno
Overview
In the spirit of transparency: parts of this project and documentation were developed with LLM coding assistance. Review code and behavior in your environment before operational use. Notably, the enum_config_checks module is still in-progress based off original content generated.
OCInferno (O-C-Inferno) is an OCI offensive security assessment framework for workspace-driven credential handling, service enumeration, artifact download, and graph-based attack-path analysis. It includes a module to generate a custom OpenGraph output which can be fed into BloodHound, as shown below, to map privilege-escalation paths.
Figure 1. Example OpenGraph/BloodHound relationship view.
Figure 2. Example module output in the CLI.
High-Level Features
- CLI UX: Interactive CLI with command and argument tab auto-complete and history.
- Authentication: Multiple supported auth methods:
- Config Profile: API key-backed and session-token-backed OCI profiles.
- Instance Principal: Compute-instance identity flow.
- Resource Principal: Runtime/workload identity flow.
- Module Model: Service-specific modules across OCI services, with proxy and rate-limiting support.
- Mass Enumeration: Broad OCI module coverage with
enum_allorchestration support (implemented inmodules/everything). - Config Audits:
enum_config_checkfindings based on enumerated/saved data (implemented inmodules/everything). - Reporting Exports: Resource export support for HTML, CSV, JSON, Excel, and graph image outputs.
- Artifact Downloads: Download support across many modules with
--downloadand selective routing. - OpenGraph / BloodHound: OpenGraph export for BloodHound ingestion, including:
- A default focused view of high-impact edges, with
--include-allavailable for broader relationship output to ideally see all relationships regardless of priv escalation weight. - Privilege-escalation path modeling across OCI IAM and Identity Domain app-role/grant relationships.
- Inheritance-aware modeling (
--expand-inherited) and conditional evaluation (--cond-eval) to improve graph accuracy.
- A default focused view of high-impact edges, with
Documentation
Documentation is maintained on the GitHub Wiki:
Contributing guidance:
CONTRIBUTING.md
Roadmap guidance:
ROADMAP.md
Sample OpenGraph JSON:
opengraph_examples/example_input.json
Installation TLDR
Option 1: Local Install
git clone https://github.com/NetSPI/OCInferno.git
# You don't need pytests to run the tool
rm -r tests/
virtualenv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m ocinferno
Run the tool:
python -m ocinferno
Option 2: PIP Install
pip3 install ocinferno
Run the tool:
ocinferno
At Startup
- Create/select a workspace.
- Add credentials using your OCI config profile (example uses
MY_PROFILEto add an API key):
profile MY_PROFILE --filepath ~/.oci/config --profile MY_PROFILE
- Start the first full run.
enum_allruns all modules.--comprecursively enumerates compartments to maximize coverage.--getfollows LIST calls with GET calls where supported for deeper detail.--downloaddownloads data where possible, choosing--not-downloads bucketsattempts to download all content except bucket object content.
# Download as much as you can
modules run enum_all --get --comp --download
# Download everything EXCEPT bucket contents
modules run enum_all --get --comp [--not-downloads buckets]
- Export a compartment tree image and Excel data output to quickly review what your current permissions can see:
(TENANT-2snxfsaa:TEST)> data export treeimage
[*] Compartment tree export complete -> ./ocinferno_output/1_TEST/exports/data/global/resource_reports/compartment_tree.svg (format=svg, renderer=svg-interactive, compartments=6)
(TENANT-2snxfsaa:TEST)> data export excel
[*] Excel export complete -> ./ocinferno_output/1_TEST/exports/data/global/sqlite_excel/sqlite_blob.xlsx (format=xlsx, databases=1, tables=173, rows=54951, single_sheet=True, condensed=True)
Figure 1. Tree image export from data export treeimage.
Figure 2. Excel export output from data export excel.
OpenGraph TLDR
Where JSON is saved
Once all data is collected, use the enum_oracle_cloud_hound_data module as seen in example below:
modules run enum_oracle_cloud_hound_data [--include-all] [--expand-inherited] [--cond-eval] --reset --out opengraph_output.json
Optional OpenGraph flags:
[--include-all]: include broader non-default relationship output, not just default high-impact allowlist-focused edges.[--expand-inherited]: expand inherited IAM scope/location relationships.[--cond-eval]: evaluate IAM statement conditions (when resolvable) to improve edge accuracy.[--reset]: Wipes Opengraph database before creating JSON. Advised to always run this if you want a fresh generation each time else there might be legacy content from past runs.
Import into BloodHound
- Open BloodHound CE. Installation instructions can be found here
- Go to data import.
- Upload
oracle_cloud_hound.json. - Run path queries against high-impact OCI edges.
Figure 3. Uploading OpenGraph JSON into BloodHound CE.
Sample Cypher Queries
// 0) See All nodes and edges
MATCH (n)
OPTIONAL MATCH (n)-[r]-(m)
RETURN n, r, m
// 1) Find all users not in any group
MATCH (u:OCIUser)
WHERE NOT (u)-[:OCI_GROUP_MEMBER]->(:OCIGroup)
RETURN u
ORDER BY coalesce(u.name, u.id);
// 2a) Find standard groups with no members
MATCH (g:OCIGroup)
WHERE NOT (:OCIUser)-[:OCI_GROUP_MEMBER]->(g)
RETURN g
ORDER BY coalesce(g.name, g.id);
// 2b) Find dynamic groups with no matched members
MATCH (dg:OCIDynamicGroup)
WHERE NOT ()-[:OCI_DYNAMIC_GROUP_MEMBER]->(dg)
RETURN dg
ORDER BY coalesce(dg.name, dg.id);
// 3) Find all paths from all principals to all-resources scopes (depth 1..6)
MATCH (p0)
WHERE p0:OCIUser OR p0:OCIGroup OR p0:OCIDynamicGroup
MATCH p = (p0)-[*1..6]->(r:OCIAllResources)
RETURN p
LIMIT 500;
// 4) Find all paths to all-resources scopes regardless of start node type (depth 1..6)
MATCH p = (s)-[*1..6]->(r:OCIAllResources)
RETURN p
LIMIT 500;
Add a custom allowlist edge (TLDR)
If you want to add your own default OpenGraph edge (for example tie GROUP_INSPECT to an edge), add a rule in:
modules/opengraph/utilities/helpers/data/static_constants.jsonunderALLOW_RULE_DEFS
Example:
{
"id": "GROUP_INSPECT",
"match": {
"resource_tokens": ["groups"],
"permissions_all": ["GROUP_INSPECT"]
},
"edge": {
"label": "OCI_GROUP_INSPECT",
"description": "Inspect IAM groups in scope."
},
"destination": {
"token": "groups",
"node_type": "OCIResourceGroup",
"allow_specific": true
}
}
Field quick reference:
id: internal rule identifier used by the builder/tests.match.resource_tokens: OCI policy resource token(s) the statement must target (for examplegroups).match.permissions_all: permission(s) that must all be present in the same statement to trigger the edge.edge.label: relationship kind written into OpenGraph.edge.description: human-readable explanation stored on the edge.destination.token: logical destination scope/resource token represented in the graph.destination.node_type: node class to emit for the destination (commonlyOCIResourceGroup).destination.allow_specific: whentrue, conditionals can resolve to specific resources (for example a specific group) instead of only generic scope nodes.
Then rerun enum_oracle_cloud_hound_data and update tests/golden outputs if behavior changed.
Dependency Inventory
| Dependency | Where Used | Purpose |
|---|---|---|
oci==2.169.0 |
Core modules | OCI SDK clients/auth/providers for enumeration and actions. |
requests==2.33.1 |
HTTP helpers/integrations | HTTP operations and API helper requests. |
PyYAML>=6.0.3 |
Config/parsing layers | YAML config and mapping parsing. |
prettytable==3.17.0 |
CLI output | Terminal table rendering. |
oci-lexer-parser==0.1.2 |
Policy/OpenGraph logic | OCI IAM policy lexing/parsing support. |
pandas>=2.2.0 |
Data export | Excel export pipeline. |
xlsxwriter>=3.2.0 |
Data export | .xlsx writer engine for exports. |
pytest>=8.0* |
Unit tests | Test framework (tests/unit). |
SVG creation for data export treeimage can be found in ocinferno/core/utils/module_helpers.py (export_compartment_tree_image, _render_compartment_tree_svg). Note it is a standard SVG with some dynamic elements, and the SVG root includes xmlns="http://www.w3.org/2000/svg" for SVG parsing.
*Dev/test-scoped dependency.
Repository Layout
ocinferno/: main Python package root.ocinferno/__main__.py:python -m ocinfernoentrypoint.ocinferno/cli/: interactive command processor and workspace command handlers.ocinferno/core/: session/config/data/logging/runtime/export primitives.ocinferno/modules/: service modules (includingeverythingorchestration andopengraphexport logic).ocinferno/mappings/: static service/resource mapping data used by modules.tests/unit/: primary unit-test suite (run in CI).tests/integration/: integration-focused tests.tests/enum_modules/: module-level enumeration behavior tests..github/workflows/: GitHub Actions workflows.images/: README and documentation images.opengraph_examples/: sample OpenGraph JSON artifacts.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ocinferno-0.5.66.tar.gz.
File metadata
- Download URL: ocinferno-0.5.66.tar.gz
- Upload date:
- Size: 391.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
520ecde503ac8943ac8171575b07da92933a1774117dfdd045c8361916878653
|
|
| MD5 |
43896ba2288636c1017bb501a1a95194
|
|
| BLAKE2b-256 |
d546b9bc23f4b73cba40ce3d301e854eab963936afb52a448c0791fbf547511d
|
Provenance
The following attestation bundles were made for ocinferno-0.5.66.tar.gz:
Publisher:
publish.yml on NetSPI/OCInferno
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ocinferno-0.5.66.tar.gz -
Subject digest:
520ecde503ac8943ac8171575b07da92933a1774117dfdd045c8361916878653 - Sigstore transparency entry: 1222589558
- Sigstore integration time:
-
Permalink:
NetSPI/OCInferno@0f49b4783139af47bfd9f9b16facc4c7b24bc809 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/NetSPI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0f49b4783139af47bfd9f9b16facc4c7b24bc809 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ocinferno-0.5.66-py3-none-any.whl.
File metadata
- Download URL: ocinferno-0.5.66-py3-none-any.whl
- Upload date:
- Size: 451.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7476665d198654e090fd94ba04b0d57df774179d9b196aabc0dd50d2f7b4096
|
|
| MD5 |
615524eabf040bf25dadb178252dd593
|
|
| BLAKE2b-256 |
b5f78ed1319e05a9100ecf7d82ecb52d81901bb0b5be70657929a6ffd6956e5a
|
Provenance
The following attestation bundles were made for ocinferno-0.5.66-py3-none-any.whl:
Publisher:
publish.yml on NetSPI/OCInferno
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ocinferno-0.5.66-py3-none-any.whl -
Subject digest:
c7476665d198654e090fd94ba04b0d57df774179d9b196aabc0dd50d2f7b4096 - Sigstore transparency entry: 1222589572
- Sigstore integration time:
-
Permalink:
NetSPI/OCInferno@0f49b4783139af47bfd9f9b16facc4c7b24bc809 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/NetSPI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@0f49b4783139af47bfd9f9b16facc4c7b24bc809 -
Trigger Event:
workflow_dispatch
-
Statement type: