mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-30 15:03:20 +00:00
483 lines
17 KiB
Markdown
483 lines
17 KiB
Markdown
# Diversos Truques de JS & Informações Relevantes
|
|
|
|
<details>
|
|
|
|
<summary><strong>Aprenda hacking na AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
* Você trabalha em uma **empresa de cibersegurança**? Gostaria de ver sua **empresa anunciada no HackTricks**? ou gostaria de ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
|
|
|
</details>
|
|
|
|
## Fuzzing de Javascript
|
|
|
|
### Caracteres de Comentário JS Válidos
|
|
```javascript
|
|
//This is a 1 line comment
|
|
/* This is a multiline comment*/
|
|
#!This is a 1 line comment, but "#!" must to be at the beggining of the line
|
|
-->This is a 1 line comment, but "-->" must to be at the beggining of the line
|
|
|
|
|
|
for (let j = 0; j < 128; j++) {
|
|
for (let k = 0; k < 128; k++) {
|
|
for (let l = 0; l < 128; l++) {
|
|
if (j == 34 || k ==34 || l ==34)
|
|
continue;
|
|
if (j == 0x0a || k ==0x0a || l ==0x0a)
|
|
continue;
|
|
if (j == 0x0d || k ==0x0d || l ==0x0d)
|
|
continue;
|
|
if (j == 0x3c || k ==0x3c || l ==0x3c)
|
|
continue;
|
|
if (
|
|
(j == 47 && k == 47)
|
|
||(k == 47 && l == 47)
|
|
)
|
|
continue;
|
|
try {
|
|
var cmd = String.fromCharCode(j) + String.fromCharCode(k) + String.fromCharCode(l) + 'a.orange.ctf"';
|
|
eval(cmd);
|
|
} catch(e) {
|
|
var err = e.toString().split('\n')[0].split(':')[0];
|
|
if (err === 'SyntaxError' || err === "ReferenceError")
|
|
continue
|
|
err = e.toString().split('\n')[0]
|
|
}
|
|
console.log(err,cmd);
|
|
}
|
|
}
|
|
}
|
|
//From: https://balsn.tw/ctf_writeup/20191012-hitconctfquals/#bounty-pl33z
|
|
|
|
// From: Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 43). Kindle Edition.
|
|
log=[];
|
|
for(let i=0;i<=0xff;i++){
|
|
for(let j=0;j<=0xfff;j++){
|
|
try {
|
|
eval(`${String.fromCodePoint(i,j)}%$£234$`)
|
|
log.push([i,j])
|
|
}catch(e){}
|
|
}
|
|
}
|
|
console.log(log)//[35,33],[47,47]
|
|
```
|
|
### Caracteres de Nova Linha JS Válidos
|
|
```javascript
|
|
//Javascript interpret as new line these chars:
|
|
String.fromCharCode(10) //0x0a
|
|
String.fromCharCode(13) //0x0d
|
|
String.fromCharCode(8232) //0xe2 0x80 0xa8
|
|
String.fromCharCode(8233) //0xe2 0x80 0xa8
|
|
|
|
for (let j = 0; j < 65536; j++) {
|
|
try {
|
|
var cmd = '"aaaaa";'+String.fromCharCode(j) + '-->a.orange.ctf"';
|
|
eval(cmd);
|
|
} catch(e) {
|
|
var err = e.toString().split('\n')[0].split(':')[0];
|
|
if (err === 'SyntaxError' || err === "ReferenceError")
|
|
continue;
|
|
err = e.toString().split('\n')[0]
|
|
}
|
|
console.log(`[${err}]`,j,cmd);
|
|
}
|
|
//From: https://balsn.tw/ctf_writeup/20191012-hitconctfquals/#bounty-pl33z
|
|
```
|
|
### Espaços JS válidos na chamada de função
|
|
```javascript
|
|
// Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (pp. 40-41). Kindle Edition.
|
|
|
|
// Check chars that can be put in between in func name and the ()
|
|
function x(){}
|
|
|
|
log=[];
|
|
for(let i=0;i<=0x10ffff;i++){
|
|
try {
|
|
eval(`x${String.fromCodePoint(i)}()`)
|
|
log.push(i)
|
|
}catch(e){}
|
|
}
|
|
|
|
console.log(log)v//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,813 232,8233,8239,8287,12288,65279
|
|
```
|
|
### **Caracteres válidos para gerar strings**
|
|
```javascript
|
|
// Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (pp. 41-42). Kindle Edition.
|
|
|
|
// Check which pairs of chars can make something be a valid string
|
|
log=[];
|
|
for(let i=0;i<=0x10ffff;i++){
|
|
try {
|
|
eval(`${String.fromCodePoint(i)}%$£234${String.fromCodePoint(i)}`)
|
|
log.push(i)
|
|
}catch(e){}
|
|
}
|
|
console.log(log) //34,39,47,96
|
|
//single quote, quotes, backticks & // (regex)
|
|
```
|
|
### **Surrogate Pairs BF**
|
|
|
|
Esta técnica não será muito útil para XSS, mas pode ser útil para contornar proteções de WAF. Este código Python recebe como entrada 2 bytes e procura pares substitutos que tenham o primeiro byte como o último byte do par substituto alto e o último byte como o último byte do par substituto baixo.
|
|
```python
|
|
def unicode(findHex):
|
|
for i in range(0,0xFFFFF):
|
|
H = hex(int(((i - 0x10000) / 0x400) + 0xD800))
|
|
h = chr(int(H[-2:],16))
|
|
L = hex(int(((i - 0x10000) % 0x400 + 0xDC00)))
|
|
l = chr(int(L[-2:],16))
|
|
if(h == findHex[0]) and (l == findHex[1]):
|
|
print(H.replace("0x","\\u")+L.replace("0x","\\u"))
|
|
```
|
|
Mais informações:
|
|
|
|
* [https://github.com/dreadlocked/ctf-writeups/blob/master/nn8ed/README.md](https://github.com/dreadlocked/ctf-writeups/blob/master/nn8ed/README.md)
|
|
* [https://mathiasbynens.be/notes/javascript-unicode](https://mathiasbynens.be/notes/javascript-unicode) [https://mathiasbynens.be/notes/javascript-encoding](https://mathiasbynens.be/notes/javascript-encoding)
|
|
|
|
### `javascript{}:` Protocolo de Fuzzing
|
|
```javascript
|
|
// Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 34). Kindle Edition.
|
|
log=[];
|
|
let anchor = document.createElement('a');
|
|
for(let i=0;i<=0x10ffff;i++){
|
|
anchor.href = `javascript${String.fromCodePoint(i)}:`;
|
|
if(anchor.protocol === 'javascript:') {
|
|
log.push(i);
|
|
}
|
|
}
|
|
console.log(log)//9,10,13,58
|
|
// Note that you could BF also other possitions of the use of multiple chars
|
|
|
|
// Test one option
|
|
let anchor = document.createElement('a');
|
|
anchor.href = `javascript${String.fromCodePoint(58)}:alert(1337)`;
|
|
anchor.append('Click me')
|
|
document.body.append(anchor)
|
|
|
|
// Another way to test
|
|
<a href="javascript:alert(1337)">Test</a>
|
|
```
|
|
### URL Fuzzing
|
|
```javascript
|
|
// Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (pp. 36-37). Kindle Edition.
|
|
|
|
// Before the protocol
|
|
a=document.createElement('a');
|
|
log=[];
|
|
for(let i=0;i<=0x10ffff;i++){
|
|
a.href = `${String.fromCodePoint(i)}https://hacktricks.xyz`;
|
|
if(a.hostname === 'hacktricks.xyz'){
|
|
log.push(i);
|
|
}
|
|
}
|
|
console.log(log) //0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
|
|
|
|
// Between the slashes
|
|
a=document.createElement('a');
|
|
log=[];
|
|
for(let i=0;i<=0x10ffff;i++){
|
|
a.href = `/${String.fromCodePoint(i)}/hacktricks.xyz`;
|
|
if(a.hostname === 'hacktricks.xyz'){
|
|
log.push(i);
|
|
}
|
|
}
|
|
console.log(log) //9,10,13,47,92
|
|
```
|
|
### Fuzzing HTML
|
|
```javascript
|
|
// Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 38). Kindle Edition.
|
|
|
|
// Fuzzing chars that can close an HTML comment
|
|
|
|
let log=[];
|
|
let div = document.createElement('div');
|
|
for(let i=0;i<=0x10ffff;i++){
|
|
div.innerHTML=`<!----${String.fromCodePoint(i)}><span></span>-->`;
|
|
if(div.querySelector('span')){
|
|
log.push(i);
|
|
}
|
|
}
|
|
console.log(log)//33,45,62
|
|
```
|
|
## **Analisando atributos**
|
|
|
|
A ferramenta **Hackability inspector** da Portswigger ajuda a **analisar** os **atributos** de um objeto javascript. Verifique: [https://portswigger-labs.net/hackability/inspector/?input=x.contentWindow\&html=%3Ciframe%20src=//subdomain1.portswigger-labs.net%20id=x%3E](https://portswigger-labs.net/hackability/inspector/?input=x.contentWindow\&html=%3Ciframe%20src=//subdomain1.portswigger-labs.net%20id=x%3E)
|
|
|
|
## **Arquivos .map js**
|
|
|
|
* Truque para baixar arquivos .map js: [https://medium.com/@bitthebyte/javascript-for-bug-bounty-hunters-part-2-f82164917e7](https://medium.com/@bitthebyte/javascript-for-bug-bounty-hunters-part-2-f82164917e7)
|
|
* Você pode usar essa ferramenta para analisar esses arquivos [https://github.com/paazmaya/shuji](https://github.com/paazmaya/shuji)
|
|
|
|
## Atribuição "--"
|
|
|
|
O operador de decremento `--` também é uma atribuição. Este operador pega um valor e então o decrementa em um. Se esse valor não for um número, será definido como `NaN`. Isso pode ser usado para **remover o conteúdo de variáveis do ambiente**.
|
|
|
|
![](<../../.gitbook/assets/image (993).png>)
|
|
|
|
![](<../../.gitbook/assets/image (329).png>)
|
|
|
|
## Truques de Funções
|
|
|
|
### .call e .apply
|
|
|
|
O método **`.call`** de uma função é usado para **executar a função**.\
|
|
O **primeiro argumento** que ele espera por padrão é o **valor de `this`** e se **nada** for fornecido, **`window`** será esse valor (a menos que seja usado o **`modo estrito`**).
|
|
```javascript
|
|
function test_call(){
|
|
console.log(this.value); //baz
|
|
}
|
|
new_this={value:"hey!"}
|
|
test_call.call(new_this);
|
|
|
|
// To pass more arguments, just pass then inside .call()
|
|
function test_call() {
|
|
console.log(arguments[0]); //"arg1"
|
|
console.log(arguments[1]); //"arg2"
|
|
console.log(this); //[object Window]
|
|
}
|
|
test_call.call(null, "arg1", "arg2")
|
|
|
|
// If you use the "use strict" directive "this" will be null instead of window:
|
|
function test_call() {
|
|
"use strict";
|
|
console.log(this); //null
|
|
}
|
|
test_call.call(null)
|
|
|
|
//The apply function is pretty much exactly the same as the call function with one important difference, you can supply an array of arguments in the second argument:
|
|
function test_apply() {
|
|
console.log(arguments[0]); //"arg1"
|
|
console.log(arguments[1]); //"arg2"
|
|
console.log(this); //[object Window]
|
|
}
|
|
test_apply.apply(null, ["arg1", "arg2"])
|
|
```
|
|
### Funções de seta
|
|
|
|
As funções de seta permitem que você gere funções em uma única linha de forma mais fácil (se você as entender)
|
|
```javascript
|
|
// Traditional
|
|
function (a){ return a + 1; }
|
|
// Arrow forms
|
|
a => a + 100;
|
|
a => {a + 100};
|
|
|
|
// Traditional
|
|
function (a, b){ return a + b + 1; }
|
|
// Arrow
|
|
(a, b) => a + b + 100;
|
|
|
|
// Tradictional no args
|
|
let a = 4;
|
|
let b = 2;
|
|
function (){ return a + b + 1; }
|
|
|
|
// Arrow
|
|
let a = 4;
|
|
let b = 2;
|
|
() => a + b + 1;
|
|
```
|
|
Portanto, a maioria das funções anteriores são realmente inúteis porque não as estamos salvando em nenhum lugar para chamá-las posteriormente. Exemplo de criação da função `plusone`:
|
|
```javascript
|
|
// Traductional
|
|
function plusone (a){ return a + 1; }
|
|
|
|
//Arrow
|
|
plusone = a => a + 100;
|
|
```
|
|
### Função Bind
|
|
|
|
A função bind permite criar uma **cópia** de uma **função modificando** o objeto **`this`** e os **parâmetros** fornecidos.
|
|
```javascript
|
|
//This will use the this object and print "Hello World"
|
|
var fn = function ( param1, param2 ) {
|
|
console.info( this, param1, param2 );
|
|
}
|
|
fn('Hello', 'World')
|
|
|
|
//This will still use the this object and print "Hello World"
|
|
var copyFn = fn.bind();
|
|
copyFn('Hello', 'World')
|
|
|
|
//This will use the "console" object as "this" object inside the function and print "fixingparam1 Hello"
|
|
var bindFn_change = fn.bind(console, "fixingparam1");
|
|
bindFn_change('Hello', 'World')
|
|
|
|
//This will still use the this object and print "fixingparam1 Hello"
|
|
var bindFn_thisnull = fn.bind(null, "fixingparam1");
|
|
bindFn_change('Hello', 'World')
|
|
|
|
//This will still use the this object and print "fixingparam1 Hello"
|
|
var bindFn_this = fn.bind(this, "fixingparam1");
|
|
bindFn_change('Hello', 'World')
|
|
```
|
|
{% hint style="info" %}
|
|
Note que usando **`bind`** você pode manipular o objeto **`this`** que será usado ao chamar a função.
|
|
{% endhint %}
|
|
|
|
### Vazamento de código da função
|
|
|
|
Se você pode **acessar o objeto** de uma função, você pode **obter o código** dessa função.
|
|
```javascript
|
|
function afunc(){
|
|
return 1+1;
|
|
}
|
|
console.log(afunc.toString()); //This will print the code of the function
|
|
console.log(String(afunc)); //This will print the code of the function
|
|
console.log(this.afunc.toString()); //This will print the code of the function
|
|
console.log(global.afunc.toString()); //This will print the code of the function
|
|
```
|
|
Em casos em que a **função não tem nome**, você ainda pode imprimir o **código da função** de dentro:
|
|
```javascript
|
|
(function (){ return arguments.callee.toString(); })()
|
|
(function (){ return arguments[0]; })("arg0")
|
|
```
|
|
Algumas **formas aleatórias** de **extrair o código** de uma função (inclusive comentários) de outra função:
|
|
```javascript
|
|
(function (){ return retFunc => String(arguments[0]) })(a=>{/* Hidden commment */})()
|
|
(function (){ return retFunc => Array(arguments[0].toString()) })(a=>{/* Hidden commment */})()
|
|
(function (){ return String(this)}).bind(()=>{ /* Hidden commment */ })()
|
|
(u=>(String(u)))(_=>{ /* Hidden commment */ })
|
|
(u=>_=>(String(u)))(_=>{ /* Hidden commment */ })()
|
|
```
|
|
## Escape do Sandbox - Recuperando o objeto window
|
|
|
|
O objeto Window permite acessar funções definidas globalmente como alert ou eval.
|
|
|
|
{% code overflow="wrap" %}
|
|
```javascript
|
|
// Some ways to access window
|
|
window.eval("alert(1)")
|
|
frames
|
|
globalThis
|
|
parent
|
|
self
|
|
top //If inside a frame, this is top most window
|
|
|
|
// Access window from document
|
|
document.defaultView.alert(1)
|
|
// Access document from a node object
|
|
node = document.createElement('div')
|
|
node.ownerDocument.defaultView.alert(1)
|
|
|
|
// There is a path property on each error event whose last element is the window
|
|
<img src onerror=event.path.pop().alert(1337)>
|
|
// In other browsers the method is
|
|
<img src onerror=event.composedPath().pop().alert(1337)>
|
|
// In case of svg, the "event" object is called "evt"
|
|
<svg><image href=1 onerror=evt.composedPath().pop().alert(1337)>
|
|
|
|
// Abusing Error.prepareStackTrace to get Window back
|
|
Error.prepareStackTrace=function(error, callSites){
|
|
2 callSites.shift().getThis().alert(1337);
|
|
3 };
|
|
4 new Error().stack
|
|
|
|
// From an HTML event
|
|
// Events from HTML are executed in this context
|
|
with(document) {
|
|
with(element) {
|
|
//executed event
|
|
}
|
|
}
|
|
// Because of that with(document) it's possible to access properties of document like:
|
|
<img src onerror=defaultView.alert(1337)>
|
|
<img src onerror=s=createElement('script');s.append('alert(1337)');appendChild(s)>
|
|
```
|
|
{% endcode %}
|
|
|
|
## Ponto de interrupção no acesso ao valor
|
|
```javascript
|
|
// Stop when a property in sessionStorage or localStorage is set/get
|
|
// via getItem or setItem functions
|
|
sessionStorage.getItem = localStorage.getItem = function(prop) {
|
|
debugger;
|
|
return sessionStorage[prop];
|
|
}
|
|
|
|
localStorage.setItem = function(prop, val) {
|
|
debugger;
|
|
localStorage[prop] = val;
|
|
}
|
|
```
|
|
|
|
```javascript
|
|
// Stop when anyone sets or gets the property "ppmap" in any object
|
|
// For example sessionStorage.ppmap
|
|
// "123".ppmap
|
|
// Useful to find where weird properties are being set or accessed
|
|
// or to find where prototype pollutions are occurring
|
|
|
|
function debugAccess(obj, prop, debugGet=true){
|
|
|
|
var origValue = obj[prop];
|
|
|
|
Object.defineProperty(obj, prop, {
|
|
get: function () {
|
|
if ( debugGet )
|
|
debugger;
|
|
return origValue;
|
|
},
|
|
set: function(val) {
|
|
debugger;
|
|
origValue = val;
|
|
}
|
|
});
|
|
};
|
|
|
|
debugAccess(Object.prototype, 'ppmap')
|
|
```
|
|
## Acesso automático do navegador para testar payloads
|
|
```javascript
|
|
//Taken from https://github.com/svennergr/writeups/blob/master/inti/0621/README.md
|
|
const puppeteer = require("puppeteer");
|
|
|
|
const realPasswordLength = 3000;
|
|
async function sleep(ms) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
}
|
|
|
|
(async () => {
|
|
const browser = await puppeteer.launch();
|
|
const page = await browser.newPage();
|
|
//Loop to iterate through different values
|
|
for (let i = 0; i < 10000; i += 100) {
|
|
console.log(`Run number ${i}`);
|
|
const input = `${"0".repeat(i)}${realPasswordLength}`;
|
|
console.log(` https://challenge-0621.intigriti.io/passgen.php?passwordLength=${input}&allowNumbers=true&allowSymbols=true×tamp=1624556811000`);
|
|
//Go to the page
|
|
await page.goto(
|
|
`https://challenge-0621.intigriti.io/passgen.php?passwordLength=${input}&allowNumbers=true&allowSymbols=true×tamp=1624556811000`
|
|
);
|
|
//Call function "generate()" inside the page
|
|
await page.evaluate("generate()");
|
|
//Get node inner text from an HTML element
|
|
const passwordContent = await page.$$eval(
|
|
".alert .page-content",
|
|
(node) => node[0].innerText
|
|
);
|
|
//Transform the content and print it in console
|
|
const plainPassword = passwordContent.replace("Your password is: ", "");
|
|
if (plainPassword.length != realPasswordLength) {
|
|
console.log(i, plainPassword.length, plainPassword);
|
|
}
|
|
|
|
await sleep(1000);
|
|
}
|
|
await browser.close();
|
|
})();
|
|
```
|
|
<details>
|
|
|
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
* Você trabalha em uma **empresa de cibersegurança**? Quer ver sua **empresa anunciada no HackTricks**? ou quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
|
|
|
</details>
|