26 KiB
杂项JS技巧和相关信息
☁️ HackTricks云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 你在一家网络安全公司工作吗?你想在HackTricks中看到你的公司广告吗?或者你想获得PEASS的最新版本或下载HackTricks的PDF吗?请查看订阅计划!
- 发现我们的独家NFTs收藏品The PEASS Family
- 获取官方PEASS和HackTricks周边产品
- 加入💬 Discord群组或电报群组,或者关注我在Twitter上的🐦@carlospolopm。
- 通过向hacktricks repo 和hacktricks-cloud repo 提交PR来分享你的黑客技巧。
Javascript模糊测试
有效的JS注释字符
//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换行字符
In JavaScript, there are several characters that can be used to represent a new line. These characters can be useful in certain situations, such as when trying to obfuscate code or bypass input filters. Here are some of the valid JS new line characters:
\n
: This is the most commonly used new line character in JavaScript. It represents a line feed.\r
: This character represents a carriage return.\u2028
: This is the Unicode character for line separator.\u2029
: This is the Unicode character for paragraph separator.
When using these characters, it's important to keep in mind that different platforms and browsers may interpret them differently. Therefore, it's recommended to test the code on the target platform to ensure compatibility.
有效的JS换行字符
在JavaScript中,有几个字符可以用来表示换行。这些字符在某些情况下非常有用,比如在尝试混淆代码或绕过输入过滤器时。以下是一些有效的JS换行字符:
\n
:这是JavaScript中最常用的换行字符。它表示换行。\r
:这个字符表示回车。\u2028
:这是行分隔符的Unicode字符。\u2029
:这是段落分隔符的Unicode字符。
在使用这些字符时,需要注意不同的平台和浏览器可能会以不同的方式解释它们。因此,建议在目标平台上测试代码,以确保兼容性。
//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空格
In some cases, when trying to bypass filters or evade detection, it may be necessary to use valid JavaScript spaces in a function call. These spaces can help obfuscate the payload and make it more difficult for security measures to detect.
在某些情况下,为了绕过过滤器或规避检测,可能需要在函数调用中使用有效的JavaScript空格。这些空格可以帮助混淆有效载荷,使其更难被安全措施检测到。
Here are some examples of valid JavaScript spaces that can be used:
以下是一些可以使用的有效JavaScript空格的示例:
-
No-Break Space: This is a non-breaking space character that can be used instead of a regular space. It can be represented by the Unicode character
\u00A0
.- 不间断空格:这是一个非间断空格字符,可以用来替代普通空格。它可以用Unicode字符
\u00A0
表示。
- 不间断空格:这是一个非间断空格字符,可以用来替代普通空格。它可以用Unicode字符
-
Zero-Width Space: This is a non-printable character that has no width when displayed. It can be represented by the Unicode character
\u200B
.- 零宽度空格:这是一个不可打印的字符,在显示时没有宽度。它可以用Unicode字符
\u200B
表示。
- 零宽度空格:这是一个不可打印的字符,在显示时没有宽度。它可以用Unicode字符
-
Zero-Width Non-Joiner: This is another non-printable character that has no width when displayed and is used to prevent the joining of two adjacent characters. It can be represented by the Unicode character
\u200C
.- 零宽度非连接符:这是另一个不可打印的字符,在显示时没有宽度,并且用于防止两个相邻字符的连接。它可以用Unicode字符
\u200C
表示。
- 零宽度非连接符:这是另一个不可打印的字符,在显示时没有宽度,并且用于防止两个相邻字符的连接。它可以用Unicode字符
By using these valid JavaScript spaces in a function call, you can add an extra layer of obfuscation to your payload and increase the chances of bypassing security measures.
通过在函数调用中使用这些有效的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
生成字符串的有效字符
The following characters can be used to generate strings in various contexts:
以下字符可用于在不同的上下文中生成字符串:
-
Alphanumeric characters (a-z, A-Z, 0-9)
-
Special characters (!, @, #, $, %, ^, &, *, (, ), -, _, +, =, [, ], {, }, |, , :, ;, ", ', <, >, ,, ., ?, /)
-
Whitespace characters (space, tab, newline)
-
Unicode characters
-
字母数字字符(a-z,A-Z,0-9)
-
特殊字符(!,@,#,$,%,^,&,*,(,),-,_,+,=,[,],{,},|,\,:,;,",',<,>,,,.,?,/)
-
空白字符(空格,制表符,换行符)
-
Unicode字符
These characters can be combined and manipulated to create strings that serve various purposes, such as injecting malicious code or bypassing input validation.
可以组合和操作这些字符,以创建用于注入恶意代码或绕过输入验证的字符串。
// 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代码接收两个字节作为输入,并搜索具有第一个字节作为高代理对的最后一个字节和最后一个字节作为低代理对的最后一个字节的代理对。
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://mathiasbynens.be/notes/javascript-unicode https://mathiasbynens.be/notes/javascript-encoding
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模糊测试
URL模糊测试是一种常用的Web应用程序渗透测试技术,用于发现可能存在的漏洞。通过对URL进行模糊测试,可以尝试各种不同的输入和参数组合,以寻找可能导致安全漏洞的情况。
URL模糊测试的目标是发现应用程序中的潜在漏洞,例如路径遍历、文件包含、SQL注入等。通过构造特定的URL请求,可以触发应用程序中的漏洞,并获取敏感信息或执行恶意操作。
URL模糊测试可以使用各种工具和技术来实现。其中一种常见的方法是使用字典文件,包含各种可能的URL路径和参数组合。通过将这些字典文件与目标URL进行组合,可以生成大量的URL请求,以便进行测试。
URL模糊测试的关键是选择合适的字典文件和参数组合。根据应用程序的特点和已知的漏洞类型,可以选择不同的字典文件和参数组合来进行测试。同时,还可以使用自动化工具来加快测试过程,并提供更全面的测试覆盖。
URL模糊测试是一项重要的渗透测试技术,可以帮助发现Web应用程序中的安全漏洞。通过对URL进行模糊测试,可以提高应用程序的安全性,并防止潜在的攻击。
// 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模糊测试
HTML模糊测试是一种测试Web应用程序的技术,旨在发现和利用HTML中的漏洞。通过向输入字段注入恶意或异常数据,可以揭示潜在的安全问题。以下是一些常见的HTML模糊测试技术:
-
标签闭合测试:在输入字段中注入不完整的HTML标签,以测试应用程序是否正确处理标签闭合。例如,将
<script>
标签注入为<script>
或<script></script>
。 -
属性注入测试:在HTML标签的属性中注入恶意代码,以测试应用程序是否正确过滤和转义用户输入。例如,将
<img>
标签的src
属性注入为" onerror="alert('XSS')" />
。 -
特殊字符测试:在输入字段中注入特殊字符,如尖括号、引号和斜杠,以测试应用程序是否正确处理和转义这些字符。例如,将
<
注入为<
。 -
编码绕过测试:尝试绕过应用程序对特殊字符的编码和转义机制,以执行恶意操作。例如,使用十六进制编码绕过
<
字符的过滤。 -
标签嵌套测试:在输入字段中嵌套HTML标签,以测试应用程序是否正确处理和解析嵌套标签。例如,将
<b>
标签嵌套在<i>
标签内。 -
事件处理程序测试:在HTML标签的事件处理程序中注入恶意代码,以测试应用程序是否正确过滤和处理用户输入。例如,将
<img>
标签的onerror
事件注入为alert('XSS')
。 -
URL注入测试:在URL参数中注入恶意代码,以测试应用程序是否正确处理和解析URL。例如,将
<script>
标签注入为URL参数的一部分。
HTML模糊测试是一种有用的技术,可以帮助发现和修复Web应用程序中的安全漏洞,特别是跨站脚本攻击(XSS)漏洞。
// 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
分析属性
来自Portswigger的工具Hackability inspector可以帮助分析javascript对象的属性。查看:https://portswigger-labs.net/hackability/inspector/?input=x.contentWindow&html=%3Ciframe%20src=//subdomain1.portswigger-labs.net%20id=x%3E
.map js文件
- 下载.map js文件的技巧:https://medium.com/@bitthebyte/javascript-for-bug-bounty-hunters-part-2-f82164917e7
- 您可以使用此工具分析这些文件:https://github.com/paazmaya/shuji
"--" 赋值
递减运算符--
也是一种赋值操作。该运算符接受一个值,然后将其递减一。如果该值不是一个数字,它将被设置为NaN
。这可以用来从环境中删除变量的内容。
函数技巧
.call 和 .apply
函数的**.call
方法用于运行函数**。
默认情况下,它期望的第一个参数是**this
的值**,如果没有提供,则该值将为**window
(除非使用了strict mode
**)。
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"])
箭头函数
箭头函数允许您更轻松地在一行中生成函数(如果您理解它们的话)
// 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
函数:
// Traductional
function plusone (a){ return a + 1; }
//Arrow
plusone = a => a + 100;
绑定函数
绑定函数允许创建一个修改了this
对象和给定参数的函数的副本**。
//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" %}
请注意,使用 bind
可以操纵在调用函数时要使用的 this
对象。
{% endhint %}
函数代码泄漏
如果你可以访问函数的对象,你可以获取该函数的代码。
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
在没有函数名称的情况下,您仍然可以从内部打印函数代码:
(function (){ return arguments.callee.toString(); })()
(function (){ return arguments[0]; })("arg0")
以下是从另一个函数中提取函数代码(包括注释)的一些随机方法:
1. 使用`toString()`方法:
```javascript
var functionCode = anotherFunction.toString();
- 使用正则表达式:
var functionCode = anotherFunction.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1];
- 使用
Function.prototype.toString()
方法:
var functionCode = Function.prototype.toString.call(anotherFunction);
- 使用
new Function()
构造函数:
var functionCode = new Function('', anotherFunction.toString());
请注意,这些方法可能会受到浏览器的限制或安全策略的影响。
(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 */ })()
逃逸沙箱 - 恢复window对象
Window对象允许访问全局定义的函数,如alert或eval。
{% code overflow="wrap" %}
// 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)>
{% endcode %}
在访问值时设置断点
// 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')
自动浏览器访问以测试有效载荷
Sometimes, when testing for Cross-Site Scripting (XSS) vulnerabilities, it is necessary to automate the process of accessing a web page with a payload. This can be achieved using various methods, such as using a headless browser or a browser automation tool.
Headless Browsers
Headless browsers are web browsers without a graphical user interface (GUI). They can be controlled programmatically to access web pages and execute JavaScript code. Some popular headless browsers include Puppeteer, PhantomJS, and Selenium WebDriver with headless mode enabled.
To automate browser access using a headless browser, you can write a script that navigates to the target web page and injects the XSS payload. The script can then capture any resulting behavior or responses from the web page.
Browser Automation Tools
Browser automation tools, such as Selenium WebDriver, allow you to control web browsers programmatically. These tools provide APIs that enable you to interact with web pages, fill out forms, click buttons, and perform other actions.
To automate browser access using a browser automation tool, you can write a script that uses the tool's API to navigate to the target web page and inject the XSS payload. The script can then capture any resulting behavior or responses from the web page.
Automating browser access can save time and effort when testing for XSS vulnerabilities, as it eliminates the need for manual interaction with the web page. However, it is important to use these techniques responsibly and with proper authorization, as unauthorized access to websites can be illegal and unethical.
//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 云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 你在一家网络安全公司工作吗?想要在 HackTricks 中宣传你的公司吗?或者你想要获取最新版本的 PEASS 或下载 HackTricks 的 PDF吗?请查看订阅计划!
- 发现我们的独家NFTs收藏品——The PEASS Family
- 获取官方 PEASS & HackTricks 商品
- 加入 💬 Discord 群组 或 Telegram 群组,或者关注我在推特上的🐦@carlospolopm。
- 通过向hacktricks 仓库和hacktricks-cloud 仓库提交 PR 来分享你的黑客技巧。