Short review of the KeyGrabber USB keylogger

keygrapper © keelog.comFew days ago I've bought a USB keylogger to use on my own computers (explanation in french here). Since then, and as I'm sitting in front of a computer more than 12 hours a day, I've got plenty of time to test it.
The exact model I've tested is the KeyGrabber USB MPC 8GB. I've had to choose the MPC model because both my current keyboards are Apple's Aluminum keyboards. They act as USB hubs, hence requiring some sort of filtering so that the keylogger won't try and log everything passing through the hub (mouse, usb headset, whatever…) and will get only what you type.
My setup is close to factory settings: I've just set LogSpecialKeys to "full" instead of "medium" and added a French layout to the keylogger, so that typing "a" will record "a", and not "q".

First of all, using the device on a Mac with a French Apple keyboard is a little bit frustrating: the French layout is for a PC keyboard, so typing alt-shift-( to get a [ will log [Alt][Sh][Up]. "[Up]"? Seriously? The only Macintosh layout available is for a US keyboard, so it's unusable here.

The KeyGrabber has a nice feature, especially on it's MPC version, that allows the user to transform the device into a USB thumbdrive with a key combination. By default if you press k-b-s the USB key is activated and mounts on your system desktop. The MPC version allows you to continue using your keyboard without having to plug it on another USB port after activation of the thumbdrive mode, which is great. You can then retrieve the log file, edit the config file, etc.
Going back to regular mode requires that you unplug and plug back the KeyGrabber.
Applying the "kbs" key combo needs some patience: press all three keys for about 5 seconds, wait about 15-20 seconds more, and the thumbdrive could show up. If it does not, try again. I've not tested it on Windows, but I'm not very optimistic, see below.

I'm using a quite special physical and logical setup on my home workstation. Basically, it's an ESXi hypervisor hosting a bunch of virtual machines. Two of these VM are extensively using PCI passthrough: dedicated GPU, audio controller, USB host controller. Different USB controllers are plugged to a USB switch, so I can share my mouse, keyboard, yubikey, USB headset, etc. between different VMs. Then, the KeyGrabber being plugged between the keyboard and the USB switch, it's shared between VMs too.
Unfortunately, for an unidentified reason, the Windows 10 VM will completely loose it's USB controller few seconds after I've switched USB devices from OSX to Windows. So for now on, I have to unplug the keylogger when I want to use the Windows VM, and that's a bummer. Being able to use a single device on my many systems was one of the reasons I've opted for a physical keylogger, instead of a piece of software.
Worse: rebooting the VM will not restore access to the USB controller, I have to reboot the ESXi. A real pain.

But in the end, it's the log file that matters, right? Well, it's a bit difficult here too, I'm afraid. I've contacted the support at Keelog, because way too often what I see in the log file does not match what I type. I'm not a fast typist, say about 50 to 55 words per minute. But it looks like it's too fast for the KeyGrabber which will happily drop letters, up to 4 letters in a 6 letters word (typed "jambon", logged "jb").
Here is a made-up phrase I've typed as a test:

c'est assez marrant parce qu'il ne me faut pas de modèle pour taper

And here is the result as logged by the device:

cesae assez ma[Alt][Ent][Alt]
rrant parc qu'l ne e faut pa de modèl pour taper

This can't be good. May be it's a matter of settings, some are not clearly described in the documentation, so I'm waiting for the vendor support to reply.

Overall, I'm not thrilled by this device. It's a 75€ gadget that won't work properly out of the box, and will crash my Win 10 system (and probably a part of the underlying ESXi). I'll update this post if the support helps me to achieve proper key logging.

Related posts

Install Fast Incident Response (FIR) on FreeBSD

FIR login screen FIR is a web application designed by CERT Société Générale. It's coded in Python and uses Django.

Installation as documented uses Nginx and pip, two tools I'm not using. I already run several Apache servers, and I do prefer relying on pkg for software installation. For me, pip is more a developer tool: very convenient with virtualenv but not what I would use for production.
If you want to use pip, just go with the official documentation :)

So on a FreeBSD 11.2-RELEASE server, you need to install all required packages. Be careful, py27-MySQLdb uses mysql56-server, not mysql57-server, and FIR works with Python 2.7, not 3.x (as far as I can say).

$ sudo pkg install gettext mysql56-server py27-pip py27-virtualenv git apache24 uwsgi py27-MySQLdb py27-django py27-cssselect py27-django-filter py27-djangorestframework py27-flup6 py27-gunicorn py27-lxml py27-markdown py27-pymongo py27-pyquery py27-dateutil py27-pytz py27-six py27-django-treebeard py27-markdown2 py27-bleach py27-python-gettext

Add those lines to /etc/rc.conf:

mysql_enable="yes"
uwsgi_enable="yes"
apache24_enable="yes"

The requirement list includes dj-database-url and whitenoise, but I was not able to find them in FreeBSD's packages. I've just ignored them and everything seems to work fine.
If needed, sudo pip install… should do the trick.

Follow the documentation:
- configure MySQL
- install FIR without virtualenv (in /usr/local/www for example)
- create and tune production.py
- create installed_apps.txt (you do want the plugins)
- create tables in the db
- create the admin user
- populate the db
- collect static files

On FreeBSD we run uwsgi as a service, under uwsgi UID. So chown must reflect that:

$ sudo chown uwsgi logs/errors.log uploads
$ sudo chmod 750 logs/errors.log uploads

Skip the uWSGI section of the documentation. Instead, create config file for uwsgi with this content:

$ cat /usr/local/etc/uwsgi/uwsgi.ini
[uwsgi]
chdir = /usr/local/www/FIR
module = fir.wsgi

You can now start the service:

$ sudo service uwsgi start

Then, skip the nginx part, and go configure Apache:

- load proxy_module and proxy_uwsgi_module in httpd.conf
- add the following to the relevant part of Apache configuration:

# FIR
ProxyPass /FIR unix:/tmp/uwsgi.sock|uwsgi://usr/local/www/FIR
Alias /files/ /usr/local/www/FIR/files/
Alias /static/ /usr/local/www/FIR/static/
<Directory /usr/local/www/FIR/static>
	Require all granted
</Directory>
<Directory /usr/local/www/FIR/files>
	Require all granted
</Directory>

Restart Apache: you're all set, point your browser to https://your-server/FIR/

Related posts

Écriture inclusive et risques de sécurité

Je ne vais pas rentrer dans le débat du pour ou contre l’écriture inclusive. Mon propos est ici d’étudier l’impact d’une forme de graphie utilisée dans le cadre de l’écriture inclusive française sur la sécurité des systèmes d’information.

Il existe différentes formes ou manière de faire de l’écriture inclusive, utilisant différents artifices typographiques. Malheureusement, une des formes les plus élémentaires - celle qui utilise le point de ponctuation pour séparer les blocs - crée parfois des noms de domaines, comme par exemple : enseignant.es, doctorant.es, etc.

L’auteur d’un texte rédigé avec cette forme d’écriture inclusive peut donc se trouver rapidement à truffer sa prose de noms de domaine espagnols. Dans le cas d’un support totalement maîtrisé comme le papier ou l’image, l’impact est faible car le texte n’est pas immédiatement accessible à la machine. Il faudrait opérer une reconnaissance optique de caractère pour retrouver un texte électronique exploitable.

Malheureusement pour cette forme d’écriture, les supports numériques prévalent de plus en plus, et la maîtrise du support disparaît presque totalement au profit d’intermédiaires, de médias, qui peuvent décider d’améliorer l’expérience utilisateur sans demander son avis à l’auteur initial. Que cet intermédiaire soit un logiciel bureautique, un CMS, une plateforme de réseau social, une application de SMS, une messagerie instantanée, etc. nombreux sont ceux qui vont s’arroger le droit d’activer les URL qu’ils détectent dans les contenus soumis. Ainsi, quand un auteur écrit que « les étudiant.es peuvent se porter candidat.es au concours d’infirmier.es », il est bien possible que le média de publication informe les lecteurs que « les étudiant.es peuvent se porter candidat.es au concours d’infirmier.es ». La différence est de taille : les mots suffixés en .es sont devenus des URL actives.

Qui dit URL actives dit aussi : téléchargement d’un aperçu, possibilité de clic volontaire ou non sur une de ces URL, et dans des cas rares de vulnérabilité logicielle, possibilité de téléchargement de l’URL sans clic de la part du lecteur.

À titre de démonstration et d'expérience j'ai personnellement enregistré les noms étudiant.es et enseignant.es, puis je les ai faits pointer sur une page web que je maîtrise pour mesurer le comportement des utilisateurs en présence de ces noms de domaines. Sur une période de 31 jours, je mesure 5265 requêtes GET tous visiteurs confondus (avec une majorité de robots donc). Sur la même période, je mesure environ 350 visiteurs réels, soit plus de 10 par jour en moyenne, et avec un pic à 54 visiteurs un jour particulier.

Nombre de "GET" par jour sur étudiant.es et enseignant.es

Nombre de "GET" par jour sur étudiant.es et enseignant.es


Estimation du nombre de "vrais visiteurs" par jour sur étudiant.es et enseignant.es


Les traces sur le serveur web montrent aussi qu'un grand nombre des requêtes de robots sont faites par des plateformes de réseau social, au moment où ces plateformes analysent le lien posté par l'utilisateur (création de l'aperçu, de l'URL raccourcie, détection de malware, analyse du contenu promu par l'utilisateur, etc.). Par exemple : Twitterbot, Facebookbot, EveryoneSocialBot, et autres.

L’URL ainsi activée va en général se retrouver sur des supports largement diffusés. On peut penser notamment à un CMS d’institution, mais aussi à des documents PDF, des emails, des messages diffusés sur des plateformes de réseau social comme Facebook, Twitter, Linked’In. Dans une grande université française, un seul auteur peut ainsi toucher directement 20000 à 60000 individus, et indirectement bien plus.

Il est donc normal dans un tel contexte d’envisager ce qu’il se passerait si par exemple quelqu’un décidait d’enregistrer tout ou partie de ces noms de domaines espagnols pour faire des choses avec :

  • Faire du profit (affichage de publicité, vente de contrefaçon, pornographie, etc.)
  • Attaquer les lecteurs de certains contenus en distribuant des malwares
  • Lancer une campagne de phishing contre les lecteurs de ces contenus
  • Porter atteinte à l’image de l’auteur (incitation à la haine, diffamation, etc.)

L’attaque en elle-même est extrêmement simple et économique. La location d’un nom de domaine à l’année coûte une poignée d’euros, et la plupart de ces mots français sont disponibles en .es. Par ailleurs, elle peut se produire à tout moment, et le plus tard est même le mieux : plus le nom de domaine est répandu, plus il est diffusé largement et dans un grand nombre de documents et supports, plus son exploitation devient intéressante.

Comme évoqué ci-dessus, les motivations de l’attaquant peuvent être diverses, néanmoins les effets de l’attaque sur l’auteur ou sur son entreprise/institution sont toujours les mêmes. Inévitablement il se produit un dégât d’image : personne ne trouverait normal en cliquant sur le mot canditat.es dans une communication officielle d’entreprise d’arriver sur un site pornographique (sauf bien évidemment si cette entreprise gère le site en question). Idem si le lecteur voit son antivirus passer au rouge suite à un clic sur infirmier.es.

Ensuite, il peut se produire une perte pour l’entreprise ou pour l’auteur : perte de temps et d’argent car il faut rapidement neutraliser les documents ou les URL dans les documents publiés. Cette opération curative est indispensable, mais impossible en pratique à faire en totalité : en effet il est impossible d’aller modifier les emails déjà envoyés, les documents PDF ou bureautique déjà téléchargés par le public, les SMS, etc.

Si l’attaquant a choisi une posture très offensive en faisant pointer les URL vers des malwares, alors l’auteur des contenus entre dans un nouveau cercle des Enfers : il pourra être amené à découvrir ce qu’il se produit lorsque Google décide de faire disparaître son site web des résultats de recherche, ce qu’il se produit quand tous les antispam de la planète décident de bloquer les emails qu’il envoie. Le blocage ne sera pas immédiat bien sûr, laissant à l’attaquant une fenêtre de tir pendant laquelle il pourra infecter d’innocents lecteurs. D’une pierre deux coups, en quelques sortes. Je n’ai pas de certitude sur le comportement des réseaux sociaux dans ce cas de figure, mais il est possible que certains décident de supprimer les messages contenant des liens vers des malwares, que d'autres suspendent le compte de l'auteur. Autant dire que tout à coup, les choses vont devenir très compliquées pour l’auteur.

À mon avis, il y a ici un risque qui vaut la peine d'être pris en compte. Même si on constate que le nombre de clics volontaires ou non sur ces liens automatiques est relativement faible, il reste très largement supérieur au "taux de conversion" habituel d'une campagne de phishing par email. Et nous protégeons tous nos utilisateurs contre le phishing, n'est-ce pas ?
Ici l'attaque part d'un support légitime, réellement écrit par son auteur : il ne s'agit pas d'un faux message de votre Support utilisateur écrit dans un français approximatif. Non, il s'agit de transformer des contenus légitimes en vecteur d'attaque sans même avoir besoin de modifier ces contenus.

À méditer.

Related posts

My take on the MySpace dump

About a year ago, a full MySpace data breach dump surfaced on the average-Joe Internet. This huge dump (15 GiB compressed) is very interesting because many user accounts have two different password hashes. The first hash is non-salted, and represents a lower-cased, striped to 10 characters, version of the user original password. The second hash, not always present, is salted, and represents the full original user password.
Hence, the dump content can be summarized by this :

id : email : id/username : sha1(strtolower(substr($pass, 0, 9))) : sha1($id . $pass) 

It contains about 116.8 million unique unsalted sha1 hashes, and about 68.5 million salted sha1 hashes.

Of course, people who crack passwords will tell you that the unsalted hashes have no value, because then don't represent real user passwords. They are right. But when you crack those hashes you have a very interesting password candidate to crack the salted hashes. And this is very interesting!

After you cracked most of unsalted hashes, the question is: how do you proceed to crack their salted counterpart? Spoiler alert: hashcat on an Nvidia GTX 1080 is more than 200 times slower than John the Ripper on a single CPU core on this very particular job.

I'm a long time John the Ripper user (on CPU), and I'm pretty fan of it's intelligent design. Working on CPU requires wits and planing. And the more versatile your software is, the more efficient you can be. Hashcat sits on the other end of the spectrum: huge raw power thanks to GPU optimization. But it lacks the most sensible attack mode: "single".

Single mode works by computing password candidates from GECOS data like login, user name, email address, etc. So it makes sense to provide a full password file to JtR, instead of just naked hashes. These passwords metadata are very efficient when you want to create contextual password candidates.
The password retrieved from unsalted hash is more than a clue to retrieve its salted counterpart, in many case it's also the real user password. And when it's not, simple variations handled by mangling rules will do the trick.
You've probably guessed by now: I've created a file where password cracked from non-salted hashes are paired with the corresponding salted hash. The known password impersonate the user login, so that with proper tuning John the Ripper will try only this particular candidate against the corresponding salted hash.
Because of a bug in JtR, I was not able to use this attack on a huge file, I had to split it into small chucks. Nevertheless, I was able to retrieve 36708130 passwords in just 87 minutes. On a single CPU core.
In order to find those passwords with hashcat, I had to rely on a wordlist attack with on a GTX 1080. It took about 14 days to complete. No matter how fast your GPU is (about 1000 MH/s in that particular case), it will brainlessly try every single candidate on every single hash. Remember hashes are salted, so each one requires its own computation. If your file is 60M hashes long, then your GPU will only try 16.6 candidates per second (1000/60). It's very slow and inefficient.

Hashcat performance on a file containing 50% of total hashes.

Sometime, brain is better than raw power. Thank you John ;)

More on this topic:
https://hashes.org/forum/viewtopic.php?t=1715
http://cynosureprime.blogspot.fr/2016/07/myspace-hashes-length-10-and-beyond.html

Related posts

Self-hosted password manager: installing Passbolt on FreeBSD

Arthur Duarte CC-BY-SA-4.0

Arthur Duarte CC-BY-SA-4.0

Password managers, or password safes, are an important thing these days. With the constant pressure we (IT people) put our users under to setup a different password for every single registration/application/web site, it's the best, if not only, way to keep track of these secrets. On one hand, the isolated client-side software can be really powerful and/or well integrated with the OS or the software ecosystem of the user, but it lacks the modern touch of "cloud" that makes your data available anywhere and anytime. On the other hand, a full commercial package will come with client for every device you own, and a monthly fee for cloud synchronization, but you have absolutely no control over your data (just imagine that tomorrow the company you rely on goes bankrupt).
Better safe than sorry: I don't rely on cloud services. It comes at a cost, but it's quite rewarding to show the world another way exists.
Disclaimer: I don't give a sh*t about smartphones, so my needs are computer-centric.

In order to store passwords, and more generally speaking "secrets", in such a way that I can access them anywhere/anytime, I've tried Passbolt. Passbolt is an OpenSource self-hosted password manager, written in PHP/Javascript with a database back end. Hence, install and config are not for the average Joe. On the user side it's quite clean and surprisingly stable for alpha software. So once a LAMP admin has finished installing the server part, any non-skilled user can register and start storing passwords.

Enough chit-chat, let's install.

My initial setup was a vanilla FreeBSD 10.3 install, so I've had to make everything. I won't replay every single step here, especially on the configuration side.

Prerequisites:

pkg install apache24
pkg install mod_php56
pkg install php56-gd
pkg install pecl-memcached
pkg install mysql57-server
pkg install pecl-gnupg
pkg install git
pkg install php56-pdo_mysql
pkg install sudo
pkg install php56-openssl
pkg install php56-ctype
pkg install php56-filter

Everything else should come as a dependency.

Tuning:

Apache must allow .htaccess, so you'll have to put an AllowOverride All somewhere in your configuration. You must also load the Rewrite module. Also, go now for SSL (letsencrypt is free and supported). Non-SSL install of Passbolt are for demo purpose only.
Apache will also need to execute gnupg commands, meaning the www user needs an extended $PATH. The Apache startup script provided on FreeBSD sources Apache environment variables from /usr/local/sbin/envvars and this very file sources every /usr/local/etc/apache24/envvars.d/*.env, so I've created mine:

$ cat /usr/local/etc/apache24/envvars.d/path.env
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin

You also need to tune your MySQL server. If you choose the 5.7, you must edit it's configuration. Just add the following line into [mysqld] section of /usr/local/etc/mysql/my.cnf:

sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

This is due to a bug in Passbolt and could be useless in a not to distant future.

Install recipe:

You can now follow the install recipe at https://www.passbolt.com/help/tech/install.
Generating the GPG key is quite straightforward but you have to keep in mind that Apache's user (www) will need access to the keyring. So if you create this key and keyring with a different user, you'll have to mv and chown -R www the full .gnupg directory somewhere www can read it (outside DocumentRoot is perfectly fine).

Use git to retrieve the application code into appropriate path (according to your Apache config):

cd /usr/local/www
git clone https://github.com/passbolt/passbolt.git

Edit php files as per the documentation.

Beware the install script: make sure you chown -R www the whole passbolt directory before using cake install.
On FreeBSD you won't be able to use su to run the install script, because www's account is locked. You can use sudo instead:

sudo -u www app/Console/cake install --no-admin

Same for the admin account creation:

sudo -u www app/Console/cake passbolt register_user -u patpro@example.com -f Pat -l Pro -r admin

Follow the end of the install doc, and you should be ok. Install the Firefox passbolt extension into your browser, and point to your server.

I'm pretty happy with passbolt so far. I'll have to install a proper production server, with SSL and all, but features are very appealing, the passbolt team is nice and responsive, and the roadmap is loaded with killing features. Yeah BRING ME 2FA \o/.

Related posts

Cracking passwords: testing PCFG password guess generator

Cracking passwords is a kind of e-sport, really. There's competition among amateurs and professionals "players", tools, gear. There are secrets, home-made recipes, software helpers, etc.
One of this software is PCFG password guess generator, for "Probabilistic Context-Free Grammar". I won't explain the concept of PCFG, some scientific literature exists you can read to discover all the math inside.
PCFG password guess generator comes as two main python programs: pcfg_trainer.py and pcfg_manager.py. Basic mechanism is the following:
- you feed pcfg_trainer.py with enough known passwords to generate comprehensive rules describing the grammar of known passwords, and supposedly unknown passwords too.
- you run pcfg_manager.py, using previously created grammar, to create millions of password candidates to feed into your favorite password cracker (John the Ripper, Hashcat…).

In order to measure PCFG password guess generator's efficiency I've made few tests. Here is my setup:

  • Huge password dump, 117205873 accounts with 61829207 unique Raw-SHA1 hashes;
  • John the Ripper, Bleeding Jumbo, downloaded 20160728, compiled on FreeBSD 10.x;
  • PCFG password guess generator, downloaded 20160801, launched with Python 3.x;

Here's my methodology:

Of these 61829207 hashes, about 35 millions are already cracked. I've extracted a random sample of 2 millions known passwords to feed the trainer. Then I've used pcfg_manager.py to create a 10 millions lines word list. I've also trimmed the famous Rockyou list to it's 10 millions first lines, to provide a known reference.

Finally, I've launched this shell script:

#!/bin/sh
for i in none wordlist jumbo; do
  ./john --wordlist=pcfg_crckr --rules=$i --session=pcfg_cracker-$i --pot=pcfg_cracker-$i.pot HugeDump
  ./john --wordlist=ry10m --rules=$i --session=ry10m-$i --pot=ry10m-$i.pot HugeDump
done

No forking, I'm running on one CPU core here. Each word list is tested three times, with no word mangling rules, with defaults JtR rules, and finally with Jumbo mangling rules.

Some results (number of cracked passwords):

Rules PCFG Rockyou
none 4409362 2774971
wordlist 5705502 5005889
Jumbo 21146209 22781889

That I can translate into efficiency, where efficiency is Cracked/WordlistLength as percentage:

Rules PCFG Rockyou
none 44.1% 27.7%
wordlist 57.1% 50.1%
Jumbo 211.5% 227.8%

It's quite interesting to see that the PCFG generated word list has a very good efficiency, compared to Rockyou list, when no rules are involved. That's to be expected, as PCFG password guess generator has been trained with a quite large sample of known passwords from the same dump I am attacking.
Also, the PCFG password guess generator creates candidates that are not very well suited for mangling, and only the jumbo set of rules achieves good results with this source. Rockyou on the other hand starts quite low with only 27.7% but jumps to 50.1% with common rules, and finally defeats PCFG when used with jumbo rules.

On the word list side, Rockyou is known and limited: it will never grow. But PCFG password guess generator looks like it can create an infinite list of candidates. Let see what happens when I create a list of +110 M candidates and feed them to JtR.

Rules PCFG Efficiency
none 9703571 8.8%
wordlist 10815243 9.8%

Efficiency plummets: only 9.7 M hashes cracked with a list of 110398024 candidates, and only 1.1 M more when the set of rules "wordlist" is applied. It's even less beneficial than with a list of 10 M candidates (+1.3 M with "wordlist" rules, compared to "none").

On the result side, both word list with jumbo rules yields to +21 M cracked passwords. But are those passwords identical, or different?

Rules Total unique cracked Yield
none 6013896 83.7%
wordlist 8184166 76.4%
Jumbo 26841735 61.1%
Yield = UniqueCracked / (PcfgCracked + RockyouCracked)

A high yield basically says that you should run both word lists into John. A yield of 50% means that all pwd cracked thanks to PCFG are identical to those cracked with the Rockyou list.

As a conclusion, I would say that the PCFG password guess generator is a very interesting tool, as it provides a way to generate valid candidates pretty easily. You probably still need a proper known passwords corpus to train it.
It's also very efficient with no rules at all, compared to the Rockyou list. That might make it a good tool for very slow hashes when you can't afford to try thousands of mangling rules on each candidate.

Some graphs to illustrate this post:

every john session on the same graph

every john session on the same graph

every session, zoomed on the first 2 minutes

every session, zoomed on the first 2 minutes

Rules "wordlist" on both lists of candidates

Rules "wordlist" on both lists of candidates

Rules "none", both lists of candidates

Rules "none", both lists of candidates

Related posts

Monter un serveur d’authentification multifacteur 3/3

insertedDans deux articles précédents j'ai présenté la création d'un serveur de validation YK-VAL et d'un serveur de clé YK-KSM permettant de créer une infrastructure d'authentification double facteur basée sur Yubico OTP.

Dans ce dernier article je vais détailler quelques étapes importantes pour connecter un client, toujours en FreeBSD 10.3. Dans ce contexte, le client est en fait un service authentifié (un serveur sshd par exemple).

Prérequis

À ce stade, posséder une Yubikey dont vous pourrez configurer un des slots est impératif. Il est aussi pertinent de télécharger sur votre poste le Yubikey Personalization Tool. Et il vous faut bien évidemment une machine sous FreeBSD 10.x qui servira de serveur sshd.

Générer une clé d'API

La validation d'une authentification par OTP Yubico requière que l'utilisateur fournisse un OTP reconnu, c'est à dire que sa Yubikey soit enregistrée dans le YK-KSM, et que l'OTP envoyé soit valide. Il est aussi nécessaire que la connexion entre le client (ici sshd+pam) et le serveur YK-VAL soit "authentifiée" par une clé d'API.

Dans l'idéal, chaque client individuel doit disposer de sa propre clé d'API, c'est plus sûr. Et même si cela peut occasionner des lourdeurs, cela permet de révoquer une clé d'API sans mettre par terre l'ensemble des clients.

La première étape pour ajouter un client dans l'infrastructure est donc de créer une clé d'API. Pour cela, il faut se connecter sur le serveur YK-VAL, et lancer la commande suivante :

ykval-gen-clients --urandom --notes "client de test 1"
1,VI5eTtCSAjdmp473G3rWFq+pL1k=

Cette commande vous donne en résultat une clé d'API, associée au client "1". La clé d'API et les informations connexes sont injectées dans la base de données du serveur YK-VAL.

Enregistrer une Yubikey

Chaque Yubikey compatible Yubico OTP dispose de deux slots de configuration. Le premier est réglé par défaut sur Yubico OTP, mais il est impossible d'en extraire la clé privée de chiffrement (configuration d'usine). Cette clé est enregistrée dans le YK-KSM des serveurs yubico.com, donc elle est opérationnelle si vous souhaitez l'utiliser pour vous authentifier sur des services qui s'appuient sur le cloud de yubico.com. Nous souhaitons nous appuyer sur notre propre infrastructure privative, donc cette clé n'est pas utilisable.
Si vous souhaitez conserver cette clé initiale, vous devrez créer une nouvelle clé privée sur le slot 2 de votre Yubikey (et je vous y encourage). Si vous êtes sûr de ne pas en avoir l'usage, vous pouvez simplement écraser le slot 1 de la Yubikey avec votre nouvelle clé privée. Sachez que l'écrasement d'un slot est irréversible : la clé privée fournie par Yubico sera définitivement perdue.

Ceci posé, vous pouvez connecter votre Yubikey à votre machine, et lancer le Yubikey Personalization Tool.
Dans l'interface, choisissez le premier onglet en haut à gauche "Yubico OTP", et cliquez sur "Quick".
La fenêtre ci-dessous est affichée :
- choisissez le slot 1 (écrasement de la configuration d'usine) ou le slot 2 (vierge)
- décochez la case "Hide values"
- copiez précieusement les chaînes de caractères des trois champs, ainsi que le serial number au format décimal ("Dec") qui se trouve au milieu à droite de la fenêtre.

Yubico Personalization Tool

Il s'agit ensuite d'enregistrer ces informations dans la base de données du YK-KSM. Dans le cadre de ces tests, j'ai simplement injecté la clé à la main dans MySQL :

INSERT INTO yubikeys VALUES (4263215,"vvgrneginvdf","","578fba7ca791","fd69d1ecc644f36dde9dfc742cf2e3fa","00000000","",1,1);

Les champs sont dans l'ordre d'apparence : le numéro de série "Dec" de votre clé physique, la date de création (non renseignée), la "Public Identity" de votre clé de chiffrement, la "Private Identity" de votre clé de chiffrement, et enfin la "Secret Key". Les champs suivants sont "lockcode", "creator" (vide), "active" et "hardware". Laissez-les simplement comme présenté ci-dessus.

Dès que vous avez procédé à l'insertion, vous pouvez tester que la clé est bien reconnue par le serveur YK-KSM. Générez un OTP avec votre clé en appuyant un court instant sur le bouton si vous utilisez le slot 1, ou 2-3 secondes si vous utilisez le slot 2 (placez au préalable votre curseur dans un document txt).
Ensuite tapez la commande suivante sur le serveur YK-KSM :

curl 'http://localhost/wsapi/decrypt?otp=vvgrneginvdfddffbdhgefnrdtgcrnntccchndebhdiv'

ou vvgrneginvdfddffbdhgefnrdtgcrnntccchndebhdiv est l'OTP que vient de générer votre clé.
Vous obtiendrez alors la réponse suivante :

OK counter=0001 low=8250 high=45 use=02

Vous pouvez ensuite tester que votre Yubikey passe bien la validation de bout en bout. À partir d'un terminal sur YK-VAL, lancez la commande suivante :

ykclient --url "http://127.0.0.1/wsapi/2.0/verify" --apikey VI5eTtCSAjdmp473G3rWFq+pL1k= 1 vvgrneginvdfihrudhtffnjigivctkujtfjlkiniideg --debug

L'argument --apikey doit être suivi de la clé d'API que vous avez générée plus haut. Elle est suivit d'un espace, puis du numéro d'ID du client que vous avez inséré (et donné dans la sortie de la commande ykval-gen-clients). À la suite de ce client ID, on injecte un OTP, et éventuellement l'argument --debug.

Si tout va bien, vous devez obtenir dans la sortie :

Input:
  validation URL: http://127.0.0.1/wsapi/2.0/verify
  client id: 1
  token: vvgrneginvdfihrudhtffnjigivctkujtfjlkiniideg
  api key: VI5eTtCSAjdmp473G3rWFq+pL1k=
Verification output (0): Success

Configuration du client

Pour brancher un serveur sshd sur une infrastructure d'authentification double facteur, le plus simple est en général d'utiliser un plugin PAM. Sur FreeBSD, on peut en quelques secondes installer le nécessaire :

pkg install pam_yubico

Ce plugin s'appuie sur deux choses : l'URL de votre service YK-VAL, et une liste qui associe les logins des utilisateurs avec une clé ("Public Identity").
Vous pouvez créer le fichier qui associe l'uid UNIX à la "Public Identity" très simplement :

cat "patpro:vvgrneginvdf" >> /etc/yubikey

Puis dans /etc/pam.d/sshd il faut ajouter la directive qui permettra à PAM de faire la requête vers YK-VAL. La ligne suivante doit être ajoutée :

auth      required      /usr/local/lib/security/pam_yubico.so mode=client authfile=/etc/yubikey id=1 key=VI5eTtCSAjdmp473G3rWFq+pL1k= url=http://192.168.0.100/wsapi/2.0/verify?id=%d&otp=%s

juste au dessus de la ligne :

auth      required      pam_unix.so     no_warn try_first_pass

authfile pointe vers votre fichier associant uid et clé OTP, id est la Client ID créée lors de l'ajout du client sur YK-VAL, key est la clé d'API associée à ce client. Pour finir, url est l'adresse du service de vérification sur YK-VAL. On peut tout à fait inscrire le nom du serveur YK-VAL dans l'URL à la place de son adresse IP, néanmoins en cas d'avarie du DNS il est souhaitable que l'authentification continue de fonctionner.

Dernière étape : la configuration du serveur sshd. Il s'agit assez simplement de modifier /etc/ssh/sshd_config pour s'assurer que les paramètres suivants sont actifs :

PasswordAuthentication no
ChallengeResponseAuthentication yes

Relancez ensuite sshd avec la commande service sshd restart et tentez la connexion à partir d'une machine sur laquelle votre Yubikey est connectée :

$ ssh patpro@192.168.0.104
YubiKey for `patpro': 
Password for patpro@test10.patpro.net:
Last login: Fri May  6 21:33:58 2016 from 192.168.0.2
FreeBSD 10.3-RELEASE (GENERIC) #0 r297264: Fri Mar 25 02:10:02 UTC 2016

Welcome to FreeBSD!
...

Enjoy.

Bibliographie

Pour réaliser cette infrastructure privative d'authentification double facteur et les articles qui en découlent, je me suis appuyé sur les sources suivantes :

yubikey-ksm, principes et installation.
yubikey-val, principes et installation.
Building a local Yubikey server infrastructure (sur Linux).
yubico-pam, README.
YubiKey on FreeBSD HOWTO, aspect "client" uniquement, utilisant en plus pam_per_user.

Related posts

Monter un serveur d’authentification multifacteur 2/3

Dans un article précédent, j'ai présenté les étapes nécessaires à l'installation du serveur de validation YK-VAL de Yubico sur FreeBSD 10.3. Ce serveur s'intègre dans l'infrastructure d'authentification double facteur Yubico selon le schéma ci-dessous.
proposition d'infrastructure YK-VAL YK-KSM

D'autres modèles sont possibles bien évidemment, comme celui qui consiste à mettre les services YK-VAL et YK-KSM sur la même machine.
La suite des opérations consiste à créer le serveur YK-KSM en suivant la documentation officielle de Yubico, et les informations ci-après.

Serveur de clés YK-KSM

Pour assurer la sécurité lors des manipulations de clés, ce serveur est supposé n'utiliser que des fichiers chiffrés via OpenPGP/GnuPG. Aussi, l'outil ykksm-import nécessite-t-il qu'une clé GnuPG soit utilisée pour chiffrer les clés en amont, à leur création sur le poste de l'administrateur par exemple. Il est néanmoins tout à fait possible de ne pas utiliser les commandes ykksm-gen-keys et ykksm-import pour faire fonctionner l'infrastructure d'auth double facteur. Il suffit alors de fournir les clés à la main en les injectant directement dans la table MySQL ad-hoc.

Les étapes supplémentaires liées à OpenPGP n'étant pas complexes à mettre en œuvre, je les présente tout de même.
Il s'agit donc dans un premier temps d'installer gnupg, et de créer une clé maîtresse. Cette clé est utilisée sur le poste qui servira à générer les clés Yubico (ici le serveur lui-même), et sur le serveur YK-KSM pour les déchiffrer au moment de les injecter dans la base de données.

Pour une raison qui m'échappe, le fonctionnement de pinentry-tty est assez hasardeux à l'intérieur d'une Jail, donc si vous souhaitez, comme moi initialement, faire l'installation du service YK-KSM dans une Jail, passez votre chemin, vous gagnerez du temps :)

La partie GnuPG est assez simple :

pkg install gnupg
gpg2 --full-gen-key

Et suivez l'exemple de la doc Yubico. Une fois que votre clé GnuPG est créée, vous pouvez passer à l'installation du service YK-KSM proprement dite.

pkg install git help2man p5-DBI mysql56-server p5-DBD-mysql apache24 mod_php56 php56-xml php56-curl php56-hash php56-pdo_mysql php56-mcrypt
git clone git://github.com/Yubico/yubikey-ksm.git
cd yubikey-ksm

L'utilisation de GIT n'est pas obligatoire, on peut aussi bien télécharger le master.zip à partir de github, comme je l'ai fait pour YK-VAL.
Tout comme pour ce dernier, le Makefile est inexploitable en l'état, j'ai donc eu recours à quelques bricoles pour générer l'environnement adéquat avant d'installer les fichiers à la main :

for DIR in $(awk '/prefix = / {print $3}' Makefile); do
	[ -d $DIR ] || mkdir -p $DIR
done

La commande awk '/prefix = / {print $1"="$3}' Makefile nous donne une série de variables, à laquelle j'ajoute DESTDIR, que l'on fourni ensuite à bash :

etcprefix=/etc/yubico/ksm
binprefix=/usr/bin
phpprefix=/usr/share/yubikey-ksm
docprefix=/usr/share/doc/yubikey-ksm
manprefix=/usr/share/man/man1
wwwprefix=/var/www/wsapi
DESTDIR=/

Cette fois-ci, les commandes ykksm-* utilisables dans le shell sont codées en Perl avec un shebang compatible Linux, pas FreeBSD. On peut faire un lien symbolique de /usr/local/bin/perl vers /usr/bin/perl ou on peut corriger les scripts avant de les installer :

sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-import
sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-gen-keys
sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-export
sed -i'.old' 's,/usr/bin/perl,/usr/local/bin/perl,' ykksm-checksum

Puis on lance la copie des différents éléments :

cp .htaccess ${DESTDIR}${phpprefix}/.htaccess
cp ykksm-decrypt.php ${DESTDIR}${phpprefix}/ykksm-decrypt.php
cp ykksm-utils.php ${DESTDIR}${phpprefix}/ykksm-utils.php
cp ykksm-gen-keys ${DESTDIR}${binprefix}/ykksm-gen-keys
cp ykksm-import ${DESTDIR}${binprefix}/ykksm-import
cp ykksm-export ${DESTDIR}${binprefix}/ykksm-export
cp ykksm-checksum ${DESTDIR}${binprefix}/ykksm-checksum
cp ykksm-config.php ${DESTDIR}${etcprefix}/ykksm-config.php
cp ykksm-gen-keys.1 ${DESTDIR}${manprefix}/ykksm-gen-keys.1
cp ykksm-import.1 ${DESTDIR}${manprefix}/ykksm-import.1
cp ykksm-export.1 ${DESTDIR}${manprefix}/ykksm-export.1
cp ykksm-checksum.1 ${DESTDIR}${manprefix}/ykksm-checksum.1
cp ykksm-db.sql ${DESTDIR}${docprefix}/ykksm-db.sql
cp Makefile ${DESTDIR}${docprefix}/ykksm.mk
cp doc/* ${DESTDIR}${docprefix}/

L'étape suivante est l'installation de la base de données. Suivez simplement les instructions de l'étape 3 de la doc Yubico.

J'ai traité l'étape 4 différemment de ce qui est proposé. J'ai préféré tout mettre dans le fichier .htaccess :

<IfModule mod_php5.c>
  php_value include_path ".:/etc/yubico/ksm:/usr/share/yubikey-ksm"
</IfModule>

RewriteEngine on
RewriteRule ^([^/\.\?]+)(\?.*)?$ $1.php$2 [L]

L'étape 5 se traite exactement de la même manière que pour YK-VAL. Et l'étape 6 se fait simplement en créant les liens symboliques à la main.

À l'étape 7, tout comme pour YK-VAL, on renseigne le mot de passe MySQL dans le fichier de configuration ykksm-config.php.

Ensuite, sous réserve que votre serveur web soit lancé, il ne vous reste qu'à tester que tout fonctionne. Comme indiqué dans la doc, le résultat attendu est une erreur de clé inconnue, ce qui est tout à fait normal.

Fabrication de clés et import dans la base de données

Les vraies clés seront ajoutées ultérieurement. Mais vous pouvez néanmoins tester l'ajout de clés bidons via ykksm-gen-keys et ykksm-import.

La fabrication de 5 clés se fait comme ceci (doc officielle) :

ykksm-gen-keys --urandom 1 5 | gpg -a --encrypt -r 67A59965 -s > keys.txt

où 67A59965 est l'ID de la clé GnuPG fabriquée un peu plus haut.

Ensuite l'import des clés se fait de cette manière (doc officielle) :

ykksm-import --verbose --database 'DBI:mysql:dbname=ykksm;host=localhost' --db-user ykksmimporter --db-passwd mot-de-passe-mysql < keys.txt

Dans un troisième et dernier article il sera question de la partie vraiment intéressante : comment provisionner de vraies clés, et comment brancher un Client YK (un serveur sshd par exemple) sur votre nouvelle infrastructure d'authentification double facteur.

Related posts