Misc JS Tricks & Relevant Info

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

JavaScript-Fuzzing

Gültige JS-Kommentarzeichen

//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]

Gültige JS-Zeilenumbruchzeichen

//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

Gültige JS-Leerzeichen im Funktionsaufruf

// 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

Gültige Zeichen zum Generieren von Zeichenfolgen

// 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)

Surrogat-Paare BF

Diese Technik wird für XSS nicht sehr nützlich sein, könnte aber nützlich sein, um WAF-Schutzmechanismen zu umgehen. Dieser Python-Code erhält als Eingabe 2 Bytes und sucht nach Surrogat-Paaren, bei denen das erste Byte dem letzten Byte des High-Surrogat-Paares und das letzte Byte dem letzten Byte des Low-Surrogat-Paares entspricht.

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"))

Weitere Informationen:

javascript{}: Protokoll Fuzzing

// 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="&#12;javascript:alert(1337)">Test</a>

URL Fuzzing

// 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

HTML Fuzzing

// 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

Analyse von Attributen

Das Tool Hackability Inspector von Portswigger hilft dabei, die Attribute eines JavaScript-Objekts zu analysieren. Überprüfen Sie: https://portswigger-labs.net/hackability/inspector/?input=x.contentWindow&html=%3Ciframe%20src=//subdomain1.portswigger-labs.net%20id=x%3E

.map js-Dateien

"--" Zuweisung

Der Dekrementoperator -- ist auch eine Zuweisung. Dieser Operator nimmt einen Wert und verringert ihn um eins. Wenn dieser Wert keine Zahl ist, wird er auf NaN gesetzt. Dies kann verwendet werden, um den Inhalt von Variablen aus der Umgebung zu entfernen.

Funktionstricks

.call und .apply

Die Methode .call einer Funktion wird verwendet, um die Funktion auszuführen. Das erste Argument, das standardmäßig erwartet wird, ist der Wert von this und wenn nichts bereitgestellt wird, wird window dieser Wert sein (sofern kein strict mode verwendet wird).

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"])

Pfeilfunktionen

Pfeilfunktionen ermöglichen es Ihnen, Funktionen in einer einzigen Zeile einfacher zu generieren (wenn Sie sie verstehen).

// 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;

Also, die meisten der vorherigen Funktionen sind tatsächlich nutzlos, weil wir sie nirgendwo speichern, um sie später aufzurufen. Beispiel für die Erstellung der plusone Funktion:

// Traductional
function plusone (a){ return a + 1; }

//Arrow
plusone = a => a + 100;

Bind-Funktion

Die Bind-Funktion ermöglicht es, eine Kopie einer Funktion zu erstellen, wobei das this-Objekt und die übergebenen Parameter modifiziert werden.

//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')

Beachten Sie, dass Sie mit bind das this-Objekt manipulieren können, das verwendet wird, wenn die Funktion aufgerufen wird.

Funktionscode-Leak

Wenn Sie auf das Objekt einer Funktion zugreifen können, können Sie den Code dieser Funktion erhalten.

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

In Fällen, in denen die Funktion keinen Namen hat, können Sie den Funktionscode dennoch von innen ausdrucken:

(function (){ return arguments.callee.toString(); })()
(function (){ return arguments[0]; })("arg0")

Einige zufällige Möglichkeiten, den Code einer Funktion (sogar Kommentare) aus einer anderen Funktion zu extrahieren:

(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 */ })()

Sandbox Escape - Wiederherstellung des window-Objekts

Das Window-Objekt ermöglicht den Zugriff auf global definierte Funktionen wie alert oder eval.

// 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)>

Haltepunkt bei Zugriff auf Wert

// 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;
}
// 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')

Automatischer Browserzugriff zum Testen von Payloads

//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&timestamp=1624556811000`);
//Go to the page
await page.goto(
`https://challenge-0621.intigriti.io/passgen.php?passwordLength=${input}&allowNumbers=true&allowSymbols=true&timestamp=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();
})();
Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Last updated