一次短信验证码攻击的应急响应

前言

前段时间客户现场被攻击,客户找到了公司,公司找到了我,于是有了这一次的应急响应,因为第一次搞,所以记录一下整个过程。

一、要做什么

刚开始不知道干啥,非常迷茫,通过老大的教导,事后总结了下面几条个人觉得非常重要的点。

  1. 事件确认,发生什么事情了,什么时间,是否紧急,影响程度等。
  2. 确定攻击动机,别人为什么攻击我们
  3. 确认攻击手段,利用什么漏洞进行攻击的,我们的应用是否存在高危漏洞,还是某一个中间件,还是其他攻击手段
  4. 制定解决方案,包括临时解决方案和最终解决方案。临时解决方案为了快速应对问题,最终解决方案为了彻底解决问题。
  5. 追踪溯源,尽可能确定攻击者的身份。
  6. 形成书面报告,说明事件的起因经过结果,说明事件的责任归属(谁的锅)。

二、详细过程

有了上面的指导,就可以第一次的应急响应了。

1. 事件确认

客户给公司反映有人投诉说收到了大量的短信验证码,然后登陆了服务器发现了大量短信验证码请求。

红色标记的就是失败的次数,非常的多,可以确认有人在利用短信验证码接口进行攻击。

2. 攻击动机

因为是大量短信验证码,所以攻击动机就有了两种:(1) 有人盯上了我们的客户,在恶意消耗我们的资源(但是我们客户是公安),所以可能性不大。(2) 我们的服务器被利用了,有人在利用服务器对特定的人进行短信验证码攻击,我们只是其中的一条。所以很可能是短信验证码轰炸平台利用了我们的资源。
后面给投诉用户打了电话,投诉的人告诉我们,他收到了很多平台的短信验证码,他的同事也收到了。(可以确定是短信验证码轰炸)

3.攻击点分析

首先先和开发确定了哪些接口都可以发送短信验证码,确定有三个可以发送短信验证码的。

#注册接口 可获取验证码
/api/user/smsxxxx?mobile=xxxx
/api/user/sms?mobile=xxxx&xxxxx
#登录接口 可获取验证码
/sendLoginMobilexxxx

通过开发确定了我们的应用存在下面的机制:每个用户每天只能发10条,每个IP可以发送100条。所以我们先确定了自己的机制是否生效,确定短信验证码机制是生效的,这里不存在安全问题。
于是我继续查看了我们的一个注册接口,发现获取短信验证码不需要输入图片验证码。如下图所示,可以直接请求短信验证码,所以才导致可以大量的爆破。

看到这里就知道是我们产品的问题了,好的产品都会在获取短信验证码前需要一个手工验证防止爆破的。

4. 制定解决方案

我以为到这里就结束了,直接上图片验证码就好了。结果开发告诉我,这个功能他们原来有,下线了,因为很多老年机加了这个功能无法收到短信验证码?这是什么情况?事情果然不简单,此处应该有图片.jpg

临时解决方案

所以我们先确定了临时的解决方案,修改短信验证码发送配置:(1)每个用户一天只能发五条,一个IP只能发10条。(2)当一个IP发送的数量超过100条后,日志中会记录大量的错误+ip这样的信息。所以我们可以根据这个信息来进行IP封锁。

最终解决方案

上图片验证码功能

5. 流量统计,进行封IP处理

因为日志都存储在ES上,而访问ES要先登录VPN,再访问堡垒机,再访问虚拟机,然后从ES上导出日志,然后从堡垒机上下载日志。非常复杂,所以这一个阶段花费了大量的时间,并且效果也不是很好。(只拿了两天的日志量,大概有100G)

这是我下载下来的日志,日志中包含了大量的报错等无用信息,因为我需要的日志都是以2020开头的,所以写了简单的脚本将信息进行过滤。

fileDir="F:\xxx\xxxx\log3"
files=os.listdir(fileDir)

with open("result3.txt","w") as f:

    for file in files:
        filePath=fileDir+"\\"+file
        for line in open(filePath,encoding="utf-8"):
            if line.startswith("2020-"):
                f.write(line)
f.close()

过滤后的流量主要有两种是我要的,第一种就是发送过多,会记录ip和手机号码。第二种是成功发送的。

2020-12-17 21:35:46.035 ERROR 7 --- [-8080-exec-1974] c.d.e.w.common.utils.CheckIpSmsPrevent   : send.message.over.the.limit,ip=111.229.73.67,mobile=138xxxxx12
2020-12-17 21:35:46.072  INFO 7 --- [-8080-exec-1347] c.d.e.w.common.message.SmsCodeRedisDao   : get code me 1350xxxxx70 redisKey [117, 97, 97, 58, 109, 101, 58, 99, 111, 100, 101, 58, 49, 51, 53, 48, 54, 56, 50, 54, 48, 55, 48]

因为数据量太大了,所以想着用sql去统计会方便一些,就写了下面的脚本。提取了时间,ip地址和手机号。

import re

#匹配时间
pattern=re.compile("2020-[0-9]{2}-[0-9]{2}.*[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}")
#匹配电话号码
pattern2=re.compile("1[0-9]{10}")
#匹配ip地址
pattern3=re.compile("[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")

filePath="F:/xxxx/xxxx/results/result3.txt"
with open("sqlResult3.txt","w") as f:

    for line in open(filePath):
        try:
            if "INFO 7" in line:
                time = re.findall(pattern, line)[0]
                phone = re.findall(pattern2, line)[0]
                ip = '0.0.0.0'
                f.write(time + ',' + phone + ',' + ip+'\n')
            elif "ERROR 7" in line:
                time = re.findall(pattern, line)[0]
                phone = re.findall(pattern2, line)[0]
                ip = re.findall(pattern3, line)[0]
                f.write(time + ',' + phone + ',' + ip+'\n')
        except:
            pass
# f.close()

最后将数据导入到mysql中,一共有600w行数据,通过sql语句进行了查询和判断,如下图所示。两天的数据量失败次数在2000次以上的就有500多个ip,这个池子还是很大的,然后查了一下其中的部分ip,发现都是阿里云,腾讯云什么的,应该都是肉鸡

因为存在大量的国内ip地址,又对ip地址的归属地进行了判断。最后发送给一线同学进行ip封锁。

总结

这次应急其实挺简单的,但是因为vpn,堡垒机不好导出日志花费了很多时间。因为是第一次做,所以做一次整体思路的笔记,为下一次应急做好充足的理论和流程准备。

点击收藏 | 8 关注 | 1
登录 后跟帖