たれながし.info

とあるITエンジニアの備忘録

responderでNTLMハッシュをキャプチャする


目的

responderというツールで、NTLMハッシュをキャプチャできると聞いたので実施してみました。クライアントがADドメインに所属している場合/していない場合の2パターンで実施します。

responderは、Kali Linuxにデフォルトで入っているので、それを使います。
www.kali.org

環境

  • Kali Linux:2022.3
    └ responder:3.1.3.0
  • ADドメコンWindows Server 2019
  • クライアント:Windows10 21H2 Enterprise

NTLMハッシュのキャプチャ

クライアントがADドメインに所属していない場合

クライアントがADドメインに所属していない場合です。


実施手順

Kali Linuxでresponderを起動 ※root権限で実行する必要あり

$ sudo responder -I eth0 -v

クライアントが所属するドメイン名を確認→ドメインには所属していない

> systeminfo | findstr "ドメイン"
ドメイン:               WORKGROUP

クライアントからresponderにファイル共有で接続する

> net use \\[Kali LinuxのIPアドレス]
結果

responderに表示された「NTLMv2-SSP Hash」の長い文字列がNTLMv2のハッシュ値らしい。


クライアントがADドメインに所属している場合

ADドメインに所属している端末はケルベロス認証を使うと聞くので、クライアントがADドメインに所属している場合に違いがあるのかも調べてみました。結果はクライアントがADドメインに所属していない場合と変わりませんでした。responderがADドメインに所属しているか、していないかでも結果は変わるかもしれません(今回はresponderはADドメインに所属していない)。


実施手順

Kali Linuxでresponderを起動 ※root権限で実行する必要あり

$ sudo responder -I eth0 -v

クライアントのADドメイン所属を確認

> whoami /UPN
user1@test.local

クライアントからresponderにファイル共有で接続する

> net use \\[Kali LinuxのIPアドレス]
結果

responderに表示された「NTLMv2-SSP Hash」の長い文字列がNTLMv2のハッシュ値らしい。

サーバーのSSL/TLS証明書のフィールドをPythonで出力する

Webサーバーなどに設定されているSSL/TLSサーバー証明書について、複数サーバーの証明書のフィールドをチェックする際にどうしたら良いか?と考えた時に、プログラム書いて調べたら良いかなと思ったので、実現方法を調べてみました。


例)www.google.comに設定されているサーバー証明書

結論としては、Pythonの標準モジュール「ssl」「socket」を使ってできました。

以下サイトを参考にしました。
www.askpython.com

実施方法

サーバーの「HostName」をキーにSSL/TLSサーバー証明書のフィールドを出力するサンプルです。

「CommonName」と「期限(開始と終了)」を出力します。
サブジェクト代替名(subjectAltName/DNSName)」なども出力可能ですが、証明書によっては大量に設定されている場合があるので出力部分はコメントアウトしています。

Pythonプログラム

import ssl
import socket
 
def verify_ssl_certificate(hostname):
    context = ssl.create_default_context() 
    with socket.create_connection((hostname, 443)) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            ssock.do_handshake()
            cert = ssock.getpeercert()
            CommonName = get_commonname(cert["subject"])
            NotBefore = cert["notBefore"]
            NotAfter = cert["notAfter"]
            # SubjectAltName = cert["subjectAltName"]
            print(f'"{hostname}","{CommonName}","{NotBefore}","{NotAfter}"')

def get_commonname(subjects):
    for subject in subjects:
        if subject[0][0] == "commonName":
            return subject[0][1]
    return ""

if __name__ == '__main__':
    print(f'"HostName","CommonName","NotBefore", "NotAfter"')
    for hostname in ["www.yahoo.co.jp", "www.google.com"]:
        verify_ssl_certificate(hostname)

実行結果

> python check_servercert.py
"HostName","CommonName","NotBefore", "NotAfter"
"www.yahoo.co.jp","edge01.yahoo.co.jp","Jul 28 02:16:59 2023 GMT","Aug 27 14:59:00 2024 GMT"
"www.google.com","www.google.com","Oct 16 08:10:46 2023 GMT","Jan  8 08:10:45 2024 GMT"

ランサムウェアグループの投稿を収集するツール「ransomwatch」を動かしたい

ここ数年ランサムウェアの被害が継続発生しています。収まる様子は見られません。
ランサムウェアの攻撃グループは、攻撃の成功や身代金の要求を彼ら自身が運営するWebサイトに投稿することが多いです。ほとんどのサイトはTor経由でないとアクセスできない.onionドメインのサイトです。

そういったランサムウェアグループの投稿を自動収集するための「ransomwatch」というツールがあります。ソースコードGitHubで公開されています。

github.com

「ransomwatch」は、作者の人がツールを定期稼働させて、結果を「https://ransomwatch.telemetry.ltd」で公開しています。なので、本来は自前の環境で動かす必要はありませんが、動作の仕組みが知りたかったので、自前の環境で動かしてみました。
結論としては、うまく動かない部分があって途中で諦めました。しかし、ここに奮闘の結果をメモしておきます。

また「ransomwatch」からフォークした「ransomware.live」というツールもあります。
こちらもgithubでソースコードが公開されていて、実行結果が公開されているサイトがあります。
こちらの方が頻繁に更新され高機能なので、「ransomware.live」を使った方が良かったのかもしれません。

動作環境について

「Torプロキシ」と「ransomwatch」を動かす必要があります。
今回は、Windows上でDockerを稼働させ、Docker上で「Torプロキシ用のコンテナ」と「ransomwatchのコンテナ」を稼働させます。必ずしもDockerを使用する必要はないですが、Dockerを使うと楽です。


  • ホストOS:Windows11 22H2 Enterprise x64
  • Docker Desktop:4.25.0
  • Ubuntu on WSL2:22.04.2 LTS

環境構築

WSL2とDockerをインストールした後、コンテナを起動します。

WSL2のインストール

WSL2はDockerを動作させるために使用します。
MS公式の手順を元にインストールしました。
WSL のインストール | Microsoft Learn

PowerShellを管理者で起動し、wslをインストールする。

> wsl --install
…
要求された操作は正常に終了しました。変更を有効にするには、システムを再起動する必要があります。

Windowsを再起動する。WSL2上でUbuntuが起動するが使いません。

> wsl -l -v
  NAME      STATE           VERSION
* Ubuntu    Running         2

Docker Desktopのインストール

Docker DesktopをDLしてインストールする

> Start-BitsTransfer -Source "https://desktop.docker.com/win/main/amd64/Docker Desktop Installer.exe" -Destination "Docker 20Desktop 20Installer.exe"

「Use WSL 2 instead of Hyper-V」にチェックを入れてインストールする

インストールが完了したらWindowsを再起動

WSL2の状態を見ると、dockerが動作している

> wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu                 Running         2
  docker-desktop         Running         2
  docker-desktop-data    Running         2

Torプロキシ用のコンテナ起動

Torプロキシ用のコンテナを起動する

> docker run -p9050:9050 ghcr.io/joshhighet/torsocc:latest
Nov 03 15:17:14.214 [notice] Tor 0.4.7.13 running on Linux with Libevent 2.1.12-stable, OpenSSL 3.0.8, Zlib 1.2.13, Liblzma 5.2.9, Libzstd 1.5.2 and Unknown N/A as libc.
…
Nov 03 15:17:54.000 [notice] Bootstrapped 100% (done): Done

9050/TCPでTorプロキシが起動する

> docker container ls
CONTAINER ID   IMAGE                               COMMAND                   CREATED          STATUS          PORTS                    NAMES
364f5a623eb8   ghcr.io/joshhighet/torsocc:latest   "tor -f /etc/tor/tor…"   27 seconds ago   Up 26 seconds   0.0.0.0:9050->9050/tcp   kind_bohr

ransomwatchのコンテナイメージ作成と起動

ransomwatchをDLし解凍する

> Start-BitsTransfer -Source https://codeload.github.com/joshhighet/ransomwatch/zip/refs/heads/main -Destination ransomwatch.zip
> Expand-Archive .\ransomwatch.zip

dockerfileからイメージを作成する

> cd ransomwatch\ransomwatch-main
> docker build -t ransomwatch:1.0 .
[+] Building 357.5s (17/17) FINISHED

>docker image ls
REPOSITORY                   TAG       IMAGE ID       CREATED          SIZE
ransomwatch                  1.0       c818deea9ad0   14 seconds ago   2GB

コンテナを起動しbashで接続する

> docker run -it --name ransomwatch --entrypoint "/bin/bash" ransomwatch:1.0

vimのインストール

# apt-get install vim

ransomwatchが参照するプロキシのIPアドレスを修正する
127.0.0.1だとコンテナ内を参照してしまうので、ホストのIPアドレスを参照するように変更

# vim sharedutils.py21行目を書き換えます。
修正前)sockshost = '127.0.0.1'
修正後)sockshost = 'host.docker.internal'

「/source」ディレクトリを作成する

# mkdir /source

ransomwatchの利用

ransomwatchを使っていきます。

スクレイピングの実施(scrape)

「scrape」でランサムウェア攻撃グループのWebサイトをスクレイピングする。
スクレイピング結果はコンテナ内の「/source」にhtmlファイルとして保存される。

スクレイピングの実施

# python3 ransomwatch.py scrape

2023-11-03:17:59:44,273 INFO     sharedutils: attempting socket connection
2023-11-03:17:59:44,291 INFO     sharedutils: socket - successful connection
…
2023-11-03:18:35:00,161 INFO     ransomwatch: scraping http://threeamkelxicjsaf2czjyz2lc4q3ngqkxhhlexyfcp2o6raw4rphyad.onion successful
2023-11-03:18:35:00,162 INFO     ransomwatch: saving /source/threeam-threeamkelxicjsaf2czjyz2lc4q3ngqkxhhlexyfcp2o6raw4rphyad.html
…
2023-11-03:18:35:29,480 INFO     ransomwatch: scrape run complete

完了すると「/source」にhtmlファイルが作成される

# ls -l /source

-rw-r--r-- 1 root root    2305 Nov  5 01:41 0mega-omegalock5zxwbhswbisc42o2q2i54vdulyvtqqbudqousisjgc7j7yd.html
-rw-r--r-- 1 root root    1205 Nov  5 01:47 0xFFF-contiuevxdgdhn3zl2kubpajtfgqq4ssj2ipv6ujw7fwhggev3rk6hqd.html
-rw-r--r-- 1 root root   34094 Nov  5 01:28 RAMP-rampjcdlqvgkoz5oywutpo6ggl7g6tvddysustfl6qzhr5osr24xxqqd.html
-rw-r--r-- 1 root root   14373 Nov  5 01:47 abyss-3ev4metjirohtdpshsqlkrqcmxq6zu3d7obrdhglpy5jpbr7whmlfgqd.html
-rw-r--r-- 1 root root   49720 Nov  5 01:48 akira-akiral2iz6a7qgd3ayp3l6yub7xx2uep76idk3u2kollpj5z3z636bad.html
…

パースの実施(parse)

「parse」で取得したhtmlから投稿を抜き出す
パーサーがおかしいのか異常終了したため、ここで諦めました

# python3 ransomwatch.py parse2023-11-04:02:13:45,99 INFO     sharedutils: running shell command -
    grep --no-filename '<a href="/company/' source/cuba-*.html | cut -d '/' -f 3 | cut -d '"' -f 1 | sort --uniq | grep -v company

grep: source/cuba-*.html: No such file or directory
Traceback (most recent call last):
  File "//ransomwatch.py", line 242, in <module>
    parsers.cuba()
  File "/parsers.py", line 298, in cuba
    posts = runshellcmd(parser)
            ^^^^^^^^^^^^^^^^^^^
  File "/sharedutils.py", line 176, in runshellcmd
    cmdout = subprocess.run(
             ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/subprocess.py", line 571, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '
    grep --no-filename '<a href="/company/' source/cuba-*.html | cut -d '/' -f 3 | cut -d '"' -f 1 | sort --uniq | grep -v company
    ' returned non-zero exit status 1.

Webページの生成(markdown

markdown」でパースした結果から、markdown形式のWebサイトを生成できるらしいです。
今回はパースができなかったので、試せていません。

# python3 ransomwatch.py markdown

結論

ということで、スクレイピングはできましたが、その後の処理が実施できませんでした。
「ransomwatch」を稼働させるだけでも、修正が必要な部分がいくつかあったので、大変でした。とはいえ、大体の仕組みは分かったので個人的には満足です。

自前でランサムウェアグループの投稿を収集したい人は、「ransomwatch」より「ransomware.live」を使った方がいいのかもしれません。もしくは自作のツールを作るとか…。
こんな記事もあります。

xtech.nikkei.com

個人的なメモ:コンテナの操作

私はDockerをほとんど触ったことがなかったので、今回知ったDocker操作コマンドのメモです。

・稼働中のコンテナ一覧の確認
> docker container ls

・停止中含めたコンテナ一覧の確認
> docker container ps -a

・ローカルのファイルをコンテナにコピーする
> docker cp [ローカルのファイルパス] [コンテナID]:[コンテナのファイルパス]

CentOSでFTPサーバーを建てた

急遽FTPサーバーを建てる必要があったので、CentOS7&vsftpdで建てた時のメモです。
セキュリティを考慮せず建てたので、あまり参考にはしないでください。

本来なら下記を考慮した方が良いと思います。

  • 最新のOSを使う(CentOSの開発は終了している)
  • FTPではなくFTPSやSFTPを使う
  • FTPを許可するユーザーを明示的に指定する
  • アクセスできるディレクトリを制限する

FTPサーバーの環境

構築環境

構築した環境です。

  • CentOS:7.6
  • vsftpd:3.0.2-29.el7_9

要件

FTPサーバーの要件です。

  • Anonymousの接続は許可しない
  • FTPサーバーにはPassiveで接続する(データのコネクションもクライアントから接続)

FTPサーバーの構築

事前準備

SELinuxは無効にする

# getenforce
Disabled

vsftpdのインストール

# yum -y install vsftpd

vsftpdの設定

# cd /etc/vsftpd
# cp -a vsftpd.conf{,.org}

# vi vsftpd.conf
※以下変更点だけ書きます。

# Anonymousの接続は許可しないに変更
anonymous_enable=YES
→anonymous_enable=NO

# パッシブモード有効化&ポート範囲を追記
# pasv_enableはDefaultっでYESなので書かなくても良いらしい
pasv_enable=YES
pasv_min_port=60100
pasv_max_port=60200

サービス起動

# systemctl start vsftpd
# systemctl status vsftpd
● vsftpd.service - Vsftpd ftp daemon
   Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled; vendor preset: disabled)
   Active: active (running) since 月 2023-10-30 20:10:05 JST; 7s ago
  Process: 6711 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
 Main PID: 6712 (vsftpd)
   CGroup: /system.slice/vsftpd.service
           mq6712 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf

Firewalldの設定

21,60100-60200/tcpを許可する

# firewall-cmd --add-service=ftp --permanent
# firewall-cmd --add-port=60100-60200/tcp --permanent
# firewall-cmd --reload

# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens192
  sources:
  services: ssh dhcpv6-client
  ports: 993/tcp 143/tcp 21/tcp 60100-60200/tcp
  ...

動作確認

無事接続できました。

注意点:Windowsの標準FTPクライアントはPassive接続に対応していない

Windowsに標準インストールされているFTPクライアントはPassive接続に対応していないそうです。
FTPクライアントのオプションやコマンド一覧を確認しても、Passiveで接続するようなものが存在しません。

>where ftp.exe
C:\Windows\System32\ftp.exe
>ftp -h

FTP サーバー サービス (デーモンとも呼ぶ) を実行するコンピューターとの間で、
ファイルの送受信を行います。FTP は対話的に使用できます。

FTP [-v] [-d] [-i] [-n] [-g] [-s:filename] [-a] [-A] [-x:sendbuffer]
    [-r:recvbuffer] [-b:asyncbuffers] [-w:windowsize] [host]

  -v              リモート サーバーの応答を表示しません。
  -n              最初の接続時に自動ログインを行いません。
  -i              複数ファイルの転送中に、対話的なメッセージ表示を
                  無効にします。
  -d              デバッグを有効にします。
  -g              ファイル名のグロビングを無効にします (GLOB コマンドを参照)。
  -s:filename     FTP コマンドを記述したテキスト ファイルを指定します。
                  これらのコマンドは、FTP の開始後に自動実行されます。
  -a              データ接続のバインド時に、いずれかのローカル インターフェイ
                  スを使用します。
  -A              匿名でログインします。
  -x:send sockbuf SO_SNDBUF の既定のサイズである 8192 を上書きします。
  -r:recv sockbuf SO_RCVBUF の既定のサイズである 8192 を上書きします。
  -b:async count  既定の非同期数である 3 を上書きします。
  -w:windowsize   既定の転送バッファー サイズである 65535 を上書きします。
  host            接続先のリモート ホストのホスト名または IP アドレス
                  を指定します。

メモ:
  - mget および mput コマンドには、それぞれ yes/no/quit の意味を表す y/n/q を
    指定します。
  - コマンドを中止するには Ctrl+C キーを押します。
>ftp
ftp> ?
コマンドは省略することができます。コマンド:

!               delete          literal         prompt          send
?               debug           ls              put             status
append          dir             mdelete         pwd             trace
ascii           disconnect      mdir            quit            type
bell            get             mget            quote           user
binary          glob            mkdir           recv            verbose
bye             hash            mls             remotehelp
cd              help            mput            rename
close           lcd             open            rmdir

FortiGateの「Web管理画面」と「SSL-VPNポータル」のトップページに違いはあるか?



FortiGateの「Web管理画面」と「SSL-VPNポータル」はいずれもHTTPSでサービスが提供されています。

異なるTCPポートでサービスを提供する必要がありますが、以下のような共通点もあるので、それぞのトップページに違いがあるか気になって調べてみた。

  • HTTPSでサービスが提供される
  • トップページにID/パスワードを入力するフォームが存在する

検証環境の構築

検証環境は、Azure VMでFortigateの仮想マシンを作成して利用しました。

  • 環境:FortiGate-VM 7.4.1

FortiGate-VMの構築

AzureのMarket Placeにある「Fortinet FortiGate Next-Generation Firewall」を利用しました。

AzureでのFortiGate-VMの作成方法は以下記事を参照ください。
ライセンスは「Pay as You Go」を選択しています。

tarenagashi.hatenablog.jp

SSL-VPNの設定

FortiGateでSSL-VPNポータルを表示するには、SSL-VPN関連の設定を行う必要があります。
SSL-VPN Settings」と「Firewall PolicyでSSL-VPNユーザを許可するポリシー」の2つをとりあえず設定すれば、SSL-VPNポータルを表示することができます。

設定手順はメーカーサイトを参照ください。
docs.fortinet.com

比較の実施

トップページの見た目の比較

「Web管理画面」と「SSL-VPNポータル」のトップページの見た目を比較しました。
明らかな違いがあります。「SSL-VPNポータル」の方は、「SSL-VPN Portal」と書いてあります。

今回はファームウェア 「Ver 7.4.1」を使用しましたが、「Ver 6.X」だと「SSL-VPNポータル」も緑色が使用されたシンプルな画面なので、「Web管理画面」との違いが分かり難いです。
しかし、「Ver 7.4.1」「Ver 6.X」のいずれの「SSL-VPNポータル」にも、「FortiClientを起動」というボタンが存在するので、そのボタンの有無により容易に「Web管理画面」と「SSV-VPNポータル」の違いを判断することができます。

Web管理画面


SSV-VPNポータル


証明書情報の比較

「Web管理画面」と「SSL-VPNポータル」の証明書情報を比較しました。
証明書のサブジェクトに違いがあります。特にコモンネームが分かり安いです。

「Web管理多面」のデフォルトの証明書のコモンネームは「CN = FortiGate」となっています。
「SSV-VPNポータル」のデフォルトの証明書のコモンネームは「CN = FGTAZRHTXXLQFNE0」というようにシリアル番号になっています。

Web管理画面

Defaultの証明書の識別名は「Fortinet_GUI_Server」、サブジェクトは以下です。

CN = FortiGate
O = Fortinet Ltd.

 

SSV-VPNポータル

Defaultの証明書の識別名は「Fortinet_Factory」、サブジェクトは以下です。

E = support@fortinet.com
CN = FGTAZRHTXXLQFNE0
OU = FortiGate
O = Fortinet
L = Sunnyvale
S = California
C = US

 

結論

FortiGateの「Web管理画面」と「SSL-VPNポータル」のトップページの違いは、以下2点で判別することができます。

  1. 「FortiClientを起動」ボタンの有無
  2. Default証明書のサブジェクト、特にコモンネーム


項目 Web管理画面 SSL-VPNポータル
「FortiClientを起動」ボタンの有無 無し 有り
Default証明書のサブジェクトのコモンネーム CN = FortiGate CN = FGTAZRHTXXLQFNE0
※個体により異なるシリアル番号

ANA国内線の機内Wi-Fiに接続してみた

はじめに

先日、羽田発→函館行きのANAの国内線に乗りました。機内Wi-Fiが無料だったので接続してみました。
その時のSSIDIPアドレスなど、個人的なメモです。

乗った機体は「ボーイング787-8(78P)」でした。


ANA国内線の機内Wi-Fiについて

今回機内Wi-Fi使った感想として、遅さは感じませんでした(使ってた人が少ないだけかもしれません)

接続結果のメモ

Wi-Fi接続

SSIDは「ANA-WiFi-Service」でした。
Wi-Fi接続にPW入力は無かったが、ブラウザでの認証が必要でした。

  

グローバルIPアドレス

グローバルIPは「205[.]220[.]148[.]142」でした。

Panasonic Avionics Corporation」は、205.220.128[.]0~205.220.159[.]255の範囲 = 8192個のグローバルIPを所持してるみたいです。

プライベートIPアドレス

端末に割り当てられたプライベートIPアドレスは以下のとおりでした。

IPアドレス 172.19.248.97/23
デフォゲ兼DNS 172.19.248.1

/23のレンジなので、飛行機1台辺り最大509台のクライアント端末からの接続を想定しているようです。
(2^9=512から、NWアドレス、BroadCastアドレス、デフォゲ兼DNSの3つを除く)

私の端末に割り当てられたプライベートIPの第4オクテットは「.97」となってましたが、96台の端末が接続されている(最大96人が利用している)わけではなく、過去フライト時のDHCPのキャッシュが残っている場合「.2」から順に割り当てられているわけではないかもしれません。

おわりに

下記も調べてみたいなと後から思いました。

  • デフォゲのMACアドレス取得(からの親機製造メーカーの推定)
  • インターネット宛のtraceroute
  • プライベートIP(/23)に対するPing疎通確認やARPの送信
  • 認証画面のホスト「inflight.pacwisp[.]net」のIPアドレスやHTTPヘッダ

PythonでTor経由のスクレイピング

はじめに

.onionドメインのWebサイトをスクレイピングしたいと思い調べたところ、ブラウザなどのWebクライアントからの通信がTorのSOCKSプロキシを経由するように構成すればスクレイピングできるとのことで、いくつかのWebクライアントを利用して実施してみます。

.onionドメインでない通常のWebサイト(*.comとか、*.jpなど)について、送信元IPアドレスを隠蔽してスクレイピングしたい場合もこの方法で可能です。

※ちなみに、WebサイトによってはTor経由のアクセスを禁止してたり、Tor経由だとreCAPTCHAが動作するサイトがあるので、そういう場合は適宜対応や諦める必要があります。

実施環境について

  • OS:Windows11 Enterprise 22H2 64bit
  • Python:3.10.0
  • Torブラウザ:バージョン不明 ※2023/10/04時点の最新
  • Chrome:バージョン117

Torブラウザ付属のTorについて

Torブラウザを利用してTorへの通信を確立すると、Windows版の場合は「tor.exe」というプログラムがTCPの9150と9151で待ち受けて起動します。

9150がTorネットワークに接続するためのSOCKSプロキシ、9151が制御ポートです。
(制御ポートを使うと、Torの設定や状態確認ができるらしい)

> $tor_process = (Get-Process | where ProcessName -eq "tor").id
> Get-NetTCPConnection | where State -eq "Listen" | where OwningProcess -eq $tor_process | Select-Object LocalAddress,LocalPort,State

LocalAddress LocalPort  State
------------ ---------  -----
127.0.0.1         9151 Listen
127.0.0.1         9150 Listen

スクレイピングの実施

3種類のWebクライアントで、.onionドメインのWebサイトをスクレイピングする例です。
htmlの取得までを実施します(htmlを取得できれば後は解析するだけなので)。

TorのSOCKSプロキシを利用するので、事前にTorブラウザを起動し、Torネットワークへの接続を確立しておく必要があります。


.onionドメインのサイトは「Facebook」と「DuckDuckGo」の.onionドメインVerを利用しました。

Webクライアントが「Chrome」の場合

Webクライアントが「Chrome」の場合です。
Selenium+ChromeDriver経由でChromeを操作してスクレイピングを実施します。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--proxy-server=socks5://127.0.0.1:9150")

driver = webdriver.Chrome(options=options)
driver.get("https://facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion")
print(driver.page_source)

Webクライアントが「requests」の場合

Webクライアントが「requests」の場合です。
https://requests.readthedocs.io/en/latest/

import requests

proxies = {
    'http' : "socks5h://localhost:9150",
    'https' : "socks5h://localhost:9150"
}

url = "https://facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion"
res = requests.get(url, proxies=proxies)
print(res.text)

Webクライアントが「requests_tor」の場合

Webクライアントが「requests_tor」の場合です。
https://github.com/deedy5/requests_tor

「requests_tor」は、Tor接続に特化したPythonのWebクライアントです。
TorブラウザのHTTPヘッダを模倣したり(User-Agentなど)、複数サイトへの同時接続などができます。

from requests_tor import RequestsTor

rt = RequestsTor(tor_ports=(9150,), tor_cport=9151)

# 単一サイトへの接続
url = 'https://facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion'
r = rt.get(url)
print(r.text)

# 複数サイトへの接続
urls = ['https://facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion', 
        'http://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion']

for r in rt.get_urls(urls):
    print(r.url)
    print(r.text)