最近学习了Redis数据库,并用Python脚本实现了一个Redis安全扫描器吧,通过扫描器可以帮助发现脆弱的Redis主机!,现写下大致思路和流程(以我的环境为例),和大家一起交流学习下。新手请大神勿喷。大体流程 1 首先在CentOS下通过源码编译的方式安装Redis数据库 2 Redis数据库安全攻防实践 3 使用Python打造Redis安全扫描器 流程1和2难度不大,我在一个实验室有介绍(http://www.hetianlab.com/cour.do?w=1&c=C172.19.104.182015052010331700001) 主要介绍下三的思路, 3.1 如何识别Redis服务特征(以我的环境为例) 思路:Redis服务并不一定只能在6379端口上进行监听,这个选项可以在Redis配置文件redis.conf里面进行修改;其次,即使6379端口处于开放状态,我们也需要对其进行判断是否是Redis服务。扫描器一般都通过端口返回的交互数据来判别端口上运行的具体服务,识别Redis服务也不例外。 首先,我们需要确保Redis服务已经运行在服务器上,使用PUTTY连接服务器。在启动Redis服务之前,我们要给它设置一个登陆密码,使用vi编辑器修改redis.conf,将requirepass foobared前面的注释符号#删除即可,在这里我已经创建好了一个需要密码的配置文件redis-pwd.conf,所以直接使用命令src/redis-server redis-pwd.conf启动Redis数据库也可以。 现在,我们开始与Redis服务器进行交互,为了更好地理解Redis客户端与服务器的交互过程,我们使用自带的命令行交互工具redis-cli。打开另一个PuTTY并连接到服务器,使用cd /home/test/redis-3.0.1/src完成目录切换,并运行redis-cli,命令如下: cd /home/test/redis-3.0.1/src # 完成目录切换 ./redis-cli -h 127.0.0.1 -p 6379 # 连接Redis服务 PING # 执行PING命令 AUTH 123456 # 执行AUTH命令,表示使用密码123456进行连接 AUTH foobared # 使用密码foobared进行连接 PING # 执行PING命令 介绍一下Redis的PING和AUTH命令。 1. PING命令 在成功连接上Redis服务器之后,客户端往服务器发送PING命令,服务器会给客户端返回PONG这个字符串。 2. AUTH命令 如果Redis服务设置了连接密码,那么首先需要通过AUTH命令确认登陆密码。 从上面的操作步骤,我们已经可以总结出识别Redis服务的方法了: 1. 指定的端口是否开放TCP服务; 2. 执行PING命令: a) 如果提示(error) NOAUTH Authentication required.表明是Redis服务,且需要登录密码; b) 如果提示PONG,表明是Redis服务,且无需登录密码; c) 提示其他结果,表明不是Redis服务; 3. 如果需要登录密码,执行AUTH命令: a) 如果提示(error) ERR invalid password,表明密码错误; b) 如果提示OK,表明密码正确;3.2 编程实现Redis服务识别 在3.1中,我们已经知道了鉴定Redis服务的方法,那么编写代码实现就很简单了,在这里我们使用Python语言来实现。 在编写代码之前,我们还需要知道的一点是:客户端通过socket往服务器发送命令时,需要在后面加上回车换行,即\r\n;我们在使用redis-cli发送PING命令时,redis-cli会自动加上\r\n,拼接成PING\r\n。在编程实现扫描器时,我们需要自己加上\r\n。 识别Redis服务的代码如下所示 代码封装在is_redis_server函数中,传入参数为IP地址以及端口号,返回-1表明端口未开放或者开放但不是Redis服务,返回0表明是Redis服务但是需要访问密码;返回1表明是Redis服务且不需要访问密码。 在上面的代码中,我们没有使用connect函数连接到目标服务器,而是使用了connect_ex函数。因为前者在连接失败的情况下会抛出一个异常,我们需要在代码中加入异常处理的代码;而使用connect_ex直接判断返回值即可,可以使得代码更加的简洁。测试环境(http://www.hetianlab.com/expc.do?w=exp_ass&ec=ECID172.19.104.182015051910565200001) 3.3 实现Redis弱口令爆破以及网段扫描功能 当我们扫描到一台需要密码的Redis服务器时,是否可以进行密码猜解呢?答案显然是可以的,因为Redis并没有限制客户端输入登录密码的次数。出于安全检测的目的,我们只对其进行弱口令检查。 实现弱口令爆破的思路很简单,我们不断的往Redis服务器发送AUTH命令即可,如果返回结果包含字符串invalid password,表明密码错误,如果返回结果包含字符串OK,则表明密码正确。那么弱口令字典哪里来呢?这里我们以CSDN泄露的数据库中最常用的100个密码建立一个弱口令字典(来自文章http://coolshell.cn/articles/6193.html),弱口令列表如下图所示(字典文件位于实验主机C:\Code\Redis\dict.txt,当然,这里必须加入Redis默认的密码foobared,为了测试效果将其放在了最后一行,实际为了提高命中率可以放在第一行): 我们将爆破密码的代码封装在check_password函数中,函数首先读取dict.txt文件的密码列表,随后遍历列表中的密码并生成AUTH命令,将生成的AUTH命令发送到服务器,根据服务器的返回信息判断密码是否正确:如果返回的信息包含OK则表明密码正确。具体的代码如下图所示: 现在,我们只需要稍微修改is_redis_server函数即可,在其中加入对check_password的调用。具体的改动如下图中的红框所示: 爆破相关的代码放在了实验机器的C:\Code\Redis\CheckPassword.py文件中,在命令行运行CheckPassword.py脚本,即可快速破解出在10.1.1.47服务器上的Redis弱口令为foobared。 现在,我们添加扫描器的最后一个功能:网段扫描功能,即可以指定要扫描的IP范围。这里扫描IP范围直接通过命令行参数指定,如10.1.1.1 10.1.1.255表明共有255台主机需要扫描,那么如何遍历这255个IP地址呢?运用预备知识中介绍的内容,可以十分方便的进行遍历: 3.3.1. 将字符串形式的点分十进制IP地址转换为数值,首先使用split将IP地址进行分离,比如"10.1.1.47".split("."),这样各个点之间的数据就分离了,得到列表["10", "1", "1", "47"],随后将列表中的元素从字符串转换为int,并乘以相应的系数后累加,代码如下: 通过步骤3.3.1,我们就可以计算出字符串IP地址对应的数值范围了,通过for循环遍历这个范围即可。遍历得到的数值IP还需要转换为字符串,这里通过位运算中的“与操作”以及“移位操作”实现。例如IP地址17.34.51.68对应的数值形式为0x11223344(16进制),那么0x11223344 & 0xFF000000得到0x11000000,再向右移动24位就可以得到0x11,即10进制的17。对应的代码如下: 网段范围扫描的代码封装在scan函数中,其中beg_ip通过sys.argv[1]获取,end_ip通过sys.argv[2]获取,具体的代码如下所示: 扫描器完整的源代码位于实验主机的C:\Code\Redis\RedisScanner.py,使用方法为通过命令行参数传入扫描IP地址的范围即可。参考测试结果环境(http://www.hetianlab.com/expc.do?w=exp_ass&ec=ECID172.19.104.182015051910565200001) 到这里Redis安全扫描器就编写完成了,我们在代码中只检测了6379端口以及101个弱口令,因为我们只是对Redis服务做安全检测,所以做完这些工作基本就够了。 简单了写了些总结,方便大家交流和学习。在一个网站搭建了实验环境,有兴趣的可以去试试。大神勿喷
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!