# Trucos JS misceláneos e información relevante
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! * Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Obtén la [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com) * **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.** * **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
## Fuzzing de Javascript ### Caracteres válidos para comentarios JS ```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 Nueva Línea Válidos en JS ```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 ``` ### Espacios válidos de JS en llamadas de función ```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 generar cadenas** ```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 no será muy útil para XSS, pero podría ser útil para evitar las protecciones de WAF. Este código de Python recibe como entrada 2 bytes y busca pares sustitutos que tengan el primer byte como los últimos bytes del par sustituto alto y el último byte como el último byte del par sustituto bajo. ```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")) ``` ### Fuzzing del protocolo `javascript{}:` El protocolo `javascript{}:` es utilizado para ejecutar código JavaScript en el contexto de una página web. Es posible utilizar este protocolo para realizar ataques de Cross-Site Scripting (XSS) en una página web. Para realizar un ataque de fuzzing en el protocolo `javascript{}:`, se pueden utilizar diferentes técnicas, como la inyección de caracteres Unicode y la codificación de caracteres. Estas técnicas permiten evadir los filtros de seguridad y ejecutar código malicioso en la página web. Es importante tener en cuenta que este tipo de ataques pueden ser detectados y prevenidos mediante la implementación de medidas de seguridad adecuadas en la página web, como la validación de entradas y la sanitización de datos. ```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 Test ``` ### Fuzzing de URL ```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=``; if(div.querySelector('span')){ log.push(i); } } console.log(log)//33,45,62 ``` ## **Análisis de atributos** La herramienta **Hackability inspector** de Portswigger ayuda a **analizar** los **atributos** de un objeto javascript. Ver: [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) ## **Archivos .map js** * Truco para descargar archivos .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) * Puedes usar esta herramienta para analizar estos archivos [https://github.com/paazmaya/shuji](https://github.com/paazmaya/shuji) ## Asignación "--" El operador de decremento `--` también es una asignación. Este operador toma un valor y luego lo decrementa en uno. Si ese valor no es un número, se establecerá en `NaN`. Esto se puede usar para **eliminar el contenido de las variables del entorno**. ![](<../../.gitbook/assets/image (553).png>) ![](<../../.gitbook/assets/image (554).png>) ## Trucos de funciones ### .call y .apply El método **`.call`** de una función se utiliza para **ejecutar la función**.\ El **primer argumento** que espera por defecto es el **valor de `this`** y si no se proporciona **nada**, **`window`** será ese valor (a menos que se use el **`modo estricto`**). ```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"]) ``` ### Funciones de flecha Las funciones de flecha te permiten generar funciones en una sola línea de manera más sencilla (si las entiendes). ```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; ``` Entonces, la mayoría de las funciones anteriores son en realidad inútiles porque no las estamos guardando en ningún lugar para guardarlas y llamarlas. Por ejemplo, al crear la función `plusone`: ```javascript // Traductional function plusone (a){ return a + 1; } //Arrow plusone = a => a + 100; ``` ### Función Bind La función Bind permite crear una **copia** de una **función modificando** el objeto **`this`** y los **parámetros** dados. ```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" %} Ten en cuenta que usando **`bind`** puedes manipular el objeto **`this`** que se usará al llamar a la función. {% endhint %} ### Fuga de código de función Si puedes **acceder al objeto** de una función, puedes **obtener el código** de esa función. ```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 ``` En casos en los que la **función no tenga nombre**, aún puedes imprimir el **código de la función** desde dentro: ```javascript (function (){ return arguments.callee.toString(); })() (function (){ return arguments[0]; })("arg0") ``` Aquí hay algunas formas **aleatorias** de **extraer el código** de una función (incluso comentarios) desde otra función: ```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 de Sandbox - Recuperando el objeto window El objeto Window permite acceder a funciones definidas globalmente como alert o 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 // In other browsers the method is // In case of svg, the "event" object is called "evt" // 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: ``` {% endcode %} ## Punto de interrupción en el acceso al 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') ``` ## Acceso automático del navegador para probar 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(); })(); ```
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? ¿O quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)! * Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Obtén la [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com) * **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) **grupo de Discord** o al [**grupo de telegram**](https://t.me/peass) o **sígueme en** **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.** * **Comparte tus trucos de hacking enviando PRs al** [**repositorio de hacktricks**](https://github.com/carlospolop/hacktricks) **y al** [**repositorio de hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).