[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.
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 ! 🙂
super script, working perfect
merci
Je viens de tester sur une Raspbian : ca ne fonctionne pas, peut être un problème de syntaxe avec awk; pas le temps pour le moment de chercher; A+
il faut remplacer « grep Location loc » par « grep Emplacement loc »
impeccable: ton script marche correctement (sans modification pour SFR Wifi Fon).
Le script fonctionne 100% en 2021, bravo!
Alors j’ai modifié ton code pour ne pas créer des fichiers temporaires, voici mon code:
Solution 1:
# -q : suppresses the progress bar and some other annoyingly chatty parts of the wget output
# -S : print the headers sent by HTTP servers
# -O – : writes the headers to the stdout (« the console »)
# s/ //g OR s/[[:space:]]//g : remove all whitespaces
location=`wget -q -S -O – http://google.com 2>&1 | grep -Fi Location: | sed ‘s/ //g’`
Solution 2:
# -s : silences everything, don’t show progress meter or error messages
# -S : allows error reports when -s is in force
# -D – : « -D »: dump headers to a file, « -« : sends it to stdout
location=`curl -s -S -D – http://perdu.com | grep -Fi Location:`
Puis récupérer les paramètres:
substr=`echo ${location#*&}`
# Note: sh or ash etc… do not support array but bash works.
array=($(echo « $substr » | tr « ^&=$ » « \n » ))
challenge=${array[5]}
nasid=${array[9]}
mac=${array[11]}
uamport=${array[3]}
uamip=${array[1]}
mode=${array[13]}
channel=${array[15]}
Voici mon code complète :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
connectSFR.sh
hosted with ❤ by GitHub