我正在使用端口扫描器来扫描我的子网。不幸的是,端口扫描器一次只能扫描一台主机的一个端口。此外,扫描仪对无法访问的主机有 1 秒的超时。扫描仪(作为外部程序)必须从 subprocess.Popen() 运行并加快速度 - 这样我就可以发送多个探测器,而之前的一些探测器正在等待回复 - 我使用线程。问题出现在具有大量线程的完整 /24 子网扫描中。一些实际打开的端口显示为关闭。我怀疑输出会以某种方式出现乱码。请注意,如果我一次扫描较少的主机或一台主机,则不会发生这种情况
以下代码是我尝试创建一个线程池,该线程池采用 IP 地址并为定义的端口运行“顺序”端口扫描。一旦扫描了所有指定的端口,它就会从列表中选择下一个 IP。
while True:
if not thread_queue.empty():
try:
hst = ip_iter.next()
except StopIteration:
break
m=thread_queue.get()
l=ThreadWork(self,hst,m)
l.start()
while open_threads != 0:
pass
该片段设置线程队列的位置
thread_list = [x for x in range(num_threads)]
for t in thread_list:
thread_queue.put(str(t))
ip_iter=iter(self.final_target)
在 ThreadWork 函数中,我保留了一个打开线程的选项卡(因为 thread_queue.empty 被证明是不可靠的,我不得不使用这种粗略的方式)
class ThreadWork(threading.Thread):
def __init__(self,i,hst,thread_no):
global open_threads
threading.Thread.__init__(self)
self.host = hst
self.ptr = i
self.t = thread_no
lock.acquire()
open_threads = open_threads + 1
lock.release()
def run(self):
global thread_queue
global open_threads
global lock
user_log.info("Executing sinfp for IP Address : %s"%self.host)
self.ptr.result.append(SinFpRes(self.host,self.ptr.init_ports,self.ptr.all_ports,self.ptr.options,self.ptr.cf))
lock.acquire()
open_threads = open_threads - 1
lock.release()
thread_queue.put(self.t)
对 SinFpRes 的调用会为一个 IP 创建一个结果对象,并仅为该 IP 启动端口的顺序扫描。每个端口的实际扫描如图所示
com_string = '/usr/local/sinfp/bin/sinfp.pl '+self.options+' -ai '+str(self.ip)+' -p '+str(p)
args = shlex.split(com_string)
self.result=subprocess.Popen(args,stdout=subprocess.PIPE).communicate()[0]
self.parse(p)
然后,解析函数利用存储在 self.result 中的结果来存储该端口的输出。所有端口的聚合构成 IP 的扫描结果。
使用 10 个线程调用此代码可提供准确的 o/p(与 nmap 输出相比)。在提供 15 个线程时,偶尔会错过打开的端口。在提供 20 个线程时,会丢失更多开放端口。在提供 50 个线程时,许多端口被遗漏。
PS - 作为第一个计时器,这段代码非常复杂。向清教徒道歉。
PPS - 对于几乎没有扫描 20 个端口的整个 C 类子网,即使是线程化端口扫描也需要 15 分钟。我想知道是否应该将此代码移至另一种语言并使用 Python 仅解析结果。有人可以建议我一种语言吗?注意 - 我正在探索 S.Lott 所示的 Shell 选项,但在将其转储到文件之前需要手动处理。