In this webpage, we provide the supplementary materials for the 3 CVEs in UnionPay SDK, following our research on the Security Analysis of Mobile Payment Platforms (Cashiers).
The findings were reported by Shangcheng Shi from CUHK MobiTeC to the MITRE CVE Database, and detailed in the research paper below.
[R2] Shangcheng Shi, Xianbo Wang, and Wing Cheong Lau. 2021.
Breaking and Fixing Third-Party Payment Service for Mobile Apps.
In Applied Cryptography and Network Security: 19th International Conference, ACNS 2021,
Kamakura, Japan, June 21–24, 2021, Proceedings, Part II.
Springer-Verlag, Berlin, Heidelberg, 3–26.
DOI:
https://doi.org/10.1007/978-3-030-78375-4_1
UnionPay is now accepted by over 28 million merchants across the globe. Many of the merchants integrate UnionPay's online payment service for their websites and mobile apps. As security researchers, we have found a serious vulnerability within UnionPay's backend SDK to the merchants which enables an attacker to shop for free in merchants' websites and mobile apps (in both Android and iOS).
When using UnionPay's online payment service, for either websites or mobile apps, each merchant needs to provide a notification URL (hosted by the merchant server) to accept the payment results that are digitally signed by UnionPay's cashier server. UnionPay provides SDKs to be incorporated in merchant servers to handle and verify these payment results. Unfortunately, UnionPay inadvertently includes a vulnerability in the PHP version of its SDK, enabling the attacker to bypass the signature verification of the payment messages. Consequently, an attacker can build malicious payloads and send them to the notification URL hosted by the merchant server to shop for free.
For web-based services: the affected SDK version up is up to 1.2.0, which has been assigned CVE-2020-23533.
For Android payment services: the affected SDK version up is up to 3.4.93.4.9, which has been assigned CVE-2020-36284.
For iOS payment services: the affected SDK version up is up to 3.3.12, which has been assigned CVE-2020-36285.
Remark: We have made the responsible disclosure to UnionPay, while the vendor immediately updated its SDKs after our report. As a result, these vulnerable SDKs mentioned above are no longer hosted on the webpage of UnionPay.
Since these SDKs are almost the same, we use the one for web-based services as illustration. The following snippets are from the SDK and used to verify the payment results (from the UnionPay's cashier server).
line 156 static function validate($params) {
line 157
line 158 $logger = LogUtil::getLogger();
line 159
line 160 $isSuccess = false;
line 161
line 162 if($params['signMethod']=='01')
line 163 {
line 164 $signature_str = $params ['signature'];
line 165 unset ( $params ['signature'] );
...
line 198 } else {
line 199 $isSuccess = AcpService::validateBySecureKey($params, SDKConfig::getSDKConfig()->secureKey);
line 200 }
line 201 return $isSuccess;
line 202 }
...
line 204 static function validateBySecureKey($params, $secureKey) {
line 205
line 206 $logger = LogUtil::getLogger();
line 207 $isSuccess = false;
line 208
line 209 $signature_str = $params ['signature'];
line 210 unset ( $params ['signature'] );
line 211 $params_str = createLinkString ( $params, true, false );
...
line 215 if($params['signMethod']=='11') {
line 216
line 217 $params_before_sha256 = hash('sha256', $secureKey);
line 218 $params_before_sha256 = $params_str.'&'.$params_before_sha256;
line 219 $params_after_sha256 = hash('sha256',$params_before_sha256);
line 220 $isSuccess = $params_after_sha256 == $signature_str;
...
line 231 return $isSuccess;
line 111 $this->secureKey = array_key_exists("acpsdk.secureKey", $sdk_array)?$sdk_array["acpsdk.secureKey"]: null;
UnionPay provides two options to protect the payment results from its cashier server, namely digital signature and message authentication code (MAC). Notably, the digital signature is the de facto standard for protecting the payment results, while the MAC is only used by old merchant servers and not adopted by new ones.
As we see from the code (line 162 in acp_service.php), validate() dynamically extracts the 'signMethod' field to determine whether digital signature (i.e., '01') or MAC (e.g., '11') is used. Such practice enables the attacker to send a message protected by MAC to the merchant server using the digital signature by controlling the 'signMethod' field. Consequently, the server will read the 'secureKey' from local configuration (line 199 in acp_service.php) and invoke validateBySecureKey() in line 204 to process the message.
Since the 'secureKey' is not set in the configuration file (sdk/acp_sdk.ini) by default, SDKConfig.php (line 111) will return null to acp_service.php (line 199). Nevertheless, acp_service.php does not check whether the returned 'secureKey' is null or not. As a result, the attacker can use null as the 'secureKey' and forge a payment result to cheat the merchant server to shop for free.
On the other hand, the same vulnerability does not exist in UnionPay's SDKs in other languages, namely Java and .NET, as the null key will trigger exceptions in the cases.
The SDKs from UnionPay include demo pages (in demo/). You may set them up with our online archives to perform a PoC.
To be specific, BackReceive.php in demo/api_01_gateway/ (i.e., http://your_ip/upacp_demo_b2c/demo/api_01_gateway/BackReceive.php) is responsible for processing the payment results. The script invokes validate() in line 45 for verifying the payment message. Once the verification succeeds, the script will print "验签成功" ("Signature Verification Success" in English).
Our PoC code (available at https://www.dropbox.com/s/o8r5yeqwb814pv3/poc.py?dl=0) can send the forged payment results to the BackReceive.php on your machine and will get successful responses, namely "验签成功".
Email: mobitec@ie.cuhk.edu.hk
Mobile Technologies Centre (MobiTeC, https://mobitec.ie.cuhk.edu.hk),
Department of Information Engineering,
The Chinese University of Hong Kong