Python 提供了多種方式與 Tor 網路互動,實作匿名瀏覽和存取隱藏服務。Stem 模組允許直接與 Tor 控制器通訊,執行更換身份、查詢電路狀態、取得伺服器描述符等操作。torpy 模組則提供純 Python 的 Tor 協定實作,無需依賴外部 Tor 客戶端。此外,torrequest 模組簡化了透過 Tor 傳送 HTTP 請求的流程,並提供更靈活的控制選項。透過結合 requests 模組,可以輕鬆實作定時更換 IP 地址,提升匿名性。除了連線 Tor 網路,文章也介紹瞭如何利用 Stem 取得隱藏服務的描述符和介紹點,以及使用 TorBot 等工具搜尋暗網資源,提供更全面的 Tor 網路探索方案。

使用Python連線Tor網路與發現隱藏服務

在前面的程式碼中,我們看到了Tor如何使用9050埠作為預設的SOCKS埠,並透過socks5h://127.0.0.1:9050字串進行連線。接著,它預設會印出你的公眾IP地址。透過get_tor_session()方法,我們建立了一個透過SOCKS代理的Tor連線。這樣做會改變我們的IP地址,並印出與預設IP地址不同的IP。

一旦我們獲得了與Tor網路的連線會話,我們就可以查詢隱藏的網路服務;例如,我們可以向位於http://3g2upl4pq6kufc4m.onion的Duckduckgo網站發出請求,並獲得回應標頭。

另一種透過Tor網路發出請求的方式是使用torrequest介面(https://github.com/erdiaker/torrequest)。你可以使用pip install torrequest命令進行安裝。

主要的類別可以在以下GitHub儲存函式庫中找到:https://github.com/erdiaker/torrequest/blob/master/torrequest.py。

TorRequest物件還暴露了底層的stem控制器和請求會話物件,以增加靈活性。

你可以在tor_request.py檔案中找到以下程式碼:

from torrequest import TorRequest

with TorRequest(proxy_port=9050, ctrl_port=9051, password=None) as tr:
    response = tr.get('http://ipecho.net/plain')
    print(response.text)
    print(type(tr.ctrl))
    tr.ctrl.signal('CLEARDNSCACHE')
    tr.reset_identity()
    response = tr.get('http://httpbin.org/ip')
    print(response.text)

內容解密:

在上述程式碼中,TorRequest類別作為與Stem控制器的介面。在這種情況下,我們使用來自torRequest物件的get()方法進行請求。要獲得新的身份,我們可以使用來自該物件的reset_identity()方法。

使用torpy模組連線Tor網路

另一種方法是使用torpy模組,它是一個純Python的Tor協定實作。在這種情況下,既不需要原生的Tor客戶端,也不需要Stem依賴。你可以在以下GitHub儲存函式庫中找到該模組的原始碼:https://github.com/torpyorg/torpy。

使用以下命令在本地儲存函式庫中安裝該模組:

$ pip3 install torpy

你可以在test-torpy.py檔案中找到以下程式碼:

from torpy.http.requests import TorRequests

with TorRequests() as tor_requests:
    print("building circuit...")
    with tor_requests.get_session() as session:
        print(session.get("http://httpbin.org/ip").json())
    print("renewing circuit...")
    with tor_requests.get_session() as session:
        print(session.get("http://httpbin.org/ip").json())
    response = session.get('http://3g2upl4pq6kufc4m.onion')
    for key, value in response.headers.items():
        print(key, value)

內容解密:

在上述程式碼中,我們使用來自torpy.http.requests套件的TorRequests類別來建立電路。我們可以看到,每次使用來自該類別的get_session()方法時,它都會在內部更新電路並獲得新的IP地址。

使用Stem模組從Tor網路中提取資訊

Stem(https://stem.torproject.org)是一個用Python編寫的模組,它對Tor客戶端和目錄權威執行各種操作。你可以使用以下命令安裝此模組:

$ pip3 install stem

透過Stem收集的資訊對於收集有關Tor網路中可用中繼器的資訊非常有用。它不僅允許你控制例項,還允許你取得授權的目錄描述符和其他節點在Tor網路上。

使用stem模組,我們基本上可以與Tor控制器進行通訊,以程式設計方式向Tor控制埠傳送和接收命令。例如,我們可以使用該模組的信令方法來獲得新的身份並建立新的電路。

你可以檢視Tor的協定規範,網址是https://gitweb.torproject.org/torspec.git/tree/control-spec.txt。在此規範中,我們可以看到可以用來存取Tor連線特定資訊的鍵,例如其版本、組態檔案、電路狀態、組態選項、事件等。

使用Python建立透過Tor的請求

另一種使用Python建立透過Tor的請求的方式是建立以下函式,所有這些函式都可以在anonymize.py指令碼中找到:

  • enable_proxy(host="127.0.0.1", port=9050):啟動代理並接收主機和埠作為引數。預設情況下,這些是localhost和9050。注意9050是Tor的預設埠。
  • disable_proxy():移除通訊端“補丁”。

你可以在anonymize.py檔案中找到以下程式碼:

import socks
import socket

temp_socket = socket.socket
temp_create_connection = socket.create_connection

def disable_proxy():
    socket.socket = temp_socket
    socket.create_connection = temp_create_connection

def enable_proxy(host="127.0.0.1", port=9050):
    def create_connection(address, timeout=None, source_address=None):
        sock = socks.socksocket()
        sock.connect(address)
        return sock
    socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, host, port, True)
    socket.socket = socks.socksocket
    socket.create_connection = create_connection

內容解密:

在上述程式碼中,我們定義了兩個函式:enable_proxy()disable_proxy()enable_proxy()函式啟動SOCKS代理,而disable_proxy()函式則停用它。我們可以使用這些函式來測試透過Tor發出的請求是否成功匿名化。

使用Python中的模組和套件連線Tor網路

在前面的章節中,我們已經瞭解了Tor網路的基本概念和架構。在本章節中,我們將介紹如何使用Python中的模組和套件來連線Tor網路並取得相關資訊。

Stem套件介紹

Stem是一個Python套件,提供了對Tor網路的程式化存取。透過Stem,我們可以取得Tor網路中的各種描述符(descriptor),例如伺服器描述符、額外資訊描述符、微描述符等。

取得Tor網路中的描述符

Tor網路中的每個重傳器(repeater)都會向客戶端公開相關資訊,這些資訊被稱為描述符。描述符包含了Tor網路的狀態資訊,例如重傳器的狀態、頻寬等。

以下是幾種常見的描述符型別:

  • 伺服器描述符:包含了重傳器的完整資訊(目前客戶端已不再下載此檔案,改用微描述符)。
  • 額外資訊描述符:包含了Tor節點作為重傳器的使用統計資訊。
  • 微描述符:僅包含了Tor客戶端與重傳器通訊所需的必要資訊。
  • 共識(網路狀態):由授權的網路實體釋出的檔案,包含了多個重傳器的資訊輸入(路由器狀態輸入)。
  • 路由器狀態條目:包含了網路上某個重傳器的資訊。

使用Stem取得描述符

以下是一個使用Stem套件取得共識描述符的範例程式碼:

from stem.descriptor.remote import DescriptorDownloader

downloader = DescriptorDownloader()
descriptors = downloader.get_consensus().run()

for descriptor in descriptors:
    print('Nickname:', descriptor.nickname)
    print('Fingerprint:', descriptor.fingerprint)
    print('Address:', descriptor.address)
    print('Bandwidth:', descriptor.bandwidth)

內容解密:

  1. 匯入DescriptorDownloader類別:用於下載Tor網路中的描述符。
  2. 建立DescriptorDownloader物件:用於下載共識描述符。
  3. 呼叫get_consensus().run()方法:下載共識描述符並執行。
  4. 遍歷描述符列表:印出每個描述符的暱稱、指紋、位址和頻寬。

取得電路狀態

以下是一個使用Stem套件取得電路狀態的範例程式碼:

from stem.control import Controller

controller = Controller.from_port(port=9051)
controller.authenticate()

print(controller.get_info('circuit-status'))

內容解密:

  1. 匯入Controller類別:用於控制Tor例項。
  2. 建立Controller物件:連線到控制埠9051。
  3. 呼叫authenticate()方法:驗證控制連線。
  4. 呼叫get_info('circuit-status')方法:取得電路狀態。

列出所有電路

以下是一個使用Stem套件列出所有電路的範例程式碼:

from stem import CircStatus
from stem.control import Controller

with Controller.from_port(port=9051) as controller:
    controller.authenticate()
    for circ in sorted(controller.get_circuits()):
        if circ.status != CircStatus.BUILT:
            continue
        print("Circuit %s (%s)" % (circ.id, circ.purpose))
        for i, entry in enumerate(circ.path):
            div = '+' if (i == len(circ.path) - 1) else '|'
            fingerprint, nickname = entry
            desc = controller.get_network_status(fingerprint, None)
            address = desc.address if desc else 'unknown'
            print(" %s- %s (%s, %s)" % (div, fingerprint, nickname, address))

內容解密:

  1. 匯入CircStatusController類別:用於控制Tor例項和取得電路狀態。
  2. 建立Controller物件:連線到控制埠9051。
  3. 呼叫authenticate()方法:驗證控制連線。
  4. 呼叫get_circuits()方法:取得所有電路。
  5. 遍歷電路列表:印出每個電路的ID、目的和路徑。

取得伺服器描述符

以下是一個使用Stem套件取得伺服器描述符的範例程式碼:

from stem.descriptor.remote import DescriptorDownloader

downloader = DescriptorDownloader()
descriptors = downloader.get_server_descriptors().run()

for descriptor in descriptors:
    print('Descriptor', str(descriptor))
    print('Certificate', descriptor.certificate)

內容解密:

  1. 匯入DescriptorDownloader類別:用於下載Tor網路中的描述符。
  2. 建立DescriptorDownloader物件:用於下載伺服器描述符。
  3. 呼叫get_server_descriptors().run()方法:下載伺服器描述符並執行。
  4. 遍歷描述符列表:印出每個描述符的字串表示和憑證。

使用Python連線Tor網路的模組與套件

在Python中,我們可以使用多個模組和套件來連線Tor網路並提取相關資訊。這些工具為開發者提供了豐富的功能,以便與Tor網路互動並取得隱藏服務的資訊。

使用Stem模組與Tor控制器互動

Stem是一個用於與Tor控制器互動的Python函式庫。它提供了豐富的功能,包括取得伺服器描述符、隱藏服務描述符以及更換身份等。

取得伺服器描述符

伺服器描述符包含了有關Tor節點的重要資訊,如其IP地址、埠和金鑰等。以下程式碼展示瞭如何使用Stem取得伺服器描述符:

from stem.descriptor import DescriptorDownloader

downloader = DescriptorDownloader()
descriptors = downloader.get_server_descriptors()

for descriptor in descriptors:
    print('伺服器指紋:', descriptor.fingerprint)
    print('Onion金鑰:', descriptor.onion_key)
    print('簽名金鑰:', descriptor.signing_key)
    print('簽名:', descriptor.signature)

內容解密:

  • DescriptorDownloader類別用於下載Tor伺服器描述符。
  • get_server_descriptors()方法傳回一個包含多個伺服器描述符的列表。
  • 迴圈遍歷每個描述符並列印其指紋、Onion金鑰、簽名金鑰和簽名。

取得隱藏服務描述符

隱藏服務描述符提供了有關.onion地址的詳細資訊,包括其介紹點。以下程式碼展示瞭如何取得DuckDuckGo的隱藏服務描述符:

from stem.control import Controller

with Controller.from_port(port=9051) as controller:
    controller.authenticate()
    desc = controller.get_hidden_service_descriptor('3g2upl4pq6kufc4m')
    print("DuckDuckGo的介紹點是...\n")
    for introduction_point in desc.introduction_points():
        print(' %s:%s => %s' % (introduction_point.address, introduction_point.port, introduction_point.identifier))

內容解密:

  • Controller類別用於與Tor控制器建立連線。
  • get_hidden_service_descriptor()方法用於取得指定.onion地址的隱藏服務描述符。
  • 遍歷介紹點並列印其地址、埠和識別符。

更換Tor身份

Stem還允許我們以程式設計方式更換Tor身份,取得新的IP地址。以下程式碼展示瞭如何使用Signal.NEWNYM訊號更換身份:

from stem import Signal
from stem.control import Controller

with Controller.from_port(port=9051) as controller:
    controller.authenticate()
    print("成功連線!")
    controller.signal(Signal.NEWNYM)
    print("新的Tor連線已處理")

內容解密:

  • Signal.NEWNYM訊號用於請求新的Tor電路,從而獲得新的出口節點和IP地址。
  • controller.signal(Signal.NEWNYM)方法傳送訊號給Tor控制器以更換身份。

結合Requests模組使用Stem

我們可以結合Requests模組和Stem來定期更換IP地址並透過Tor網路傳送請求。以下程式碼展示瞭如何每5秒更換一次IP地址:

import time
from stem import Signal
from stem.control import Controller
import requests

def get_tor_session():
    session = requests.session()
    session.proxies = {'http': 'socks5h://127.0.0.1:9050', 'https': 'socks5h://127.0.0.1:9050'}
    return session

def main():
    while True:
        time.sleep(5)
        print("正在輪換IP...")
        with Controller.from_port(port=9051) as controller:
            controller.authenticate()
            controller.signal(Signal.NEWNYM)
        session = get_tor_session()
        print(session.get("http://httpbin.org/ip").text)

if __name__ == '__main__':
    main()

內容解密:

  • get_tor_session()函式建立一個透過Tor代理的Requests會話。
  • main()函式中,每5秒更換一次Tor身份並傳送請求以取得可見的IP地址。

使用TorBot進行隱藏服務搜尋

TorBot是一個用於暗網的OSINT工具,可以用來收集.onion網域名稱的資訊。以下是如何使用TorBot的簡要步驟:

  1. 啟動Tor服務:sudo service tor start
  2. 確保torrc組態正確,SOCKS_PORT設為9050。
  3. 安裝必要的Python依賴:pip3 install -r requirements.txt
  4. 執行TorBot:python3 torBot.py -i -u http://cnkj6nippubgycuj.onion/search?query=bitcoin&action=search

TorBot允許使用者提取與特定主題相關的連結,並將結果儲存為JSON等格式。