sec875
- 关注

讲故事
某人邮件收到,预订酒店50%折扣活动。
预订过程中出现了问题,信用卡已过期,某人试图联系银行。 银行回应的是需要15个工作日。
某人开打浏览器中的开发人员工具在网站上进行长时间的探索。发现了以下内容:
某人查看了几个变量,有的值是日期,有的值是时间戳。
修改后,某人的卡被接受了。最后收到满意的邮件。感谢JavaScript。
实战:收集JavaScript文件
有很多方法收集js文件,这里已burpsuite为例。
这里操作没必要重造轮子,很简单,就用材料里的图了。
专业版
免费版
复制这些URL保存到文本文件中:targetJS.txt。然后批量下载。
for i in $(cat targetJS.txt);do wget $i;done
js文件提取工具
从列表URL中提取js文件的工具
https://github.com/Mesh3l911/JS_Scrapper
其他工具
在js文件里查找端点
https://github.com/GerbenJavado/LinkFinder
存档:索引参数是 url
https://web.archive.org/cdx/search/cdx?url=google.com&matchType=domain&fl=original&collapse=urlkey&output=text&filter=statuscode:200
注意:测试时,将响应状态码从403改成200,有时可以bypass 403。
当然,这里仅是部分。还有更多的方法与工具
实战:寻找DOM XSS
从js文件里索引innerHTML,将js文件集中到test文件夹里,一起找。没什么有趣的内容出现。
grep "innerHTML" -r test
索引 document.location
针对这个场景的练习例子为:https://github.com/Ph33rr/attack/blob/main/Javascript/mctaps.js
我们在这个练习js文件中发现了有趣的内容。
找到了这个函数。调试和跟踪它,这是整篇文章的灵魂所在。
方法很简单:试图追踪一个特定的函数或变量时,打印输出它的值
假设我们进入了一个带有 javascript 文件的站点,该文件在浏览器中打印了一个帐户名称。我们如何跟踪该变量?
第一步是查看页面源码,打印输出前,js源码有没有执行。没执行哪里来的调试。
练习场景:https://github.com/Ph33rr/attack/blob/main/Javascript/test.html
查看源码:
整个练习过程中就只有一个变量,因此打印它。当js文件很多,代码量很大时,也只有打印它们。。
在 JavaScript打印功能是 console.log()
让我们重新修改源码,将变量的变化情况观察得更仔细。
这样,我们就可以更好的发现与跟踪这个变量在不同的阶段中,它是否存在漏洞。
再回到练习的js文件中,我们修改一下源码,来观察每一次变化情况。将函数里面的代码提出来调试。
调试结果如下: 两个变量第一次打印是 无定义 和 路径;第二次打印是 -1 和 路径;-1 使得if语句没有被执行。
让我们检查一下为啥是 -1 。没查到 # 所以返回 -1
我们手动在URL加上#去调试。然后就发现这里的函数与变量可以在URL被我们控制与利用。
最后 ,我们返回跟踪整个函数以及脚本中需要利用的位置。
最后,不要忘记了正则表达式在手动搜索漏洞中的重要性。
这里用一个例子来举一反三。其他函数的索引可以参考一下备忘单:
https://raw.githubusercontent.com/Ph33rr/attack/main/Javascript/Javascript2.png
可以通过,IDE phpstrom等 调试js代码。利用IDE插件里的代码质量与静态漏洞扫描等,检查js代码。这种方法更快更容易。
库与框架
关于库与框架的介绍
https://3alam.pro/mnsor-alaatyby/articles/javascript-libraries-and-frameworks
收集有关使用的库和框架的信息
使用网站来收集是最简单的方式:
https://www.wappalyzer.com/
https://www.similartech.com/
还有kali的whatweb,建议多用。
还有查看源代码
公共库检测版本poc
https://www.exploit-db.com/
https://snyk.io/vuln?type=any
https://snyk.io/test/npm/jquery/1.11.2
查看项目中关于bug的讨论,这里面的内容都在告诉您怎么定位,排查。。全都有用。
https://github.com/jquery
代码质量分析与POC
https://rules.sonarsource.com/javascript/RSPEC-5696?search=xss
当我们一时半会儿找不到什么实例与场景时,可以来这里看看。
原型污染
创建最简单的对象。我们可以看到多个属性返回一些东西
var obj = {};
这些东西的完整列表可以在这里查看
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
要理解这一部分,我们需要查看 JavaScript 语言中的类是如何存在的。
JavaScript 中类的概念始于函数。 函数本身充当类的构造函数。
function MyClass() { # 函数
}
var inst = new MyClass(); #类的构造
MyClass所有实例上可用的函数都在原型上声明。原型在运行时可以被修改。
MyClass.prototype.myFunction = function () {
return 42;
};
var inst = new MyClass();
var theAnswer = inst.myFunction();
属性访问
在 JavaScript 中,属性和实例函数之间没有区别。访问方式都一样。
两种访问方式:obj.a 和 obj["a"]
var obj = { “a” : 1, “b” : function() { return 41; } };
var name1 = “a”;
obj.a // 1
obj[“a”] // 1
obj[name1] // 1
var name2 = “b”;
obj.b() // 41
obj.b // function.
obj[“b”] // function
obj[name2] // function
魔术属性
对象原型上存在大量属性,这里探索两个。constructor构造函数 和__proto__
.
构造函数是一个魔法属性,它返回创建对象的函数。在每个构造函数上都有一个属性“prototype”,它指向类的原型。
function MyClass() {
}
MyClass.prototype.myFunc = function () {
return 7;
}
var inst = new MyClass();
inst.constructor // returns the function MyClass
inst.constructor.prototype // returns the prototype of MyClass
inst.constructor.prototype.myFunc() // returns 7
__proto__
是一个魔法属性,它返回对象的类的“原型”。
这个属性在 JavaScript 语言中不是标准的,但它在 NodeJS 环境中完全支持。
这个属性是作为一个 getter/setter 属性实现的,它在读/写时调用 getPrototypeOf/setPrototypeOf。
为属性__proto__
分配一个新值不会影响原型上定义的继承值。改变这种情况的唯一方法是使用 Object.defineProperty
function MyClass() {
}
MyClass.prototype.myFunc = function () {
return 7;
}
var inst = new MyClass();
inst.__proto__ // returns the prototype of MyClass
inst.__proto__.myFunc() // returns 7
inst.__proto__ = { “a” : “123” }; // changing the prototype at runtime.
inst.hasOwnProperty(“__proto__”) // false. We haven’t redefined the property. It’s still the original getter/setter magic property
识别易受攻击的库
攻击者至少可以控制以下形式的任何表达式的参数和value。
obj[a][b] = value
obj[a][b][c] = value
攻击者将a设置为__proto__
。其实就是属性的访问。__proto__.myFunc()
这样放入同一个地方也行。
payload可以放入键或值中:
{“__proto__”:{“cookie”:”sess=fixedsessionid; garbage=”}}
拒绝服务POC
wget --header="Content-Type: application/javascript+json" --post-data='{"__proto__":{"toString":"123","valueOf":"It works !"}}' http://localhost:3000/ -O- -q
运行漏洞利用脚本时,“toString”和“valueOf”函数被破坏,随后的每个请求都将返回 500 错误。
for循环污染
for循环调用key
{“__proto__”:{“my malicious command”:”echo yay > /tmp/evil”}}
属性注入
NodeJS http模块支持多个同名的头部,污染了例如键cookie,那么request.headers.cookie的值将始终以我们污染的值开头。形成了会话固定攻击。
{“__proto__”:{“cookie”:”sess=fixedsessionid; garbage=”}}
危害
如上所述:从对象的具体使用情况来看,受到从拒绝服务到RCE等不同程度的影响。
缓解
NPM 上的多个库(例如:avj5)为 JSON 数据提供模式验证。在 avj 中,将“additionalProperties”设置为“false”来拒绝不需要的属性。
使用Map:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
使用Object.create(null) 创建没有任何原型的对象
其他参考资料
https://github.com/BlackFan/client-side-prototype-pollution
结尾
感谢师傅们很有耐心的看到了这里。
我们还会再见面的。
共勉。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)