Xiaomi Mi Fit – Krótka analiza ruchu sieciowego

Zachęcony dobrymi opiniami, niewielką ceną (~15$) oraz potencjalnymi możliwościami researchu 😉  tydzień temu nabyłem opaskę Xiaomi MiBand.

Głównym przeznaczeniem urządzenia jest zbieranie informacji o dystansie przebytym każdego dnia, fazach snu oraz wybudzanie w najbardziej odpowiednim momencie danej fazy. Dodatkowo umożliwia informowanie o oczekających powiadomieniach (sztuczne ograniczenie tylko do trzech aplikacji).

W związku z niewielką ilością badań przetwarzanych danych oraz bezpieczeństwa technologii typu wereable, postanowiłem przyjrzeć się aplikacji Android – Mi Fit, której zadaniem jest zbieranie danych z opaski poprzez Bluetooth.

Opaska Xiaomi Mi Band

Aplikacja była testowana na Androidzie 4.4.4, wersja aplikacji 1.7.521 – najnowsza na dzień pisania posta.

Ruch był przechwytywany za pomocą darmowej wersji Burp Suite. Świetny artykuł o tym jak skonfigurować proxy HTTP na smartfonie z Androidem znajdziesz na Sekuraku.

Analiza ruchu HTTP

Pierwszą rzeczą którą postanowiłem sprawdzić, była komunikacja z API Xiaomi (aplikacja wymaga założenia konta do działania). Wszelki ruch sieciowy aplikacji odbywa się poprzez SSL\TLS.

Aplikacja w trakcie swojego działania łączy się z pięcioma domenami:

  • account.xiaomi.com – wszystkie akcje dotyczące kont użytkowników
  • api.weibo.com – integracja z Weibo, chińskim połączeniem Facebooka i Twittera
  • data.mistat.xiaomi.com – statystyki instalacji aplikacji od Xiaomi
  • hm.xiaomi.com – pobieranie widoków do aplikacji mobilnej
  • hm.mi-ae.com – wszystkie akcje dotyczące aktywności fizycznej, snu oraz alarmów

W dalszej części posta skupię się na komunikacji pomiędzy ostatnią domeną a aplikacją Mi Fit, gdyż, mówiąc językiem malware, jest C&C dla tej aplikacji.

Wszystkie dane wysyłane przez aplikacje można znaleźć w pliku mili_log.txt (polecam zrzucić plik z telefonu i otwierać na komputerze – jest dosyć duży), znajdującego się w katalogu głównym miejsca, gdzie została zainstalowana aplikacja Mi Fit.

Informacje o aktywnościach

Każda aktywność sychronizowana z opaski, podczas wykrycia połączenia sieciowego jest wysyłana w tle na serwery Xiaomi. Dotyczy to zarówno chodzenia / biegania, jak również i danych o śnie.

Żądanie synchronizacji danych z Xiaomi:

  <item>
    <time>Thu Dec 10 19:20:57 CET 2015</time>
    <url><![CDATA[https://hm.mi-ae.com/huami.health.receiveData.json]]></url>
    <host ip="52.25.221.37">hm.mi-ae.com</host>
    <port>443</port>
    <protocol>https</protocol>
    <method>POST</method>
    <path><![CDATA[/huami.health.receiveData.json]]></path>
    <extension>json</extension>
    <request base64="false"><![CDATA[POST /huami.health.receiveData.json HTTP/1.1 Content-Length: 6789 Content-Type: application/x-www-form-urlencoded Host: hm.mi-ae.com Connection: Keep-Alive Accept-Encoding: gzip device_type=android_phone&cv=1594_1.7.521&security=XXXX&data_type=0&source=5&callid=1449771649079&device=android_19&v=1.0&uuid=ffffffff-ddbd-ebe5-ffff-fffffb7ffffd&data_json=[{"summary":"{\"slp\":{\"lt\":234,\"st\":1449615540,\"wk\":0,\"dp\":108,\"ed\":1449636060},\"v\":5,\"goal\":9000,\"stp\":{\"rn\":3,\"cal\":436,\"runDist\":521,\"wk\":110,\"ttl\":9326,\"runCal\":31,\"dis\":7421}}","data":"[wycięte dużo śmieci]","type":0,"source":5,"date":"2015-12-09","indexs":"[{\"stopIndex\":4832,\"startIndex\":0},{\"stopIndex\":5756,\"startIndex\":4912}]"}]&timezone=Europe/Warsaw&data_len=6116&appid=2882303761517154077&lang=pl&userid=159XXXXXXX&deviceid=88E9XXXXXXXXXXXXX&channel=play&country=PL]]></request>
    <status></status>
    <responselength></responselength>
    <mimetype></mimetype>
    <response base64="false"></response>
    <comment></comment>
  </item>

Ciekawsze parametry żądania:

  • lt / dp – czas trwania lekkiego / głębokiegu snu w minutach
  • st / ed – czas początku oraz końca snu, wyrażony w czasie Unix’a
  • cal – spalone kalorie
  • runDis / dis – dystans biegu i ogółem, w metrach

Informacje osobiste oraz o przypomnieniach i budzikach

Wszystkie ustawienia budzików oraz zmiany w profilu użytkownika (co jest zrozumiałe) są niezłwocznie synchronizowane z API:

<item>
    <time>Thu Dec 10 19:25:06 CET 2015</time>
    <url><![CDATA[https://hm.mi-ae.com/huami.health.bindProfile.json]]></url>
    <host ip="52.25.221.37">hm.mi-ae.com</host>
    <port>443</port>
    <protocol>https</protocol>
    <method>POST</method>
    <path><![CDATA[/huami.health.bindProfile.json]]></path>
    <extension>json</extension>
    <request base64="false"><![CDATA[POST /huami.health.bindProfile.json HTTP/1.1 Content-Length: 1299 Content-Type: application/x-www-form-urlencoded Host: hm.mi-ae.com Connection: Keep-Alive Accept-Encoding: gzip device_type=android_phone&height=XXX&birthday=XXXX-X&alarm_clock=[{"calendar":{"year":2015,"month":11,"dayOfMonth":10,"hourOfDay":5,"minute":30,"second":0},"enabled":true,"isUpdate":true,"mDays":127,"mSmartWakeupDuration":30},{"calendar":{"year":2015,"month":11,"dayOfMonth":8,"hourOfDay":22,"minute":0,"second":0},"enabled":true,"isUpdate":true,"mDays":127,"mSmartWakeupDuration":0},{"calendar":{"year":2015,"month":11,"dayOfMonth":8,"hourOfDay":8,"minute":0,"second":55},"enabled":false,"isUpdate":false,"mDays":31,"mSmartWakeupDuration":0}]&cv=1594_1.7.521&security=ea4d600d6e10d09a8da434adcf2e8e09&version=0&callid=1449772122629&gender=1&device=android_19&nick_name=James&v=1.0&age=XX&timezone=Europe/Warsaw&weight=XX000.0&person_sh=&icon_url=&appid=2882303761517154077&lang=pl&config={"wearHand":"LEFT_HAND","dayReportNoti":"OFF","lightColor":"BLUE","enableConnectedBtAdv":false,"goalStepsCount":9000,"hasHeartRate":false,"inComingCallNotifyTime":3,"incallContactNotifyEnabled":false,"incallNotifyEnabled":true,"disconnectedReminder":0,"mOpenSleepNotify":false,"sleepAssist":false,"smsContactNotifyEnabled":false,"smsNotifyEnabled":false,"unit":0,"vibrate":false,"alarmNotifyEnabled":false,"weightMergeResult":false,"weightUnit":0}&location={"city":"","latitude":"","longitude":""}&userid=159XXXXXXX&channel=play&country=PL&person_signature=]]>
    <status></status>
    <responselength></responselength>
    <mimetype></mimetype>
    <response base64="false"></response>
    <comment></comment>
  </item>
  <item>

Interesujące parametry żądania:

  • cała sekcja calendar – wszystko o budzikach zaprogramowanych w aplikacji
  • weight – waga użytkownika, podana w gramach
  • wearHand – ręka na której noszona jest opaska
  • inComingCallNotifyTime – czas od rozpoczęcia połączenia, po którym aplikacja zaczyna wibrować

Gdzie leży problem?

Nie da się ukryć, że dane przetwarzane przez aplikację są dosyć osobiste i pozwalają na jednoznaczną identyfikację osoby oraz jej nawyków czy przyzwyczajeń. Dane te w połączeniu z informacjami z innych źródeł, pozwalają stworzyć pełen profil konkretnej osoby, który będzie łakomym kąskiem dla służb czy firm ubezpieczeniowych.

Aplikacja nie informuje wprost co jest wysyłane na serwery Xiaomi. Co prawda bardzo ogólnie jest to opisane po przewinięciu 3/4 polityki prywatności, lecz nie sposób dostać się do dalszej części opisu, wiemy jedynie, że “Mi Band data” jest gdzieś wysyłane:

Tak, nie da się “przescrollować” w prawo…

Na chwilę obecną w ekosystemie stworzonym dla opaski, nie ma narzędzia webowego (takiego jak np. w Endomondo), które mogłoby zrobić użytek z danych wysyłanych do dostawcy aplikacji.

Dane są zbierane dla samego zbierania (nie są to backupy), a poniższy screen to mówiąc kolokwialnie (i bardzo delikatnie) “lekka ściema”.

Ekran powitalny aplikacji Mi Fit

Mam taką opaskę, jak mam teraz żyć?

Niestety alternatywne aplikacje do obsługi Mi Band działają słabo i mają problemy z synchronizacją. Jedynie Google Fit, nieźle sychronizuje aktywność, lecz nie obsługuje alarmów.

Gdyby ktoś jednak się pokusił to podrzucam linki dla pozostałych aplikacji na Androida:

Ze swojej strony proponuje korzystanie z oryginalnej aplikacji Mi Fit + dodatkowego firewalla np. NoRoot Firewall, który będzie blokował jej cały ruch sieciowy. Na chwilę obecną jest to jedyne połączenie, które zapewnia wszystkie funkcjonalności aplikacji, wraz ze stabilnością.

Zawsze istnieje również możliwość napisania własnej aplikacji. Protokół wymiany danych z opaską został zreverse’owany, co otwiera pole do popisu dla niezależnych deweloperów 🙂