Posts

Fun with SteelCase RoomWizard II

On vient de déménager dans un nouveau bureau où tout le mobilier est fourni par SteelCase, une compagnie qui se spécialise dans le mobilier d’entreprise. Une des nombreuses nouveautés: des RoomWizard pour chaque salle de rencontre. Il s’agit d’un appareil qui gère la disponibilité des salles en temps réel.

Officiellement, nous avons trois façons de réserver une salle:

  1. Utiliser le site web de réservation de salle prévu à cet effet
  2. Communiquer avec la réception
  3. Utiliser l’appareil directement (maximum de 2h)

Officieusement, il existe une quatrième façon: les appareils ont des adresses IP accessibles du même réseau que les employés.

Comment trouver l’adresse IP d’un RoomWizard? Le bouton “Details” sur l’écran.

Interface web

En effet, les appareils exposent une jolie interface web qui permet de visualiser l’occupation de toutes les salles.

Aucun mot de passe n’est requis pour l’accès en lecture seule, mais il existe un panneau d’administration accessible en ajoutant /admin/ à l’URL. Intéressant.

L’appareil effectue ses opérations avec le serveur du système directement dans le navigateur du client en envoyant un POST à un API exposé par l’appareil.

Il n’est pas possible de créer, modifier ou annuler des réservations avec l’interface graphique ou web. Mais ça l’est en communiquant directement avec l’API

On sait ce qui arrive quand on expose des services qui n’ont pas besoin d’authentification.

Communiquer directement avec l’API

Une combinaison de rétro-ingénierie, de google-fu et d’essais aveugles m’a permis de tester avec succès les appels suivants:

get_bookings

Retourne les réservations d’une salle pour une période de temps donnée.

Paramètredescriptionnotes
room_idID de la salleOptionnel. La salle par défaut est celle à qui on envoie la requête
range_start_date range_start_timeDébut de la période de temps pour laquelle on veut avoir les réservations.Format: YYYYMMDD et HHMMSS
range_end_date range_end_timeFin de la période de temps pour laquelle on veut avoir les réservations.Format: YYYYMMDD et HHMMSS

Exemple

http://rwdevice/Connector?command=get_bookings&format=json&range_start_date=20140114&range_start_time=080000&range_end_date=20140114&range_end_time=170000

Réponse du serveur

add_booking

Ajoute une réservation au système. Cet appel permet de contourner la limite maximale de 2h par réservation.

Paramètredescriptionnotes
room_idID de la salleOptionnel. La salle par défaut est celle à qui on envoie la requête
start_date start_timeDate et heure du début de la réservationFormat: YYYYMMDD et HHMMSS
end_date end_timeDate et heure de la fin de la réservation.Format: YYYYMMDD et HHMMSS
purposeRaison de la réservationCe texte sera affiché sur l’appareil

Exemple

http://rwdevice/Connector?command=add_booking&start_date=20140114&start_time=080000&end_date=20140114&end_time=170000&purpose=HACK%20THE%20PLANET

Réponse du serveur

edit_booking

J’imagine que ça sert normalement à modifier les réservations, mais j’ai seulement été capable de m’en servir pour supprimer une réservation.

Paramètredescriptionnotes
room_idID de la salleOptionnel. La salle par défaut est celle à qui on envoie la requête
booking_idID de la réservation qu’on veut modifier.Cet identifiant est retourné par get_bookings.
operationCode d’opérationC = Cancel

Exemple

http://rwdevice/Connector?command=edit_booking& booking_id=2776708&operation=C

Réponse du serveur

Bonus: La liste de tous les appareils RoomWizard du réseau

L’appareil expose également une méthode qui retourne tous les autres RoomWizard du même groupe. Utile pour avoir l’adresse IP de tous les appareils de l’étage!

http://rwdevice/getGroupTimeLineJSON.action?date=20140114

Mot de la fin

J’espère qu’il s’agit ici d’un problème de configuration mais j’en doute. SteelCase ne devrait tout simplement pas utiliser le navigateur du client pour faire ses opérations et tout faire côté serveur.

Entre temps, je ne devrais pas non plus avoir accès à ces appareils à partir du réseau des employés. Les RoomWizard devraient au moins avoir leur propre VLAN isolé, tout comme les téléphones IP et les photocopieurs.

Je ne suis pas le premier qui s’intéresse à ces choses.

Je suis convaincu que quelque part, une réceptionniste est en train de devenir folle parce que quelqu’un s’amuse à faire disparaitre toutes les réservations de l’étage aléatoirement sans raison apparente ou en faisant afficher du texte douteux sur les appareils.

Maintenant que vous savez, ne le faites pas et gardez ça en tête lors de votre prochain déménagement.

Si vous tenez un concours sur le web sans rien valider…

Contexte: Je suis finaliste pour le semi-concours Musique Plus “Geek Recherché” où le public est invité à influencer les juges en votant pour leur geek préféré.

Projet: Automatiser des votes, parce que je me dis que ça serait amusant et que c’est une façon comme une autre de prouver le geekness.

Analyse

2013-10-22 09-54-23On commence par vérifier quels appels JavaScript sont faits au moment où on clique sur le bouton pour voter à l’aide des “Developpers Tools” de Google Chrome (F12). On identifie alors 3 URL:

  • Gigya, un tiers parti qui fait de l’intégration sociale et qui expose un API bien documenté
  • M+ Backend, qui nous indique par le nom de la méthode qu’on a affaire à Atex Web CMS. L’étude de cas qu’ils ont réalisée pour Astral est une bonne lecture.
  • M+ Vote qui est juste un .php*

En faisant la même requête une deuxième fois, on remarque que certains paramètres changent d’une session à l’autre. Cela pourrait poser problème puisqu’il faut idéalement être capable de recréer la requête au complet.

Dans notre cas, on parle des paramètres “callback” et “_” des appels vers M+. Parce qu’on est vraiment geek et qu’on sait ces choses-là, on peut tout de suite ignorer callback parce que c’est un appel de retour pour jQuery. “_”, quant à lui, est en fait l’heure Unix (ou le epoch time) actuelle.

*Quand on a codé le jeudi 17 octobre, il n’y avait que deux appels. Je me suis rendu compte qu’ils avaient ajouté un troisième appel vers vote.musiqueplus.com en écrivant ce billet.

Solution 1

blobbChristof Graf a été le premier à arriver à une solution. Il a créé un petit programme en C# qui automatise les appels aux URLs en faisant varier la durée entre chaque appel. Il dirige alors son trafic vers le réseau TOR, qui anonymise le trafic et change d’adresse IP toutes les 10 minutes.  Cela a pour effet que M+ voit que les votes générés viennent d’adresses IP différentes et peut plus difficilement éliminer ces votes.

Défense: Retirer les votes où les IPs correspondent avec des TOR exit node.

Solution 2

J’ai moi-même écrit quelque chose de semblable en Python. Ma méthode utilise une liste de proxy et vote une fois pour chaque proxy.

Défense: Retirer les votes où les IPs correspondent avec des serveurs proxy ou juste retirer tous les IPs ne venant pas du Canada (je ne suis pas si populaire que ça en Chine).

Solution 3

mctraffic_code2SynneR y est allé un peu plus méchant, en utilisant une plateforme de publicité en ligne qui permet d’y insérer son propre html, McTraffics. Mais même si seuls les tags <img> et <a> sont permis, on peut quand même faire des appels vers des ressources JavaScript si les paramètres ne changent pas.

La méthode de SynneR a l’avantage d’utiliser des vraies machines avec des vrais IPs venant du Québec (et non pas des IPs potentiellement listés comme louche parce qu’on y trouve des web proxy ou des TOR exit node, contrairement à Chris et moi).

Défense: Ajouter un jeton anti-CSRF aux requêtes.

Dans tous les cas, nous n’avons pas pris la peine de modifier le paramètre “_” pour changer l’heure de nos votes. Alors assumant que M+ enregistre tous les paramètres lors du vote, tous les votes qui ont 1382063817115 ou 1382063676307 comme date/heure (au millième de seconde près) ne sont pas légitimes.

Conclusion

Ça nous semblait une belle opportunité de montrer que nous sommes geek. Ça n’est pas méchant: j’en parle, je documente, le vote des autres n’a pas été trafiqué et nous n’avons pas causés d’attaques de déni de service. Juste un petit projet entre chums un jeudi soir: rien de bien grave, quoi.

On en profite pour sensibiliser les gens au sujet des risques associés à exécuter un tel évènement sur Internet. Les futurs concours organisés par Musique Plus n’en seront que plus représentatifs. Au cours des prochains jours, je travaillerai avec M+ pour mitiger ce type “d’attaque” à l’avenir. Le code source des trois méthodes sera éventuellement rendu disponible.

À suivre…

Mises à jour

Comment je me sens comparé à mes collègues qui font carrière en sécurité

Comment je me sens comparé à mes collègues qui font carrière en sécurité

2013-10-24 13:05
J’ai envoyé un courriel au service de l’auditoire de Musique Plus pour leur demander si ils étaient intéressés à jaser pour mitiger un peu ce qu’on a fait avant que je libère le code. Je mentionne la politique de Rain Forest Puppy.

2013-10-24 14:07
“Votre message a été transféré aux personnes concernées.”

2013-10-31 17:00
Le “mainteneur” chez M+ ne m’a toujours pas contacté. Le code source qui a rendu ce billet possible est maintenant disponible.

CISSP Groupies @ Plaid CTF

I was invited by Montréal computer security team CISSP Groupies to participate in the Plaid CTF hosted by Plaid Parliament of Pwning (PPP).

While not a security guru or 31337 h4x0r like most of my teammates, I’m very interested in computer security and was really excited about this competition.

We finished 31st which is lower than what the team is used to, but we did represent Canada by being well ahead of our country’s second team (yay! first in Canada! :P).

Props to the Groupies, the PPP team, Foulab and everyone who participated in this CTF! I had a blast, learned a lot and can’t wait for the next event! 😀

Challenges

View the challenges

Download the challenge files

Photo Gallery

Time Lapse

Plaid CTF “Torrents” write-up

Note

This post is about a challenge from the Plaid CTF computer security competition. Check out this blog post for more information about the competition in general.

Challenge (200)

It turns out that robots, like humans, are cheap and do not like paying for their movies and music. We were able to intercept some torrent downloads but are unsure what the file being downloaded was. Can you figure it out?

The file is a wireshark capture containing a torrent transfer between 2 peers. We had to extract the data inside the pieces and sort them in the right order.

Solution

My solution is not as pretty as Squall’s or Michael’s but I’m pretty sure I’m the only one crazy enough that did it with Powershell instead of Python.

[powershell]# Ask tshark
$raw= &amp; ‘tshark.exe’ -r torrent.pcap -R ‘bittorrent.piece.data’ -T fields -e bittorrent.piece.index -e bittorrent.piece.data -E separator=/s

# Split into pieces
$data = @{}
$raw -split ‘[nn]’ | ForEach-Object {
$packet = $_ -split ‘ ‘
if ($data.ContainsKey($packet[0])) { # There are 2 packets for each piece so we concat them here
$data.set_Item($packet[0], (‘{0}:{1}’ -f $data.get_Item($packet[0]), $packet[1]))
} else {
$data.Add($packet[0], $packet[1])
}
}

# Sort and concat
$HexString = [String] ”
$data.GetEnumerator() | Sort-Object Name | Select-Object Value | ForEach-Object {
$HexString += (‘{0}:’) -f $_.Value
}

# Convert hex to byte
$count = $hexString.Length
$byteCount = $count/3
$bytes = New-Object byte[] $byteCount
$byte = $null

$x = 0
for ( $i = 0; $i -le $count-1; $i+=3 )
{
$bytes[$x] = [Byte]::Parse($hexString.Substring($i,2), [System.Globalization.NumberStyles]::HexNumber)
$x += 1
}

# Write in a file
set-content -encoding byte ‘output’ -value $bytes[/powershell]

It was a bzipped file with a mp3 and a key containing the answer: t0renz0_v0n_m4tt3rh0rn.
Fun was had.