Skip navigation.

devloop :: blog

Blog sur la sécurité informatique, la programmation, Linux et le Web

Posts tagged with "wapiti"

Démo de Wapiti

, , ,

Wapiti SVN - scan with terminal colors

L'occasion pour tester à la fois recordMyDesktop et la plateforme d'hébergement de vidéos Vimeo.
Le résultat est largement satisfaisant. Les vidéos ogg sont légères tout en restant de bonne qualité et le réencodage sur Vimeo ne détériore pas trop la vidéo :smile:

Dans cette vidéo vous pouvez voir Wapiti (dans la version actuelle sur le SVN) lancé sur mes scripts de test perso (ne faites donc pas attention au noms de variables...)
Vous pouvez constater que les messages sont en bonne partie français (internationalisation en fr, es, en) :smile: Je pense en avoir terminé avec l'affichage en mode console (couleurs, niveau de bavardage).
En revanche je vais devoir travailler sur la génération des rapports qui pose problème (on ne peut pas insérer de la même façon certains caractères dans un rapport au format txt et un rapport au format html).

Encore et toujours des modifications à apporter p:

Wapiti 1, MySQL 0

, , , ...

Le développement de Wapiti continue doucement mais sûrement. J'ai mis en place le système de module dont j'avais parlé, ça commence à avoir de la gueule :smile:
Dans les dernières révisions sur le SVN j'ai pu réimplémenter l'injection SQL en aveugle et la recherche des XSS permanents qui avaient été virés dans les changements.

Aujourd'hui j'ai joué un peu avec Mutillidae (après quelques minutes à modifier le code car pas assez "strict" pour ma config).
Ca a permis de trouver quelques problèmes stupides avec l'injection en aveugle, notemment l'utilisation du mot clé "AND" qui est bien moins efficace qu'un bon "OR" p: et aussi quelques payloads simples que j'ai rajouté.

Sans ces 2/3 payloads simples, Wapiti injectait la fonction SQL "benchmark(10000000,MD5(1))" alors qu'il aurait pu tout aussi bien le faire avec un "sleep()" (si un caractère supplémentaire n'avait pas été présent).
La différence entre ces deux fonctions c'est que la première prend beaucoup de ressources. On voit les requêtes s'entasser sous MySQL ("show processlist;") et le process passe à plus de 95% d'utilisation du CPU... et finalement MySQL semble baisser les bras : le processus tourne encore mais le serveur ne traite plus les requêtes.

Wapiti vainqueur par K.O. p:

Maintenant je compte vérifier la façon dont est géré la verbosité dans les différents modules puis je vous reparlerais prochainement du système de modules et comment en créer de nouveaux ;-)

Pour obtenir la dernière version du SVN :
svn co https://wapiti.svn.sourceforge.net/svnroot/wapiti wapiti

Wapiti 2.1.0 RPM

,

wapiti-2.1.0-devloop.noarch.rpm

C'est mon premier RPM penguin , par conséquent il n'est pas impossible que vous rencontriez des erreurs lors de l'installation bug Cela dis chez moi ça marche :smile:

Nouvelle version de Wapiti

, , , ...

Comme promis précédemment, une nouvelle version stable de Wapiti est disponible au téléchargements dans différents formats d'archivage (toujours l'appréhension de merder en les faisant alors j'ai vérifié à deux fois p: )

Peu de changements depuis le dernier post sur le sujet et sa version SVN correspondante mais ça vaut quand même le coup de se mettre à jour puisque j'ai rajouté quelques "patterns" pour la détection de failles PHP et modifié les utilitaires cookie.py et getcookie.py pour qu'ils fonctionnent sur les applications web qui s'entêteraient à gérer les entête HTTP de façon peut conventionnelle.

D'ailleurs je devrais remercier au passage les auteurs des applis my little forum (juste un petit XSS) et iDB (une petite inclusion locale à l'exploitation limitée) sur lesquels j'effectuais mes tests en plus des petits scripts que j'ai fait à l'occasion :smile:

Maintenant il va falloir que je mette le site web à jour :whistle:

Télécharger Wapiti sur SourceForge.net

Awesome !!

, , , ...

Après une semaine à me concentrer sur le développement de Wapiti, j'ai mis à jour les ChangeLog de Wapiti et lswww et j'en ai profité pour rectifier le fichier README.

Je me suis alors rendu compte du travail effectué depuis la version 2.0.0 béta et aussi que je ne vous en ait parlé que très récemment et sans réelles explications :eyes: (même si j'avais donné quelques infos en commentaire sur la dernière béta :left: ).

Le moment est donc venu de vous tenir au courant de ce que la prochaine version à venir apportera et à quoi vous attendre :wink:
Tout d'abord la version 2.0.0-béta ne verra pas sa version stable. En effet il y a eu tellement de changement qu'il ne s'agit plus du tout de la même version :ko:
Cette version apportait tout de même son lot de nouveautés comme une nouvelle technique de scan pour les XSS, la génération de rapports de scans, l'ajout d'option --nice évitant les boucles infinies lors des scans et la correction de l'authentification HTTP.

Le changement radical qui s'est effectué est avant tout l'abandon de la librairie urllib2 pour httplib2, petite librairie basée sur httplib et sous licence MIT.
Le grand avantage de ce changement, c'est le support des connexions HTTP persistantes par httplib2. Alors que les anciennes versions de Wapiti basées sur urllib2 pouvait avoir un effet néfaste (saturation du nombre de connexions du serveur web :eek: ), ici le maximum de requêtes possible sera envoyé à travers une même connexion. Non seulement le serveur ne se fatigue pas mais en plus on obtient un gain important en vitesse de scan :ninja:
Bien sûr l'intégration de cette librairie ne s'est pas faite sans quelques nouveaux bugs qui ont fait leur apparition mais ils ont pû être corrigés.
L'une des premières conséquence a été la perte du support des proxies. Pour moi il semblait évident que httplib2 supporait les proxies HTTP "standards"... ce n'était pas le cas nervous
Il a donc fallu modifier cette librairie et aussi permettre l'intégration de toutes les bonnes choses qui étaient offertes.

Au final on a du nouveau sur les proxies avec le support des proxies HTTP, SOCKS v4, SOCKS v5 (passage à travers Tor) ou tunneling par HTTP CONNECT :yes:
Je n'ai pas eu l'occastion de tester cette dernière mais pour les proxies SOCKS ça fonctionne :happy:

On a ensuite croisé des soucis avec les entêtes et codes d'erreurs HTTP ainsi que les redirections traitées de façon invisible par la librairie. Comme Wapiti essaye de déclencher des erreurs dans les pages, httplib2 n'a pas forcément apprécié et on lui a retiré le support des redirections pour le laisser à Wapiti qui faisait ça très bien.

Pour terminer sur les bugs bug , j'ai rajouté des vérifications sur les timeouts dans les différents modules et cloturé la quasi-totalité des bugs rapportés sur le tracker.

J'ai rajouté une nouvelle option à lswww : -e (ou --export) qui permet de générer un fichier XML des urls et des formulaires trouvés durant un scan. Pour l'instant cette option n'a aucune utilité mais j'espère que d'autres logiciels intégreront une option pour importer ces données (à l'occasion j'en toucherais quelques mots aux développeurs de sqlmap :smile: )

Les attaques SQL ne sont d'ailleurs pas en reste puisque le scan des failles d'injection SQL en aveugle ("time-based") a été ajouté. Je vous invite à jeter un oeil aux payloads utilisés :sherlock:

Restez dans les parages pour être tenu au courant de la sortie de cette prochaine version (encore des vérifications à faire).
Les plus impatients peuvent déjà récupérer la version présente sur le SVN :
svn co https://wapiti.svn.sourceforge.net/svnroot/wapiti/trunk wapiti

Et pendant que j'y pense, Wapiti a été intégré au Live-CD OWASP 2008 :cool:

Python en vrac : Wapiti, Imeem.com, Mesk et Emesene

, , , ...

Hier, corrections et fermetures de bugs dans Wapiti bug
Il y avait une vérification sensible à la casse qui n'aurait pas dû y être, du contenu non retourné sur une erreur 500 résolu lors du passage à httplib2, des problèmes d'analyse de code HTML qui ont été normalement résolu par l'inclusion de BeautifulSoup mais un parser supplémentaire basé uniquement sur des expressions régulières a tout de même été ajouté.
J'ai aussi corrigé un bug d'encodage de caractère au niveau des injections SQL que j'avais trouvé et modifié httplib2 pour le faire utiliser le module hashlib au lieu des anciens obsolètes.
Voir sur le SVN pour ces modifications.

Imeem toujours... alors que la lecture passait très bien avec VLC, je me suis rendu compte que ce dernier ne soumettait pas les titres à Last.FM car la musique était lue depuis Internet :furious:
Au lieu de chercher à corriger/recompiler le module VLC, je me suis repenché sur le cas de Mesk.
Mesk supporte le format XSPF, il enregistre ses playlists dans ce format mais ne permet pas d'en importer d'une source externe. On peut tricher en écrasant une de ses playlists par une playlist externe mais on se rend compte que le lecteur n'affiche pas son contenu :frown:
C'est parce que la playlist en question n'a pas l'extension Mesk pour XSPF. J'ai donc modifié le script d'extraction précédent pour le rendre compatible : mesk.py.
L'autre problème était la manie que Mesk a d'envoyer des requêtes HTTP HEAD pour savoir si la ressource est présente. J'ai dû modifier le serveur pour qu'il renvoit un 200 OK sur ces requêtes : imeem_url_server.py.
Le résultat fonctionne très bien et les soumissions Last.FM s'effectuent correctement :cool:

Et enfin, pour les fans d'emesene, j'ai fait un module qui permet d'afficher la musique en cours de lecture dans Mesk. Il faut récupérer le fichier Emesene_Mesk_current_song.py, le renommer en Mesk.py, le placer dans le dossier emesene/plugins_base/currentSong/ (présent dans /usr/share/ chez moi) avec sa version compilée et modifier le fichier __init__.py pour y ajouter la ligne "from Mesk import Mesk".
Je vais soumettre le script aux dev d'emesene en espérant qu'ils l'intègrent bientôt. penguin

Wapiti 2.0.0 Béta

, , , ...

Alors que Wapiti a dépassé doucement mais surement la barre des 16200 téléchargements sur SourceForge, les plus observateurs auront remarqué la sortie d'une version 2.0.0 béta avant-hier soir.

La question que vous vous posez certainement c'est comment l'on peut passer d'une version 1.1.7-alpha à une version 2.0.0-béta...
Tout simplement avec beaucoup de changements !! Et il s'en est passé des choses depuis la sortie de la précédente version.

Premièrement, le nombre de développeurs est passé de 1 à 3 grace à l'aide de 2 développeurs espagnols de ICT-Romulus.
Leur souhait était de pouvoir apporter des nouvelles fonctionnalités à Wapiti, notamment pour faciliter son intégration dans un projet de framework J2EE basé sur Maven (si j'ai tout compris lol).
Dans tous les cas ils ont proposé de participer au développement de Wapiti afin que tout les utilisateurs puissent profiter de leurs idées et de leurs modifications :smile: Cela est passé par la mise en place d'un espace SVN pour le projet pour faciliter le développement.

Leur objectif principal était de travailler sur le rendu final fournit par Wapiti. Ainsi il est possible d'obtenir un compte rendu des vulnérabilités dans 3 formats différents : XML, HTML et texte simple. Pour cela les options -f (format) et -o (output) ont été rajoutés.
Ils ont aussi réussi à séparer les payloads du code, ce qui rend plus simple leur ajout. Le code a été aussi revu et est plus modulaire.
Des règles de détection pour les failles SQL ont aussi été rajoutées.

De mon côté j'ai pû enfin résoudre le problème des boucles sans fin lors du scan d'urls en ajoutant l'option -n (ou --nice) qui permet de définir un "seuil de tolérance" au niveau des urls du même type.
Ainsi si les pages suivantes ont déjà été scannées :
http://server/p?a=x&b=1&c=x
http://server/p?a=x&b=2&c=x
http://server/p?a=x&b=2&c=y

Avec un seuil de 2, quand l'url "http://server/p?a=x&b=3&c=x" sera trouvée, elle sera exclue car déjà 2 urls du même pattern ont déjà été trouvées (http://server/p?a=x&b=*&c=x).
Même chose avec l'url http://server/p?a=x&b=2&c=z.
Par défaut aucun seuil n'est spécifié (ce qui revient à le fixer à 0). A vous de voir la valeur qui vous semble juste (10 me parait en bon compromis pour faire beaucoup de possibilités sans tourner en boucle).

J'ai aussi réussi à faire fonctionner l'authentification HTTP (option -a) en pompant sur le code de sqlmap. Même si les instructions sont sensiblement différentes par rapport à ce que Wapiti faisait, le principe est le même et je ne saurais pas dire pourquoi ça ne fonctionnait pas auparavant (alors que proxies et cookies fonctionnaient)... un des mystères de Python :left:
Malheureusement, étant donné la façon dont les modules urllib2 fonctionnent, il est préférable de retirer l'authentification sur le serveur et d'utiliser Wapiti simplement. En effet pour chaque url, si l'authentification est présente, Python va émettre deux requêtes : une première sans authentification qui va renvoyer une erreur 401. Et une seconde avec les identifiants pour passer la vérification :left:

Enfin la nouvelle méthode de scan XSS est complètement implémentée et la librairie Beautiful Soup a été mis à jour.

Pour la prochaine version, différents changements sont à faire comme pouvoir gérer les erreurs HTTP 500 (nouveau bug), améliorer la qualité des rapports de scan, limiter le nombre de plantages liés au décodage Unicode :frown: et enfin travailler sur la vitesse de scan de Wapiti.
En effet lors de certains tests, on s'apperçoit que Wapiti peut avoir un effet DoS sur le serveur web (voir que les 152 process lancés par Apache pour répondre aux requêtes sont tous occupés c'est pas top...) Il faut donc essayer d'envoyer le plus de requêtes possibles par connexion (ou trouver la juste proportion entre les deux)

Dans tous les cas, je ne peux que vous conseiller de passer à cette nouvelle version qui apporte des fonctionnalités importantes :smile:

Télécharger Wapiti-2.0.0-béta.

Wapiti 1.1.7 Alpha

, , , ...

Je viens à l'instant de placer sur SourceForge une nouvelle version de Wapiti.

C'est une version alpha (avec tout que ça implique) de la prochaine version à venir (la 1.1.7). L'objectif étant de montrer vers où se dirige Wapiti dans son développement, quelles sont les améliorations en cours et permettre à ceux qui ont des modifications à soumettre de se baser sur un code plus à jour que la version précédente.
Je compte aussi sur tous ceux qui utiliseront cette version pour soumettre les bugs qu'ils trouveront, en particulier s'il s'agit de stabilité.

La principale nouveauté c'est la nouvelle fonction de détection de failles XSS (actuellement nommée "new_attackXSS") qui se base sur mes expérimentations avec la librairie Beautiful Soup pour détecter où se situe le code injecté dans la page (d'un point de vue DOM/HTML...) et choisir en conséquence le payload le mieux adapté.
Ce n'est pas la seule amélioration sur ce point puisque vous verez dans le fichier XSS.py un certain nombre de payloads dont l'objectif est de pouvoir passer d'éventuels filtres anti-XSS.
Parmis les filtres visés il y a :
  • ceux qui filtrent sur le mot "script"
  • ceux qui retirent les quote (apostrophes) et double-quotes (guillements)
  • ceux qui filtrent les signes inférieur et supérieur des balises HTML/XML

L'algorithme pour détecter les XSS a sensiblement changé :

Pour une url que l'on aura trouvé, avec des paramêtres A, B et C, on va essayer d'injecter du code dans chacune des variables séparément mais toutes ces variables resteront présentes dans l'url telle qu'on l'a trouvée (le payload se "déplace" de variables en variables dans l'url)
Au lieu d'attaquer directement avec un payload, Wapiti commence par injecter un identifiant alpha-numérique de 10 caractères et vérifie que se dernier est bien injecté dans la page.
Si c'est le cas, il va étudier cette page et pour chaque occurence de l'identifiant il va déterminer quelle liste de payloads utiliser en fonction de sa position dans la page.
Dès qu'un payload semble fonctionner, il sort de la boucle et passe à la variable suivante (ou la page suivante s'il a fait toutes les variables)

La plupart des payloads sont "user-friendly", il suffit de recopier l'url proposée par Wapiti pour voir un beau "alert". Mais d'autres ne donnent pas un résultat immédiatement visible (par exemple ceux qui injectent un String.fromCharCode) pour des raisons de taille du payload.
Enfin parmis les payloads on trouve ceux qui cherchent juste à appeler un script externe.
Dans l'ensemble, l'objectif était que Wapiti puisse donner à l'utilisateur une url d'attaque se rapprochant au mieux de ce qu'il aurait pû trouver lui-même avec son navigateur.

Les navigateurs qui (mattez la transition :cool: ) ne réagissent malheureusement pas tous de la même façon devant une page malformée. Lors de l'injection du payload, celui-ci peut se retrouver à différents endroits de la page, par exemple dans le "title" de la page alors qu'on le retrouvera puis loin dans le "href" d'un lien ou enfin dans un code CSS.
Pour commencer, on ne peut pas injecter directement du javascript dans la balise title : il faut fermer cette balise puis ouvrir une balise script.
Comme le payload est propre à la variable on va le retrouver aux différents endroits correspondants de la page. Donc notre balise title que l'on aura fermée va se retrouver dans le href et dans le code CSS...
Puisque les navigateurs ont généralement une lecture linéaire, le résultat obtenu avec la première injection devrait être satisfaisant... Mais si on est obligé de passer par la seconde occurence du payload dans la page, il va falloir faire avec le code injecté dans la balise title qui peut rendre le code HTML chaotique et empécher l'interprétation du payload en seconde position...

Cette interprétation étant propre au navigateur (sa capacité à gérer les erreurs), on ne peut jamais être à 100% sûr que le payload généré sera fonctionnel sur l'un des principaux navigateurs.
Dans Wapiti, la gestion de ces erreurs se fait à l'aide de Beautiful Soup qui se rapproche probablement du comportement qu'aura un navigateur.
J'ai aussi fait des tests avec Tidy et les différences sont radicales. Alors que Beautiful Soup cherche plutôt à fontionner malgré les erreurs, Tidy les corrige ou les supprime donnant des résultats parfois surprenants.

C'est l'une des raisons que me pousse à me recentrer sur l'utilisation de Beautiful Soup pour les futures versions de Wapiti, la seconde raison d'importance est qu'il est difficile pour un utilisateur de Windows de disposer de Tidy avec Python (les pauvres, déjà qu'ils ont pas un OS facile p: )

Pour terminer sur cette partie, ce nouveau "moteur" XSS ne concerne pour le moment que la méthode GET, je dois encore la mettre en place pour le POST.
Il y a aussi un système d'historisation des requêtes (pour la détection des XSS permanents) qui est en cours de réécriture.

En dehors de ça, quelques bugs corrigés, le plus important concernait les formulaires où la méthode (GET ou POST) n'était pas spécifié. Désormais GET est utilisé par défaut (comme voulu par les standards HTML).

Wapiti 1.1.7-alpha

Playing with Beautiful Soup

, , , ...

Trouvez des failles d'injection SQL ou d'exécution de commandes dans une application web est relativement simple : il suffit de passer les "caractères d'échappement" propres au langage ou à l'interpréteur gérant les données et d'observer les messages d'erreurs qui sont générés.

Pour les failles XSS, le problème est différent. Il est facile de voir si des données passées à une variable se retrouvent dans la page renvoyée et il est facile de déterminer quels caractères sont filtrés et lesquels passent.
Malheureusement ce n'est pas parce que l'on parvient à injecter un <script>alert("XSS");</script> dans une page que l'on a pour autant une faille XSS. Notre payload est peu intéressant s'il se retrouve dans une balise input du style :

<input type='text' value='<script>alert("XSS");</script>' />


Pour peu que les apostrophes soit automatiquement supprimés, ça risque de compliquer fortement l'exploitation.

Pour un humain, c'est facile de faire quelques tests, comprendre à quel type de filtrage il a affaire et essayer de trouver comment passer le filtre. Pour un scanneur de vulnérabilités c'est plus compliqué.
Par exemple il y a quelques temps on m'a reporté une faille XSS que Wapiti n'avait réussi à trouver dans une webapp. La valeur passée à une variable vulnérable était automatiquement tronqué à une certaine taille, avec un payload plus court, la faille aurait pû être détecté.

C'est un cas peut-être tiré par les cheveux, mais il montre bien les limitations des scanneurs. Je pourrais faire une régression, remplacer le "scan XSS" par la "détection d'un mauvais filtrage de caractères html", m'en tenir à donner une liste de caractères non-filtrés pour chaque variable et laisser l'utilisateur se dépatouiller avec ces informations.
Mais c'est peu intéressant et ça risque de donner beaucoup de résultats non-exploitables. Il faut encore définir la liste des caractères malicieux et, si on choisit par exemple les signes inférieur, supérieur, simple et doubles quotes, égal et point virgule, on risque de ne pas détecter le cas (certes quasi-surréaliste) où l'on peut injecter directement un payload comme eval(String.fromCharCode(x,x,x)) en plein milieu d'une balise script !

Tout ça pour en venir au fait qu'il est nécessaire de savoir où sont injectés nos données dans la page html afin de déterminer quel type de payload on peu utiliser et quelles balises doivent être fermées pour que l'exploitation fonctionne.

A l'aide de la librairie Beautiful Soup, on peut déjà régler le premier problème. J'ai fait un petit script capable de retrouver dans quelle balise (et quelle partie de la balise) se situe un mot clé. L'exemple ci-dessous cherche le mot "Gmail" sur l'index de google.fr :
import BeautifulSoup, urllib2

keyword="Gmail"

def study(obj,parent=None):
  if parent==None:
    print "Keyword is:",keyword
  if str(obj).find(keyword)>=0:
    if isinstance(obj,BeautifulSoup.Tag):
      if str(obj.attrs).find(keyword)>=0:
        for k,v in obj.attrs:
          if v.find(keyword)>=0:
            print "Found in attribute value ",k,"of tag",obj.name
          if k.find(keyword)>=0:
            print "Found in attribute name ",k,"of tag",obj.name
      elif obj.name.find(keyword)>=0:
        print "Found in tag name"
      else:
        for x in obj.contents:
          study(x,obj)
    elif isinstance(obj,BeautifulSoup.NavigableString):
      if str(obj).find(keyword)>=0:
        print "Found in text, tag", parent.name

doc=urllib2.urlopen("http://www.google.fr/").read()
soup=BeautifulSoup.BeautifulSoup(doc)
study(soup)

Le problème c'est que Beautiful Soup fait automatiquement le ménage dans le code html qu'on lui soumet, plaçant des doubles quotes autour des valeurs des attributs dans les balises. Il va alors falloir jongler avec le code corrigé par BS et le code "brut" d'origine pour déterminer comment fermer la balise en cours.
Mais j'espère bien intégrer tout ça pour une prochaine version de Wapiti ;-)

Wapiti 1.1.6

, , , ...

Je viens de mettre en ligne une nouvelle version de Wapiti.
Les changements apportés concernent uniquement lswww (la partie chargée de l'exploration des sites Internet).

Les anciennes versions se basaient sur l'extension d'un fichier et ensuite sur son contenu (tel que déclaré par le serveur web) pour déterminer s'il s'agissait d'une page web (donc potentiellement exploitable).
Maintenant lswww compte principalement sur le Content-Type, ce qui fait qu'il peut dorénavant attaquer des scripts avec des extensions plus exotiques.
Exemple avec un site utilisant mod_python :

python lswww.py http://www.csb.sunysb.edu/bsb/
...........................
+ URLs :
http://www.csb.sunysb.edu/bsb/
http://www.csb.sunysb.edu/bsb/formdata.py
http://www.csb.sunysb.edu/bsb/images/X26C.jpg
http://www.csb.sunysb.edu/bsb/images/lnxcluster.jpg
http://www.csb.sunysb.edu/bsb/images/nmr_spect.jpg
http://www.csb.sunysb.edu/bsb/images/rigaku.jpg
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=A
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=B
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=C
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=D
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=E
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=F
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=G
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=H
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=I
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=J
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=K
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=L
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=admission
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=contact
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=courses
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=degreereq
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=facilities
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=faculty
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=facultyres
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=home
http://www.csb.sunysb.edu/bsb/mkpage.py?fref=onapply

+ Forms Info :
From: http://www.csb.sunysb.edu/bsb/mkpage.py?fref=contact
To: http://www.csb.sunysb.edu/bsb/formdata.py
        note : on
        name : on
        email : on

BeautifulSoup a été rajouté au package. lswww s'en sert pour nettoyer les pages web avant de les étudier dans le cas où uTidyLib n'est pas présent sur le système. C'est moins puissant que Tidy mais ça permet au moins de fermer les balises restées ouvertes.
L'objectif de cet ajout est de rendre lswww et Wapiti plus performant "out of the box" (sans installation de modules supplémentaires)

Et dans le cas où ni uTidyLib ni BeautifulSoup ne sont présent, une petite expression régulière pourra prendre le relais :smile:

Des modifications ont aussi été faites pour que le logiciel fonctionne si cookielib n'est pas installé. Par contre les options pour les cookies n'auront plus effet.

Télécharger Wapiti 1.1.6