通过云端入侵汽车摄像头

2025-02-16 17:23:15 5 647

来源:https://www.00xbyte.com/posts/hacking-dash-cams/

简介

随着全世界都在努力实现互联互通,上市时间往往比安全性更重要。 今天的文章中将介绍如何发现智能汽车应用中的漏洞!

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

受影响的供应商:

  • Szime
  • Proof.co.il(已修复)

作者于 2023 年 11 月发现了此漏洞,在一年多的时间里多次尝试联系两家供应商(通过多种渠道)后,作者发布了此漏洞的详细信息,以便用户可以保护自己免受车辆监控。 Proof.co.il 已确认并修复了该问题,但 Szime 尚未做出回应。

漏洞

系统简介

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

问题 1 - IMEI 号码可预测

作者发现 IMEI 号码由 14 位数字组成,其中前 13 位数字是标识符,最后一位数字是Luhn算法(https://en.wikipedia.org/wiki/Luhn_algorithm)计算出的校验和数字。 问题是 IMEI 号码是连续的。例如,如果您的车载摄像头有 IMEI 01234567891233,那么之前的 IMEI 很有可能01234567891225属于另一台摄像头。

还有一个 API 请求用于检查 IMEI 是否存在: 首先,登录以获取access_token

...

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" 

    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 用户断开设备与互联网的连接。

关于作者

whoami105篇文章157篇回复

勤快的搬运工。

评论5次

要评论?请先  登录  或  注册