サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考 5章 勉強まとめ
遅くなりましたが続きです。
本来は7月中に全章終えるつもりだった……。
Pythonを使ってwebサーバーとやり取りをする章。
webのソケットライブラリ:urllib
Webを扱うツールを作る際にはurllib2ライブラリを使う……と本にはあるんですが、このライブラリはpython3では使えないらしい。
なので、Python3の標準ライブラリであるurllibを使っていきます。
import urllib.request body = urllib.request.urlopen("http://www.google.com") print(body.read())
import urllib.request
URLを取得するためのモジュール。
urllib.request.urlopen("http://www.google.com")
URLを開く。bytes オブジェクトを返す。
import urllib.request url = "http://www.google.com" headers = {} headers['User-Agent'] = "Googlebot" request = urllib.request.Request(url, headers=headers) response = urllib.request.urlopen(request) print(response.read()) response.close()
headers = {}
headers['User-Agent'] = "Googlebot"
HTTPヘッダーとその値を設定。HTTPヘッダーとは、ユーザーエージェント名やリファラなどをことを言うらしい
ここでは、Googlebotとしてユーザーエージェント名を設定している。
request = urllib.request.Request(url, headers=headers)
URLリクエストを抽象化したもの。URLとHTTPヘッダーを与える。
オープンソースのWebアプリケーションのインストール
保留。気になったものだけまとめておきます。
os.chdir()
指定したディレクトリを移動する。
16.1. os — 雑多なオペレーティングシステムインタフェース — Python 3.5.1 ドキュメント
queue.Queue()
FIFOキューのコンストラクタ。引数を指定すると、要素の上限を決められる。
キューに入れるときは、put。キューから出すときは、getを用いる。分かりやすい。
ちなみに、LIFOキューは、
queue.LifoQueue
優先順位付きキューは、
queue.PriorityQueue
です。優先順位付きキューっていまいちよく分からなかったので調べたところ…よく分からなかった。
17.7. queue — 同期キュークラス — Python 3.5.1 ドキュメント
ディレクトリとファイルの総当り攻撃
総当り攻撃用の辞書を使って、ツールのテスト用に公開されている脆弱なWebアプリケーションに総当り攻撃をしてみる。
# -*- coding: utf-8 -*- import urllib.request import threading import queue import urllib.parse threads = 5 target_url = "http://testphp.vulnweb.com" wordlist_file = "/root/SVNDigger/all.txt" resume = None user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0" def build_wordlist(wordlist_file): #単語の辞書を読み取る fd = open(wordlist_file, "rb") raw_words = fd.readlines() fd.close() founnd_resume = False words = queue.Queue() for word in raw_words: word = word.rstrip() if resume is not None: if founnd_resume: words.put(word) else: if word == resume: founnd_resume = True print("Resuming wordlist from {}".format(resume)) else: words.put(word) return words def dir_bruter(word_queue, extensions=None): while not word_queue.empty(): attempt = word_queue.get().decode() attempt_list = [] #ファイルに拡張子があるかどうかチェック。 #なければ、ディレクトリのパスとして総当り攻撃の対象に if "." not in attempt: attempt_list.append("/{}/".format(attempt)) else: attempt_list.append("/{}".format(attempt)) #拡張子の総当りをする場合 if extensions: for extension in extensions: attempt_list.append("/{0}{1}".format(attempt, extension)) #作成したリストを最後まで繰り返す for brute in attempt_list: url = "{0}{1}".format(target_url, urllib.parse.quote(brute)) try: headers = {} headers["User-Agent"] = user_agent r = urllib.request.Request(url, headers=headers) response = urllib.request.urlopen(r) if len(response.read()): print("[{0}] => {1}".format(response.code, url)) except urllib.error.URLError as e: if hasattr(e, "code") and e.code != 404: print("!!! {0} => {1}".format(e.code, url)) pass word_queue = build_wordlist(wordlist_file) extensions = [".php", ".bak", ".orig", ".inc"] for i in range(threads): t = threading.Thread(target=dir_bruter, args=(word_queue, extensions,)) t.start()
target_url = "http://testphp.vulnweb.com"
今回のターゲット。脆弱なWebアプリケーションのURL。
wordlist_file = "/root/SVNDigger/all.txt"
総当り攻撃用の辞書。よくあるファイル名やディレクトリ名が載ってる。
def build_wordlist(wordlist_file)
辞書から一行ずつ取り出してキューに入れる関数。
def dir_bruter(word_queue, extensions=None)
キューより、検索対象のURLを総当りする。
attempt = word_queue.get().decode()
キューから取り出したデータがbyte型だったのでデコードした。
response.code
urlopen関数は、ファイルのようなオブジェクトを返します。なので、ファイルを扱うように、readだのなんだのしてきましたが、codeという属性を持っているオブジェクトみたいです。
codeという属性がHTTPステータスコードを指しているのでしょう。
公式ドキュメントに
この関数は コンテクストマネージャ として機能するオブジェクトを常に返します。このオブジェクトには以下のメソッドがあります。
geturl() — 取得されたリソースの URL を返します。 主に、リダイレクトが発生したかどうかを確認するために利用します
info() — 取得されたページのヘッダーなどのメタ情報を、 email.message_from_string() インスタンスとして返します。 (Quick Reference to HTTP Headers を参照してください)
getcode() – レスポンスの HTTP ステータスコードです。
とあるので、メソッドを呼び出して使うのもありですね。
21.6. urllib.request — URL を開くための拡張可能なライブラリ — Python 3.5.1 ドキュメント
実際実行してみると、(実行速度は遅かったですが)無事結果が得られた。
何度か、
Remote end closed connection without response
とエラーが出てしまったので、プログラム側か処理速度に問題があるのかも。
HTMLファームの認証を総当り攻撃で破る
こちらもとりあえず保留。Cookie関連が2系とだいぶ違うみたい。
再読時に躓きそうだから、参考になりそうなリンクを貼っておく。
http://www.yoheim.net/blog.php?q=20151101
http://matsulib.hatenablog.jp/entry/2015/03/06/161546
http://ymotongpoo.hatenablog.com/entry/20081211/1228985067
20.2. html.parser— HTML および XHTML のシンプルなパーサー — Python 3.5.1 ドキュメント