本实践披露了中国广电5G国网业务支撑系统存在RSA私钥泄漏、业务校验缺失等严重缺陷,骇客可利用这些缺陷,完成给任意账户订购任意业务、变更任意套餐等损害企业利益的高危非法操作。
【修复状态】
尚未全部修复
【可能涉及的产品和受影响的企业单位】
产品:
中国广电国网BSS业务支撑系统
中国广电国网网上营业厅(手机营业厅、小程序营业厅)
企业单位:
亚信科技(中国)有限公司(及其关联子公司)
中国广电网络股份有限公司
中国广播电视网络集团有限公司
【实践环境】
公共互联网
【缺陷简要说明】
[1] 前端文件RSA私钥泄漏、签名算法泄漏
[2] 业务接口存在业务逻辑判断缺陷
[3] 不同业务接口复用混用,造成意料之外的逻辑判断缺失
中国广电网上营业厅后台API以POST方式为主,其合法校验逻辑是:对请求体Body进行RSA加密,并在HTTP协议头Header中插入对请求体参数进行的签名Access。
而在中国广电网上营业厅网站前端文件中,直接存储了与后台接口通信所用的RSA公钥、私钥,造成 [1] RSA私钥泄漏 ,API请求数据、响应数据可被轻易解密,暴露出请求参数结构。
此外,前端文件涉及接口通信部分的JavaScript未经良好混淆、打乱干扰,[1] 暴露了对请求体参数签名的逻辑。
由此,骇客可极其轻易地伪造非法请求并发送到后台接口。
同时,中国广电网上营业厅 [2] 后台接口存在严重的逻辑判断缺陷 ,几乎可谓:对请求“来者不拒”,尽全力满足骇客的要求。对于变更套餐、订购商品的请求,权限校验和业务校验存在严重不足,即使在不满足业务要求的情况下,也发起业务变更。
在中国广电手机营业厅App中,还发现了 [3] 不同类别业务使用了同一接口,逻辑混乱,不利于维护,且还造成了 业务逻辑判断遗漏 的情况(对于“遗漏”存疑,仅为作者猜测),也出现了 未进行变更套餐、订购商品的权限校验和业务校验 的情况。
【复现步骤】
[1] 前端文件泄漏RSA私钥、签名算法
1.获取泄漏的RSA私钥
访问中国广电网上营业厅网站,使用Charles抓取HTTP请求。

在访问网站时,存在JavaScript文件common-8d730.js
在该JavaScript文件中寻找关键字encrypt、decrypt,

可见用于接口请求时加解密请求体的RSA公钥、私钥。
现在对该私钥进行验证。
随机选择一个接口请求,可见其对请求参数进行了RSA加密,并封装进了JSON中。

使用刚刚得到的RSA私钥对该请求体尝试解密。
解密成功,并得到原始的请求参数如下:
%7B%22channelId%22%3A%22cd_20220516_093342%22%2C%22sessionId%22%3A%2290234d2b70e248f06238e067ae0187f1%22%2C%22v%22%3A%221.1.7.0915_release%22%2C%22timestamp%22%3A1711512027123%7D对其进行URL解码,并进行格式化。
{
"channelId": "cd_20220516_093342",
"sessionId": "90234d******************ae0187f1",
"v": "1.1.7.0915_release",
"timestamp": 171151*******
}可见其封装模式为JSON,至此所有请求对于得到RSA私钥的骇客来说已经变得透明。
2.获取签名算法
现在,我们模拟骇客,伪造一个非法的接口请求欺骗服务器。
除了知晓请求体的封装格式外,还需要知道在这些接口请求中对请求参数的签名方法。

从抓取的HTTP请求中,可以发现签名被放至在了HTTP Header的Access字段内。
在之前得到的JavaScript文件中检索关键字Access。

可以发现签名Access的计算逻辑为:
取出请求体JSON中的所有属性Params[key, value],对Params按照key进行排序(a-Z)
"channelId": "cd_20220516_093342"
"sessionId": "90234d******************ae0187f1"
"timestamp": 171151*******
"v": "1.1.7.0915_release"将排序后的Params以key=value的格式,使用&进行拼接,得到待签名字符串StringToSign。若属性为数组则跳过,为对象则递归。
channelId=cd_20220516_093342&sessionId=90234d******************ae0187f1×tamp=171151*******&v=1.1.7.0915_release将StringToSign进行MD5运算,得到Access
b3a3d88449************268589b629
3.测试伪造请求
至此,即已经知晓了中国广电国网业务支撑系统后台接口的完整调用方式。现在开始伪造非法的请求,尝试欺骗服务器。此处选择接口queryOffersByBoss,该接口用于向服务器请求BOSS系统内的产品信息。
该接口的请求参数有:
伪造的请求信息如下:
计算Access为:e6556b3db4********10bc1a05c5d5a9
发送请求,成功获得后台响应数据如下:
{
"status": "000000",
"message": "操作成功",
"updateMes": null,
"data": {
"respDesc": "调用成功",
"intfResultBean": {
"offerInfo": {
"msgFee": "0.1",
"offerName": "慧家18元套餐特惠版(员工套餐)",
"validDate": "20220618161541",
"fee": "1800",
"description": "标准 资费:18元/月,包含:套内国内流量20GB、套内国内语音100分钟、国内语音接听免费,送来电显示;套外国内流量3元/GB、套外国内语音0.15元/分钟、套外国内短信0.1元/条,本套餐最多可以办理2张副卡,副卡月费3元/张/月,主副卡可共享语音、流量、套外单价。本 套餐可开通亲情网主号3元/月,可以免费添加3张成员号,3张以外1元/张/月,国内互拨免费。",
"dataMin": "100",
"minFee": "0.15",
"multiMsgFee": null,
"gbFee": "3",
"dataGb": "20",
"offerCode": "10000285",
"offerId": null,
"expireDate": "20991231235959",
"ext5": null,
"ext4": null,
"ext3": null,
"ext2": null,
"ext1": null
},
"beanId": null
},
"respObject": null,
"respCode": "000000"
},
"timestamp": 1711531******,
"ok": true
}可见该产品为集团内部使用的员工套餐,没有公开给市场,但却获得了正确响应,说明伪造请求是成功的。
[2] 后台接口存在严重的逻辑判断缺陷
该缺陷主要存在于订购商品、变更套餐等操作,这里以一个可能未向市场投放、未对用户公开办理(或具有限制性办理条件)的套餐[广电手表卡]为例,我将演示绕过业务变更校验,强行变更为该套餐。
访问中国广电营业厅网站,抓取变更套餐的相关API。
在变更套餐的流程中涉及众多API的调用,其中涉及到套餐变更的核心API为trade/submitOrder。经过多次测试,在调用API trade/submitOrder时,系统会对流程中前置的其他API进行校验,若用户没有调用过前置API(即没有按照标准流程调用),则会响应错误信息。
此处不再对前置API进行演示,仅演示trade/submitOrder的调用。
该接口的请求参数有:
在更改套餐中起关键作用的参数为goodsParams,而非offerCode。goodsParams中的goodsId、goodsSkuId决定了本次订购的主商品(套餐),而offerList则决定了附加的产商品。因此这也意味着,骇客可以在offerList中添加任意产商品代码,以在变更套餐时订购一些通常不能的订购的业务。
为什么不是通过修改goodsId、goodsSkuId来订购任意业务呢?
经过测试发现,goodsId、goodsSkuId为商品库中的代码,每个goodsSkuId映射了对应的业务offerCode。但遗憾的是,并不是所有的业务(例如一些营销活动使用的流量包)都有在商品中的映射,通常只有部分套餐才有对应的goodsId、goodsSkuId。
在此处,作者想演示变更的套餐为“广电手表卡”,然而经过各种渠道的检索,没有找到该套餐对应的goodsId、goodsSkuId。但这并不意味着我们没办法通过该接口变更到这个套餐。前面提到,“骇客可以在offerList中添加任意产商品代码,以在变更套餐时订购一些通常不能的订购的业务”。因此,我们可以将“广电手表卡”的offerCode 10001664添加进offerList当中来完成订购。
此处引出了一个问题,一个移网账户(当然)只能同时拥有一个主产品(套餐),因此如果goodsId、goodsSkuId为一个套餐产品,offerList中也有一个套餐产品,就会出现“不允许同时订购多个主产品”的错误。
解决方案很简单,使用一个非主产品(套餐)的goodsId、goodsSkuId来替换即可。此处我们使用“视频彩铃内容增值包(点播)-1元”的goodsId、goodsSkuId来替换。
因此,在此次订购演示中,我们订购的产品如下:
主商品:视频彩铃内容增值包(点播)-1元
附加产品:广电手表卡(offerCode: 10001664)
计算好Access,将伪造好的请求发送到服务端成功获得响应。(此处不展示)
稍等数秒后,手机接收到短信,提示成功变更到未向市场投放、未对用户公开办理的“广电手表卡”套餐。

[3] 不同业务接口复用混用,造成意料之外的逻辑判断缺失
该缺陷主要存在于服务性业务订购等操作,骇客可以凭借该接口完成任意业务的订购。
在网上营业厅-服务-国际来话板块,用户可以自助开关“国际来话拦截”、“国际来话提醒”功能。该功能的实现是通过订购/退订下面两个产品来控制的。

抓取开关该功能的相关API,发现订购/退订这两个产品都是通过API trade/cancelOrder来进行的(即服用了API trade/cancelOrder)。
API trade/cancelOrder是干什么的?
根据API的命名可以猜测到,该API本用于订单回退、业务退订。但经过测试发现,该接口同时还用于业务订购(通过参数action置不同值实现)
0=订购业务,1=退订增值业务,2=退订待生效套餐
该API的请求参数有:
在作者写本报告时,发现通过该接口订购业务已经增加多个校验环节,在一定程度上增加了骇客的恶意利用难度。但这样的通过(比较滑稽的)复用接口方法实现功能依然是极不推荐的,在生产环境中不应该继续使用。
事实上,该接口曾导致过严重的后果。
作者在2022年时便成为了中国广电5G的友好用户(开户时间较早的用户),曾经历过多次因系统建设不完善导致的生产事故,其中就包含该接口被恶意利用导致的事故,给中国广电5G业务带来了大量客户投诉。
2023年中左右,该接口的校验环节还不完善(没有作任何业务校验,只要调用即按照提交参数完成工作流程)。有骇客利用该接口,批量为部分用户订购“福兔卡赠送流量132G月”的流量包产品(offerCode: 10001248)。
“福兔卡赠送流量132G月”是什么?
该产品收费:0元/月,包含:国内通用流量132G/月,次月可结转。
该产品本用于“福兔卡”套餐营销活动使用,限制办理了“福兔卡”电话卡的用户参加指定充话费活动后,系统自动为用户订购该产品,赠送流量。
在骇客已为大量用户订购该产品后,IT部门才发现该接口存在逻辑判断缺陷(本应限制仅能订购“国际来话拦截”、“停用国际来话提醒”产品,但API开发时竟然没有做相关业务校验),被恶意利用。因此IT部分在后台为所有通过违规手段订购了该产品但还未生效的用户(通常订购产品需次月生效)做了沉默式回退处理(即回退业务的同时不告知用户)。大量用户发现“福兔卡赠送流量132G月”被回退后,纷纷通过“工信部电信用户申诉处理中心”、省通信管理局,甚至信访部门进行投诉,给中国广电5G客户关系部门带来了巨大工作量,且对中国广电5G品牌带来了舆论压力和负面影响。
虽然经过了IT部门强硬的处理,使大量用户违规订购的“福兔卡赠送流量132G月”没有生效,避免了给业务带来的巨大损失,但仍有少数在IT部门处理前生效的用户逃过了业务的回退。
一个小遗憾
作者在2023年中曾见过许多成功违规订购“福兔卡赠送流量132G月”的用户,但当时未对中国广电5G业务系统进行深入研究,没能知晓他们是通过该接口实现违规订购的。因此没能亲历这次生产事故探寻更多细节,是一个小小的遗憾!~
【安全建议】
「立即」更改RSA密钥对、签名算法,移除在前端文件中的RSA私钥。避免骇客获取到RSA密钥对后,对API的请求体进行解密。
检查trade/submitOrder、trade/cancelOrder等API代码中涉及业务校验的部分,修复不完善、不正确的业务校验。
彻底移除API trade/cancelOrder除业务退订外的所有操作类型,确保该接口仅用于业务退订,避免骇客通过该接口违规变更业务。
❤️ 感谢
中国广电5G为用户提供的优质通信服务。作者为中国广电5G首批友好用户,自中广电5G业务2022年6月试商用以来,见证了中广电5G在品牌战略和运营、通信服务技术等方面的快速成长,也亲身体验了中广电5G提供的优质的、极具竞争力的通信服务。❤️祝愿中国广电5G越来越好!~