mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
475 lines
16 KiB
Markdown
475 lines
16 KiB
Markdown
# Різні JS трюки та відповідна інформація
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Javascript Fuzzing
|
||
|
||
### Дійсні символи коментарів 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]
|
||
```
|
||
### Дійсні символи нових рядків 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
|
||
```
|
||
### Дійсні пробіли JS у виклику функції
|
||
```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
|
||
```
|
||
### **Дійсні символи для генерації рядків**
|
||
```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**
|
||
|
||
Ця техніка не буде дуже корисною для XSS, але може бути корисною для обходу захисту WAF. Цей код на python приймає на вхід 2 байти і шукає сурогатні пари, які мають перший байт як останній байт високої сурогатної пари і останній байт як останній байт низької сурогатної пари.
|
||
```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"))
|
||
```
|
||
Більше інформації:
|
||
|
||
- [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{}:` Протокол Фаззингу
|
||
```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
|
||
```
|
||
## **Аналіз атрибутів**
|
||
|
||
The tool **Hackability inspector** from Portswigger helps to **analyze** the **атрибутів** of a javascript object. Check: [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 файли**
|
||
|
||
- Trick to download .map js files: [https://medium.com/@bitthebyte/javascript-for-bug-bounty-hunters-part-2-f82164917e7](https://medium.com/@bitthebyte/javascript-for-bug-bounty-hunters-part-2-f82164917e7)
|
||
- You can use this tool to analyze these files [https://github.com/paazmaya/shuji](https://github.com/paazmaya/shuji)
|
||
|
||
## "--" Присвоєння
|
||
|
||
The decrement operator `--` is also an asignment. This operator takes a value and then decrements it by one. If that value is not a number, it will be set to `NaN`. This can be used to **remove the content of variables from the environment**.
|
||
|
||
.png>)
|
||
|
||
.png>)
|
||
|
||
## Трюки з функціями
|
||
|
||
### .call and .apply
|
||
|
||
The **`.call`** method of a function is used to **run the function**.\
|
||
The **first argument** it expects by default is the **value of `this`** and if **nothing** is provided, **`window`** will be that value (unless **`strict mode`** is used).
|
||
```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"])
|
||
```
|
||
### Стрілкові функції
|
||
|
||
Стрілкові функції дозволяють вам генерувати функції в один рядок простіше (якщо ви їх розумієте)
|
||
```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;
|
||
```
|
||
Отже, більшість попередніх функцій насправді марні, оскільки ми їх ніде не зберігаємо, щоб зберегти та викликати. Приклад створення функції `plusone`:
|
||
```javascript
|
||
// Traductional
|
||
function plusone(a) {
|
||
return a + 1
|
||
}
|
||
|
||
//Arrow
|
||
plusone = (a) => a + 100
|
||
```
|
||
### Bind function
|
||
|
||
Функція bind дозволяє створити **копію** **функції, модифікуючи** **об'єкт `this`** та **параметри**, що передаються.
|
||
```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]
|
||
> Зверніть увагу, що використовуючи **`bind`**, ви можете маніпулювати об'єктом **`this`**, який буде використовуватися при виклику функції.
|
||
|
||
### Витік коду функції
|
||
|
||
Якщо ви можете **отримати доступ до об'єкта** функції, ви можете **отримати код** цієї функції.
|
||
```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
|
||
```
|
||
У випадках, коли **функція не має жодного імені**, ви все ще можете вивести **код функції** зсередини:
|
||
```javascript
|
||
;(function () {
|
||
return arguments.callee.toString()
|
||
})()(function () {
|
||
return arguments[0]
|
||
})("arg0")
|
||
```
|
||
Деякі **випадкові** способи **витягти код** функції (навіть коментарі) з іншої функції:
|
||
```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 - Відновлення об'єкта window
|
||
|
||
Об'єкт Window дозволяє отримувати доступ до глобально визначених функцій, таких як alert або eval.
|
||
```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)>
|
||
```
|
||
## Точка зупинки при доступі до значення
|
||
```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")
|
||
```
|
||
## Автоматичний доступ до браузера для тестування payload'ів
|
||
```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}}
|