通过云端入侵汽车摄像头

科技   2024-12-16 14:15   广东  

简介

随着全世界竞相实现互联互通,上市时间往往比安全性更重要。

今天的节目将介绍如何发现智能汽车应用中的漏洞!

如果您认出了上图中的某个徽标,那么您可能面临风险!授权不当可能会导致未经授权访问智能汽车应用(行车记录仪、汽车信息娱乐系统),允许访问位置历史记录、视频等。

受影响的供应商:

  • Szime

  • Proof.co.il(已修复)

我于 2023 年 11 月发现了此漏洞,在一年多的时间里多次尝试联系两家供应商(通过多种渠道)后,我发布了此漏洞的详细信息,以便用户可以保护自己免受车辆监控。Proof.co.il

已确认并修复了该问题,但 Szime 尚未做出回应。

漏洞 -系统简介

当客户购买新设备时,他们会下载相关应用程序,并使用名为 的唯一标识符将设备注册到该应用程序IMEI。此过程称为设备绑定。一旦用户将相机绑定到手机,他们就可以完全控制它并可以访问其所有功能,包括位置历史记录和视频。

问题 1 - IMEI 号码可预测

我发现 IMEI 号码由 14 位数字组成,其中前 13 位数字是标识符,最后一位数字是Luhn 算法计算出的校验和数字。

问题是 IMEI 号码是连续的。例如,如果您的车载摄像头有 IMEI 01234567891233,那么之前的 IMEI 很有可能01234567891225属于另一台摄像头。

还有一个 API 请求用于检查 IMEI 是否存在:

首先,登录以获取access_token

POST /oauth/token HTTP/1.1
...

grant_type=password&client_id=app&client_secret=api1234&scope=SCOPE_READ&username=xxxxxxxxxx&password=yyyyyyyyyy

(🤦‍♂️让我们花一点时间来欣赏客户端应用程序中嵌入的这个奇妙的秘密 API 密钥api1234:)

username是一个电话号码。

然后检查 IMEI 是否存在:

GET /api/v2/user/sendbindreq?access_token=xxxxxxxxx&did=yyyyyyyyyyyyyy HTTP/1.1
...

did是设备 ID - 又名 IMEI。

这使得攻击者能够通过暴力破解的方式检索所有现有的 IMEI。

由于 api 无法验证绑定到新相机的手机所有者是否也是该相机的所有者,因此:

任何用户都可以通过猜测 IMEI 为自己注册任何未注册的相机

此外,IMEI 号码在某些设备(如行车记录仪)上可见,行人可以透过车窗查看并获取 IMEI 号码。

由于所有的 IMEI 都已经刷入相机,遗憾的是这个问题无法修复!

问题 #2 - “窃取”已绑定的相机

我们已经确定,一旦将相机绑定到手机,只有他们才能访问其功能。

但如果攻击者能够通过将相机绑定到手机来“窃取”相机怎么办?不幸的是,这是可能的。

我发现解除绑定的过程没有得到适当的授权。看一看:

如果攻击者发送此“解除绑定”请求,并且其中imei含有受害者设备的 IMEI:

POST /api/v2/user/debinddev?access_token=xxxxxxxxx HTTP/1.1
...

{"imei":"yyyyyyyyyyyyyy" }

无需验证请求发起者是否是设备所有者,设备会立即解绑!

这意味着任何有帐户的用户都可以根据设备的 IMEI 号码解绑任何设备!

接下来,攻击者需要做的就是通过以下请求将设备绑定到他们的帐户:

POST /api/v2/user/binddev?access_token=xxxxxxxxx HTTP/1.1
...

{"name":"yyyyyyyyyy","imei":"zzzzzzzzzzzzzz", "nick":"notImportant"}

name是电话号码。

就这样!设备现在已绑定到他们的帐户,他们可以访问设备的所有直播和录制数据!

后端代码(猜测)

虽然我无法知道后端服务器上运行的是什么代码,但如果使用 flask 框架用 python 编写,我猜测代码是这样的:

@app.route('/api/v2/user/debinddev', methods=['POST'])
def debind_dev():
    access_token = request.args.get('access_token')
    imei = request.json.get('imei')

    if not access_token or not imei:
        return "Bad Args"

    response = db.verify_access_token_valid(access_token)
    if not response.is_ok:
        return "Bad Token" 

    db.debind_camera(imei)
    return "OK"

解决办法(猜测)

我认为修复方法如下:

@app.route('/api/v2/user/debinddev', methods=['POST'])
def debind_dev():
    access_token = request.args.get('access_token')
    imei = request.json.get('imei')

    if not access_token or not imei:
        return "Bad Args"

    response = db.verify_access_token_valid(access_token)
    if not response.is_ok:
        return "Bad Token" 

    # --------- FIX -----------
    user = db.get_user_for_access_token(access_token)
    if not user.does_own_camera(imei):
        return "Bad Permissions" 
    # -------------------------

    db.debind_camera(imei)
    return "OK"

额外问题 - 无需电话验证即可注册

没有验证注册的电话号码是否属于用户。没有短信,什么都没有。

这个问题使这些攻击变得更容易,因为这消除了对活跃电话号码的要求,并允许整个攻击从脚本执行!

POST /api/v2/user/register HTTP/1.0
...

{"pn":"xxxxxxxxxx", "pwd":"yyyyyyyyyy"}

pn代表电话号码,pwd代表密码

减轻

我已收到确认,Proof.co.il 已修复其服务器上的问题。另一方面,Szime 没有回应,因此在他们修复此问题之前,我建议 Szime 用户断开其设备与互联网的连接。Szime,如果您正在阅读此内容,请停止对安全研究人员进行击。


感谢您抽出

.

.

来阅读本文

点它,分享点赞在看都在这里

Ots安全
持续发展共享方向:威胁情报、漏洞情报、恶意分析、渗透技术(工具)等,不会回复任何私信,感谢关注。
 最新文章