PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Reverse Engineering - Fitbit API's



Cystasy
13.10.2016, 13:07
Heute geht es darum die Fitbit Web API's zu reversen.
Warum? Nun - Fitbit hat sein Geschäftsmodell darauf aufgebaut, das sie eure Fitness Armband Daten auf ihren Servern speichern.
Diese Daten könnt ihr dann nur durch eine Premium Mitgliedschaft exportieren - ergo lässt sich Fitbit von euch dafür bezahlen,
euch eure Daten auszuhändigen die ihr selbst aufgezeichnet habt. Das muss man sich erstmal auf der Zunge zergehen lassen.
Man zeichnet Tag für Tag seine Fitness Daten auf.. und um dann an diese Daten zu kommen soll man zahlen? Na! So gehts ja mal nich.

Da ich gerne mit meinen (!) Daten einige Analysen durchführen würde (und kb hab Premium zu kaufen um an meine Daten zu kommen),
werde ich mir die Daten auf dem klassischen Weg besorgen - Ich werde die API reversen und mir meine Daten selbst holen.

Wo fangen wir an? Ersteinmal müssen wir uns anschauen wie das ganze bei Fitbit mit den Daten funktioniert:

Man trägt den jeweiligen Fitness Tracker (meistens Armbänder) bei sich. Dieser Tracker besitzt einen internen Speicher auf dem bis zu
7 Tage eure Daten (Ruhepuls, Herzfrequenz allgemein, Schlafqualität & co.) gespeichert werden. Nun kann man den Tracker
per Smartphone App oder einer Desktop Anwendung mit den Fitbit Servern Syncronisieren woraufhin diese Daten aus dem Internen
Speicher des Trackers auf den Servern von Fitbit landen. Anders als auf diesem Weg kommt man nicht an seine Daten ran.
Die Datenübertragung vom Tracker zur App / Desktop Anwendung läuft über Bluetooth 4.0 und ist verschlüsselt.
Ein Abgreifen der Daten per Bluetooth ist also ohne größeren Aufwand nicht drin (zu aufwändig).

Jedoch gibt es von Fitbit ein Dashboard für den Browser in dem man seine Daten anschauen kann, das sieht dann folgendermaßen aus:

http://i.imgur.com/ADOQguO.png

Wie wir hier sehen gibt es hier eine Repräsentation von unseren Daten, die auf dem Server abgespeichert sind.
Ergo muss es eine Art Schnittstelle geben, worüber der Browser dann die ganzen Daten vom Server abrufen & anzeigen kann.
Zunächst dachte ich das diese Daten einfach über Javascript im JSON Format in die Webseite eingebunden sind.
Deshalb hatte ich mir zunächst den Quellcode der jeweiligen Startseite zum Dashboard genauer angesehen.. doch
leider fand ich dort nichts. Über meine Schlafqualität hätte ich jedoch über Umwege dann die Daten über meine Schlafqualität auslesen
können. Mich interessierte aber vielmehr mein Herzschlag (mein Fitness Armband von Fitbit zeichnet 24/7 meinen Puls auf).
Da ich nach ner halben Stunde rumsuchen nicht die benötigten URLs gefunden hatte um näher zu reversen woher die ganzen
Daten kamen, entschied ich mich zu drastischeren Mitteln :D...

Und diese lauten.. Javascript Funktions Hooks.
Wem dieser Begriff nichts sagt -> Ein Javascript Funktion Hook bedeutet, das wir eine bereits existierende Funktion durch unsere eigene ersetzen.
Dadurch erlangen wir kompletten Zugriff auf die jeweilige Funktion (und der Daten die an sie übergeben werden).
Doch welche Funktion könnten wir denn Hooken um bei unserem Reversing weiter zu kommen?

Nun - was möchten wir denn erreichen? Grundsätzlich gesehen möchten wir einen Link rausfinden, unter dem wir dann
unsere Daten abrufen können. Dieser Link muss existieren da sonst unser Browser die Daten die er zum Rendern der Graphen
und Daten nicht abrufen könnte. Wenn wir diesen Link also finden, haben wir die Daten in unseren Händen - und das ganz ohne für Premium zu blechen.

Bevor wir nun jedoch weiter machen, muss ich kurz einige Grundlagen für Webanwendungen erklären damit ihr meine Gedankengänge besser nachvollziehen könnt.
Also - wenn man in einer Webanwendungen mit einem Server kommunizieren möchte, geht dies über 2-3 verschiedene Arten.
Die eine nennt sich Ajax, die andere Websockets. Websockets besitzen ähnlichkeiten mit Winsockets und Sockets im allgemeinen.
Man kann Verbindungen öffnen, Daten senden und natürlich auch empfangen. Websockets werden meistens eher von Multiplayer Spielen wie Agar.io benutzt.
Ajax ist eher dafür geeignet Daten von einer URL abzurufen (meist formatiert in JSON oder XML Format).
Ajax bietet genauso wie Websockets eine Möglichkeit eine Verbindung zu öffnen und Daten zu senden und zu empfangen.
Im Quellcode von Fitbit sah ich das Fitbit für die Kommunikation mit ihren Server Ajax (XMLHttpRequest) verwendet - und genau hier wollte ich ansetzen.
Ich habe die jeweiligen API Urls nicht im Quellcode gefunden, also entschied ich mich die


XMLHttpRequest.prototype.open

Funktion von Ajax zu hooken.

Zunächst - weshalb gerade diese Funktion und keine andere?
Nun, diese Funktion ist für einen Verbindungsaufbau da - mit dieser Funktion stellt man die Verbindung mit einem Server her.
Die Funktion ist folgendermaßen aufgebaut:




void open(
DOMString method,
DOMString url,
optional boolean async,
optional DOMString user,
optional DOMString password
);


Wir sehen hier das unteranderem die Request Methode, die jeweilige URL und 3 weitere Variablen die für diesen Fall unwichtig sind an diese
Funktion übergeben werden. Möchte also jemand über Ajax eine Verbindung aufbauen, muss er diese Funktion mit den entsprechenden Parametern
wie beispielweise der URL aufrufen. Wir sehen hier also - Fitbit muss diese Funktion aufrufen um eine Verbindung mit ihren Servern aufzunehmen
um an meine Daten zu kommen. Ergo.. hooken wir diese Funktion, kommen wir auch gleichzeitig an die URL die wir soooo sehnlichst wollen!

Wie das Hooking dieser Funktion nun im Detail funktioniert, werde ich hier in diesem Thread jedoch NICHT erwähnen da ich hierzu schon
eine HowTo verfasst habe in dem ich dies schildere. Falls ihr mehr dazu lesen wollt, empfehle ich euch mein HowTo

https://free-hack.com/showthread.php?77249-Javascript-Function-Hooking-HowTo

So.. verfassen wir nun mal unseren Hooking Javascript Code um die Funktion zu hooken:



var xml_open = XMLHttpRequest.prototype.open; //Alte Funktion zwischenspeichern
XMLHttpRequest.prototype.open = function(method, url, async, user, password) //Funktion Hooken
{
console.log(method+": "+url+" (async: "+async); //Daten in Webconsole ausgeben
xml_open(method, url, async, user, password); //Zwischengespeicherte Funktion abrufen damit die Serverkommunikation funzt
}


Kurzgesagt tut der obige Code folgendes:

1) Wir kopieren die Funktion die wir hooken wollen und geben der Kopie den Namen "xml_open" (xml_open(method,url,async,user,password))

2) Wir Hooken die Funktion die wir benötigen und Manipulieren sie.
Die Manipulation besteht darin, das die Funktion nun alle Parameter die an sie übergeben werden in unserer Webconsole ausgeben.

3) Nun rufen wir die im 1. Schritt kopierte Funktion mit den entsprechenden Parametern auf damit die Serverkommunikation
trotz unserer Manipulation weiterhin funktioniert (und der Browser an seine Daten kommt :D).

Dieses Script packe ich nun in ein Greasyemonkey Script für Firefox und rufe Fitbit.com (natürlich eingeloggt) auf.
Nun.. schauen wir mal in die Webconsole!

http://i.imgur.com/AvXQdLz.png

Wir sehen hier nun eine vielzahl von URLs über die jeweils eine Kommunikation stattfand.
Hier sticht mir direkt folgende URL ins Auge:


https://web-api.fitbit.com/1/user/*ZENSIERT*/activities/heart/date/2016-10-13/2016-10-06.json

Rufen wir diese Url auf, sehen wir folgende Meldung:


{"errors":[{"errorType":"invalid_client","message":"Invalid authorization header format. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."}],"success":false}

Dang it! Was tun wir jetzt? Eine Fehlermeldung..hmm!
errorType: invalid_client? Soso.. falscher Client also!
Schauen wir doch mal den Request genauer an der von Fitbit gemacht wird - hier wird sehr wahrscheinlich
über die GET Parameter etwas mitgeschickt das dem Server sagt was für ein Client unsere Daten abrufen möchte.
Diese Daten müssen wir nun ebenfalls in unserem Request senden (ein einfaches aufrufen der URL im Browser genügt hier nicht mehr).

Tamper Data zeigte mir bei einer näheren Analyse, das bei jedem Request 3 Parameter mitgeschickt werden.
Der 1. Parameter ist zur Authentifizierung des Requests (das selbe wie die öffentliche API),
die anderen 2 um den Referrer und die Origin anzugeben.

Um nun einen Request an den Server zu machen, müssen wir zunächst einmal ein bisschen Javascript Code
aufschreiben - denn ein einfacher Aufruf der URL reicht hier nicht aus.



var s = new XMLHttpRequest();
s.open("GET","https://api.fitbit.com/1/user/-/activities/heart/date/2016-10-13/1d/1sec.json");
s.setRequestHeader("Authorization","Bearer *ZENSIERT*");
s.setRequestHeader("Referer","https://www.fitbit.com/");
s.setRequestHeader("Origin","https://www.fitbit.com/");
s.send();
setTimeout(function(){console.log(s.responseText); },1000);


Was macht dieser Code? Nun - im Prinzip ist dieser Code enorm simpel.
Mal der Ablauf was hier im Code passiert:

1) Wir erstellen unseren eigenen XMLHttpRequest und stellen ein das wir gerne unseren Request an die URL https://api.fitbit.com/1/user/-/activities/heart/date/2016-10-13/1d/1sec.json schicken möchten
Diese URL ist quasi die URL, an der wir meine Herzschlag Daten von Heute (13.10.2016) in einer Auflösung von 1 Sekunde pro Datenpunkt abrufen können.

2) Nun bauen wir unseren eigenen Header zusammen, dort geben wir unseren Authentifizierungs Code ein und den Referrer und die Origin.
Dies ist dazu da um sich zu Authentifizieren & damit der Server weiß das wir berechtigt dazu sind die Daten abzurufen.
Den Auth Code habe ich jeweils mit Tamper Data mitgeschnitten (Theoretisch hätte ich auch über das DEV Programm von Fitbit nen API Acces beantragen können).

3) Nun senden wir den Request an den Server

4) Nach 1 Sekunde lesen wir nun die Antwort des Servers aus. Wieso 1 Sekunde? Nunja.. der Server braucht einige ms bis er Antwortet.. und deshalb warten
wir 1 Sekunde bevor wir versuchen die Variable auszulesen in der dann die Antwort des Servers steht (s.responseText).
Würden wir keine Sekunde warten, wäre diese Variable leer da wir noch garkeine Antwort erhalten hätten wenn versucht
wird die Variable auszulesen.

Nun fragt ihr euch vielleicht wo ich diese URL im obigen Code habe.. die ist ja nicht im Bild von vorhin zu sehen.
Die Antwort ist einfach.. aus der API Dokumentation von Fitbit die unter https://dev.fitbit.com/docs/heart-rate/ zu finden ist^-^*
Dabei fand ich übrigens auch raus, das man mittlerweile scheinbar für Persönlichen Gebrauch über die API die jeweiligen Daten nutzen darf.
Das heißt im Grunde genommen das ich mir ziemlich umsonst die Mühe gemacht habe die API ein bisschen zu reversen und ich einfach
die normale API Schnittstelle nutzen hätte können. Das gute daran? Ich habe etwas Produktives getan & brauchte auf diesem Wege
kein eigenen API Zugriff bei Fitbit beantragen.. ich nutze für den Zugriff auf die API einfach den API Key der auch vom Browser benutzt wird.
Das ganze ist nun nicht ideal, aber angenehmer als durch den Prozess der beantragung eines API Schlüssels gehen zu müssen usw.

Nun.. in s.responseText steht nun die Antwort des Fitbits Servers an uns.. und diese Antwort ist JSON Formatiert und enthält meine gewollten
Daten (Herzschlag für Heute). Theoretisch könnte man nun sich in Javascript ein Tool schreiben was die Daten von einem beliebigen Zeitabschnitt
abfrägt und exportiert. So könnte man dann Analysen über sein Schlafverhalten, Gesundheit und weiteres erledigen.
Die API Schnittstelle von Fitbit bietet noch viele mehr Datenpunkte die man anfragen kann - beispielweise Schlafqualität, gelaufene Schritte etc.

Kurzfassung: Nun steht uns die Welt offen.. auch wenn wir es uns hier ein bisschen komplizierter gemacht haben als es nötig gewesen wäre.
Dadurch haben wir immerhin ein BISSCHEN produktives getan & ein bisschen mehr gelernt. Und das wichtigste daran?
Ich konnte nochmals zeigen wie ich in etwa beim Reversen von Web Anwendungen vorgehe, was meine Schritte sind und wie sowas im Groben funktionieren kann.

Bei Fragen oder Anregungen stehe ich gerne zur Verfügung^-^*

grüße, Cy

zzurc
13.10.2016, 13:24
oh ja schön zu lesen

gORDon_vdLg
13.10.2016, 18:54
Danke, es ist interessant sowas zu lesen, ich persönlich hätte jetzt irgendwie mit Livehttpheaders rumgefrickelt weil ich wenig in JavaScript mache und daher nicht unbedingt auf den Ansatz gekommen wäre. Der Hook ist natürlich schöner weil man auf die Art auch Einfluss auf die übertragenen Daten nehmen kann, und auch vieles was unwichtig ist und einen bei Livehttpheaders nur die Übersicht nimmt weg fällt. Das wird mir sicher nochmal nützlich sein.

Cystasy
13.10.2016, 20:03
Danke, es ist interessant sowas zu lesen, ich persönlich hätte jetzt irgendwie mit Livehttpheaders rumgefrickelt weil ich wenig in JavaScript mache und daher nicht unbedingt auf den Ansatz gekommen wäre. Der Hook ist natürlich schöner weil man auf die Art auch Einfluss auf die übertragenen Daten nehmen kann, und auch vieles was unwichtig ist und einen bei Livehttpheaders nur die Übersicht nimmt weg fällt. Das wird mir sicher nochmal nützlich sein.

Unteranderem habe ich diesen Weg gewählt weil ich es immer tierisch ätzend finde mit z.b TamperData sowas zu analysieren.. weil dort auch von ALLEN Tabs die man offen hat dann die mitschnitte kommen. Und da ich oft Youtube laufen habe nebenbei für Musik ist das dann immer ein Chaos in TamperData.. da fand ich die Lösung mit dem Hook besser weil ich so wie du es schon erwähnt hast auch direkt eingriff auf die Daten habe usw^^

zzurc
13.10.2016, 20:36
Unteranderem habe ich diesen Weg gewählt weil ich es immer tierisch ätzend finde mit z.b TamperData sowas zu analysieren.. weil dort auch von ALLEN Tabs die man offen hat dann die mitschnitte kommen. Und da ich oft Youtube laufen habe nebenbei für Musik ist das dann immer ein Chaos in TamperData.. da fand ich die Lösung mit dem Hook besser weil ich so wie du es schon erwähnt hast auch direkt eingriff auf die Daten habe usw^^

Ich war nie ein Fan von TamperData. Kann ich aber burpsuite empfehlen:D

Alucart
14.10.2016, 21:19
Da hat J0hn.X3r (https://free-hack.com/member.php?36233-J0hn-X3r) gestern schon den Thread des Monats gekürt und jetzt kommt hier so eine Granate! Hut ab!

// Mich würde es mal interessieren wie man sich überhaupt in die Thematik vom Reversen einlesen kann. Man braucht ja ein unglaubliches Wissen von Anwendungen und Abläufen.
Dazu könntest Du auch mal ein TUT machen. How to Reversen!

Cystasy
14.10.2016, 21:42
Mich würde es mal interessieren wie man sich überhaupt in die Thematik vom Reversen einlesen kann. Man braucht ja ein unglaubliches Wissen von Anwendungen und Abläufen.


Das dürfte schwer sein das in einem einzigen Thread zu erklären.. vorallem weil es abhängig davon ist was man reversen möchte.
Bei Webanwendungen muss man sich sehr gut mit Javascript & Hintergrundabläufen auskennen und viel Experimentieren, bei anderen Anwendungen benötigt man wieder andere Kenntnisse wie Assembler usw. Da gibt es keinen Ultimativen Ansatz / Weg zum reversen lernen^^

Ich würde jedem der lernen möchte wie man reversed empfehlen sich einfach mal ins Kalte Wasser zu begeben und es auszuprobieren :D
Durch die Praxis lernt man immer noch am meisten :) Bei meinem reversing der Jodel App für Smartphones z.b habe ich ewige Stunden dran
gesessen um rauszubekommen wie die Sturktur hinter der API ist, wie man Dinge an den Server schicken muss etc..
Beim reversen braucht man folgendes:

- Viel Zeit (Sehr viel!)
- Grundwissen (Programmieren, Scriptsprachen, Grundlagenwissen in Informatik)

Und dann experimentiert man einfach und lernt dabei wie man vorgehen kann bei diversen Dingen :)
Bei Webanwendungen sind z.b die API's häufig sehr ähnlich aufgebaut - das sorgt dafür das man dann oft mit Ajax oder Websockets auf sie zugreifen kann.
WIE man das aber macht, muss man anhand des Sourcecodes, Hooking usw lernen am jeweiligen Service / App / Programm / Webanwendung^^

Man muss da einfach mal ins Wasser reinspringen und sich die Füße nass machen hehe :D
Ich habe ja schon 2 Beispielthreads gemacht um ein bisschen zu zeigen wie man beim reversen vorgehen kann.. um ein bisschen ein Beispiel zu bringen.
Ich denke daran kann man sich ganz gut orientieren.

Was ich aber mal machen könnte, wäre vielleicht für Webanwendungen ein paar Grundkniffe zu zeigen.. Beispielweise Kommunikation mit Servern über Ajax um auf die Grundlegendsten API's zuzugreifen, Hooking und solche Dinge.. Grund-Dinge um Webanwendungen ein bisschen zu reversen.

grüße

sn0w
14.10.2016, 22:13
Gerade beim reversen hilft es viel wenn man etwas ähnliches schonmal programmiert hat. Gerade bei Web Apps und/oder DB Anwendungen, weil man dann meist schon weiß, wie grundsätzliche Sachen funktionieren und auch wie die Abläufe sind. Zudem ist man evtl schonmal auf solche Fehler in seinen eigenen Programmen/Apps gestoßen und weiß daher schonmal den ersten Angriffvektor.

MfG

Cystasy
15.10.2016, 19:43
Grafische Darstellung der Herzschlag Aufzeichnung über den Tag verteilt basierend auf dem Reversing in diesem Thread:

http://i.imgur.com/H3SSnBK.png

Das Tool liest über die API die Daten aus und stellt sie grafisch dar.
Hätte man nun Echtzeit Zugriff auf die Daten (nicht nur im nachhinein) könnte man eine App basteln die erkennt wenn man schläft :P

p.s:

Grüne Balken = niedriger Puls (75-85 rum) ...tritt beim Schlaf auf..ergo Grüner Balken = Schlaf
Blauer Punkt = Eine Stunde (zum Zeitlichen einordnen der Daten)

Cystasy
19.10.2016, 11:45
So, habe das ganze noch ein bisschen weiter getrieben und die Webanwendung bisschen verbessert + versucht Schlafphasen anhand den Daten zu erkennen.. ich denke es hat geklappt, bin mir da aber nicht zu 100% sicher weil das Schlafphasenerkennen allein mit Herzschlag Messung nicht wirklich 100% klappt.

Naja, schaut selbst:
http://imgur.com/gallery/dTmSVnz