├── README.md ├── circuit-status.py ├── current_descriptors.py ├── darkweb_python_hidden_services.pdf ├── descriptor_from_tor_data_directory.py ├── get_hidden_service_descriptor.py ├── hidden_service.py ├── info_top_relays.py ├── introduction_points.png ├── introduction_points.py ├── list_circuits.png ├── list_circuits.py ├── network-status.py ├── proxy_pysocks.py ├── python_stem.png ├── relay_connections.png ├── relay_connections.py ├── search_dark_web.py ├── servers_descriptors.py ├── show-descriptors.py ├── sock_requets.py ├── stem_connect.py ├── stem_new_identity.py ├── tor_descriptors.png ├── tor_descriptors.py ├── tor_network.png ├── tor_request.py ├── traffic.py └── utilities.py /README.md: -------------------------------------------------------------------------------- 1 | # DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 2 | 3 | 4 | DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 5 | 6 | This is the code repository for [DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES](https://www.pycon.it/conference/talks/darkweb-python-discover-analyze-and-extract-information-from-hidden-services) 7 | 8 | The talk will start explaining how Tor project can help us to the research and development of tools for online anonymity and privacy of its users while surfing the Internet, by establishing virtual circuits between the different nodes that make up the Tor network. In addition, we will review how Tor works from anonymity point of view, preventing websites from tracking you. Python help us to automate the process to search an discover hidden services thanks to packages like requests,requesocks and sockspy,At this point we will review the crawling process and show tools in python ecosystem available for this task. 9 | 10 | These could be the talking points: 11 | 12 | *Introduction to Tor project and hidden services 13 | 14 | *Discovering hidden services. 15 | 16 | *Modules and packages we can use in python for connecting with Tor network 17 | 18 | *Tools that allow search hidden services and atomate the crawling process in Tor network 19 | 20 | # Tools: 21 | ## Stem 22 | https://stem.torproject.org 23 | 24 | ## Requests 25 | https://3.python-requests.org/ 26 | 27 | ## BeautifulSoup 28 | https://www.crummy.com/software/BeautifulSoup/bs4/doc/ 29 | 30 | ## Scripts execution 31 | 32 | ### tor_descriptors.py 33 | DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 34 | 35 | ### relay_connections.py 36 | DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 37 | 38 | ### introduction_points.py 39 | DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 40 | 41 | ### list_circuits.py 42 | DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 43 | 44 | ## Videos scripts execution 45 | 46 | ### Get information about Tor network with python stem 47 | 48 | DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 49 | 50 | 51 | ### Search hidden services in dark web with python 52 | 53 | DARKWEB + PYTHON: DISCOVER, ANALYZE AND EXTRACT INFORMATION FROM HIDDEN SERVICES 54 | 55 | 56 | -------------------------------------------------------------------------------- /circuit-status.py: -------------------------------------------------------------------------------- 1 | from stem.control import Controller 2 | 3 | controller = Controller.from_port(port=9051) 4 | controller.authenticate() 5 | 6 | print(controller.get_info('circuit-status')) 7 | 8 | -------------------------------------------------------------------------------- /current_descriptors.py: -------------------------------------------------------------------------------- 1 | import stem.descriptor.remote 2 | 3 | try: 4 | for desc in stem.descriptor.remote.get_consensus(): 5 | print("found relay %s (%s)" % (desc.nickname, desc.fingerprint)) 6 | except Exception as exc: 7 | print("Unable to retrieve the consensus: %s" % exc) 8 | -------------------------------------------------------------------------------- /darkweb_python_hidden_services.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmortega/python_dark_web/017085eb5c71ec064224e96329fa42bca46ad034/darkweb_python_hidden_services.pdf -------------------------------------------------------------------------------- /descriptor_from_tor_data_directory.py: -------------------------------------------------------------------------------- 1 | from stem.descriptor import parse_file 2 | 3 | for desc in parse_file('/home/jmoc/.tor/cached-microdesc-consensus'): 4 | print('found relay %s (%s)' % (desc.nickname, desc.fingerprint)) 5 | -------------------------------------------------------------------------------- /get_hidden_service_descriptor.py: -------------------------------------------------------------------------------- 1 | from stem.control import Controller 2 | 3 | with Controller.from_port(port = 9051) as controller: 4 | controller.authenticate() 5 | 6 | # descriptor of duck-duck-go's hidden service (http://3g2upl4pq6kufc4m.onion) 7 | 8 | print(controller.get_hidden_service_descriptor('3g2upl4pq6kufc4m')) 9 | -------------------------------------------------------------------------------- /hidden_service.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | def get_tor_session(): 4 | session = requests.session() 5 | # Tor uses the 9050 port as the default socks port 6 | session.proxies = {'http': 'socks5h://127.0.0.1:9050','https': 'socks5h://127.0.0.1:9050'} 7 | return session 8 | 9 | def searchUnderDir(address,session): 10 | for page in range(1,5): 11 | for searchItem in ['bitcoin']: 12 | addressWithCriteria = address.replace("CRITERIA_WILDCARD",searchItem) 13 | #http://underdj5ziov3ic7.onion/search/bitcoin/pg/1 14 | addressToSearch = addressWithCriteria + "/"+ str(page) 15 | print(addressToSearch) 16 | response = session.get(address) 17 | print(response) 18 | print(response.text) 19 | 20 | # Following prints your normal public IP 21 | print(requests.get("http://httpbin.org/ip").text) 22 | 23 | # Make a request through the Tor connection 24 | # IP visible through Tor 25 | # Should print an IP different than your public IP 26 | session = get_tor_session() 27 | print(session.get("http://httpbin.org/ip").text) 28 | 29 | searchUnderDir('http://underdj5ziov3ic7.onion/search/CRITERIA_WILDCARD/pg',session) 30 | 31 | #http://underdj5ziov3ic7.onion/category/HACKING 32 | 33 | -------------------------------------------------------------------------------- /info_top_relays.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import stem.descriptor.remote 4 | 5 | from stem.util import str_tools 6 | 7 | # provides a mapping of observed bandwidth to the relay nicknames 8 | def get_bw_to_relay(): 9 | bw_to_relay = {} 10 | 11 | try: 12 | for desc in stem.descriptor.remote.get_server_descriptors().run(): 13 | if desc.exit_policy.is_exiting_allowed(): 14 | bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname) 15 | except Exception as exc: 16 | print("Unable to retrieve the server descriptors: %s" % exc) 17 | 18 | return bw_to_relay 19 | 20 | # prints the top fifteen relays 21 | 22 | bw_to_relay = get_bw_to_relay() 23 | count = 1 24 | 25 | for bw_value in sorted(bw_to_relay.keys(), reverse = True): 26 | for nickname in bw_to_relay[bw_value]: 27 | print("%i. %s (%s/s)" % (count, nickname, str_tools.size_label(bw_value, 2))) 28 | count += 1 29 | 30 | if count > 15: 31 | sys.exit() 32 | -------------------------------------------------------------------------------- /introduction_points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmortega/python_dark_web/017085eb5c71ec064224e96329fa42bca46ad034/introduction_points.png -------------------------------------------------------------------------------- /introduction_points.py: -------------------------------------------------------------------------------- 1 | from stem.control import Controller 2 | 3 | with Controller.from_port(port = 9051) as controller: 4 | controller.authenticate() 5 | desc = controller.get_hidden_service_descriptor('3g2upl4pq6kufc4m') 6 | 7 | print("DuckDuckGo's introduction points are...\n") 8 | 9 | for introduction_point in desc.introduction_points(): 10 | print(' %s:%s => %s' % (introduction_point.address, introduction_point.port, introduction_point.identifier)) 11 | -------------------------------------------------------------------------------- /list_circuits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmortega/python_dark_web/017085eb5c71ec064224e96329fa42bca46ad034/list_circuits.png -------------------------------------------------------------------------------- /list_circuits.py: -------------------------------------------------------------------------------- 1 | from stem import CircStatus 2 | from stem.control import Controller 3 | 4 | with Controller.from_port(port = 9051) as controller: 5 | controller.authenticate() 6 | 7 | for circ in sorted(controller.get_circuits()): 8 | if circ.status != CircStatus.BUILT: 9 | continue 10 | 11 | print("") 12 | print("Circuit %s (%s)" % (circ.id, circ.purpose)) 13 | 14 | for i, entry in enumerate(circ.path): 15 | div = '+' if (i == len(circ.path) - 1) else '|' 16 | fingerprint, nickname = entry 17 | 18 | desc = controller.get_network_status(fingerprint, None) 19 | address = desc.address if desc else 'unknown' 20 | 21 | print(" %s- %s (%s, %s)" % (div, fingerprint, nickname, address)) 22 | -------------------------------------------------------------------------------- /network-status.py: -------------------------------------------------------------------------------- 1 | from stem.control import Controller 2 | 3 | controller = Controller.from_port(port=9051) 4 | controller.authenticate() 5 | 6 | entries = controller.get_network_statuses() 7 | for routerEntry in entries: 8 | print('Nickname:',routerEntry.nickname) 9 | print('Fingerprint:',routerEntry.fingerprint) 10 | 11 | -------------------------------------------------------------------------------- /proxy_pysocks.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import socket 3 | import socks 4 | 5 | # Following prints your normal public IP 6 | print(requests.get("http://httpbin.org/ip").text) 7 | 8 | socks.set_default_proxy(socks.SOCKS5, "localhost",9050) 9 | socket.socket = socks.socksocket 10 | 11 | # All requests will pass through the SOCKS proxy 12 | # Should print an IP different than your public IP 13 | print(requests.get("http://httpbin.org/ip").text) 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /python_stem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmortega/python_dark_web/017085eb5c71ec064224e96329fa42bca46ad034/python_stem.png -------------------------------------------------------------------------------- /relay_connections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmortega/python_dark_web/017085eb5c71ec064224e96329fa42bca46ad034/relay_connections.png -------------------------------------------------------------------------------- /relay_connections.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import collections 3 | import time 4 | 5 | import stem.connection 6 | import stem.util.system 7 | import stem.util.str_tools 8 | 9 | from stem.control import Listener 10 | from stem.util.connection import get_connections, port_usage, is_valid_ipv4_address 11 | 12 | HEADER_LINE = " {version} uptime: {uptime} flags: {flags}\n" 13 | 14 | DIV = '+%s+%s+%s+' % ('-' * 30, '-' * 6, '-' * 6) 15 | COLUMN = '| %-28s | %4s | %4s |' 16 | 17 | INBOUND_ORPORT = 'Inbound to our ORPort' 18 | INBOUND_DIRPORT = 'Inbound to our DirPort' 19 | INBOUND_CONTROLPORT = 'Inbound to our ControlPort' 20 | 21 | OUTBOUND_ORPORT = 'Outbound to a relay' 22 | OUTBOUND_EXIT = 'Outbound exit traffic' 23 | OUTBOUND_UNKNOWN = 'Outbound uncategorized' 24 | 25 | 26 | def main(): 27 | parser = argparse.ArgumentParser() 28 | parser.add_argument("--ctrlport", help="default: 9051 or 9151") 29 | parser.add_argument("--resolver", help="default: autodetected") 30 | args = parser.parse_args() 31 | 32 | control_port = int(args.ctrlport) if args.ctrlport else 'default' 33 | controller = stem.connection.connect(control_port = ('127.0.0.1', control_port)) 34 | 35 | if not controller: 36 | return 37 | 38 | desc = controller.get_network_status(default = None) 39 | pid = controller.get_pid() 40 | 41 | print(HEADER_LINE.format( 42 | version = str(controller.get_version()).split()[0], 43 | uptime = stem.util.str_tools.short_time_label(time.time() - stem.util.system.start_time(pid)), 44 | flags = ', '.join(desc.flags if desc else ['none']), 45 | )) 46 | 47 | policy = controller.get_exit_policy() 48 | relays = {} # address => [orports...] 49 | 50 | for desc in controller.get_network_statuses(): 51 | relays.setdefault(desc.address, []).append(desc.or_port) 52 | 53 | # categorize our connections 54 | 55 | categories = collections.OrderedDict(( 56 | (INBOUND_ORPORT, []), 57 | (INBOUND_DIRPORT, []), 58 | (INBOUND_CONTROLPORT, []), 59 | (OUTBOUND_ORPORT, []), 60 | (OUTBOUND_EXIT, []), 61 | (OUTBOUND_UNKNOWN, []), 62 | )) 63 | 64 | exit_connections = {} # port => [connections] 65 | 66 | for conn in get_connections(resolver = args.resolver, process_pid = pid): 67 | if conn.protocol == 'udp': 68 | continue 69 | 70 | if conn.local_port in controller.get_ports(Listener.OR, []): 71 | categories[INBOUND_ORPORT].append(conn) 72 | elif conn.local_port in controller.get_ports(Listener.DIR, []): 73 | categories[INBOUND_DIRPORT].append(conn) 74 | elif conn.local_port in controller.get_ports(Listener.CONTROL, []): 75 | categories[INBOUND_CONTROLPORT].append(conn) 76 | elif conn.remote_port in relays.get(conn.remote_address, []): 77 | categories[OUTBOUND_ORPORT].append(conn) 78 | elif policy.can_exit_to(conn.remote_address, conn.remote_port): 79 | categories[OUTBOUND_EXIT].append(conn) 80 | exit_connections.setdefault(conn.remote_port, []).append(conn) 81 | else: 82 | categories[OUTBOUND_UNKNOWN].append(conn) 83 | 84 | print(DIV) 85 | print(COLUMN % ('Type', 'IPv4', 'IPv6')) 86 | print(DIV) 87 | 88 | total_ipv4, total_ipv6 = 0, 0 89 | 90 | for label, connections in categories.items(): 91 | if len(connections) == 0: 92 | continue 93 | 94 | ipv4_count = len([conn for conn in connections if is_valid_ipv4_address(conn.remote_address)]) 95 | ipv6_count = len(connections) - ipv4_count 96 | 97 | total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count 98 | print(COLUMN % (label, ipv4_count, ipv6_count)) 99 | 100 | print(DIV) 101 | print(COLUMN % ('Total', total_ipv4, total_ipv6)) 102 | print(DIV) 103 | print('') 104 | 105 | if exit_connections: 106 | print(DIV) 107 | print(COLUMN % ('Exit Port', 'IPv4', 'IPv6')) 108 | print(DIV) 109 | 110 | total_ipv4, total_ipv6 = 0, 0 111 | 112 | for port in sorted(exit_connections): 113 | connections = exit_connections[port] 114 | ipv4_count = len([conn for conn in connections if is_valid_ipv4_address(conn.remote_address)]) 115 | ipv6_count = len(connections) - ipv4_count 116 | total_ipv4, total_ipv6 = total_ipv4 + ipv4_count, total_ipv6 + ipv6_count 117 | 118 | usage = port_usage(port) 119 | label = '%s (%s)' % (port, usage) if usage else port 120 | 121 | print(COLUMN % (label, ipv4_count, ipv6_count)) 122 | 123 | print(DIV) 124 | print(COLUMN % ('Total', total_ipv4, total_ipv6)) 125 | print(DIV) 126 | print('') 127 | 128 | 129 | if __name__ == '__main__': 130 | main() 131 | -------------------------------------------------------------------------------- /search_dark_web.py: -------------------------------------------------------------------------------- 1 | 2 | from time import sleep 3 | from interruptingcow import timeout 4 | import sys 5 | from bs4 import BeautifulSoup 6 | import requests 7 | import os 8 | 9 | # -------------------- REQUEST SESSION PROXIES -------------------- 10 | 11 | def get_tor_session(): 12 | session = requests.session() 13 | # Tor uses the 9050 port as the default socks port 14 | session.proxies = {'http': 'socks5h://127.0.0.1:9050','https': 'socks5h://127.0.0.1:9050'} 15 | return session 16 | 17 | 18 | def crawl(option, deeplinks, link, intexts, session): 19 | error=0 20 | if option is "default": 21 | length_of_web_links_to_crawl = len(deeplinks) 22 | iterations = 0 23 | 24 | while len(deeplinks) <= number_results or length_of_web_links_to_crawl <= iterations: 25 | try: 26 | with timeout(10): 27 | crawl = session.get(deeplinks[iterations]) 28 | except: 29 | error=1 30 | if not error: 31 | crawl = crawl.text 32 | try: 33 | soup = BeautifulSoup(crawl, "lxml") 34 | except: 35 | print("Error creating 'soup' object") 36 | os.system("sudo service tor stop") 37 | exit() 38 | 39 | for a in soup.find_all('a', href=True): 40 | if len(deeplinks) >= number_results: 41 | print(" \033[0;32m LINKS COLLECTED!\033[0m") 42 | os.system("sudo service tor stop") 43 | exit() 44 | darklink = isValidOnionAdress(deeplinks[iterations],session) 45 | if darklink: 46 | if not darklink in deeplinks: 47 | if intexts in crawl or intexts == "": 48 | print(darklink) 49 | else: 50 | print("valid link, but have not '" + intexts + "' inside: \033[0;31m" + darklink + "\033[0m") 51 | iterations+=1 52 | if option is "all": 53 | try: 54 | with timeout(10): 55 | crawl = session.get(link) 56 | except: 57 | error = 1 58 | if not error: 59 | crawl = crawl.text 60 | try: 61 | soup = BeautifulSoup(crawl, "lxml") 62 | except: 63 | print("Error creating 'soup' object") 64 | os.system("sudo service tor stop") 65 | exit() 66 | print("Crawling from : " + "[\033[0;31m" + link + "\033[0m]") 67 | for a in soup.find_all('a', href=True): 68 | if len(deeplinks) >= number_results: 69 | print(" \033[0;32m LINKS COLLECTED!\033[0m") 70 | os.system("sudo service tor stop") 71 | exit() 72 | 73 | darklink = isValidOnionAdress(a['href'],session) 74 | if darklink: 75 | if not darklink in deeplinks: 76 | if intexts in crawl or intexts == "": 77 | deeplinks.append(darklink) 78 | print(darklink) 79 | else: 80 | print("valid link, but have not '" + intexts + "' inside: \033[0;31m" + darklink + "\033[0m") 81 | else: 82 | print("Skipping, takes to long") 83 | 84 | def isValidOnionAdress(darklink,session): 85 | if not ".onion" in darklink: # if there's not ".onion" in href 86 | return False 87 | 88 | if "http://" in darklink: # if we are here, the link contains a .onion so, lets 'clean' it 89 | isvalid = darklink.split("http://")[1].split(".onion")[0] 90 | isvalid = "http://" + isvalid + ".onion" 91 | print(isvalid) 92 | try: 93 | with timeout(10): 94 | maybevalid = session.get(isvalid) # can we connect to it? 95 | except: 96 | return False 97 | if maybevalid.status_code is not 200: 98 | return False 99 | else: 100 | return isvalid 101 | 102 | def search(crawling, intexts, session): 103 | darklinks = [] 104 | 105 | print("Searching. . . ") 106 | 107 | #process first 5 pages 108 | for page in range(1,5): 109 | #http://underdj5ziov3ic7.onion/search/bitcoin/pg 110 | #http://www.xmh57jrzrnw6insl.onion/4a1f6b371c/search.cgi?s=DRP&q=bitcoin 111 | search_query = "http://underdj5ziov3ic7.onion/search/"+search_string+"/pg/"+str(page) 112 | #search_query = "http://www.xmh57jrzrnw6insl.onion/4a1f6b371c/search.cgi?s=DRP&q="+search_string+"&np="+str(page) 113 | 114 | print("Search query",search_query) 115 | try: 116 | content = session.get(search_query) 117 | content = content.text 118 | except: 119 | print("\nError connecting to server") 120 | exit() 121 | try: 122 | soup = BeautifulSoup(content, "lxml") 123 | except: 124 | print("\nError creating 'soup' object") 125 | os.system("sudo service tor stop") 126 | exit() 127 | print(" \033[0;32m [OK]\033[0m") 128 | print("Checking links ") 129 | print(soup) 130 | for a in soup.find_all('a', href=True): # for each href in browser response 131 | if len(darklinks) >= number_results: # if reached number of links 132 | print(len(darklinks)) 133 | print("SEARCH COMPLETE" + "\033[0;32m [OK]\033[0m") 134 | os.system("sudo service tor stop") 135 | exit() 136 | 137 | darklink = isValidOnionAdress(a['href'],session) 138 | darklinkd = True 139 | try: 140 | contain = session.get(darklink) 141 | contain = contain.text 142 | except: 143 | darklinkd = False 144 | if darklink and darklinkd: # if valid 145 | 146 | if not darklink in darklinks: # if not present in list 147 | if intexts in contain: 148 | print(darklink) 149 | darklinks.append(darklink) # add it 150 | if "all" in crawling: 151 | crawl("all", darklinks, darklink, intexts,session) 152 | else: 153 | print("valid link, but have not '" + intexts + "' inside: \033[0;31m" + darklink + "\033[0m") 154 | if "none" in crawling: 155 | print("Search completed.") 156 | exit() 157 | print("Not enought links in browser, crawling...") 158 | if darklinks: 159 | if "default" in crawling: 160 | crawl("default", darklinks, darklink, intexts,session) 161 | else: 162 | print("Not enought links in browser, but crawl disabled") 163 | os.system("sudo service tor stop") 164 | exit() 165 | else: 166 | print("0 links!, cant crawl...") 167 | os.system("sudo service tor stop") 168 | exit() 169 | 170 | def torproxy(session): 171 | print("Checking Tor instance") 172 | try: 173 | print(session.get("http://httpbin.org/ip").text) 174 | except Exception as exception: 175 | print(" [\033[0;31mNot connected\033[0m]",exception) 176 | print("Starting Tor instance ") 177 | os.system("service tor start") 178 | sleep(8) 179 | print(" \033[0;32m [OK]\033[0m") 180 | print("Checking Tor proxy ") 181 | try: 182 | print(session.get("http://httpbin.org/ip").text) 183 | except Exception as exception: 184 | print(" => [\033[0;31mERROR\033[0m] proxy is refusing connections",exception) 185 | os.system("sudo service tor stop") 186 | exit() 187 | print(" \033[0;32m [OK]\033[0m") 188 | 189 | # -------------------- MAIN PROGRAM -------------------- 190 | if len(sys.argv) not in [4,5] or sys.argv[3] not in ["all", "none", "default"]: 191 | print("search_dark_web.py SEARCH NUMBER_OF_RESULTS crawl_options intext") 192 | print("Crawl Options:") 193 | print(" all) crawl each link") 194 | print(" none) dont crawl") 195 | print(" default) crawl if not enough links") 196 | 197 | exit() 198 | 199 | 200 | if __name__ == "__main__": 201 | try: 202 | session = get_tor_session() 203 | torproxy(session) # set up tor proxy 204 | search_string = sys.argv[1] 205 | number_results = int(sys.argv[2]) 206 | crawld = sys.argv[3] 207 | if len(sys.argv) is 5: 208 | intext = sys.argv[4] 209 | else: 210 | intext = "" 211 | search(crawld, intext,session) 212 | except KeyboardInterrupt: 213 | print("\nExiting. . .") 214 | os.system("sudo service tor stop") 215 | exit() 216 | -------------------------------------------------------------------------------- /servers_descriptors.py: -------------------------------------------------------------------------------- 1 | from stem.descriptor.remote import DescriptorDownloader 2 | 3 | downloader = DescriptorDownloader() 4 | 5 | descriptors = downloader.get_server_descriptors().run() 6 | 7 | for descriptor in descriptors: 8 | print('Descriptor', str(descriptor)) 9 | print('Certificate', descriptor.certificate) 10 | print('ONion key', descriptor.onion_key) 11 | print('Signing key', descriptor.signing_key) 12 | print('Signature', descriptor.signature) 13 | 14 | -------------------------------------------------------------------------------- /show-descriptors.py: -------------------------------------------------------------------------------- 1 | from stem.descriptor.remote import DescriptorDownloader 2 | 3 | downloader = DescriptorDownloader() 4 | descriptors = downloader.get_consensus().run() 5 | 6 | for descriptor in descriptors: 7 | print('Nickname:',descriptor.nickname) 8 | print('Fingerprint:',descriptor.fingerprint) 9 | print('Address:',descriptor.address) 10 | print('Bandwidth:',descriptor.bandwidth) 11 | 12 | -------------------------------------------------------------------------------- /sock_requets.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | def get_tor_session(): 4 | session = requests.session() 5 | # Tor uses the 9050 port as the default socks port 6 | session.proxies = {'http': 'socks5h://127.0.0.1:9050','https': 'socks5h://127.0.0.1:9050'} 7 | return session 8 | 9 | # Following prints your normal public IP 10 | print(requests.get("http://httpbin.org/ip").text) 11 | 12 | # Make a request through the Tor connection 13 | # IP visible through Tor 14 | # Should print an IP different than your public IP 15 | session = get_tor_session() 16 | print(session.get("http://httpbin.org/ip").text) 17 | 18 | r = session.get('https://www.facebookcorewwwi.onion/') 19 | #get headers dictionary 20 | for key,value in r.headers.items(): 21 | print(key,value) 22 | 23 | 24 | -------------------------------------------------------------------------------- /stem_connect.py: -------------------------------------------------------------------------------- 1 | from stem import Signal 2 | from stem.control import Controller 3 | 4 | with Controller.from_port(port = 9051) as controller: 5 | controller.authenticate() 6 | print("Success!") 7 | controller.signal(Signal.NEWNYM) 8 | print("New Tor connection processed") 9 | 10 | -------------------------------------------------------------------------------- /stem_new_identity.py: -------------------------------------------------------------------------------- 1 | import time 2 | from stem import Signal 3 | from stem.control import Controller 4 | 5 | import requests 6 | 7 | def get_tor_session(): 8 | session = requests.session() 9 | # Tor uses the 9050 port as the default socks port 10 | session.proxies = {'http': 'socks5h://127.0.0.1:9050','https': 'socks5h://127.0.0.1:9050'} 11 | return session 12 | 13 | 14 | def main(): 15 | while True: 16 | time.sleep(5) 17 | print ("Rotating IP") 18 | with Controller.from_port(port = 9051) as controller: 19 | controller.authenticate() 20 | controller.signal(Signal.NEWNYM) #gets new identity 21 | # Make a request through the Tor connection 22 | # IP visible through Tor 23 | # Should print an IP different than your public IP 24 | session = get_tor_session() 25 | print(session.get("http://httpbin.org/ip").text) 26 | 27 | if __name__ == '__main__': 28 | main() 29 | 30 | -------------------------------------------------------------------------------- /tor_descriptors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmortega/python_dark_web/017085eb5c71ec064224e96329fa42bca46ad034/tor_descriptors.png -------------------------------------------------------------------------------- /tor_descriptors.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import stem.descriptor.remote 4 | 5 | from stem.util import str_tools 6 | 7 | # provides a mapping of observed bandwidth to the relay nicknames 8 | def get_bw_to_relay(): 9 | bw_to_relay = {} 10 | 11 | try: 12 | for desc in stem.descriptor.remote.get_server_descriptors().run(): 13 | if desc.exit_policy.is_exiting_allowed(): 14 | bw_to_relay.setdefault(desc.observed_bandwidth, []).append(desc.nickname) 15 | except Exception as exc: 16 | print("Unable to retrieve the server descriptors: %s" % exc) 17 | 18 | return bw_to_relay 19 | 20 | # prints the top fifteen relays 21 | 22 | bw_to_relay = get_bw_to_relay() 23 | count = 1 24 | 25 | for bw_value in sorted(bw_to_relay.keys(), reverse = True): 26 | for nickname in bw_to_relay[bw_value]: 27 | print("%i. %s (%s/s)" % (count, nickname, str_tools.size_label(bw_value, 2))) 28 | count += 1 29 | 30 | if count > 15: 31 | sys.exit() 32 | -------------------------------------------------------------------------------- /tor_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmortega/python_dark_web/017085eb5c71ec064224e96329fa42bca46ad034/tor_network.png -------------------------------------------------------------------------------- /tor_request.py: -------------------------------------------------------------------------------- 1 | from torrequest import TorRequest 2 | 3 | with TorRequest(proxy_port=9050, ctrl_port=9051, password=None) as tr: 4 | response = tr.get('http://ipecho.net/plain') 5 | print(response.text) # not your IP address 6 | 7 | # TorRequest object also exposes the underlying Stem controller 8 | # and Requests session objects for more flexibility. 9 | 10 | print(type(tr.ctrl)) # a stem.control.Controller object 11 | tr.ctrl.signal('CLEARDNSCACHE') # see Stem docs for the full AP 12 | 13 | tr.reset_identity() 14 | 15 | response = tr.get('http://ipecho.net/plain') 16 | print(response.text) # another IP address 17 | 18 | -------------------------------------------------------------------------------- /traffic.py: -------------------------------------------------------------------------------- 1 | from stem.control import Controller 2 | 3 | with Controller.from_port(port = 9051) as controller: 4 | controller.authenticate() 5 | 6 | bytes_read = controller.get_info("traffic/read") 7 | bytes_written = controller.get_info("traffic/written") 8 | 9 | print("My Tor relay has read %s bytes and written %s." % (bytes_read, bytes_written)) 10 | -------------------------------------------------------------------------------- /utilities.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from stem.util.connection import get_connections, system_resolvers 4 | from stem.util.system import pid_by_name 5 | 6 | resolvers = system_resolvers() 7 | 8 | if not resolvers: 9 | print("Stem doesn't support any connection resolvers on our platform.") 10 | sys.exit(1) 11 | 12 | picked_resolver = resolvers[0] # lets just opt for the first 13 | print("Our platform supports connection resolution via: %s (picked %s)" % (', '.join(resolvers), picked_resolver)) 14 | 15 | tor_pids = pid_by_name('tor', multiple = True) 16 | 17 | if not tor_pids: 18 | print("Unable to get tor's pid. Is it running?") 19 | sys.exit(1) 20 | elif len(tor_pids) > 1: 21 | print("You're running %i instances of tor, picking the one with pid %i" % (len(tor_pids), tor_pids[0])) 22 | else: 23 | print("Tor is running with pid %i" % tor_pids[0]) 24 | 25 | print("\nConnections:\n") 26 | 27 | for conn in get_connections(picked_resolver, process_pid = tor_pids[0], process_name = 'tor'): 28 | print(" %s:%s => %s:%s" % (conn.local_address, conn.local_port, conn.remote_address, conn.remote_port)) 29 | --------------------------------------------------------------------------------