//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 linefor (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")continueerr =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换行字符
- New Line
- Carriage Return
\u2028 - Line Separator
\u2029 - Paragraph Separator
//Javascript interpret as new line these chars:String.fromCharCode(10) //0x0aString.fromCharCode(13) //0x0dString.fromCharCode(8232) //0xe2 0x80 0xa8String.fromCharCode(8233) //0xe2 0x80 0xa8for (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空格
有效JS空格在函数调用中
// 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 ()functionx(){}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
生成字符串的有效字符
// 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 stringlog=[];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)
// 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 optionlet anchor =document.createElement('a');anchor.href =`javascript${String.fromCodePoint(58)}:alert(1337)`;anchor.append('Click me')document.body.append(anchor)// Another way to test<ahref="javascript:alert(1337)">Test</a>
URL Fuzzing
URL模糊测试
// Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (pp. 36-37). Kindle Edition.// Before the protocola=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 slashesa=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模糊测试
// Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 38). Kindle Edition.// Fuzzing chars that can close an HTML commentlet 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
functiontest_call(){console.log(this.value); //baz}new_this={value:"hey!"}test_call.call(new_this);// To pass more arguments, just pass then inside .call()functiontest_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:functiontest_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:functiontest_apply() {console.log(arguments[0]); //"arg1"console.log(arguments[1]); //"arg2"console.log(this); //[object Window]}test_apply.apply(null, ["arg1","arg2"])
箭头函数
箭头函数允许您更轻松地在一行中生成函数(如果您理解它们的话)
// Traditionalfunction (a){ return a +1; }// Arrow formsa => a +100;a => {a +100};// Traditionalfunction (a, b){ return a + b +1; }// Arrow(a, b) => a + b +100;// Tradictional no argslet a =4;let b =2;function (){ return a + b +1; }// Arrowlet a =4;let b =2;() => a + b +1;
// Traductionalfunctionplusone (a){ return a +1; }//Arrowplusone= a => a +100;
绑定函数
绑定函数允许创建一个修改this对象和给定参数的函数的副本**。
//This will use the this object and print "Hello World"varfn=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')
请注意,使用 bind 可以操纵在调用函数时将要使用的 this 对象。
函数代码泄漏
如果你可以访问函数的对象,你就可以获取该函数的代码。
functionafunc(){return1+1;}console.log(afunc.toString()); //This will print the code of the functionconsole.log(String(afunc)); //This will print the code of the functionconsole.log(this.afunc.toString()); //This will print the code of the functionconsole.log(global.afunc.toString()); //This will print the code of the function
```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)
// Abusing Error.prepareStackTrace to get Window back Error.prepareStackTrace=function(error, callSites){ 2 callSites.shift().getThis().alert(1337); 3 }; 4 new Error().stack
## 在访问值时设置断点
```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;
}
// 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 occurringfunctiondebugAccess(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')
自动浏览器访问以测试有效载荷
//Taken from https://github.com/svennergr/writeups/blob/master/inti/0621/README.mdconstpuppeteer=require("puppeteer");constrealPasswordLength=3000;asyncfunctionsleep(ms) {returnnewPromise((resolve) =>setTimeout(resolve, ms));}(async () => {constbrowser=awaitpuppeteer.launch();constpage=awaitbrowser.newPage();//Loop to iterate through different valuesfor (let i =0; i <10000; i +=100) {console.log(`Run number ${i}`);constinput=`${"0".repeat(i)}${realPasswordLength}`;console.log(` https://challenge-0621.intigriti.io/passgen.php?passwordLength=${input}&allowNumbers=true&allowSymbols=true×tamp=1624556811000`);//Go to the pageawaitpage.goto(`https://challenge-0621.intigriti.io/passgen.php?passwordLength=${input}&allowNumbers=true&allowSymbols=true×tamp=1624556811000`);//Call function "generate()" inside the pageawaitpage.evaluate("generate()");//Get node inner text from an HTML elementconstpasswordContent=awaitpage.$$eval(".alert .page-content",(node) => node[0].innerText);//Transform the content and print it in consoleconstplainPassword=passwordContent.replace("Your password is: ","");if (plainPassword.length!= realPasswordLength) {console.log(i,plainPassword.length, plainPassword);}awaitsleep(1000);}awaitbrowser.close();})();
// 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"
// 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=s=createElement('script');s.append('alert(1337)');appendChild(s)>