mercredi 22 août 2012

[2/3] Python bot irc - Kit de première Analyse d'un fichier

Alors grâce à la partie [1/3] de ce tutoriel nous avons un bot connecté à un channel, mais qui ne sait rien faire d'autres.

Comment faire réagir notre bot:


Alors sur irc depuis mon client, j'ai écris : "test" voilà ce que le bot reçoit :

  • :nowz!nowz@I.saw.you.on.a.s3xtapz PRIVMSG #lechannel :test
  • :<user> PRIVMSG <chan> :<message>
Donc s'il y a plus de 3 mots et que le deuxième est PRIVMSG, nous avons donc reçu un message, mais nous allons aussi prendre le 3eme mots car, si par exemple vous êtes sur plusieurs channel il va falloir savoir sur lequel répondre, mais nous allons surtout le vérifier car quand votre bot reçoit un message privé il le reçoit de cette manière: 

  • :nowz!nowz@I.saw.you.on.a.s3xtapz PRIVMSG lePseudo :test
  • :<user> PRIVMSG <pseudoDuBot> :<message>
Comme vous pouvez le constater il y a seulement le 3ème mot qui change, c'est pour cela qu'on met une condition sur le mot n°3 (mot[2]) :

if len(mot) > 3 and mot[1] == 'PRIVMSG':
 if mot[2] == bChannel and mot[3] == ':test':
  irc.send('PRIVMSG %s :reponse au test\r\n' % mot[2])

J'ai créais deux conditions, afin que on évite de répéter la première condition pour toutes les commandes du mêmes types qu'on aimerait faire.

Screen ci-dessous: 




Téléchargement d'un fichier:

Nous allons réaliser une commande qui va télécharger un fichier à l'aide de la commande "!info <url>" que nous allons créer.

Depuis mon client j'ai tapé : !info http://site.fr/file.png, le bot reçoit :

  • :nowz!nowz@I.saw.you.on.a.s3xtapz PRIVMSG #lechannel :!info http://site.fr/file.png
On compte 5mots et le 4ème est !info et le 5ème est une adresse 


if len(mot) == 5 and mot[2] == bChannel and mot[3] == ':!info':
 get_file(mot[4])


Maintenant il faut créer cette fonction qui va télécharger notre fichier à l'adresse:

Donc pour ca on va utiliser la lib urllib

On ouvre le lien:


def get_file(chan, url):
 webFile = urllib.urlopen(url)


On met le nom du fichier dans une variable:


file_name = url.split('/')[-1]


On créait un fichier avec le même nom et y écrit le fichier distant et on ferme les 2 fichiers


 localFile = open('files/'+file_name, 'w')
 localFile.write(webFile.read())
 webFile.close()
 localFile.close()


Vous pouvez constater que je créais le fichier dans un dossier "files/", donc pensez à créer votre dossier.

Note importante
Je déconseille l'usage de cette fonction pour les utilisateurs car n'importe qui pourrait écrire n'importe quoi et ce n'importe où :).
Par exemple si il tape : !info http://site.fr/\..\..\file.exe , il arrivera à créer un fichier file.exe dans le dossier en amont de celui où est votre fichier .py

Comme vous pouvez le constater dans le screen ci-dessous, une fois que j'ai tapé !info <url> il a téléchargé le fichier et la bien enregistrer dans le dossier files.




Maintenant nous allons depuis ce fichier grâce à la lib hashlib trouver le hash md5 et sha1 de ce fichier tout fraichement téléchargé

On creait donc une nouvelle fonction (qui sera appellé depuis la première)

def get_info(chan, file_name):
 fmd5 = hashlib.md5(open('files/'+file_name, 'rb').read()).hexdigest()
 fsha1 = hashlib.sha1(open('files/'+file_name, 'rb').read()).hexdigest()


Une autre information qui pourrait être interessante est la réponse de la commande GNU/Linux file qui permet de determiner quel type de fichier nous faisons face.

Exemple de réponse de file sur le fichier fait téléchargé précedemment au bot:

$ file arduino_uno_test.jpg
arduino_uno_test.jpg: JPEG image data, JFIF standard 1.01

Et pour effectuer cette commande et récuperer le resultat on va utiliser la lib os .


  ffile = os.popen('file %s' % 'files/'+file_name).read()
  ffile = ffile.replace('files/%s: ' % file_name, '', 1)
  
  irc.send('PRIVMSG %s :md5: %s\r\n' % (chan, fmd5))
  irc.send('PRIVMSG %s :sha1: %s\r\n' % (chan, fsha1))
  irc.send('PRIVMSG %s :file: %s\r\n' % (chan, ffile))


Voici un screen du rendu:


Dans la partie suivante nous utiliserons yara-packer pour verifier si l'executable est passé sous les mains d'un packer, ainsi qu'une verification du hash md5 dans la bdd de VirusTotal, et d'autres petites infos qui pourraient être interessantes 

Code source entier: (Lien: pastie )


# -*- coding: utf-8 -*-

#import
import time
import socket
import string
import urllib
import hashlib
import os
 
#variables
bHost = 'irc.rizon.net'
bIp = socket.gethostbyname(bHost)
bPort = 6667
bPseudo = 'lePseudo'
bChannel = '#lechannel'

#autres variables
loop = 1

#fonctions
def get_file(chan, url):
 webFile = urllib.urlopen(url)
 file_name = url.split('/')[-1]

 localFile = open('files/'+file_name, 'w')
 localFile.write(webFile.read())
 webFile.close()
 localFile.close()
 
 get_info(chan, file_name)
 
def get_info(chan, file_name):
 fmd5 = hashlib.md5(open('files/'+file_name, 'rb').read()).hexdigest()
 fsha1 = hashlib.sha1(open('files/'+file_name, 'rb').read()).hexdigest()
 
 ffile = os.popen('file %s' % 'files/'+file_name).read()
 ffile = ffile.replace('files/%s: ' % file_name, '', 1)
 
 irc.send('PRIVMSG %s :md5: %s\r\n' % (chan, fmd5))
 irc.send('PRIVMSG %s :sha1: %s\r\n' % (chan, fsha1))
 irc.send('PRIVMSG %s :file: %s\r\n' % (chan, ffile))
 

#connection
irc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
irc.connect((bIp, bPort))

#message pour établir la connexion
irc.send('NICK %s\r\n' % bPseudo)
irc.send('USER %s %s %s :Python bot irc\r\n' % (bPseudo, bPseudo, bPseudo))

#boucle infinie
while loop == 1:
 data = irc.recv(4096)

 ligne = data.split("\r")

 for i in ligne:
  i = i.strip("\n")
  print "[%s] %s" % (time.strftime('%X'), i)
  mot = i.split(' ')

  if len(mot) > 2 and mot[1] == '376':
   irc.send('JOIN %s\r\n' % bChannel)
  

  if len(mot) == 2 and mot[0] == 'PING':
   irc.send('PONG %s\r\n' % mot[1])

  if len(mot) > 3 and mot[1] == 'PRIVMSG':
   if mot[2] == bChannel and mot[3] == ':test':
    irc.send('PRIVMSG %s :reponse au test\r\n' % mot[2])

   if len(mot) == 5 and mot[2] == bChannel and mot[3] == ':!info':
    get_file(mot[2], mot[4])

Aucun commentaire:

Enregistrer un commentaire