2007年的时候,我在印度最大的国有银行中的一家注册了一个账号,这个国家的银行(政府或者民营)普遍所使用的技术与当前水平相比至少落后了10年。
2015年末,我账号所在的银行与外包公司合作,开发了一款手机银行应用,分为安卓版和IOS版。这是一个典型的瑞典冬天的周末,没有阳光的迹象,所以我决定留在室内,并研究一下这个应用。
我一开始是打算用安卓来进行测试的,但是一想起上次在安卓上安装一个自签名证书(用于Burp监听)所遇到的挫折,我果断选择了iPhone6作为测试平台。
当你在安卓上安装自签名证书时,安卓会一直提醒你“第三方证书已被添加到您的设备的信任库”,但是因为成本的关系你有时候不得不这么做(在企业环境或者测试环境中),再加上测试的过程中会一直看到讨厌的提醒信息“您的通信可能被监控”,所以IOS是最好的选择,我在MacBook Pro上运行Burp用来作为代理服务器。
Burp拦截到的初始请求显示了与app进行通信的主机名和端口,这是一个中间件应用程序,之所以会这样,那是因为银行通常会从大型厂商购买软件,比如说TCS 的Bancs、Infosys 的Finacle,、Oracle Finance 的Flexcube。因为这个手机银行app是由多个不同的外包公司合作开发的,所以能够有效的阻止核心API的曝光。在对OpenSSL进行研究之后,我发现这个中间件使用的是SSL3.0,并且可以被迫降到SSL2.0。
我尝试通过Burp添加一个自签名证书用来抓取请求/响应中的明文数据,结果发现很成功的就抓到数据了,这说明app没有使用“证书锁定”。考虑到这是一个银行的手机应用,没有使用“证书锁定”就是一个史诗级的错误!
这显然是一个不符合规范的架构或者说是不够到位的代码审查的案例。这个app的初始请求是向服务器确认是否有可用的更新,而这个请求是发生在你登录前的。
这个更新请求会产生一个session ID,这个session ID可被重复使用来发起真正的请求(比如说查询账户余额,存款名单),而这样的行为是只有用户登录后才能发起的,这等于说是绕过了密码验证。下图是我在未验证登录的情况下通过构造数据包来进行账户查询的图像。而且我说了这个session ID是不会失效的,请继续往下阅读。
当我在把玩这个app时,前端弹出了一个窗口(操作时间即将到期?),询问我是否要重新登录或者退出当前窗口。这样的处理行为是正确的,我想知道这个计时是不是只在前端进行的,而后端却没有处理。
我的直觉是对的,后端并没有设置会话失效控制,所以除非客户端调用API销毁session,否则你的会话IDs永不失效。
我测试了一下该app中接收账户的验证控制的有效性。我发现接收账户必须存在于收款人列表中,如果这个账户不在收款人列表中,转账时屏幕就会弹出错误,要求你将接收账户添加至收款列表中。而添加一个新的接收账号到收款列表中会要求输入PIN(MPTIN会在0x05提到)。
事实上我一点都不会对“这个验证是在前端进行”的这件事感到惊奇,所以直接通过CURL调用转账的API就能绕过接收人/受益人账户验证,我就能够将钱转账到不在我的受益人列表中的账户。原本我还想测试其他的关键的流程(转账中的余额验证,转账限制),但是这可能是违法的,所以我只能跳过了。
(从收到的来自银行的响应数据,似乎能看出我上面提到的关键流程的验证都是在前端验证的)。
从上面提到的这些漏洞就可以写一个严重程度为中高的POC了。在0x02和0x03中,只需要5行代码就能枚举所有用户的记录(当前账户余额和存款)。
我决定挖掘的更深一点。
在我挖掘的更深之前,我要先解释一下此应用程序的身份验证机制。
这里有两个PINs(身份认证PIN[MPIN],交易授权PIN[MTPIN])。从名字来看就知道你可以用MPIN来进行登录,用MTPIN来对重要的操作进行验证,比如添加一个接收账号到受益人名单中,转义资金,创建一个新的定期存款,关闭现有的定期存款。这个应用中的用户名为你的用户ID[CID]
当请求被反序列化后,会传递给如下的函数处理:
你发现错误了吗?
问题出现在,这个validateAuthenticator方法会验证MTPIN与用户ID对应的MTPIN是否匹配,这两者的值都是由用户提交的,但是却没有验证提交的用户ID或者MTPIN是否属于当前发送者。所以通过使用我的用户ID和我对应的MTPIN,我能够实现在任意账户间进行金额互转。我用我们家庭中的账户进行了测试,发现甚至一些没有开通网上银行或者手机银行的用户也能通过这种手段进行转账。
如下面的图片,1303是我的用户ID的后4位,列表中是我账户关联的其他用户的ID。(SB-存款账号,RIP-定期存款)。
如下是我做的一个成功的交易。你可以看到我构造了一个请求,请求中用到的是我的用户ID和我的MTPIN,但是发送者账户(6254)却不是我的。(= = 作者的图挂了,各位脑补下吧!)
我快速的用bash写了一个13行的代码,供给银行或者外包进行测试。
用手机银行进行转账时,银行会给当前账号绑定的手机号发送短信即时通知,问题是在这里他们又处理错了。
发送提醒短信的代码和上面的代码是类似的:
和0x05相似,要发送提醒短信的手机号码是从客户ID中获取的,而不是账户号码。因此,当攻击者窃取了受害者的资金后,提醒短信会发送到攻击者那,而不是受害者。(作者的图挂了,各位就再脑补一次吧!)
我很快速的写了一个poc,然后在2015.11.3号将此poc发给了该银行的一堆总经理、副总经理、IT经理、部门经理,一个礼拜过去了都没有收到任何回复。8天后,我收到了该银行的一个非官方的确认信息(该银行的一个中层经理)说他们正在调查这个问题。大概第9/10天左右,开发该app的外包公司的副总裁访问了我的linkedIn主页。最后在第12天的时候,我收到了来自该银行的副总经理的官方回复,他们基本上采用了我提交的漏洞修复建议。这让我有点惊喜的同时也让我感到害怕,他们居然用了12天的时间来回应我,并且就像在说“嘿,你的数十亿身价存款有风险”,真是太令人吃惊了。
我回信询问漏洞何时会被修复以及是否会为此漏洞提供赏金,鉴于这家银行有将近250亿美元的存款(2015年的数据),为什么不尝试着要点赏金呢,但是就如预期的一样,他们没有再回复任何信息了。
所以这就是印度,这么大的漏洞0赏金!
*参考来源:boris.in/blog,FB小编东二门陈冠希编译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)