Darwin
Published on 2024-03-27 / 242 Visits
1
0

中国广电5G业务支撑系统存在的严重缺陷研究

本实践披露了中国广电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的计算逻辑为:

  1. 取出请求体JSON中的所有属性Params[key, value],对Params按照key进行排序(a-Z)
    "channelId": "cd_20220516_093342"
    "sessionId": "90234d******************ae0187f1"
    "timestamp": 171151*******
    "v": "1.1.7.0915_release"

  2. 将排序后的Params以key=value的格式,使用&进行拼接,得到待签名字符串StringToSign若属性为数组则跳过,为对象则递归。
    channelId=cd_20220516_093342&sessionId=90234d******************ae0187f1&timestamp=171151*******&v=1.1.7.0915_release

  3. StringToSign进行MD5运算,得到Access
    b3a3d88449************268589b629

3.测试伪造请求

至此,即已经知晓了中国广电国网业务支撑系统后台接口的完整调用方式。现在开始伪造非法的请求,尝试欺骗服务器。此处选择接口queryOffersByBoss,该接口用于向服务器请求BOSS系统内的产品信息。

该接口的请求参数有:

参数名

必填

用途

sessionId

会话Token,在网上营业厅登录后可获得

channelId

请求渠道ID

regionId

归属地ID

offerCode

产品代码

childGoodsId

子商品代码

v

客户端版本

timestamp

请求时间戳

伪造的请求信息如下:

参数名

sessionId

******

channelId

cd_20220516_093342

regionId

CQ00

offerCode

10000285

childGoodsId

(空)

v

1.2.5

timestamp

1711531******

计算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的调用。

该接口的请求参数有:

参数名

必填

用途

sessionId

会话Token,在网上营业厅登录后可获得

******

channelId

请求渠道ID

cd_20220626_540692

channelCode

请求渠道码

EB002

channelType

渠道类型

1

v

客户端版本

1.2.5

phoneSessionId

会话标识

********-****-****-1728-bd********13

phone

业务手机号码

192****8888

orderType

订单类型。5=套餐变更

5

areaCode

归属地(市)代码

****

areaName

归属地(市)名

**市

regionId

归属地(省)代码

**00

payMoney

支付金额

0

payWay

支付方式。1=不需要支付

1

offerCode

产商品代码

10000817

goodsParams

订购商品参数

{
"action": "0",
"goodsId": "5da396914322********496027257f2c",
"goodsSkuId": "e974178e0bd0********6496c40dfd0b",
"offerList": [
{
"offerCode": "10001664"
}
]
}

timestamp

时间戳

1711531******

在更改套餐中起关键作用的参数为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的请求参数有:

参数名

必填

用途

示例值

sessionId

会话Token,在网上营业厅登录后可获得

******

channelId

请求渠道ID

cd_20220626_540692

tfChannelId

请求渠道码

39104

v

客户端版本

1.2.5

phone

业务手机号码

192****8888

offerCode

产商品代码

10000817

token

短信验证码校验凭据,通过短信验证码校验得到

22d99ef5bf60********1aace62046d5

smsCode

短信验证码

26**91

type

短信验证码所属类型(接口)。8=cancelOrder

8

action

操作类型。0=订购业务,1=退订增值业务,2=退订待生效套餐

0

orderId

欲回退的订单ID

timestamp

时间戳

1711531******

在作者写本报告时,发现通过该接口订购业务已经增加多个校验环节,在一定程度上增加了骇客的恶意利用难度。但这样的通过(比较滑稽的)复用接口方法实现功能依然是极不推荐的,在生产环境中不应该继续使用。

事实上,该接口曾导致过严重的后果。

作者在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越来越好!~


Comment