[TL;DR : le script bash ici]

Vous êtes en vacances, loin de chez vous et de votre connexion à Internet. Vous voulez bidouiller sur votre ordinateur. Vous captez des réseaux SFR WiFi mais il faut ouvrir un navigateur, attendre que SFR renvoie sa page d’authentification, saisir ses identifiants, … C’est chiant, surtout quand vous utilisez un vieux netbook tout juste capable de faire tourner Firefox. Mais vous êtes ingénieux, malin, intelligent (au moins tout ça), vous êtes sous Linux donc vous allez étudier le fonctionnement de ce système et automatiser la procédure pour ne plus avoir à lancer une interface graphique ou pire, un navigateur juste pour faire un commit.

Et puis même si vous ne vous sentez pas de réaliser cela, quelqu’un l’a déjà fait pour vous et va vous expliquer tout ça dans cet article (en l’occurence, moi :-°).

Overview

Voyons comment le système fonctionne. On se connecte à un SFR WiFi Fon, on lance Firefox, on ouvre Tamper Data et on essaie d’aller sur un site web. Tamper Data est une extension Firefox qui permet de voir les requêtes HTTP émises par le navigateur, ainsi que les en-têtes des réponses. En tapant une adresse quelconque, on voit qu’on est redirigé (302) vers une page SFR qui contient des tas de paramètres dans l’URL.

Formulaire d'authentification SFR

Formulaire d’authentification SFR

On saisit ses identifiants et on voit qu’une requête POST est soumise, contenant en paramètres les identifiants bien sûr, mais aussi les paramètres précédemment transmis dans l’URL.

Une page HTML nous est alors envoyée en réponse. Elle contient un morceau de Javascript qui veut nous rediriger vers une page du réseau local, à priori pour confirmer le succès de l’opération. Une fois que cette page a été demandée, on peut enfin sortir sur le net.

Début de script

Deux opérations nous seront vitales dans l’automatisation : la récupération de pages en HTTP et la récupération de valeurs dans une URL. Nous utiliserons respectivement wget et awk pour cela. Sous Linux, il y a de fortes chances pour que vous ayez déjà ces outils.

La première étape consiste à récupérer l’URL de redirection, car elle contient un challenge (token ou jeton) qu’il faudra réinjecter dans le formulaire (les autres informations sont normalement toujours les mêmes, mais nous les récupèrerons quand même pour ne pas à avoir à modifier notre code si cela changeait du jour au lendemain). On va donc chercher une page quelconque avec wget et récupérer cette adresse.

wget -O /dev/null -o loc http://perdu.com
echo `grep Location loc` > loc
location=`awk 'BEGIN { FS=" " } { print $2 }' loc`

Pour isoler l’adresse, n’étant pas trop doué pour cela, j’ai jonglé avec grep et awk pour obtenir un truc qui fonctionne. C’est sûrement pas très propre mais ça marche. Je ne vais pas m’étendre sur le fonctionnement de awk, j’ai cherché rapidement un exemple sur Google que j’ai adapté aux circonstances…

Histoire de ne pas tout condenser en une seule ligne, j’ai préféré enregistrer la sortie de wget dans un fichier pour n’en garder que la ligne indiquant la localisation de la page de redirection (d’où le « grep Location »). Si vous ne voulez ou ne pouvez pas utiliser de fichier temporaire de sortie, rien ne vous empêche de chainer les instructions (bon courage pour reprendre le code plusieurs mois après).

Les paramètres

On a récupéré l’adresse dans une variable. Il faut isoler les différents paramètres contenus dans cette URL pour pouvoir les injecter par la suite, quand il faudra soumettre les identifiants. Pareillement, on va profiter de la puissance de awk pour stocker cela dans des variables.

challenge=`awk 'BEGIN { FS="&" } { print $4 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
nasid=`awk 'BEGIN { FS="&" } { print $6 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
mac=`awk 'BEGIN { FS="&" } { print $7 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
uamport=`awk 'BEGIN { FS="&" } { print $3 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
uamip=`awk 'BEGIN { FS="&" } { print $2 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
mode=`awk 'BEGIN { FS="&" } { print $8 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
channel=`awk 'BEGIN { FS="&" } { print $9 }' loc | awk 'BEGIN { FS="=" } { print $2 }' | awk 'BEGIN { FS=" " } { print $1 }'`

Préparation du POST

Pour soumettre des paramètres en POST avec wget, on utilise l’option –post-data key=value (avec autant de paramètres qu’on souhaite tant qu’on les sépare par des esperluettes (&)). Histoire d’éviter d’avoir dans notre script une commande suffisamment longue pour relier la Terre à la Lune, on va stocker la postdata dans une variable.

postdata="choix=neuf&username=$uname&password=$pass&conditions=on&challenge=$challenge&username2=$uname&accessType=neuf&lang=fr&mode=$mode&userurl=http://perdu.com&uamip=$uamip&uamport=$uamport&channel=$channel&mac=$nasid|mac&connexion=Connexion"

Bien entendu, les identifiants font partie de ces données. Pour simplifier le code, ils sont définis dans des variables en début de script (à vous de le faire avec les vôtres).

Envoi de la demande de connexion

Il ne reste plus qu’à envoyer la requête. L’adresse est définie par l’attribut « action » du formulaire de la page d’authentification, il suffit de jeter un œil au code HTML. Cette adresse semblant immuable (pas de challenge), on la met directement dans le code (mais quand même dans une variable pour la retrouver facilement). Hop, on envoie tout ça !

target=https://hotspot.wifi.sfr.fr/nb4_crypt.php # Cette variable devrait être en début de script
wget -O debug $target --post-data="$postdata"

Une page HTML nous est retournée. Elle contient un morceau de Javascript voulant nous rediriger vers une page du réseau local (en cas de succès). Il est nécessaire de suivre cette page pour pouvoir commencer à naviguer. On isole donc cette adresse pour pouvoir la suivre.

     window.location = "http://192.168.2.1:3990/logon?username=*USERNAME*@ssowifi.neuf.fr&response=*CODE*&uamip=192.168.2.1&userurl=http%3A%2F%2Fperdu.com%3Bneuf%3Bfr%3B4%3Bhttp%3A%2F%2Fperdu.com%3B";

 

newloc=`grep location debug | awk 'BEGIN { FS="\"" } { print $2 }'`
wget $newloc -O newloc

Comme au début, j’ai préféré utiliser un fichier temporaire pour raccourcir les instructions.

Et voilà ! On a un beau code permettant de s’authentifier sur le réseau SFR WiFi sans avoir à ouvrir un navigateur ou même cliquer sur le bouton de connexion ! L’idéal est de lancer ce script à chaque connexion sur un réseau de ce type. Cela est faisable avec Wicd en interface graphique (propriétés du réseau – script de post-connexion).

Prochaine étape : la redistribution du réseau pour pouvoir connecter plusieurs machines au même réseau communautaire sans qu’elles n’aient à s’authentifier. On peut aussi peaufiner le code pour qu’il n’utilise pas de fichier temporaire.

Le code final, aussi téléchargeable ici :

#!/bin/bash

# Auto-connect to SFR WiFi
# To use in combination with wicd

# VARS
# location: URL associated with 302 reply (contains challenge)
# challenge: part of POST data to be sent
# target: target URL for POST
# nasid: hotspot's MAC address (part of location)
# mac: client's MAC address (part of location)
# uamport: same here
# uamip: same here
# mode, channel: ...
# uname: username
# pass: password
uname=#SFR ADDRESS OR TELEPHONE NUMBER
pass=#ACCOUNT PASSWORD
target=https://hotspot.wifi.sfr.fr/nb4_crypt.php

# Step 0: wait for the connection to establish
sleep 2

# Step 1: get the location with wget
wget -O /dev/null -o loc http://perdu.com
echo `grep Location loc` > loc
location=`awk 'BEGIN { FS=" " } { print $2 }' loc`

# Step 2: extract challenge, MAC addresses, ... from location

challenge=`awk 'BEGIN { FS="&" } { print $4 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
nasid=`awk 'BEGIN { FS="&" } { print $6 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
mac=`awk 'BEGIN { FS="&" } { print $7 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
uamport=`awk 'BEGIN { FS="&" } { print $3 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
uamip=`awk 'BEGIN { FS="&" } { print $2 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
mode=`awk 'BEGIN { FS="&" } { print $8 }' loc | awk 'BEGIN { FS="=" } { print $2 }'`
channel=`awk 'BEGIN { FS="&" } { print $9 }' loc | awk 'BEGIN { FS="=" } { print $2 }' | awk 'BEGIN { FS=" " } { print $1 }'`

# Step 3: prepare POST with target URL (set in the code)
postdata="choix=neuf&username=$uname&password=$pass&conditions=on&challenge=$challenge&username2=$uname&accessType=neuf&lang=fr&mode=$mode&userurl=http://perdu.com&uamip=$uamip&uamport=$uamport&channel=$channel&mac=$nasid|mac&connexion=Connexion"

# Step 4: send POST request
wget -O debug $target --post-data="$postdata"

# Step 5: get a page on local AP
newloc=`grep location debug | awk 'BEGIN { FS="\"" } { print $2 }'`
wget $newloc -O newloc

# DEBUG
echo START DEBUG
echo challenge $challenge
echo nasid $nasid
echo mac $mac
echo uamport $uamport
echo uamip $uamip
echo mode $mode
echo channel $channel
echo location $location

Voilà, un code sûrement affreux mais qui a le mérite de fonctionner et de m’avoir dépanné plus d’une fois ! 🙂