select based trivial port scanner

This commit is contained in:
Oleksii Shevchuk 2017-03-05 12:18:58 +02:00
parent b089e69ac5
commit 08fc22a932
3 changed files with 127 additions and 81 deletions

View File

@ -1,23 +1,27 @@
# -*- coding: UTF8 -*-
# -*- coding: utf-8 -*-
from pupylib.PupyModule import *
from modules.lib.windows.winpcap import init_winpcap
from netaddr import IPNetwork, IPAddress
import logging
from datetime import datetime
from netaddr import *
import random
import threading
__class_name__="PortScan"
@config(cat="network")
class PortScan(PupyModule):
""" run a TCP port scan """
dependencies=['portscan', 'scapy']
abort = None
terminated = threading.Event()
max_clients = 1
connectable = []
def init_argparse(self):
self.arg_parser = PupyArgumentParser(prog="port_scan", description=self.__doc__)
self.arg_parser.add_argument('--ports','-p', default="21,22,23,80,139,443,445,1433,1521,3389,7001,8000,8080", help='ports to scan ex: 22,80,443')
self.arg_parser.add_argument('--timeout', default=4, help='timeout (default: %(default)s)')
self.arg_parser.add_argument('--threads', default=10, help='number of threads (default: %(default)s)')
self.arg_parser.add_argument('--timeout', default=10, help='timeout (default: %(default)s)')
self.arg_parser.add_argument('--portion', default=32, help='number of ports scanned per timeout (default: %(default)s)')
self.arg_parser.add_argument('target', metavar="ip/range", help='IP/range')
def run(self, args):
@ -27,20 +31,47 @@ class PortScan(PupyModule):
hosts = list()
hosts.append(args.target)
ports = [int(p.strip()) for p in args.ports.split(',')]
ports = [
p for prange in args.ports.split(',') for p in (
xrange(
int(prange.split('-')[0]), int(prange.split('-')[1])+1
) if '-' in prange else xrange(
int(prange), int(prange)+1
)
)
]
ports = list(set(ports))
random.shuffle(ports)
for host in hosts:
self.success("Scanning remote host: %s" % host)
scanner = self.client.conn.modules['network.lib.scan']
t1 = datetime.now()
open_ports = self.client.conn.modules['portscan'].scan(host, ports, args.threads, args.timeout)
if open_ports:
self.log('PORT STATE')
for p in open_ports:
self.log("%s open" % p)
def set_connectable(ports):
self.connectable = ports
self.terminated.set()
self.abort = scanner.scanthread(
str(host), ports, set_connectable, timeout=args.timeout, portion=args.portion
)
self.terminated.wait()
ports = sorted(self.connectable)
if ports:
self.log('{}: {}'.format(host, ', '.join([str(x) for x in ports])))
else:
self.error('No open port found')
self.log('{}: closed'.format(host))
# Checking the time again
t2 = datetime.now()
total = t2 - t1
self.success('Scanning Completed in: %s' % total)
if self.abort.is_set():
break
self.abort = None
def interrupt(self):
if self.abort:
self.abort.set()
if self.terminated:
self.terminated.set()

73
pupy/network/lib/scan.py Normal file
View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
import socket
import select
import errno
import time
import threading
import rpyc
def chunks(l, n):
for i in xrange(0, len(l), n):
yield l[i:i + n]
def create_socket(host, port):
sock = socket.socket()
sock.setblocking(0)
r = sock.connect_ex((host, port))
return sock, r
def scan(host, ports, abort=None, timeout=10, portion=32, on_complete=None):
connectable=[]
for portion in chunks(list(ports), portion):
if not portion:
continue
if abort and abort.is_set():
break
sockets = {}
for port in portion:
sock, r = create_socket(host, port)
if r:
if r in (errno.EAGAIN, errno.EINPROGRESS):
sockets[sock] = port
else:
sock.close()
continue
else:
connectable.append(port)
sock.close()
start = time.time()
while sockets and time.time() - start < timeout:
socks = list(sockets.iterkeys())
_, w, _ = select.select([], socks, [], timeout - (time.time() - start))
for sock in w:
errcode = sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
if errcode == 0:
connectable.append(sockets[sock])
sock.close()
del sockets[sock]
if on_complete:
if abort and not abort.is_set():
on_complete(connectable)
else:
return connectable
def scanthread(host, ports, on_complete, **kwargs):
host = str(host)
ports = [ x for x in ports ]
abort = threading.Event()
connectable = []
kwargs.update({
'abort': abort,
'on_complete': rpyc.async(on_complete)
})
scanner = threading.Thread(target=scan, args=(host, ports), kwargs=kwargs)
scanner.daemon = True
scanner.start()
return abort

View File

@ -1,58 +0,0 @@
#!/usr/bin/env python
import socket
import sys
import threading
import Queue
open_port = []
class WorkerThread(threading.Thread) :
def __init__(self, queue, tid, remote_ip, ports, settimeout) :
threading.Thread.__init__(self)
self.queue = queue
self.tid = tid
self.ports = ports
self.remote_ip = remote_ip
self.timeout = settimeout
def check_open_port(self, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(self.timeout)
result = sock.connect_ex((self.remote_ip, port))
if result == 0:
sock.close()
open_port.append(port)
def run(self):
for port in self.ports:
try :
port = self.queue.get(timeout=1)
except Queue.Empty :
return
self.check_open_port(port)
self.queue.task_done()
def scan(remote_ip, ports, nb_threads, settimeout):
global open_port
open_port = []
queue = Queue.Queue()
threads = []
for i in range(1, nb_threads):
worker = WorkerThread(queue, i, remote_ip, ports, settimeout)
worker.setDaemon(True)
worker.start()
threads.append(worker)
for j in ports:
queue.put(j)
queue.join()
# wait for all threads to exit
for item in threads :
item.join()
return open_port