├── 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 |
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 |
34 |
35 | ### relay_connections.py
36 |
37 |
38 | ### introduction_points.py
39 |
40 |
41 | ### list_circuits.py
42 |
43 |
44 | ## Videos scripts execution
45 |
46 | ### Get information about Tor network with python stem
47 |
48 |
49 |
50 |
51 | ### Search hidden services in dark web with python
52 |
53 |
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 |
--------------------------------------------------------------------------------