mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
472 lines
14 KiB
Markdown
472 lines
14 KiB
Markdown
# Verskeie JS Tricks & Relevante Inligting
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## Javascript Fuzzing
|
|
|
|
### Geldige JS Kommentaar Karakters
|
|
```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]
|
|
```
|
|
### Geldige JS Nuwe Lyn Karakters
|
|
```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
|
|
```
|
|
### Geldige JS Spasies in funksie-aanroep
|
|
```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
|
|
```
|
|
### **Geldige karakters om Strings te genereer**
|
|
```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**
|
|
|
|
Hierdie tegniek sal nie baie nuttig wees vir XSS nie, maar dit kan nuttig wees om WAF-beskermings te omseil. Hierdie python kode ontvang 2 bytes as invoer en soek 'n surrogate paar wat die eerste byte as die laaste byte van die hoë surrogate paar het en die laaste byte as die laaste byte van die lae surrogate paar.
|
|
```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"))
|
|
```
|
|
Meer inligting:
|
|
|
|
### `javascript{}:` Protokol 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.wiki`
|
|
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
|
|
```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
|
|
```
|
|
## **Analiseer attribuutte**
|
|
|
|
Die hulpmiddel **Hackability inspector** van Portswigger help om die **attribuutte** van 'n javascript objek te **analiseer**. Kyk: [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)
|
|
|
|
## **.map js lêers**
|
|
|
|
- Trick om .map js lêers af te laai: [https://medium.com/@bitthebyte/javascript-for-bug-bounty-hunters-part-2-f82164917e7](https://medium.com/@bitthebyte/javascript-for-bug-bounty-hunters-part-2-f82164917e7)
|
|
- Jy kan hierdie hulpmiddel gebruik om hierdie lêers te analiseer [https://github.com/paazmaya/shuji](https://github.com/paazmaya/shuji)
|
|
|
|
## "--" Toewysing
|
|
|
|
Die afname operator `--` is ook 'n toewysing. Hierdie operator neem 'n waarde en verminder dit dan met een. As daardie waarde nie 'n getal is nie, sal dit op `NaN` gestel word. Dit kan gebruik word om die **inhoud van veranderlikes uit die omgewing te verwyder**.
|
|
|
|
.png>)
|
|
|
|
.png>)
|
|
|
|
## Funksies Tricks
|
|
|
|
### .call en .apply
|
|
|
|
Die **`.call`** metode van 'n funksie word gebruik om die **funksie** te **hardloop**.\
|
|
Die **eerste argument** wat dit standaard verwag, is die **waarde van `this`** en as **niks** verskaf word nie, sal **`window`** daardie waarde wees (tenzij **`strict mode`** gebruik word).
|
|
```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"])
|
|
```
|
|
### Pylfunksies
|
|
|
|
Pylfunksies laat jou toe om funksies in 'n enkele lyn makliker te genereer (as jy hulle verstaan)
|
|
```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;
|
|
```
|
|
So, die meeste van die vorige funksies is eintlik nutteloos omdat ons hulle nêrens stoor om te stoor en aan te roep nie. Voorbeeld om die `plusone` funksie te skep:
|
|
```javascript
|
|
// Traductional
|
|
function plusone(a) {
|
|
return a + 1
|
|
}
|
|
|
|
//Arrow
|
|
plusone = (a) => a + 100
|
|
```
|
|
### Bind-funksie
|
|
|
|
Die bind-funksie laat jou toe om 'n **kopie** van 'n **funksie te skep wat** die **`this`** objek en die **parameters** wat gegee is, te wysig.
|
|
```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")
|
|
```
|
|
> [!NOTE]
|
|
> Let daarop dat jy met **`bind`** die **`this`** objek kan manipuleer wat gebruik gaan word wanneer die funksie aangeroep word.
|
|
|
|
### Funksie kode lek
|
|
|
|
As jy die **objek** van 'n funksie kan **toegang** kry, kan jy die **kode** van daardie funksie kry.
|
|
```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
|
|
```
|
|
In gevalle waar die **funksie geen naam het nie**, kan jy steeds die **funksie kode** van binne druk:
|
|
```javascript
|
|
;(function () {
|
|
return arguments.callee.toString()
|
|
})()(function () {
|
|
return arguments[0]
|
|
})("arg0")
|
|
```
|
|
Sommige **ewekansige** maniere om die **kode** van 'n funksie (selfs kommentaar) uit 'n ander funksie te **onttrek**:
|
|
```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 */
|
|
})()
|
|
```
|
|
## Sandbox Escape - Herwinning van die window objek
|
|
|
|
Die Window objek maak dit moontlik om wêreldwyd gedefinieerde funksies soos alert of eval te bereik.
|
|
```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)>
|
|
```
|
|
## Breekpunt op toegang tot waarde
|
|
```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")
|
|
```
|
|
## Outomatiese Blaaier Toegang om payloads te toets
|
|
```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()
|
|
})()
|
|
```
|
|
{{#include ../../banners/hacktricks-training.md}}
|