Y a plein de mails intéressants sur yopmail.com

Y a plein de mails intéressants sur yopmail.com

Introduction

http://www.yopmail.com/ est un service de messagerie électronique temporaire, gratuit, et ne nécessitant strictement aucun mot de passe. N’importe qui peut y accéder avec n’importe quel identifiant, lequel peut être soit généré aléatoirement, soit choisit par l’utilisateur lui-même. Le service permet principalement la réception de messages. L’envoi de messages n’est uniquement possible que d’une adresse YOPmail vers une autre.

Lorsqu’un identifiant est utilisé pour la toute première fois, l’utilisateur a accès à une interface sans le moindre message. Par contre, lorsqu’un identifiant a déjà été utilisé, l’utilisateur a accès à l’intégralité des messages déjà reçus à l’adresse concernée, mais utilisée par un tout autre utilisateur. C’est là que ce service va nous intéresser !

Dans cet article, nous nous proposons de procéder à une analyse de l’état de l’art OSINT quant aux possibilités de YOPmail.

Scraping

L’outil suivant offre des possibilités de scraping très intéressantes :

https://github.com/antham/yogo

Pour peu qu’un expéditeur revienne fréquemment dans la liste des messages récupérés d’un compte, il y a de fortes chances pour que celui-ci soit particulièrement intéressant. L’OSINTer n’ayant pas le goût de la programmation de scripts pourra même utiliser l’outil suivant à cet effet :

https://www.browserling.com/tools/word-frequency

Une adresse mail est souvent utilisée lorsqu’il s’agit de procéder à des notifications, que ce soit sur la supervision d’un serveur de production, ou tout simplement sur un réseau social ou sur un services de petites annonces (« vous avez un nouveau message », « vous avez un nouvel appartement correspondant à votre recherche », … etc).

De telles adresses YOPmail pourront alors être facilement extraites et mises en évidence en utilisant yogo. Un point de vigilance sera cependant à considérer : à partir du moment où yogo est utilisé en masse, les équipements de sécurité derrière le site de YOPmail finissent par interdire l’accès du poste informatique d’où le scraping est lancé. Il conviendra alors d’utiliser un VPN pour procéder aux requêtes (la base …), et surtout de changer régulièrement de proxy.

Avoir le bon mindset

Sur quels types de comptes va t il être pertinent de procéder à nos recherches ?

YOPmail est un outil particulièrement facile d’utilisation et ne nécessite aucun effort de créativité ou d’imagination. Contrairement aux services de messagerie classique, tous les identifiants imaginables et possibles peuvent être utilisés ! Alors, en toute logique, autant considérer en priorité ceux les plus simples, voire même les plus idiots, non ? Ainsi, on pourra considérer :

  • les onomatopées d’informaticiens en test : toto, titi, tata, tutu, test, …
  • les jurons et les grossièretés
  • les célébrités les plus standards (inspiration : « Arrêtez, arrêtez! Vous vous êtes trompé, c’est le président de la République!« , Coluche dans l’Aile ou la Cuisse)
  • les variations Goldberg sur un clavier d’ordinateur (azertyuiop et ses cousins)

On pourra cependant noter que des résultats intéressants existent avec des variantes autour de nepasrepondre/noreply/donotreply.

Pivots et en-têtes

YOPmail n’est pas totalement standard, à l’exception de la possibilité d’affichage des Headers d’un message :

AInsi, pour peu qu’un message apparaisse comme pertinent, on pourra procéder à des recherches supplémentaires, afin de déterminer d’où il a été envoyé.

Quand un administrateur système fait un test …

Il fait un test ! Ci-après, voici des traces logicielles d’erreur alertant quant à un mot de passe invalide :

Et parfois il se sent juste en verve par rapport à l’actualité :

Par acquis de conscience, et afin de prévenir tout faux positif, l’examen des en-têtes du mail de « Didier Raoult » nous permet bien de retrouver sur Shodan la machine à l’origine du message. Elle fait effectivement partie d’une banque :

C’est toto qui fait du phishing

Au gré de quelques recherches rapides, on découvre le message suivant semblant lié à une banque :

Bien évidemment, l’URL derrière « Mon pass-sécurité » ne correspond en rien à celle d’une banque. Via quelques recherches sur le moteur urlscan.io, on découvre que le domaine derrière cette URL pourrait héberger de multiples plateformes de phishing bancaire :

Le hacking sans avoir à hacker

Sur la base des règles de recherche de compte préétablies (pas d’imagination, pas de recherche, pas de créativité), on trouve également le mail suivant :

Un examen des en-têtes du message ainsi qu’une recherche IP inversée nous permettent bien d’attester que ce message provient de Twitter :

Le compte Twitter associé apparaît comme tout à fait valide. En initiant le process de réinitialisation de compte, on retrouve même l’adresse de messagerie apparaissant dans les en-têtes du mail :

L’adresse en question est une variante/redirection de yopmail.com : courriel.fr.nf. Là où bon nombre de sites empêchent une inscription utilisant yopmail.com, il apparaît que Twitter accepte les adresses utilisant ce nom de domaine alternatif.

Conclusion

Les trouvailles de cet article sont loin d’être exhaustives. A moyen et long terme, il pourrait être pertinent de procéder à une étude plus détaillée des possibilités offertes par YOPmail. Incontestablement, par le biais de quelques recherches au final pas si compliquées, les potentialités de nuisance associées à ce service de messagerie s’avèrent particulièrement nombreuses.

En terme de recherche en sources ouvertes, on remarquera qu’une fois de plus, la puissance et la pertinence d’une source de pivots comme YOPmail ne repose pas sur une grande technicité. Comme toujours, c’est l’analyste qui fait d’abord l’OSINT, et en aucun cas ses outils de travail.

#JeSuisProf – OpenFacto met à disposition un petit guide de la vie privée

#JeSuisProf – OpenFacto met à disposition un petit guide de la vie privée

En réaction aux événements de Conflans Sainte Honorine, OpenFacto met à disposition un petit guide basique sur la vie privée en ligne pour qu’un compte Facebook mal paramétré ou une adresse de domicile publique ne soit pas un frein au travail fantastique et à la sécurité des professeurs dans les écoles, collèges, lycées et fac.

N’hésitez pas à diffuser ce guide et à nous contacter si vous voulez le mettre à jour, apporter des précisions ou des corrections.

Guide à télécharger ici

Reconnaissance faciale et OSINT – Digikam

Reconnaissance faciale et OSINT – Digikam

Inquiétante à plus d’un titre, la reconnaissance faciale peut tout de même s’avérer extrêmement pratique pour l’OSINT. La plus grosse problématique pour son utilisation reste la chaîne d’outils nécessaire : bien souvent des scripts python, des ressources systèmes importantes, une ergonomie douteuse pour le néophyte.

Nous vous proposons aujourd’hui à travers un cas simple, de mettre en œuvre un outil de reconnaissance faciale à moindre effort : Digikam.

Digikam

Digikam est un outil de gestion de bibliothèque photo qui reprend les grands principe de logiciels tels que iPhotos par exemple. Son gros avantage c’est qu’il est gratuit, open-source, et multiplateforme : originellement développé pour Linux, il est désormais disponible pour Windows et Mac. Vous le savez, à OpenFacto, nous sommes friands de logiciels libres!

Digikam est sorti ces jours-ci en version 7 – son développement est très actif! – et cette nouvelle mouture met l’accent sur son nouveau moteur de reconnaissance faciale. Un gros effort a en effet été réalisé pour améliorer les performance de Digikam sur ce point. Et le moins que l’on puisse dire, c’est que ça marche très très bien! y compris sur les animaux!

L’interface de Digikam

On ne s’attardera pas ici sur l’immensité des fonctions de Digikam pour la gestion de sa bibliothèque d’images mais plutôt sur la reconnaissance faciale proprement dite.

Création d’un corpus photo de référence

A l’aide d’Instaloader nous allons télécharger des photos d’un personnage public, pour constituer une base de connaissance de visages. Instaloader est un logiciel python qui permet de télécharger en masse des photos d’instagram. Mais vous pouvez utiliser votre propre technique pour faire de même, y compris télécharger vos photos manuellement. Dans votre répertoire d’images, créez un sous-répertoire et téléchargez-y vos images de références.

instaloader --login votre_login fhollande 

L’idéal est d’avoir plusieurs images sous différents angles de la personne, de près, de loin… Pour cet exemple, j’ai téléchargé au hasard une trentaine de photos, que j’importe ensuite dans Digikam.

L’interface de Digikam sur cet exemple.

Il faut maintenant lancer l’outil de détection de visages. Cliquez bouton droit, puis « Cherchez des visages » sur le nom de l’album.

Puis pour chaque photo de référence, placez un tag mentionnant le nom de la personne sur chaque image.

Sur chaque visage, placez le nom de la personne.

Certains visages ont pu ne pas être détectés par l’application : vous pouvez tout de même les identifier manuellement:

L’icône d’identification manuelle.

Une fois cette étape achevée, vous obtenez une base de référence :

Application sur des photos inconnues

Nous allons maintenant télécharger en masse des photos inconnues, comportant le hashtag « #francoishollande », grâce à Instaloader.

instaloader --login votre_login "#francoishollande"
(n'oubliez pas les guillemets autour du hashtag...

Nous réitérons ensuite la recherche de visages comme ci-dessus, en validant cette fois-ci « recognize faces« , puis en allant dans les « settings » pour baisser la sensibilité à 50%.

Après avoir appuyé sur « Analyser une collection…. » dans le premier onglet, et au bout de quelques secondes, Digikam indique les visages détectés.

Il suffit de les valider un par un pour confirmer la détection ET améliorer la détection future…..

Il est possible de jouer un peu à la hausse ou à la baisse avec le niveau de détection, en fonction de la base de référence (si elle contient beaucoup d’image ou pas), et de la forme des différentes photos.

ici par exemple avec un réglage à 41 au lieu de 50, de nombreux visages sont « reconnus » mais avec une marge d’erreur plus forte…

Conclusion

En détournant un outil tel que Digikam, on peut obtenir très rapidement un très chouette outil d’OSINT et vous faire gagner un temps précieux pour l’exploitation de milliers de clichés.

Attention toutefois. Digikam reste un outil… jamais parfait!
Fiez vous aussi à votre œil!

CTF Trace Labs #5 – Recherches de micro-informations, gestion du temps, et Mr Freeze

CTF Trace Labs #5 – Recherches de micro-informations, gestion du temps, et Mr Freeze

Quand l’un des membres d’OpenFacto a annoncé sur Slack qu’un nouveau CTF (Capture The Flag) Trace Labs allait avoir lieu le 11 juillet, quelques mains se sont levées pour participer. Quand il a annoncé que cette fois-ci il aurait lieu de 17h à 23h, donc pas de minuit à 6h comme lors de la précédente édition, c’est une avalanche de membres qui a manifesté son intérêt ! (ou en tout cas assez pour constituer deux équipes de quatre, l’auteur étant simplement friand de formules grandiloquentes).


Vous n’avez jamais entendu parler de ces évènements organisés en vue de retrouver des personnes disparues ? Envie d’avoir un peu plus de détails ? Nous vous invitons à lire notre premier retour d’expérience écrit suite à notre précédente participation.


Aujourd’hui, pas d’article visant à approfondir un point de connaissance, comme avec le premier article qui s’intéressait à la question de l’analyse des tatouages.

L’idée est plutôt de faire le point sur notre organisation, ce qui a marché, ce qui a moins marché, et des axes d’amélioration possibles pour le futur.
Si vous avez des avis à partager sur ce qui suit, n’hésitez pas à nous répondre ici en commentaire ou via Twitter. Et si nous oublions de mentionner des éléments qui vous semblent importants, faites-nous signe et nous mettrons à jour l’article avec ces derniers.

Organisation

Pour cette édition, huit membres d’OpenFacto étaient motivés pour participer, nous avons donc fait deux équipes :

  • OpenFacto (obviously), comptant à son bord Capteurso, Hervé, Sébastien et ştəf// – fini 26ème sur 190 équipes ;
  • The French Flair by OF, composée notamment de L003, 0skAr et Roman – fini 23ème.
Tableau des scores final


Ensuite, pour répartir les gens entre les deux équipes, nous avons fait passer des tests d’aptitude à l’OSINT, évalué les CVs de chacun(e), et… non pas du tout, nous avons pris le premier (littéralement) site de répartition aléatoire en équipe sur Google, et défini les équipes à partir de là. Il s’est avéré que les teams ainsi formées ont bien fonctionné ; à voir pour la prochaine édition si nous essayons de déployer une réelle stratégie quant à ce sujet – nous y reviendrons plus tard.


Pour la communication écrite, nous avons privilégié Slack, qui permet de faire un thread par profil, afin de ne pas mélanger toutes les informations. Le canal vocal était assuré par Jitsi.

Il était envisagé d’utiliser framamind afin de faciliter la visualisation des profils et informations récoltées. Finalement, le fait de ne pas forcément changer souvent de cas d’analyse a fait que les threads Slack étaient suffisants. 

A noter toutefois que TraceLabs recommande dans son guide de ne pas passer plus d’une heure sur un cas où l’on ne trouverait aucune information, et conseille également l’utilisation de cartes mentales (cf. p.15-16).

Cette édition proposait l’analyse de huit cas, chaque membre d’une équipe était donc en charge de deux profils a minima, avec possibilité de passer sur d’autres en cas d’impasse. 

Quelques points à retenir pour les prochaines éditions

Ci-dessous une liste de points en vrac, sans classement suivant l’importance du contenu, mais qu’il nous semble pertinent d’avoir en tête pour les prochaines fois :

  • Si aucun flag n’est validé ni rejeté au bout d’une heure, ne pas hésiter à pinger l’équipe TraceLabs sur Slack, par exemple AK47Intel. Et même, mieux : vérifier à l’avance que l’équipe s’est bien vue assigner un juge (un fichier csv est fourni dans le channel du CTF afin de connaître le nom du juge qui s’occupe de l’équipe).
  • La recherche de profils snapchat via snapdex.com ne renvoie pas forcément de résultats pertinents.
  • Les copies d’écrans Android ne servent à rien si la preuve ne peut être rattachée à une URL (l’URL snapcode ne suffit pas).
  • Prendre le temps de faire une première passe, pour les profils US, sur des sites de recherches US (ex : spytox.com, thatsthem.com, etc.). MAIS bien prendre avec des pincettes ce que renvoient ces sites. Idéalement effectuer quelques vérifications derrière, avant de soumettre le flag.
  • Prendre le temps aussi de faire une première passe sur les informations basiques (ex : dates de naissance) qui, si elles ne rapportent que peu de points, une fois accumulés en fournissent finalement un nombre conséquent.
  • Prendre le temps – si réalisable – de lire les posts sur les réseaux sociaux de la personne disparue (notamment pour connaître ses hobbies). A minima aux alentours de la date de sa disparition. Se pencher aussi sur les commentaires et tags de personnes proches permettant (potentiellement) de récupérer d’autres profils de la cible, ainsi que leur nouveau compagnon/nouvelle histoire, qui les renvoient à leur profil actuel.
  • A ce sujet, Twint se révèle bien pratique pour ne récupérer que les tweets postés au moment de la disparition de la personne (notamment profils Twitter de ses amis).
  • La question de savoir comment déterminer si un numéro de téléphone US est assigné à un fixe ou un mobile s’est posée pendant l’évènement. A tête reposée, nous pouvons maintenant dire qu’il aurait pu être intéressant de passer par des services tels que TrueCaller ou OpenCnam, FreeCarrierLookup ou encore HLR Lookup déjà mentionné il y a quelques temps sur le discord d’OSINT-FR – mais aucune garantie quant à l’identification mobile/fixe.
  • Faire la liste d’un ensemble de sélecteurs (adresses mails, numéros de téléphones, création d’adresses mails et pseudos à partir du nom+prénom, etc.). Puis les vérifier sur autant de plateformes que possible (via whatsmyname ou instantusername), et lister le tout dans un document collaboratif. Envisager ensuite de désigner une à deux personnes afin d’approfondir ces données et réaliser une investigation latérale (recherche massive de sélecteurs et de sources potentielles) de l’investigation transversale (approfondissement d’un profil, ses commentaires, etc.).
  • Préparer des outils et moteurs pour le darkweb en amont et y passer au crible tous les sélecteurs (identité, email, username, etc.). Envisager de préparer une base de leaks avant l’évènement.
  • Préparer également un ensemble de services de « reconnaissance faciale » : Yandex, Bing, Tineye, etc..
  • Dans l’ensemble, nous avons réalisé beaucoup de recherches manuelles. A voir donc si et comment il serait possible d’en automatiser une partie.
  • Voir pour passer moins de temps sur certains profils. 6h, c’est à la fois très peu et très long, mais il s’agirait de réfléchir si passer 4 à 5h sur le même profil – ce qui a été le cas pour un ou deux membres – est vraiment un choix efficace.
  • Autre point à voir plus tard : envisager peut-être un rôle/spécialité par personne/compétence.
    • un/e « forgeron » qui récupère, par OSINT ou recréation, tous les sélecteurs, qu’il met à disposition ;
    • un/e ou deux enquêteurs qui approfondissent les profils et les subtilités historiques et comportementales ;
    • un/e spécial deepweb/darkweb.
      L’autre possibilité consistant à d’abord se concentrer sur un ou deux profils, puis passer à une revue de tous les profils en ne s’intéressant qu’à un des aspects mentionnés ci-dessus.

Conclusion

Ce qui est pas mal ressorti de nos discussions post-CTF, c’est la frustration de ne pas trouver des informations particulièrement remarquables sur chaque profil. Est-ce que cela vaut vraiment le coup de passer 6h sur le cas de deux à trois personnes disparues, pour ne ressortir finalement que des éléments facilement retrouvables : numéro de téléphone posté sur instagram, liens vers les différents profils sur les réseaux sociaux, etc. ?


A cette question que bon nombre se posent, Trace Labs réponds oui, cela vaut la peine : « We may not always find relevant or useful information to pass along to Law Enforcement (LE). But what we did accomplish was showing Law Enforcement that they truly have exhausted every lead and that they did their jobs well and to the best of their abilities. To them, that’s extremely valuable and it puts their minds at ease. » 


Chaque information, aussi minime qu’elle soit à vos yeux, doit être remontée : marque du téléphone de la personne (information intéressante pour les forces de l’ordre), goût prononcé pour le dessin, l’alcool, les Mr Freeze, etc.. Tout peut avoir son importance, pour peu que les personnes en charge de l’enquête n’y ait pas prêté attention. Et si c’est déjà le cas, cela les rassurera néanmoins quant au fait qu’elles ont cherché autant que possible.


En outre Trace Labs insiste sur le fait qu’il ne faut pas oublier les deux buts principaux de ces évènements :

  • trouver des informations sur des personnes disparues ;
  • améliorer nos compétences en OSINT – car oui, cela compte aussi.

Vous avez, vous aussi, été frustré par les données obtenues après de longues heures de recherches ? Hauts les cœurs, cela fait partie de l’apprentissage ! Et si vous n’avez pas l’impression d’être devenu une rock star de l’OSINT en 6h, vous avez néanmoins mis en pratique des connaissances déjà acquises – vous n’en deviendrez que plus efficace – voire appris de nouvelles techniques – on ne peut espérer mieux – et participé à un effort positif international. Donc rien de tout cela n’est perdu.


Un autre point qui nous a été remonté, c’est qu’il était encore plus sympa de réaliser ce genre d’évènements dans un même lieu avec le reste de l’équipe. Ainsi, à titre informatif, OpenFacto commence à réfléchir à comment réunir, une fois par an, l’ensemble de ses membres participant au CTF dans un espace commun, afin que les coéquipiers puissent interagir ensemble de vive voix, et que les différentes teams puissent ensuite échanger sur les cas abordés une fois le CTF fini.

Intéressé ? Faites-le-nous savoir sur Twitter ou notre Slack !


Un grand bravo à toutes les équipes !

Export de Telegram au format csv – introduction à BeautifulSoup

Export de Telegram au format csv – introduction à BeautifulSoup


Quand les petites mains ne suffisent plus pour parcourir des quantités monstrueuses de données.
Quand les expressions régulières sont hors-jeu face au html.
Quand l’agrégation de données dans un beau fichier csv ne semble qu’un rêve lointain.

BeautifulSoup (et Python dans sa globalité) est là !

Il y a quelques temps, la question de comment récupérer l’historique des messages Telegram pour les transférer dans un fichier au format csv a été posée par un des membres d’OpenFacto. Si la réponse vous intéresse, et que vous souhaitez apprendre quelques bases de programmation Python en chemin, vous êtes sur le bon article.

*****
TL;DR : voir le premier paragraphe pour l’export Telegram, le code python html → csv se trouve à la fin.
*****

Export de l’historique Telegram

La version bureautique de Telegram propose une fonctionnalité d’export des messages :

Export de l’historique Telegram

Il est possible de sélectionner les éléments à exporter parmi les messages texte seuls, photos, vidéos, messages vocaux, etc.

Options pour l’export du salon de discussion


A l’issue du téléchargement, on obtient un ensemble de fichiers au format html contenant l’historique récupéré. 
Vous vous apprêtez à sortir vos meilleures expressions régulières pour parser ces fichiers ? Retirez immédiatement vos doigts de ce clavier, malheureux ! Les expressions régulières, aussi élégantes soient-elles, ne sont pas adaptées pour parser du html (voir notamment cette fameuse réponse sur StackOverflow). Oui, c’est réalisable, mais le format d’une page html fait qu’en général vous passerez plus de temps à trouver la bonne regex qui matche la bonne balise à chaque fois, que si vous utilisiez un outil créé expressément pour cette tâche.
Ici nous allons faire usage de la librairie Python BeautifulSoup.

Quelques bases pour Python et BeautifulSoup

En programmation, il est recommandé d’utiliser un environnement de développement intégré (IDE en anglais), par exemple VSCodium, logiciel libre, ou Pycharm, spécifique à python. Un IDE est un éditeur de texte exclusivement utilisé pour coder, qui permet par exemple la coloration syntaxique du code, et facilite son écriture en soulignant notamment les librairies non installées, les variables non déclarées/mal orthographiées, etc. Oui, au vu de la taille du code, cela peut s’écrire bêtement sous Vim (ce qui a d’ailleurs été le cas). Cependant, à la longue, un IDE est objectivement appréciable. 

Pour pouvoir utiliser une librairie comme csv, permettant de créer/manipuler un fichier csv, on utilise le mot clé import suivi du nom de la librairie. Nous avons également besoin de os, pour la manipulation de noms de fichiers et dossiers. Et pour BeautifulSoup il suffit d’importer une partie seulement de la librairie, à savoir bs4. Si la librairie n’est pas déjà installée sur l’ordinateur, on l’installe via la commande pip install beautifulsoup4, à taper soit dans un terminal classique, soit dans le terminal intégré à l’IDE.

Note : il s’agit d’une simple copie d’écran. Le code complet se trouve à la fin de l’article.


Nous partons ici du postulat que nous plaçons le code dans un fichier (par exemple telegram.py) se trouvant dans le même dossier que l’ensemble des fichiers html récoltés. Nous définissons donc la variable directory, à laquelle on assigne le chemin vers le dossier contenant le fichier python (et donc les fichiers html voisins).

Ensuite, pour créer un tableau csv, avec des lignes, des colonnes, nous allons d’abord créer une liste python (cf. [ ], qui est une liste vide), elle-même constituée de listes : par exemple le n-ième élément de cette liste correspond à la n-ième ligne du tableau, et est implémenté sous la forme d’une liste  où le premier élément correspond à la première colonne, le deuxième élément à la deuxième colonne, etc.. En résumé, un tableau = une liste de listes.

Pour une question d’esthétisme et de clarté, nous allons nommer nos colonnes. A cette fin, nous ajoutons (.append()) à la liste (vide) le nom de chaque colonne, la première ligne des fichiers csv étant généralement utilisée pour déterminer les noms des colonnes.


A titre de rappel, Python est un langage faisant usage de l’indentation (tabulation ou quatre espaces) afin de délimiter ses blocs de code (boucle, condition, fonction, classe, etc.). Ici nous allons parcourir (boucle for – ne pas oublier le caractère ‘:’ en fin de ligne, et l’incrémentation de l’indentation) l’ensemble des fichiers contenus dans le dossier directory. Puis si le fichier se termine par l’extension « .html » (condition « if », à nouveau ne pas oublier le caractère ‘:’ et l’incrémentation de l’indentation),  alors on l’ouvre en lecture simple.


Avant de nous plonger dans les fonctions offertes par BeautifulSoup, il faut jeter un œil aux fichiers html pour déterminer les informations que nous souhaitons extraire ainsi que leur emplacement.A titre d’exemple, voilà ce qu’un message Telegram peut donner :

     <div class="message default clearfix" id="message197514">
      <div class="pull_left userpic_wrap">
       <div class="userpic userpic2" style="width: 42px; height: 42px">
        <div class="initials" style="line-height: 42px">
        </div>
       </div>
      </div>
      <div class="body">
       <div class="pull_right date details" title="11.02.2020 09:03:59">
09:03
       </div>
       <div class="from_name">
Toto
       </div>
       <div class="text">
10:03: Hello world !
       </div>
      </div>
     </div>

On voit qu’un message est délimité par des balises <div> qui ont pour classe message default clearfix.
A l’intérieur de chaque message, l’heure et la date de réception par le serveur se trouvent dans une autre balise <div> dont la classe est pull_right date details, plus exactement en tant que valeur de l’attribut title. De manière similaire, l’expéditeur se trouve dans une balise <div> de classe from_name, à la différence que cette fois il s’agit du texte contenu dans la balise et non de la valeur d’un attribut de cette balise. 


Voyons maintenant comment récupérer tout cela avec BeautifulSoup : 

  • Pour récupérer toutes les balises html correspondant à un critère, on utilise la méthode findAll(). Il est possible de spécifier notamment le nom de la balise recherchée et la classe.
  • Si une seule balise doit être récupérée, on utilise la méthode find().
  • Le contenu d’un attribut de balise s’obtient, comme pour un dictionnaire, en spécifiant son nom dans .attrs .
  • Enfn le contenu d’une balise est lisible via .text .

Il s’agit ici d’une partie infinitésimale de toutes les fonctions offertes par BeautifulSoup. Sentez-vous libres de lire la documentation pour en découvrir plus !


On notera dans le code ci-dessous que l’heure et la date ont été séparés dans deux variables distinctes afin de créer deux colonnes toutes aussi distinctes. En outre, une condition a été rajoutée dans la récupération du contenu du message pour gérer un cas spécifique à l’historique étudié lors de l’écriture du code.


La méthode .append() permet d’ajouter une nouvelle colonne à la ligne courante row. Une fois la ligne complète, on l’ajoute à la liste de lignes output_rows.


A noter toutefois que ce code est simplifié au maximum et ne gère pas les erreurs (exceptions) pouvant être levées. Un bon programmeur prendra le temps de vérifier par exemple que la méthode find() ne retourne pas un None – lorsque l’élément cherché n’est pas trouvé – avant d’appliquer une autre méthode sur l’élément retourné, ce qui évitera au programme de planter.


Il ne reste alors plus qu’à écrire le contenu de output_rows dans notre fichier csv. Le fichier peut être ouvert avec le paramètre ‘a’ – et non ‘w’ – si l’on souhaite ajouter (append) de nouvelles données à celles déjà présentes dans le fichier plutôt que d’écraser celles déjà existantes.


Pour faire tourner ce bout de code, il suffit lancer la commande python suivie du nom du fichier (ici telegram.py) dans un terminal, et un fichier output.csv apparaîtra quelques secondes plus tard dans le même répertoire.

Code complet

Ici le code étudié ci-dessus :

from bs4 import BeautifulSoup
import csv
import os

# Placer le script dans le meme repertoire que les fichiers d'historique
directory = os.path.dirname(os.path.realpath(__file__))

# Creation du tableau et des noms de colonnes
output_rows = []
output_rows.append(("Date", "Time", "Sender", "Message"))

for html_file in os.listdir(directory):
    filename = os.fsdecode(html_file)

    if filename.endswith(".html"):
        html = open(filename).read()
        soup = BeautifulSoup(html, features="html.parser")

        msgs = soup.findAll("div", {"class": "message default clearfix"})
        for msg in msgs:
            row = []

            # Date et heure
            time = msg.find("div", {"class": "pull_right date details"}).attrs["title"]
            date, time = time.split()
            row.extend((date, time))

            # Expediteur
            row.append(msg.find("div", {"class": "from_name"}).text.strip())

            # Message
            date_msg = msg.find("div", {"class": "text"}).text
            if ": " in date_msg:
                msg_alone = date_msg.split(": ")[1].strip()
            else:
                msg_alone = date_msg.strip()
            row.append(msg_alone)

            output_rows.append(row)

with open("output.csv", "w") as csv_file:
    writer = csv.writer(csv_file)
    writer.writerows(output_rows)

Le code mis à jour est disponible sur le dépôt GitHub OpenFacto.

Pour aller plus loin

Scraper les internets

Si Telegram a pris le parti de faire usage du format html pour stocker ses historiques, il n’est pas le seul à l’utiliser :  Internet regorge de pages html ! (ce qui est sans doute le principal cas d’application visé au départ par BeautifulSoup, plus que les historiques Telegram…)

Alors pourquoi ne pas employer ces nouvelles connaissances en vue de parcourir (on dira « scraper ») la toile mondiale ?
La seule différence notable est qu’il faudra dans un premier temps récupérer la page html qui nous intéresse. Python met à disposition la librairie request, qu’il suffit d’importer comme précédemment avec le mot clé import. Nous obtenons le contenu de la page via la méthode request() à laquelle nous passons la variable contenant l’url ainsi que, astuce de sioux, un objet headers. Celui-ci permettra de contourner certaines vérifications qui s’assurent que les requêtes sont bien réalisées par un navigateur et non un robot.
Pensez également à mettre un temps de pause (via la méthode sleep()) entre deux requêtes pour éviter de surcharger le serveur requêté – et provoquer un DoS si ce dernier est un peu fragile.

import requests
from random import randint
from time import sleep

useragent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0'
headers = {
    'User-Agent': useragent
}
url = "" # url du site à requêter

sleep(randint(3,10))
response = requests.get(url, headers = headers)

Crontab

Quid si vous souhaitez aller toujours plus loin dans l’automatisation ? C’est le moment de passer à… cron ! Il s’agit du programme, sous Linux et Mac, permettant de programmer une tâche afin qu’elle soit exécutée de manière répétitive à un moment précis. L’équivalent Windows-ien est le Task Scheduler. Nous allons nous concentrer ici sur cron.

Pour lister les tables cron déjà disponibles, on lance la commande suivante :
crontab -l

Pour éditer les tables, on utilise l’option -e :
crontab -e

Un doute sur une commande ? On utilise man crontab afin d’afficher le manuel (appuyer sur la touche ‘q’ pour le quitter).
Une fois la commande d’édition lancée, vous vous trouvez dans un éditeur de texte (généralement Vi(m) ou Nano). Pour éditer (entrer dans le mode édition) de Vi(m), appuyez sur la touche ‘i’. Pour sortir de ce mode, appuyez sur la touche echap. Pour quitter le document sans sauvegarder (si, si, c’est possible de quitter Vi(m)), appuyez sur echap puis « :q! ». Pour sauvegarder, echap puis « :w ». Pour plus de commandes : .


Chaque ligne correspond à une tâche à exécuter et a le format suivant :

mm hh jj MM JJ tâche avec :

  • mm : les minutes (0-59) ;
  • hh : les heures (0-23) ;
  • jj : le jour du mois (0-31) ;
  • MM : le mois (1-12, ou les noms) ;
  • JJ : le jour de la semaine (0-7, 7 correspondant à dimanche, ou les noms) ;
  • tâche : la tâche à exécuter.

Les ranges sont acceptés, tel que 0-15 dans les minutes pour une exécution à chaque minute durant le premier quart d’heure. Le charactère spécial ‘*’ signifie « du premier au dernier », et peut être « divisé », comme avec « */2 » dans les heures pour signifier « toutes les deux heures ».

Par exemple, pour faire tourner un script tous les jours à 23h59 :
59 23 * * * /chemin/vers/mon_script.py

Ou toutes les 10 minutes :
*/10 * * * *  /chemin/vers/mon_script.py

IMPORTANT : ce code est donc exécuté automatiquement suivant la configuration dans la crontab. Il est essentiel que le fichier exécuté soit détenu et éditable par votre utilisateur et seulement votre utilisateur. Si le script est lancé en tant que root (ou autre équivalent à l’administrateur de la machine), il ne doit appartenir qu’à root (ou équivalent) et seulement éditable par lui. Autrement, si votre machine se fait compromettre, un attaquant pourra éditer le script et attendre tranquillement l’exécution automatique de son code malveillant avec les droits de votre utilisateur, ou, pire, ceux de root.

Prenez donc le temps de vérifier les droits sur votre script :

ls -la /chemin/vers/mon_script.py

Les droits inscrits doivent ressembler à quelque chose comme :
-rwxrw-r--.  1 nom_utilisteur nom_groupe taille date  mon_script.py

Ce qui signifie :

  • lecture (r), écriture (w), exécution (x) pour l’utilisateur nom_utilisateur ;
  • lecture, écriture pour l’ensemble des utilisateurs appartenant au groupe nom_groupe ;
  • lecture seule pour tous les autres utilisateurs.

Utilisez la commande chown nom_utilisateur: mon_script.py pour modifier l’utilisateur et le groupe propriétaires du script.

Utilisez la commande chmod 764 mon_script.py pour positionner les droits ci-dessus.

Au besoin, vérifiez que tous les dossiers parents appartiennent à l’utilisateur en question – ou un utilisateur plus privilégié comme root.

Retour sur enquête: monitorer un événement public sur les réseaux sociaux

Retour sur enquête: monitorer un événement public sur les réseaux sociaux

Dans une enquête pour Bellingcat, Sébastien s’intéressait à la présence d’un militant de l’extrême-droite française au festival néo-nazi “Asgardsrei” qui avait lieu en Ukraine en décembre 2019. A travers cet exemple, il fait ici un rappel des techniques basiques pour monitorer un événement public (concert, manifestation etc.) sur les réseaux sociaux.


L’unique point de départ de mon enquête était une photo diffusée via Telegram montrant un drapeau du Groupe Union Défense (GUD) brandi dans la foule lors du festival de “Black Métal National Socialiste” (NSBM) “Asgardsrei” qui avait lieu à Kiev, en Ukraine, le week-end du 14–15 décembre 2019. Celle-ci indiquait vraisemblablement qu’au moins un militant français avait fait le déplacement.

La photo diffusée via Telegram.

Bien évidemment, la personne apparaissant sur la photo avait pris soin de ne laisser apparaître aucun élément permettant de l’identifier, on voit simplement une main ainsi qu’une ombre à travers le drapeau. 

Dans un premier temps, j’ai donc décidé de collecter d’autres images du festival. Comme pour n’importe quel événement de ce type, le nombre important de vidéos, photos souvenirs et autres selfies publiés sur les réseaux sociaux multipliait la probabilité que ce militant français ait été capté par un objectif autre que le sien.

Récolter le maximum d’images du festival

Puisque je cherchais des images de l’événement, je me suis intéressé dans un premier temps à Instagram, réseau social par excellence en la matière. Pour essayer d’être le plus exhaustif possible, j’ai procédé selon deux approches différentes.

D’une part, quelques recherches rapides m’avaient appris que le festival avait eu lieu au “Bingo Club” à Kiev. J’ai donc cherché les photos et vidéos tagués comme ayant été prises dans cette salle. Comme souvent, il existait plusieurs geocodes liés à cette salle (Bingo Club, BingoClub Kyiv, Bingo Club Kiev…), et je les ai donc consultés les uns après les autres.

Les deux premiers geotags correspondent à la salle située à Kiev
Exemple d’une photo geo-taguée par un utilisateur au Bingo Club.

Pour récupérer l’ensemble des photos et vidéos, j’ai utilisé l’extension chrome “Downloader of Instagram + Direct Message” qui permet de télécharger automatiquement un grand nombre de publications. Si c’était à refaire aujourd’hui, j’utiliserais plutôt l’outil python “Instaloader” (pour les adhérents, voir l’excellent guide d’Hervé !) qui permet d’être plus précis, notamment en indiquant la date des photos et vidéos qui nous intéressent, ou bien de récupérer les commentaires associés à une publication.

Dans un second temps, j’ai cherché les publications contenant certains hashtags qui pouvaient être liés au festival. J’ai tout simplement commencé par #Asgardsrei, puis je me suis servi des autres hashtags associés par les utilisateurs à ce premier pour pivoter vers d’autres recherches.

Photos avec le #Asgardsrei.
En plus du #Asgardsrei, cette photo utilise d’autres # pouvant être utilisés pour multiplier les recherches.
Exemple d’une vidéo du festival que je n’aurais pas trouvé si j’avais simplement cherché avec le #Asgardsrei ou via les geotags.

Puisque j’ai effectué mes premières recherches alors que le festival avait encore lieu, j’ai également téléchargé toutes les stories (publications qui disparaissent au bout de 24h) associées aux différents hashtags, ainsi que celles géo-tagués au Bingo Club.

En suivant peu ou prou le même procédé, j’ai cherché des images du festival sur Facebook, Vkontakte, Twitter, Youtube, Snapchat… Je me suis également intéressé aux différentes pages en rapport avec le festival: événement sur VKontakte, pages sur les réseaux sociaux des groupes présents, site internet du festival etc.

L’analyse

Après avoir récupéré des centaines de photos et vidéos du festival, il s’agissait désormais de repérer dans la foule le drapeau du GUD ou bien un visage familier.

Puisque la plupart des images étaient prises dans l’obscurité de la salle de concert, seulement interrompue par quelques flashs lumineux liés à la mise en scène, j’ai essayé de situer dans l’espace la personne que je cherchais. La foule semblait relativement statique (mis à part un mosh vers le centre de la salle à certains moments), j’en ai donc conclu que l’individu qui m’intéressait devait probablement se situer en face de la scène, vers l’avant de la salle. Si un simple croquis et un œil attentif m’ont permis de le repérer assez rapidement (quelques heures tout de même), j’ai aussi envisagé la possibilité de synchroniser différentes vidéos du festival pour en reconstituer des parties sous plusieurs angles.

Ce travail m’a donc permis de repérer le drapeau du GUD à de multiples reprises lors du festival (principalement lors des passages des groupes “Baise Ma Hache” et “Goatmoon”), mais surtout d’apercevoir son porteur.

Captures d’écran d’une vidéo publiée sur Youtube.

Identifier le porteur du drapeau

Cette silhouette qui m’était familière, ainsi que d’autres indices publiés sur la page Facebook “Ouest Casual” (associée au canal Telegram) laissant penser que le militant s’étant rendu en Ukraine était lié au groupe “Zouaves Paris”, m’ont conduit à consulter le profil d’un certain Marc “Hassin”. Ancien membre du GUD et militant bien connu des Zouaves Paris, Marc avait récemment mis à jour sa photo de profil Facebook, indiquant que celle-ci avait été prise en Ukraine, le 21/10/2019.

La photo de profil Facebook de Marc “Hassin”.

Peu convaincu par la possibilité que Marc “Hassin” ait effectué un voyage en Ukraine presque deux mois jours pour jours avant Asgardsrei, et en partant du principe que la date indiquée pouvait contenir une faute de frappe (10 pour le mois au lieu de 12) ou bien avoir été volontairement modifiée, j’ai décidé d’effectuer des recherches sur ce championnat de kick-boxing.

Ayant peu de résultats convaincants via Google et Yandex, j’ai encore une fois utilisé Instagram et cherché des photos utilisant #kickboxing aux alentours du 21 décembre. Sur plusieurs d’entre-elles, j’ai remarqué un décor similaire à celui en arrière-plan sur la photo de Marc “Hassin”.

Photo du championnat auquel a participé Marc “Hassin” publiée sur Instagram avec le #kickboxing.

Après vérification, il s’agissait bel et bien du même événement, un championnat s’étant déroulé au “Спорткомплекс КПИ” à Kiev du 20 au 22 décembre. J’ai donc une fois de plus réuni le maximum de photos et vidéos du championnat, que ce soit via divers #hashtags ou bien le géotag.

Marc n’apparaissant visiblement pas sur celles-ci, j’ai consulté méthodiquement les profils Instagram des personnes ayant publié ces photos: autres photos publiées, photos sur lesquels le compte est identifié, stories “à la une” (stories archivées par l’utilisateur et donc en ligne au delà des 24h initiales).

Après de longues recherches, j’ai finalement identifié Marc sur plusieurs photos, notamment des stories archivées. Sur l’une d’entre elles, Marc posait avec le même drapeau que celui brandit à Asgardsrei.

Photo de Marc “Hassin” au championnat de kick-boxing à Kiev avec un drapeau du GUD, publiée sur Instagram et archivée en “stories à la une”.

Conclusion

Si d’autres informations sont venues compléter mon enquête, ce sont les deux éléments présentés ici (la silhouette du porteur du drapeau et la photo de Marc avec ce même drapeau à Kiev quelques jours plus tard) qui en ont formé la base.

En somme, donc, pas de recours à des techniques de sorcellerie très poussées en OSINT, mais un travail se voulant méthodique et exhaustif. Comme quoi multiplier ses recherches autours de différents hashtags ou geotags et compulser des dizaines de profils efficacement peut (parfois) suffire!