O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

Pythonを使った簡易診断スクリプトの作り方

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Carregando em…3
×

Confira estes a seguir

1 de 78 Anúncio

Mais Conteúdo rRelacionado

Diapositivos para si (20)

Semelhante a Pythonを使った簡易診断スクリプトの作り方 (20)

Anúncio

Mais recentes (20)

Pythonを使った簡易診断スクリプトの作り方

  1. 1. Pythonを使った簡易診断 スクリプトの作り方 OWASP Kyushu Chapter Leader 服部祐一
  2. 2. 自己紹介 • OWASP Kyushu Chapter Leader • SECCON 実行委員 • 北九州情報セキュリティ勉強会「セキュ鉄」代表
  3. 3. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  4. 4. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  5. 5. はじめに • Pythonを使って • 情報の取得 • 自動ログイン • 自動書き込み • 最終的に簡易診断スクリプトを作成
  6. 6. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  7. 7. デモ環境 • 仮想マシンをノートPC内に立ち上げて • 仮想マシン上のWebアプリに対して ホスト側からスクリプトを実行 ノートPC 仮想マシン Webサーバ 対象アプリ 自動ログインスクリプト 自動書き込みスクリプト 自動診断スクリプト 対象アプリ
  8. 8. 対象アプリ • 攻防戦用に作成した脆弱性を多数含むPHPのWebアプリ • https://github.com/Eidwinds/a_and_d_web_hokkaido
  9. 9. 対象アプリ • OWASP Broken Web Applications Project • 脆弱なアプリケーションを集めた仮想マシンを提供しているプ ロジェクト • 2年近く更新されていないが、いろいろ入っていて便利なので ここにあるWebアプリも対象に使う。
  10. 10. 実行環境(Python) • Python3系を用います。
  11. 11. 使用するライブラリ • Requests • 人が使いやすいように設計されたHTTPのライブラリ。 • これを使ってHTMLの取得やPOSTの送信を行う。 • beautifulsoup4 • HTMLやXMLファイルからデータを取得するライブラリ。
  12. 12. Requests http://requests-docs-ja.readthedocs.io/en/latest/
  13. 13. beautifulsoup4 http://kondou.com/BS4/
  14. 14. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  15. 15. タイトルの取得 • まず、最初にタイトルタグに書かれている文字を 取得してみます。 流れとしては、 1. Requestsを使いGETリクエストでトップページのHTMLを取得。 2. HTMLをbeautifulsoup4を使ってパースする。 3. パースした結果からタイトルタグを取り出し、表示する。
  16. 16. HTMLの取得 • まず、Requestsを使ってトップページのHTMLを取得します。 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") print(r.text) 指定したページに対し てGETリクエストを 行います。 r.textでGETリクエスト の結果のBodyをテキス トで取得します。
  17. 17. HTMLの取得
  18. 18. Response Headerの取得 • おまけとしてResponse Headerを取る場合は、 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") print(r.headers) r.Headersでkeyとvalue のペアとして取得する ことができます。
  19. 19. Response Headerの取得
  20. 20. HTMLをbeautifulsoup4を使ってパースする。 • Requestsで取得したHTMLをbeautifulsoup4を使ってパースし てみましょう。 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") bs = BeautifulSoup(r.text, "html.parser") print(type(bs)) パースするHTMLを指定 しています。 パーサーを 指定しています。 オブジェクトのタイプ を出力してます。
  21. 21. HTMLをbeautifulsoup4を使ってパースする。
  22. 22. タイトルタグを取り出し、表示する • パースした結果からタイトルタグを取り出し、表示します。 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") bs = BeautifulSoup(r.text, "html.parser") print(bs.title) bs.titleでタイトルタグ を取得しています。
  23. 23. タイトルタグを取り出し、表示する
  24. 24. タグの中身だけを取り出す • <title>も一緒についてきましたが今度はタグの中身だけを取り 出します。 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") bs = BeautifulSoup(r.text, "html.parser") print(bs.title.string) .stringを付けることによ り中身だけを取得でき ます。
  25. 25. タグの中身だけを取り出す
  26. 26. 他のタグの取得 • 今の書き方だと複数同じタグがある場合にはどうなるのか? • ためしにAタグで試してみます。 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") bs = BeautifulSoup(r.text, "html.parser") print(bs.a)
  27. 27. 他のタグの取得 一番最初のものだけ表示されました。
  28. 28. 複数あるタグの取得 • 他のやり方でAタグの一覧を取得してみます。 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") bs = BeautifulSoup(r.text, "html.parser") a_list = bs.find_all(“a") for a in a_list: print(a) .find_allで指定したタグ のリストを取得します。
  29. 29. 複数あるタグの取得
  30. 30. タグの属性の取得 • おまけとしてAタグのhref属性だけを表示してみます。 import requests from bs4 import BeautifulSoup r = requests.get("http://192.168.237.130/page.php?p=index&t=TOP") bs = BeautifulSoup(r.text, "html.parser") a_list = bs.find_all(“a") for a in a_list: print(a.get(“href”)) .getで指定した属性を取 得します。
  31. 31. タグの属性の取得
  32. 32. URLをコマンドライン引数にする • URLが固定だと毎回ソースコードをいじる必要があるので、 ここで、URLの設定をコマンドライン引数にしておきましょう。 import sys import requests from bs4 import BeautifulSoup r = requests.get(sys.argv[1]) bs = BeautifulSoup(r.text, "html.parser") a_list = bs.find_all(“a") for a in a_list: print(a.get(“href”)) sys.argv[1]で赤字の部分を取得します。 python test.py [argv1]
  33. 33. URLをコマンドライン引数にする
  34. 34. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  35. 35. 自動ログインの実装(CSRFTokenなし) • inputタグの情報などはすべてわかってる前提での自動ログイン を行う。 HTMLを解析し 必要な情報を取得 取得した情報を元 にログインページ にログイン情報を 送信 ログイン成功
  36. 36. WackoPicko • 脆弱性のあるWebサイト • 画像の共有 • 画像の売買 • ゲストブック • etc
  37. 37. HTMLの解析(手動) • http://***.***.***.***/WackoPicko/users/login.php <div class="column prepend-1 span-23 first last"> <h2>Login</h2> <table style="width:320px" cellspacing="0"> <form action="/WackoPicko/users/login.php" method="POST"> <tr><td>Username :</td><td> <input type="text" name="username" /></td></tr> <tr><td>Password :</td><td> <input type="password" name="password" /></td></tr> <tr><td><input type="submit" value="login" /></td><td> <a href="/WackoPicko/users/register.php">Register</a></td></tr> </form> </table> </div> 送信先 ユーザ名 パスワード
  38. 38. 自動ログインの実装(CSRFTokenなし) import sys import requests payload = { "username": "scanner1", "password": "scanner1" } r = requests.post(sys.argv[1], data=payload) print(r.text) pyloadにログイン情報を入れます。 dataにpyloadを指定します。
  39. 39. 自動ログインの実装(CSRFTokenなし)
  40. 40. ログインできているかの確認 • ログイン時にはLogoutボタンが表示されている。 • ログアウトボタンのリンクをログイン時の確認にしてみます。
  41. 41. ログインできているかの確認 import sys import requests from bs4 import BeautifulSoup payload = { "username": "scanner1", "password": "scanner1" } r = requests.post(sys.argv[1], data=payload) bs = BeautifulSoup(r.text, "html.parser") a_list = bs.find_all("a") for a in a_list: if a.get("href") == "/WackoPicko/users/logout.php": print("SUCCESS") sys.exit() print("FAILED") ログアウトのURL 見つけたら終了
  42. 42. ログインできているかの確認
  43. 43. 自動ログインの実装(CSRFTokenあり) • CSRF対策されているログインフォームに対してログインする。 HTMLを解析し 必要な情報を取得 取得した情報を元 にログインページ にログイン情報を 送信 ログイン成功 このフェーズで CSRFTokenを取得する
  44. 44. 対象アプリ • BWAによさそうな対象がなかったのでCSRF対策されている公 開されているCTF用のスコアサーバーで試してみます。 • https://github.com/CyberSEAGame/score-server • ユーザーは、test@example.com:test で作成しています。
  45. 45. 先ほどのスクリプトでログインできるか • 先ほどのCSRF対策の回避がないスクリプトでログインできな いことを確認します。 import sys import requests payload = { “email": test@example.com, "password": “test" } r = requests.post(sys.argv[1], data=payload) print(r.text)
  46. 46. 先ほどのスクリプトでログインできるか 再度ログインフォー ムがあるので失敗し ているようです。
  47. 47. HTMLを読んでみる。 <form method="post" action="" class="normal-form"> <input name="fuel_csrf_token" value="6eef0df3c731588c20cf6063d05c829135f82dd9becf29049a23c60c4a993 963a4cf406218a6de107b4bdc5ee3178b79ead7e61701de3ed6588d515ed998bc3 5" type="hidden" id="form_fuel_csrf_token" /> <fieldset> <label for="email">Email:</label> <input type="email" required="" name="email" id="email"> </fieldset> <fieldset> <label for="password">Password:</label> <input type="password" required="" name="password" id="password"> </fieldset> <button type="submit" class="normal-button center">Signin</button> </form> csrf tokenらしきもの がある!
  48. 48. 自動ログインの実装(CSRFTokenあり) • CSRF対策されているログインフォームに対してログインする。 HTMLを解析し 必要な情報を取得 取得した情報を元 にログインページ にログイン情報を 送信 ログイン成功 このフェーズで CSRFTokenを取得する
  49. 49. CSRF Tokenの取得 • まず、CSRF Tokenを取得します。 • 対象はnameがfuel_csrf_tokenのinputタグです。 import sys import requests from bs4 import BeautifulSoup r = requests.post(sys.argv[1]) bs = BeautifulSoup(r.text, "html.parser") input_list = bs.find_all(“input”) for input in input_list: if input.get(“name”) == “fuel_csrf_token”: print(input.get(“value”))
  50. 50. CSRF Tokenの取得
  51. 51. CSRF Tokenを一緒に送ってみる。 • 今度は、CSRF TokenもPyloadにいれて送信してみます。 import sys import requests from bs4 import BeautifulSoup token = "" r = requests.post(sys.argv[1]) bs = BeautifulSoup(r.text, "html.parser") input_list = bs.find_all("input") for input in input_list: if input.get("name") == "fuel_csrf_token": token = input.get("value") payload = { "email": "test@example.com", "password": "test", "fuel_csrf_token": token } r = requests.post(sys.argv[1], data=payload) print(r.text)
  52. 52. ログインできてない?
  53. 53. 別のところにもTokenがあるようです。 • Cookieの値も見てみましょう。 import sys import requests r = requests.post(sys.argv[1]) print(r.cookies)
  54. 54. CookieにもTokenが保存されているようだ。 fuel_csrf_tokenがある!
  55. 55. CookieにもTokenを設定して送る。 import sys import requests from bs4 import BeautifulSoup token = "" cookie_token = "" r = requests.post(sys.argv[1]) cookie_token = r.cookies["fuel_csrf_token"] bs = BeautifulSoup(r.text, "html.parser") input_list = bs.find_all("input") for input in input_list: if input.get("name") == "fuel_csrf_token": token = input.get("value") payload = { "email": "test@example.com", "password": "test", "fuel_csrf_token": token } cookies = dict(fuel_csrf_token=cookie_token) r = requests.post(sys.argv[1], data=payload, cookies=cookies) print(r.text) Cookieをセット 辞書型のCookie一覧を作成
  56. 56. ログイン成功! Logoutボタンがあるので ログインに成功している
  57. 57. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  58. 58. ログイン後ページでの情報の取得 • ログイン後に特定ページの情報が取得できるか試してみます。 • 今回は、ログイン後にしか見ることができないQuestionsペー ジを取得できるかを試します。 • なお、ログインしていないと404に飛ばされます。
  59. 59. まず、先ほどのスクリプトの後にアクセスしてみます。 import sys import requests from bs4 import BeautifulSoup token = "" cookie_token = "" r = requests.post(sys.argv[1]) cookie_token = r.cookies["fuel_csrf_token"] bs = BeautifulSoup(r.text, "html.parser") input_list = bs.find_all("input") for input in input_list: if input.get("name") == "fuel_csrf_token": token = input.get("value") payload = { "email": "test@example.com", "password": "test", "fuel_csrf_token": token } cookies = dict(fuel_csrf_token=cookie_token) r = requests.post(sys.argv[1], data=payload, cookies=cookies) r = requests.post(sys.argv[2], data=payload) print(r.text)
  60. 60. 失敗して404が返ってきました。
  61. 61. ログインに関する情報はCookieに • 今度は、ログイン後のCookieをそのまま引き継いでアクセスし てみます。 • 長いのでソースは次のページに。
  62. 62. ログインに関する情報はCookieに import sys import requests from bs4 import BeautifulSoup token = "" cookie_token = "" r = requests.post(sys.argv[1]) cookie_token = r.cookies["fuel_csrf_token"] bs = BeautifulSoup(r.text, "html.parser") input_list = bs.find_all("input") for input in input_list: if input.get("name") == "fuel_csrf_token": token = input.get("value") payload = { "email": "test@example.com", "password": "test", "fuel_csrf_token": token } cookies = dict(fuel_csrf_token=cookie_token) r = requests.post(sys.argv[1], data=payload, cookies=cookies) r = requests.post(sys.argv[2], data=payload, cookies=r.cookies) print(r.text)
  63. 63. Questionsのページが取得できました。
  64. 64. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  65. 65. 掲示板への自動書き込み • ここでは、 • 掲示板への書き込み • ちゃんと書き込めたのかのチェック • を行います。
  66. 66. まず書き込んでみる。 • 先ほどのログインの要領で今度は掲示板に書き込みます。 import sys import requests payload = { "title": "タイトル", "name": "名前", "body": "本文" } r = requests.post(sys.argv[1], data=payload) print(r.text)
  67. 67. 書き込まれました!
  68. 68. ちゃんと書き込めたのかのチェック • 書き込んだ内容がちゃんと反映されているか確認してみます。 かぶると面倒なのでタイトルに時間を書き込みます。 import sys import requests from bs4 import BeautifulSoup from datetime import datetime title = datetime.now().isoformat() payload = { "title": title, "name": "名前", "body": "本文" } r = requests.post(sys.argv[1], data=payload) bs = BeautifulSoup(r.text, "html.parser") h2_list = bs.find_all("h2") for h2 in h2_list: if h2.string == title: print("SUCCESS") sys.exit() print("FAILED") 現在時刻の文字列をiso フォーマットで取得 タイトルを確認
  69. 69. ちゃんと書き込めたのかのチェック
  70. 70. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  71. 71. 自動書き込みによる脆弱性診断(XSSチェック) • 先ほどの書き込む文字列をJavaScriptの入った文字列に変えて みましょう。 import sys import requests from bs4 import BeautifulSoup from datetime import datetime xss = '<script>console.log(1);</script>' payload = { "title": xss, "name": "名前", "body": "本文" } r = requests.post(sys.argv[1], data=payload) bs = BeautifulSoup(r.text, "html.parser") h2_list = bs.find_all("h2") for h2 in h2_list: if h2.string == xss: print("SUCCESS") sys.exit() print("FAILED")
  72. 72.
  73. 73. 確認できなかった • HTMLとして意味を持ったためにさっきの書き方だと破壊され るようだ。 http://kondou.com/BS4/
  74. 74. 別のメソッドを使ってみよう • これだけ多くのメソッドがあるなら使えるものがあるはず! http://kondou.com/BS4/
  75. 75. 別のメソッドを使ってみよう import sys import requests from bs4 import BeautifulSoup from datetime import datetime xss = '<script>console.log(1);</script>' payload = { "title": xss, "name": "名前", "body": "本文" } r = requests.post(sys.argv[1], data=payload) bs = BeautifulSoup(r.text, "html.parser") h2_list = bs.find_all("h2") for h2 in h2_list: for child in h2.children: if str(child) == xss: print("SUCCESS") sys.exit() print("FAILED") HTML構造になるならそれに ならって子要素を探索
  76. 76. 成功!
  77. 77. アジェンダ • はじめに • デモ環境について • 情報の取得 • 自動ログインの実装 • ログイン後ページでの情報の取得 • 掲示板への自動書き込み • 自動書き込みによる脆弱性診断(XSSチェック) • まとめ
  78. 78. まとめ • Pythonのライブラリである Requestsとbeautifulsoup4を使って • Webページから情報を入手する方法 • CSRFトークンのあるページでの自動ログイン • 自動書き込みによる脆弱性の検査

×