Bonjour, j'ai tenté de mon coté d'utiliser aussi l'API pour un automatiser le reboot de la box toutes les semaines et comme la commande
system.reboot est en mode d'accès "privé" donc soumise à authentification.
Je me suis aussi basé sur la documentation
apirest_4.0.pdf qui est en fichier joint... et j'ai fini par avoir la même chose que l'exemple d'authentification page 7 sur 40 :
NB : tout ce qui est en italique dans la suite de ce post provient de la documentation !Exemple avec login valant admin et mot de passe valant admin.$ curl -s -G http://neufbox/api/1.0/?method=auth.getToken
<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok" version="1.0">
<auth token="43f6168e635b9a90774cc4d3212d5703c11c9302" method="passwd" />
</rsp>
Jusque là, c'est simple, on demande à la box un token qui servira de clé pour le HMAC-SHA256, donc ici on reçoit le token
43f6168e635b9a90774cc4d3212d5703c11c9302, ensuite on le "hashe" selon la
documentation$ ./hash 43f6168e635b9a90774cc4d3212d5703c11c9302 admin
hash = 7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffaEnsuite avec ce token, on calcule un hash (terme pas forcement bien choisi en fait, c'est un HMAC-SHA256 basé sur UN hash SHA256) avec la méthode de la
documentation :
Un hash d’une valeur est composé de 64 caractères (32 digest SHA256 en représentation hexadécimal) et se calcul ainsi (value étant la valeur a hasher et key le token):
fh = sha256_hash(value)
hash = hmac_sha256_hash(key, fh)Et c'est là que les soucis commencent en général, reproduire ce calcul, car il faut de le langage supporte nativement les fonctions de hachage SHA-* et le HMAC associé, c'est pour ça (et aussi le coté cross-plateforme) que j'ai choisi le langage
go :
...
password := "admin"
hashP := sha256.Sum256([]byte(password))
hashPHex := hex.EncodeToString(hashP[:])
fmt.Printf("sha256(password) = %s\n", hashPHex)
...Ce petit bout de code calcule le SHA256 du mot de passe par défaut (
admin) et l'affiche sous forme hexadécimale.
~/dev/src/go/pocHashSFR
$ go run pocHashSFR.go
sha256(password) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918La suite pour calculer le HMAC-SHA256 de ce hash :
...
secret = "43f6168e635b9a90774cc4d3212d5703c11c9302"
fmt.Printf("secret = %s\n", secret)
macP := hmac.New(sha256.New, []byte(secret))
macP.Write([]byte(hashPHex))
hmacP := hex.EncodeToString(macP.Sum(nil))
fmt.Printf("hmac-sha256(token, password) = %s\n", hmacP)
...Et cette fois cela donne :
~/dev/src/go/pocHashSFR
$ go run pocHashSFR.go
sha256(password) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
secret = 43f6168e635b9a90774cc4d3212d5703c11c9302
hmac-sha256(token, password) = 7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffaDonc super, j'ai pu reproduire le
BON "hachage" avec SHA256 du mot de passe et le HMAC avec le token d'exemple !
J'ai tenté de l'injecter à la box avec l'appel à la méthode auth.checkToken et forcement, ça bloque:
~/dev/src/go/pocHashSFR
$ go run pocHashSFR.go
sha256(password) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
secret = 43f6168e635b9a90774cc4d3212d5703c11c9302
hmac-sha256(token, password) = 7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffa
urlCheck = http://192.168.1.1/api/1.0/?method=auth.checkToken&token=43f6168e635b9a90774cc4d3212d5703c11c9302&hash=7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffa
xmlBody = <?xml version="1.0" encoding="UTF-8"?>
<rsp stat="fail" version="1.0">
<err code="201" msg="Invalid session : this token doesn't exist" />
</rsp>Logique, le token de l'exemple n'est pas valide... Je repasse la box avec le mot de passe par défaut (
admin) le temps de tester que ça fonctionne en demandant un token valide avec la méthode
auth.getToken à la box et en signant avec celui-ci le message HMAC qui est donc le SHA256 du "nouveau" mot de passe (qui est donc
admin). Je me suis dit que comme le login de la box est fixé à
admin, il faut juste travailler avec le mot de passe, et donc qu'il n'y a pas besoin de la concaténation pourtant annoncée dans la documentation :
Pour s’authentifier avec un login et un mot de passe, il faut procéder comme avec l’authentification par bouton de service sauf qu’il faut utiliser en plus le paramétre hash lors de l’appel de la méthode auth.checkToken. Ce paramétre hash est la concaténation du hash du login et du hash du mot de passeSauf que le hash envoyé pour tester la validation du token
dans la documentation est
7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffa qui fait 64 octets sous forme hexadécimale pour les 32 octets du HMAC-SHA256.
$ curl -s http://neufbox/api/1.0/?method=auth.checkToken\&token=43f6168e635b9a90774cc4d3212d5703c11c9302\&hash=7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffa
<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok" version="1.0">
<auth token="43f6168e635b9a90774cc4d3212d5703c11c9302" />
</rsp>Je teste donc avec un token valide dynamique reçu par la box:
sha256(password) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
authGetToken.Token = 0a52c33994f138c0894cf20ccc6075
hmac-sha256(token, login/password) = 8aece4accd32ac5841b11ecb451f66ed22406a931fa1e06322284c14bdccbed4
urlCheck = http://192.168.1.1/api/1.0/?method=auth.checkToken&token=0a52c33994f138c0894cf20ccc6075&hash=8aece4accd32ac5841b11ecb451f66ed22406a931fa1e06322284c14bdccbed4
xmlBody = <?xml version="1.0" encoding="UTF-8"?>
<rsp stat="fail" version="1.0">
<err code="204" msg="Invalid login and/or password" />
</rsp>Mince, ça aurait du passer... Je tente donc en mettant
adminadmin à hacher en SHA256 et ensuite avec le HMAC-SHA256 d'un nouveau token...
sha256(password) = d82494f05d6917ba02f7aaa29689ccb444bb73f20380876cb05d1f37537b7892
authGetToken.Token = d48e13e5b4ac4068c0a17f9fccabaf
hmac-sha256(token, password) = 5cb951d883ffa4db3d8b12bf4c0a99e18c05d6b5129598f6fee64042ce044396
urlCheck = http://192.168.1.1/api/1.0/?method=auth.checkToken&token=d48e13e5b4ac4068c0a17f9fccabaf&hash=5cb951d883ffa4db3d8b12bf4c0a99e18c05d6b5129598f6fee64042ce044396
xmlBody = <?xml version="1.0" encoding="UTF-8"?>
<rsp stat="fail" version="1.0">
<err code="204" msg="Invalid login and/or password" />
</rsp>C'était assez prévisible, car ça divergeait trop de ce que fait aussi le code C donné en exemple dans la documentation pour calculer le HMAC-SHA256 avec comme message
admin.
J'ai essayé pas mal de combinaisons, mais bien sur ça ne fonctionnait pas !! La documentation est fausse, mais il fallait trouver à quel endroit. J'ai donc capturé les échanges entre un navigateur et l'interface d'administration de la box lorsqu'elle demande de s'authentifier avec
admin comme login (il est par défaut) et le mot de passe qui a ce moment là était aussi
admin.
Il y a d'abord une requête
POST sur
http://192.168.1.1/login avec comme body
action=challenge qui donne la réponse :
<rsp stat="ok">
<challenge>0cd5abf2cd96110d37144a9e456aa5</challenge>
</rsp>Intéressant, ce challenge fait la même taille et à une forme similaire que le token envoyé par la box avec
auth.getToken !
Ensuite, une autre requête
POST sur
http://192.168.1.1/login avec un body plus "complexe" :
method: passwd
page_ref: /maintenance
zsid: 0cd5abf2cd96110d37144a9e456aa5
hash: 11a9aaf2d2d5bb89e57e3b15b83aa86b760d38df6490863190eb522917097d6311a9aaf2d2d5bb89e57e3b15b83aa86b760d38df6490863190eb522917097d63
login:
password: On envoie donc un peu comme l'API, un
zsid qui ressemble à un
token et un
hash mais
BEAUCOUP plus long ! En fait
DEUX fois plus long ! Et donc vous avez compris... La concaténation est là !! En effet si on regarde bien le
hash, on retrouve DEUX fois la même valeur sur 64 octets mise bout à bout !
C'est bien
11a9aaf2d2d5bb89e57e3b15b83aa86b760d38df6490863190eb522917097d63 +
11a9aaf2d2d5bb89e57e3b15b83aa86b760d38df6490863190eb522917097d63 qui est envoyé !
Après cette découverte, je modifie le programme pour envoyer
admin comme login ET aussi mot de passe avec un
hash "double taille":
~/dev/src/go/pocHashSFR
$ go run pocHashSFR.go
sha256(login) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
sha256(password) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
authGetToken.Token = dd7d783f6ad658db3f5bbaf774a732
hmac-sha256(token, login) = b61d9b6e29bad3626d3008f9595aa0b422c031cce63aee56505663ddd043aa6b
hmac-sha256(token, password) = b61d9b6e29bad3626d3008f9595aa0b422c031cce63aee56505663ddd043aa6b
urlCheck = http://192.168.1.1/api/1.0/?method=auth.checkToken&token=dd7d783f6ad658db3f5bbaf774a732&hash=b61d9b6e29bad3626d3008f9595aa0b422c031cce63aee56505663ddd043aa6bb61d9b6e29bad3626d3008f9595aa0b422c031cce63aee56505663ddd043aa6b
xmlBody = <?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok" version="1.0">
<auth token="dd7d783f6ad658db3f5bbaf774a732" />
</rsp>et en mettant un mot de passe fort autre que admin:
~/dev/src/go/pocHashSFR
$ go run pocHashSFR.go
sha256(login) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
sha256(password) = cefb5e330c049cfbc509912a6f481d4308361b1904468b7cba0fbeb676fff2d8
authGetToken.Token = c6a91332e1336491298fcb6b796d08
hmac-sha256(token, login) = b32c930fd388f9da73dd0e95c4deb93274511a758a63383f5761c9ee5a98b7c1
hmac-sha256(token, password) = e08ada919f734abc35044b18976fbe03400afaa473b49169944e678654c15a70
urlCheck = http://192.168.1.1/api/1.0/?method=auth.checkToken&token=c6a91332e1336491298fcb6b796d08&hash=b32c930fd388f9da73dd0e95c4deb93274511a758a63383f5761c9ee5a98b7c1e08ada919f734abc35044b18976fbe03400afaa473b49169944e678654c15a70
xmlBody = <?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok" version="1.0">
<auth token="c6a91332e1336491298fcb6b796d08" />
</rsp>L'erreur de la documentation est de n'avoir envoyé qu'un seul des deux hash normalement demandés par l'authentification :
$ curl -s http://neufbox/api/1.0/?method=auth.checkToken\&token=43f6168e635b9a90774cc4d3212d5703c11c9302\&hash=7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffa
<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok" version="1.0">
<auth token="43f6168e635b9a90774cc4d3212d5703c11c9302" />
</rsp>L'exemple DEVRAIT donc être :$ curl -s http://neufbox/api/1.0/?method=auth.checkToken\&token=43f6168e635b9a90774cc4d3212d5703c11c9302\&hash=7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffa7aa3e8b3ed7dfd7796800b4c4c67a0c56c5e4a66502155c17a7bcef5ae945ffa
<?xml version="1.0" encoding="UTF-8"?>
<rsp stat="ok" version="1.0">
<auth token="43f6168e635b9a90774cc4d3212d5703c11c9302" />
</rsp>C'est d'ailleurs anormal que l'exemple de la documentation valide le token étant donné que l'on a "haché" que le login ou mot de passe, comme ils sont tous les deux à
admin dans l'exemple.
Après, il y avait un indice dans la documentation sur la partie
auth.checkToken :
Note : le paramètre hash est obtenue en concaténant le hash du login et le hash du mot de passe (la longueur de cette valeur est donc de 128 caractères).Voilà pour le pavé d'explications ! J'espère que ça pourra en aider certains à utiliser l'API sans passer par l'interface graphique et du parsing HTML inutile.