讲故事
某人邮件收到,预订酒店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) 创建没有任何原型的对象
福利视频
笔者自己录制的一套php视频教程(适合0基础的),感兴趣的童鞋可以看看,基础视频总共约200多集,目前已经录制完毕,后续还有更多视频出品
https://space.bilibili.com/177546377/channel/seriesdetail?sid=2949374
技术交流
技术交流请加笔者微信:richardo1o1 (暗号:growing)
如果你是一个长期主义者,欢迎加入我的知识星球(优先查看这个链接,里面可能还有优惠券),我们一起往前走,每日都会更新,精细化运营,微信识别二维码付费即可加入,如不满意,72 小时内可在 App 内无条件自助退款
往期回顾
参考
https://github.com/BlackFan/client-side-prototype-pollution
原文始发于微信公众号(迪哥讲事):JavaScript静态分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论