kapieciiのブログ

日々学んだことを残しておくためのブログです。このブログはGoogle Analyticsを利用しています。

MQTTを利用したサービスの攻撃シナリオを検証してみた

下記のAvastのブログで2018年8月時点のMQTTに関する情勢や、攻撃シナリオについて解説していました。
とても興味深かったので、攻撃シナリオの中の1つをローカル環境で検証してみました。

Are smart homes vulnerable to hacking?
https://blog.avast.com/mqtt-vulnerabilities-hacking-smart-homes

目次

この記事の目的

攻撃シナリオを通して、MQTTを適切に利用しなかった場合の危険性を感じてもらい、安全なシステム開発につなげてもらえればと考えています。

MQTTとは?

f:id:kapiecii:20190103165218p:plain

参照: Hacking the IoT with MQTT – Morphus Labs

図のようにBrokerを介してPubliisherからSubscriberへメッセージを送信します。
MQTT自体はシンプルなプロトコルを旨としているらしく、「認証」や「暗号化」、「接続元の確認」といった機能はもっていません。

MQTTの利用状況

Avastの記事によると、2018年8月頃の時点で、49,197台のMQTTサーバがインターネットに公開されており、そのうち32,888台にはパスワード無しでアクセスすることができる状態だったそうです。

f:id:kapiecii:20190103165353p:plain

参照: At least 32,000 smart homes and businesses at risk of leaking data | Avast

検証

それでは検証をはじめます。

検証環境

Ubuntu 16.04

MQTT Brokerをインストール

こちらの記事を参照して、MosquittoというMQTTブローカーをインストールしました。

UbuntuにMosquittoをインストールしてMQTTブローカーを構築 - Qiita

$ sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa
$ sudo apt-get update
$ sudo apt-get install mosquitto

MQTT動作確認

publisherとsubscriberを作成します。
「paho-mqttwo」を使ってサンプルコードを作成しました。

paho-mqttwoインストール

$ pip install paho-mqtt

今回はローカルにBroker設置しているので、接続先IPアドレスは「127.0.0.1」です。
ポートはMQTTのデフォルトの「1883」を指定します。
Topicは「mqtt-test」というTopicで、「test」というメッセージを送信しました。
本来はサンプルコードの全てを載せた方がいいのでしょうが、検証内容の性質上、ソースコードは割愛しています。
悪意の無い簡単なサンプルコードでも、色々とややこしいことになる場合があるらしいので。

publisher.py(一部抜粋)

host = '127.0.0.1'
port = 1883
topic = 'mqtt-test'

subscriber.py(一部抜粋)

host = '127.0.0.1'
port = 1883
topic = 'mqtt-test'

publisherとsubscriberを作成したら、subscriberを起動します。

$ python subscriber.py

publisherでMQTTメッセージを送信します。

$ python publisher.py

f:id:kapiecii:20190103171041p:plain

publisher.pyから送信した「test」という文字をshubscriber.pyで受け取ることができました。

正常系の動作確認が終わったので、攻撃シナリオの検証に移ります。

攻撃シナリオ概要

今回は、「自宅ガレージの扉にIoT鍵が設置されていて、スマホアプリから解錠命令を送信することで扉を開けることができる」というシナリオで話を進めます。
※このシナリオは攻撃シナリオをイメージしてもらうためのフィクションです。実在する製品とは一切関係ありません。

攻撃者は、下記のような流れで攻撃を実施します。

  • 情報収集:MQTTサーバに接続し、ワイルドカードで全topicのメッセージを受信する
  • 解析:受信した情報を解析し、メッセージの形式を調べる
  • 攻撃:調べたメッセージ形式で、攻撃リクエストを送信する

攻撃対象となるMQTTサーバを見つける

shodanを使ったり、各種スマホアプリやIoTデバイスの通信処理を解析することで、攻撃対象となるMQTTサーバのIPアドレスを特定します。

情報収集

対象となるMQTTサーバに接続したら、まずは情報収集です。
今回正規のクライアントは「/random-123abc/house/garage/」というTopicでメッセージをやり取りします。
「random-123abc」の部分は、利用者を一意に定めるランダムなIDなどが入るイメージです。
攻撃者は「#」というワイルドカードを使って全てのTopicの内容を受信します。

subscriber-attacker.py(一部抜粋)

host = '127.0.0.1'
port = 1883
topic = '#'

subscriber-user.py(一部抜粋)

host = '127.0.0.1'
port = 1883
topic = '/random-123abc/house/garage/'

publisher.py(一部抜粋)

host = '127.0.0.1'
port = 1883
topic = '/random-123abc/house/garage/'

攻撃者を想定したsubscriber-attacker.pyと、正規の利用者を想定したsubscriber-user.pyを起動した後、publisher.pyでメッセージを送信します。

f:id:kapiecii:20190103172719p:plain

ワイルドカードを利用した攻撃者が、正規のメッセージを受信できました。

f:id:kapiecii:20190103171957p:plain

解析

攻撃者は「/random-123abc/house/garage」のTopicに対して、json形式のメッセージを送信してやればいいことがわかります。

攻撃

あとは、判明したTopicに対して攻撃者がメッセージを送信することで任意にガレージの扉を操作することができます。

感想

非常にシンプルなサンプルコードでAvastの記事に記載されていた攻撃シナリオを検証することができました。
似たような記事で「ワイルドカードでメッセージを受信したところ、利用者の位置情報を取得するとができた」というような情報もありました。おそらく、スマートウォッチなどのウェアラブルバイスや、位置をロギングするようなサービスだったのでしょう。

MQTT自体は非常にシンプルなプロトコルで、認証認可や暗号化の機能は持っていません。
そのため、アプリケーション開発者の方が、サービスに合わせた認証認可処理や暗号化処理を準備する必要があります。

この記事が、「便利で安全なサービス」が世の中に生まれる一助になれば幸いです。

kapieciiのブログについてお問い合わせがある場合、下記のフォームからご連絡をお願い致します。
お問い合わせはこちら