En particulier, je déteste le fait qu'un plantage en fin de scan sur des milliers d'adresses perdent le résultat des machines correctement scannées. Et des plantages, ce n'est pas rare. C'est d'ailleurs extrêmement courant en UDP et avec des scripts NSE comme les enumérations netbios.
Sans quand on recherche l'exhaustivité totale, il est devenu plus logique de faire un premier scan de détection des live hosts. Là encore nmap est la référence, mais il risque de se faire détrôner par zmap ou masscan (que je n'ai pas testé de peur de faire tomber les réseaux). Pour nmap, je n'ai jamais réussi à maîtriser totalement les retry et timeout, ce qui fait que la durée des scans dérive parfois énormément. J'ai finalement opté pour mon programme en python/scapy.
Je commence par définir les paquets que je souhaite envoyer avec quelques informations :
ICMP 8 ICMP 13 ICMP 17 TCP 80 S TCP 80 A TCP 443 S TCP 443 A UDP 53 UDP 161
Puis une liste d'IP ou de hostname :
example.com example.com google.com scanme.insecure.org
Et enfin mon programme qui enverra uniquement les paquets que j'ai défini et rien d'autre :
#!/usr/bin/python # -*- coding: utf-8 -*- import argparse from threading import * from scapy.all import * import Queue import time conf.verb = 0 conf.noenum.add(TCP.sport, TCP.dport, UDP.sport, UDP.dport, ICMP.type) maxConnections = 100 timeoutPing = 3 connection_lock = BoundedSemaphore(value=maxConnections) logQueue = Queue.Queue() threads = [] endScript = False def printThread(logQueue,logFile): while True: if not logQueue.empty(): val = logQueue.get() logFile.write(val+"\n") print val else: if endScript: break time.sleep(2) def sendPacketICMP(packet,logQueue): ans=sr1(packet,timeout=timeoutPing) text='' if ans: text = '[+] ' + packet.sprintf("%IP.dst% ICMP/%ICMP.type%") + \ ' > ' + ans.sprintf("%IP.src% ICMP/%ICMP.type%") logQueue.put(text) else: text = '[-] ' + packet.sprintf("%IP.dst% ICMP/%ICMP.type%") + ' > No response' logQueue.put(text) def sendPacketTCP(packet,logQueue): ans=sr1(packet,timeout=timeoutPing) text='' if ans: text = '[+] ' + packet.sprintf("%IP.dst% TCP/%TCP.dport%/%TCP.flags%") + \ ' > ' + ans.sprintf("{IP:%IP.src% {ICMP:ICMP/%ICMP.type%}{TCP:TCP/%TCP.sport%/%TCP.flags%}}") logQueue.put(text) else: text = '[-] ' + packet.sprintf("%IP.dst% TCP/%TCP.dport%/%TCP.flags%") + ' > No response' logQueue.put(text) def sendPacketUDP(packet,logQueue): ans=sr1(packet,timeout=timeoutPing) text='' if ans: text = '[+] ' + packet.sprintf("%IP.dst% UDP/%UDP.dport%") + \ ' > ' + ans.sprintf("{IP:%IP.src% {ICMP:ICMP/%ICMP.type%}{UDP:UDP/%UDP.sport%}}") logQueue.put(text) else: text = '[-] ' + packet.sprintf("%IP.dst% UDP/%UDP.dport%") + ' > No response' logQueue.put(text) def sendPacket(ip,logQueue,proto,port,flag): if proto=='ICMP': packet=IP(dst=ip)/ICMP(type=port) sendPacketICMP(packet,logQueue) elif proto=='TCP': packet=IP(dst=ip)/TCP(dport=port,flags=flag) sendPacketTCP(packet,logQueue) elif proto=='UDP': packet=IP(dst=ip)/UDP(dport=port) sendPacketUDP(packet,logQueue) def ping_ip(ip,logQueue,config): try: for p in config: if len(p)==2: sendPacket(ip,logQueue,p[0],int(p[1]),'') else: sendPacket(ip,logQueue,p[0],int(p[1]),p[2]) finally: connection_lock.release() def main(): parser = argparse.ArgumentParser(description='Superping') parser.add_argument('-i', metavar='ip list', type=argparse.FileType('rt'), required=True) parser.add_argument('-c', metavar='config', type=argparse.FileType('rt'), required=True) parser.add_argument('-o', metavar='out-file', type=argparse.FileType('wt'), required=True) parser.add_argument('--version', action='version', version='%(prog)s 1.0') try: results = parser.parse_args() except IOError, msg: parser.error(str(msg)) lc = sum(1 for l in results.c) results.c.seek(0, 0) print '[*] Chargement de '+ str(lc) +' types de ping' config = [line.strip().split() for line in results.c.readlines()] lc = sum(1 for l in results.i) results.i.seek(0, 0) print '[*] Lancement du scan de '+ str(lc) +' machines' t = Thread(target=printThread,args=(logQueue,results.o)) t.daemon = True child = t.start() lines = results.i.readlines() for ip_line in lines: connection_lock.acquire() t = Thread(target=ping_ip,\ args=(ip_line.rstrip('\n'),logQueue,config)) t.daemon = True child = t.start() threads.append(t) [x.join() for x in threads] endScript = True print '[*] Fin des threads' if __name__ == '__main__': main()
La commande suivante me sort le résultat attendu :
./superping.py -i ip_list -c config -o log 2> /dev/null [*] Chargement de 9 types de ping [*] Lancement du scan de 3 machines [+] Net('google.com') ICMP/8 > 74.125.132.138 ICMP/0 [+] Net('example.com') ICMP/8 > 93.184.216.119 ICMP/0 [+] Net('scanme.insecure.org') ICMP/8 > 74.207.244.221 ICMP/0 [+] Net('scanme.insecure.org') ICMP/13 > 74.207.244.221 ICMP/14 [-] Net('google.com') ICMP/13 > No response [-] Net('example.com') ICMP/13 > No response [-] Net('scanme.insecure.org') ICMP/17 > No response [+] Net('scanme.insecure.org') TCP/80/S > 74.207.244.221 TCP/80/SA [-] Net('google.com') ICMP/17 > No response [-] Net('example.com') ICMP/17 > No response [+] Net('google.com') TCP/80/S > 74.125.132.138 TCP/80/SA [+] Net('example.com') TCP/80/S > 93.184.216.119 TCP/80/RA [+] Net('google.com') TCP/80/A > 74.125.132.139 TCP/80/R [-] Net('scanme.insecure.org') TCP/80/A > No response [+] Net('example.com') TCP/80/A > 93.184.216.119 TCP/80/R [+] Net('google.com') TCP/443/S > 74.125.132.113 TCP/443/SA [+] Net('scanme.insecure.org') TCP/443/S > 74.207.244.221 TCP/443/RA [+] Net('example.com') TCP/443/S > 93.184.216.119 TCP/443/RA [+] Net('example.com') TCP/443/A > 93.184.216.119 TCP/443/R [+] Net('google.com') TCP/443/A > 74.125.132.138 TCP/443/R [+] Net('scanme.insecure.org') TCP/443/A > 74.207.244.221 TCP/443/R [+] Net('scanme.insecure.org') UDP/53 > 74.207.244.221 ICMP/3 [+] Net('scanme.insecure.org') UDP/161 > 74.207.244.221 ICMP/3 [-] Net('google.com') UDP/53 > No response [-] Net('example.com') UDP/53 > No response [*] Fin des threads
Et voilà ! On obtient une jolie liste des IP up qu'on va pouvoir scanner intégralement avec Nmap.
Aucun commentaire:
Enregistrer un commentaire