使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)


使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

几年前,我使用RTL-SDR在浏览器中构建了一个项目,用于从过往飞机获取实时原始数据。由于我想进一步探索使用软件定义无线电,我购买了一台可以接收和发送数据的HackRF One设备,并下载了Universal Radio Hacker开始试用。经过一番尝试后,我预感到,可能可以在浏览器中重新创建一个类似的工具,全部使用 JavaScript,所以我花时间做了这件事!

我的最终目标是回答这个问题……是否有可能使用 JavaScript 来破解汽车?我完全不知道我是否能做到这一点,因为我对 SDR 相关知识的了解仍然很少,但我很高兴与大家分享它确实有效!!😃 这篇博文解释了我解决问题的过程。

⚠️重要说明⚠️ 我写这篇博文只是为了教育目的。尽管使用 SDR 收听和传输数据本身并不违法,但请查阅当地法律,了解在特定频率上传输数据是否需要获得无线电执照。此外,未经明确同意重现本博文中解释的一些实验是违法的。对于您决定如何使用本帖中分享的信息,我不承担任何责任。

演示

在深入了解技术细节之前,您可以查看可用于接收、记录和传输数据的网站,以便使用它来破解门铃、车库门等。下面是一个简短的演示视频,使用它来运行 rolljam/replay 攻击来破解我朋友的汽车(经同意)。

接收数据

为了从 HackRF 接收数据,我首先编写了使用WebUSB API将设备连接到浏览器所需的代码。

在网络上,当连接到 USB 设备时,用户首先需要从弹出窗口中选择它。

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

以下代码用于在弹出窗口中显示可用设备列表。filters参数值是可选的。如果未指定任何值,弹出窗口将列出当前通过 USB 连接到计算机的所有设备,但如果您传递带有产品和供应商 ID 的对象,它将仅显示您要连接的设备。

const device = await connect();

const connect = async () => {
  const dev = await navigator.usb
    .requestDevice({
      filters: [
        // see: https://github.com/mossmann/hackrf/blob/master/host/libhackrf/53-hackrf.rules
        { vendorId: 0x1d50, productId: 0x6089 },
      ],
    })
    .catch((e) => null);
  return dev;
};

有几种不同的方法可以找到设备的供应商和产品 ID,但在 WebUSB API 上下文中,最简单的方法是chrome://usb-internals将 HackRF 设备插入计算机后在 Chrome 中访问并选择选项卡。您应该会看到一个带有和列Devices的表格,如下所示:vendor IDproduct ID

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)


然后您可以将这些值复制到您的代码中。

一旦在 UI 中选择了该设备,以下代码就会处理连接:

await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);

可以通过两种方式找到作为配置和接口传递的值,要么通过阅读官方 HackRF SDK中的代码,要么通过在浏览器中检查设备。

对于第一个选项,您可以通读 SDK 的源代码,找到配置和接口的设置位置并查看传递的值。

否则,第二个选项会更快一些,并且依赖于chrome://usb-internals前面提到的页面。如果您单击Inspect表中的按钮,您将获得有关该设备的其他详细信息,包括配置(应该是1)和接口(应该是0)。

此时,浏览器应该已连接到设备,但实际上什么也没有发生。仍需要设置增益、采样率和频率等设置。

设置增益

为了设置 LNA(低噪声放大器)增益,我使用了controlTransferInWebUSB API 的方法。为了准确确定要传递给此方法的值,我参考了官方的 HackRF SDK。在 SDK 中,设置 LNA 增益的函数调用了另一个函数,libusb_control_transfer这让我找到了官方的libusb 文档,其中描述了需要传入的参数。

该libsub_control_transfer函数有 8 个参数。查看官方 HackRF SDK,该函数的使用方式如下:

result = libusb_control_transfer(
  device->usb_device,
  LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
  HACKRF_VENDOR_REQUEST_SET_LNA_GAIN,
  0,
  value,
  &retval,
  1,
  0)

我不会在这里深入解释不同的参数,因为它们已经在文档中解释过了,但对这个项目特别重要的是第 2、第 3、第 4 和第 5 个参数。

第二个参数将有助于我们了解是否需要使用controlTransferIn或controlTransferOut来自 WebUSB API。LIBUSB_ENDPOINT_IN表示我们需要使用controlTransferIn。

第三个参数HACKRF_VENDOR_REQUEST_SET_LNA_GAIN将用作requestWebUSB API 中的参数。

第四个(0)将用作参数value,第五个(value,即使用的增益值)将作为index参数。

const result = await device.controlTransferIn(
  {
    requestType: "vendor",
    recipient: "device",
    request: HackRF.HACKRF_VENDOR_REQUEST_SET_LNA_GAIN,
    value: 0,
    index: 40, // The gain can be between 0 and 40
  },
  1
);

您还可以参考MDN 网络文档来了解有关此功能的更多信息。

此时,应设置 LNA 增益,但需要更多设置。

设置采样率

按照与上一节相同的逻辑,也可以设置采样率,如果您查看下面的代码示例,您可能会注意到略有不同:

const params = new DataView(new ArrayBuffer(8));
params.setUint32(0, freqHz, true);
params.setUint32(4, divider, true);

const result = await device.controlTransferOut(
  {
    requestType: "vendor",
    recipient: "device",
    request: HackRF.HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET,
    value: 0,
    index: 0,
  },
  params.buffer
);

首先,使用 设置采样率controlTransferOut。我参考了HackRF SDK 的这一部分来弄清楚,注意它使用的是LIBUSB_ENDPOINT_OUT。

然后,您会注意到索引设置为0,并且代表采样率的数据实际上用作第二个参数,这在MDN 文档controlTransferOut中有描述。

设置频率

现在我已经解释了如何设置 LNA 增益和采样率,设置频率遵循相同的逻辑,并使用以下代码完成:

const data = new DataView(new ArrayBuffer(8));
const freqMhz = Math.floor(freqHz / 1e6);
const freqHz0 = freqHz - freqMhz * 1e6;
data.setUint32(0, freqMhz, true);
data.setUint32(4, freqHz0, true);

const result = await device.controlTransferOut(
  {
    requestType: "vendor",
    recipient: "device",
    request: HackRF.HACKRF_VENDOR_REQUEST_SET_FREQ,
    value: 0,
    index: 0,
  },
  data.buffer
);

此时,必要的设置已完成,但设备尚未开始监听。


开始接收数据

开始接收数据的最后两个步骤是将设备设置为接收模式,并使用transferInWebUSB API 中的方法指示设备开始将数据传输到 UI。

const setDeviceReceivingMode = async () => {
  return await device.controlTransferOut({
    requestType: "vendor",
    recipient: "device",
    request: HackRF.HACKRF_VENDOR_REQUEST_SET_TRANSCEIVER_MODE,
    value: HackRF.HACKRF_TRANSCEIVER_MODE_RECEIVE,
    index: 0,
  });
};

一旦设备处于接收模式,以下代码就会触发数据的传输.

const startRx = async (callback) => {
  await setDeviceReceivingMode(); // function defined above

  const transfer = async () => {
    const result = await device.transferIn(1, HackRF.TRANSFER_BUFFER_SIZE);

    if (result) {
      callback(new Uint8Array(result.data.buffer));
    }
    await transfer();
  };

  await transfer();
};

await startRx((data) => {
  console.log(data); // live radio frequency data
});

然后,您可以使用Canvas API来构建此数据的可视化。在我的工具中,我将天线调到 433.92MHz 的频率,按下我买的便宜门铃上的按钮,然后通过查看频谱可视化工具中的数据来确认一切正常。

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

记录数据

一旦我确认可以接收实时数据,我就会使用文件系统 Web API来实现录制功能。

首先,用户需要选择要记录数据的文件:

let fH;

const selectFile = async () => {
  [fH] = await window.showOpenFilePicker();
  let writableFile = await fH.createWritable();
  return writableFile;
};

然后,当接收数据时,我们可以将其写入文件:

await startRx((data) => { // Function defined in the previous section
  if(recording){ // variable set on click in the UI when starting the recording
    await writableFile.write(data);
  } else {
    await writableFile.close();
  }
})

就这样!实时数据将保存到所选文件中。

传输数据

一旦接收和记录数据成功,下一步就是将其传输回去。为此,我再次使用文件系统 Web API 加载本地文件中记录的数据,并使用transferOutWeb USB API 传输它。

let file, fH;

const selectFile = async () => {
  [fH] = await window.showOpenFilePicker();
  file = await fH.getFile();
  return file;
};

选择文件后,需要设置设备transmit模式。

await device.controlTransferOut({
  requestType: "vendor",
  recipient: "device",
  request: HackRF.HACKRF_VENDOR_REQUEST_SET_TRANSCEIVER_MODE,
  value: HackRF.HACKRF_TRANSCEIVER_MODE_TRANSMIT,
  index: 0,
});

然后,需要设置发射增益,方式与本文前面定义的其他设置相同。

await device.controlTransferIn(
  {
    requestType: "vendor",
    recipient: "device",
    request: HackRF.HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN,
    value: 0,
    index: 40, // Value must be <= 40.
  },
  1
);

最后,我们可以从文件中获取数据,将其存储到变量中并将其作为第二个参数传递给方法transferOut。

const data = await file.arrayBuffer();

await device.transferOut(2, data);

为了检查它是否正常工作,我还决定使用 Canvas API 来可视化导入的数据,这样我就可以了解记录的信号是什么样的。

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

此时,您可以在浏览器中接收、记录和传输来自 HackRF 设备的数据,只需使用原始 JavaScript 和浏览器 API!

Rolljam 和重放攻击

我实际上对恶意入侵汽车并不感兴趣,但我想尝试的事情之一是从浏览器运行 rolljam/replay 攻击,这可以通过我在本文其余部分解释的三个功能来完成。

那么 Rolljam 攻击是如何运作的呢?

首先,我们来简单谈谈汽车通常如何打开和关闭。简单来说,要锁定/解锁汽车,通常只需按下遥控器上的按钮即可将代码发送到汽车的接收器。如果汽车识别出该代码,就会锁定或解锁汽车。

1995 年之前,该系统每次都使用相同的代码来锁定汽车,一个代码用于锁定,另一个代码用于解锁。然而,这种系统存在安全风险,因为如果代码被拦截,任何记录信号的人都可以锁定和解锁汽车。您可以看到,使用上述代码以这种方式破解汽车是多么容易。

为了缓解这种情况,1995 年以后生产的大多数汽车都采用了所谓的“滚动码”。锁定和解锁不再使用唯一的代码,而是使用一个代码列表进行轮换,因此当其中一个代码被使用时,它会暂时失效,直到列表轮换并恢复到该代码。

因此,rolljam 攻击包括干扰汽车的接收器,使其无法接收遥控器发送的代码,同时记录该代码,以便攻击者可以重放它。

在本帖中显示的代码上下文中,唯一缺少的是干扰部分。但是,干扰基本上是传输一堆随机数据,因此可以更新传输录制文件的代码示例以改为传输随机值,例如:

const randomData = Array.from({ length: 3670000 }, () =>
  Math.floor(Math.random() * 100)
);

for (let i = 0; i < 20; i++) {
  await startTx(new Uint8Array(randomData));
}

此外,由于此攻击需要同时设置传输和记录,因此需要两个 HackRF 设备才能工作。一个用于监听遥控器使用的频率并将信号记录到文件中,而另一个将干扰接收器。一旦成功记录信号,其中一个设备就可以重放该信号。

结论

总的来说,这是一个超级有趣的项目,能够验证使用 JavaScript 入侵汽车是可能的,真的很令人兴奋!🎉

尽管这篇文章专门讨论汽车,但它可以用来破解车库门、遥控灯、门铃、一些无人机,理论上任何由射频接收器/发射器远程控制的东西。

该项目的部分工作仍在进行中,我真的很想实现一项功能来分析记录的二进制数据,以便能够进行一些逆向工程,但我还没有开始。

如果您最终获得 HackRF 或其他设备并用它构建了一些东西,请告诉我!



感谢您抽出

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

.

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

.

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

来阅读本文

使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

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

原文始发于微信公众号(Ots安全):使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击)

版权声明:admin 发表于 2024年11月7日 下午1:44。
转载请注明:使用 JavaScript 入侵汽车(使用 HackRF 在浏览器中运行重放攻击) | CTF导航

相关文章