目录
- 前言
- 一、TCP全连接
- 二、程序编写
- 1.获得主机名和端口
- 2.解析主机名和端口
- 3.抓取应用的Banner
- 4.线程扫描
- 5.信号量机制
- 总结
前言
任何一个靠谱的网络攻击都是起步于侦查的。在这里,我们将使用Python来编写一个扫描目标主机或服务器开放的TCP端口的侦查脚本程序。
一、TCP全连接
所以成功的网络攻击一般都是以端口扫描拉开序幕的,因此在此我们使用TCP全连接扫描来确定目标主机的端口开放情况。
TCP连接的基本概念:
三次握手:
1、第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
2、第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
3、第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
则顾名思义,TCP全连接就是完成三次握手步骤的过程。
二、程序编写
1.获得主机名和端口
为了实现从用户方获取数据,我们在程序中使用optparse库解析命令行参数。调用optparse.OptionParser(usage)
会生成一个参数解析器类的实例。接着在parser.add_option
中指定这个脚本具体要解析哪个命令行参数。
代码实例:
usage="usage %prog -H <target host> -p/-P <target ports>"
parser=optparse.OptionParser(usage)
parser.add_option('-H',dest='Host',type='string',help='target host')
parser.add_option('-P','-p',dest='Ports',type='string',help='target ports')
2.解析主机名和端口
接下来,我们要生成两个函数:ConnScan和portScan。portScan函数以参数形式接收主机名和目标端口列表。它首先会尝试用gethostbyname()函数确定主机名对应的IP地址。接下来,它会实验ConnScan函数输出主机名(或IP地址),并使用ConnScan()函数尝试逐个建立与目标端口的连接。如果成功,则打印一个端口开放的信息,如果失败,则打印端口关闭的信息。
代码:
def connScan(tgtHost,tgtPort):
try:
conn=socket(AF_INET,SOCK_STREAM)
conn.connect((tgtHost,tgtPort))
screenLock.acquire()
print('[+]%d/tcp open'% tgtPort)
conn.close()
except Exception as e:
screenLock.acquire()
print(e)
print('[-]%d/tcp closed'% tgtPort)
finally:
screenLock.release()
conn.close()
def portScan(tgtHost,tgtPorts):
try:
tgtIP=gethostbyname(tgtHost)
except:
print("[-] Cannot resolve '%s':Unknown host" %tgtHost)
return
try:
Name=gethostbyaddr(tgtIP)
print ("\n[+] Scan Results for:"+Name[0])
except:
print ("\n[+] Scan Results for:"+tgtIP)
setdefaulttimeout(1)
for Port in tgtPorts:
t = Thread(target=connScan,args=(tgtHost,int(Port)))
t.start()
3.抓取应用的Banner
为了抓取目标主机上的应用的Banner,我们必须在ConnScan函数中插入一些新增的代码。找到开放的端口后,我们向它发送一个数据串并等待响应。跟进收集到的响应,我们就推断出目标主机和端口上运行的应用。
代码:
conn.send('test message\r\n'.encode("utf-8"))
results=conn.recv(100)
print('[+] '+results.decode("utf-8"))
4.线程扫描
根据套接字中timeout变量的值,每扫描一个套接字都会花费几秒钟,看上去微不足道。但如果一旦要扫描的主机和端口多起来时,就会造成效率的严重下降。因此我们引入Python线程,线程是一种能提供这类同时执行多项任务的方法。具体到我们的脚本代码中,即我们要修改portScan()函数中迭代循环的代码。
代码:
for Port in tgtPorts:
t = Thread(target=connScan,args=(tgtHost,int(Port)))
t.start()
这让我们的速度有了显著提升。
5.信号量机制
增加线程机制后程序的运行效率得到了提升,但这又有一个缺点。ConnScan()函数会在屏幕上打印一个输出。如果多个线程同时打印输出,就可能出现乱码和失序。为了让输出按正常顺序流程实现,我们需要使用信号量机制(semaphare)。一个简单的信号量就能阻止其他线程运行。注意,在打印输出前,我们用Lock.acquire()执行一个加锁操作。如果信号量还没有被锁上,线程就有权继续运行,并打印输出到屏幕上。如果信号量被锁定,当前线程只能等待正在持有信号量的线程释放信号量。通过利用信号量,我们确保了任何时间段只能有一个线程打印屏幕。
代码:
screenLock.acquire()
print('[+]%d/tcp open'% tgtPort)
print('[+] '+results.decode("utf-8"))
conn.close()
except Exception as e:
screenLock.acquire()
print(e)
print('[-]%d/tcp closed'% tgtPort)
finally:
screenLock.release()
conn.close()
总结
综上所述,汇总在一起,并添加一些函数解析代码,这就有了我们最终的一个简单的TCP连接端口扫描器脚本。
代码:
import optparse
from socket import *
from threading import *
screenLock = Semaphore(value=1)
def connScan(tgtHost,tgtPort):
try:
conn=socket(AF_INET,SOCK_STREAM)
conn.connect((tgtHost,tgtPort))
conn.send('test message\r\n'.encode("utf-8"))
results=conn.recv(100)
screenLock.acquire()
print('[+]%d/tcp open'% tgtPort)
print('[+] '+results.decode("utf-8"))
conn.close()
except Exception as e:
screenLock.acquire()
print(e)
print('[-]%d/tcp closed'% tgtPort)
finally:
screenLock.release()
conn.close()
def portScan(tgtHost,tgtPorts):
try:
tgtIP=gethostbyname(tgtHost)
except:
print("[-] Cannot resolve '%s':Unknown host" %tgtHost)
return
try:
Name=gethostbyaddr(tgtIP)
print ("\n[+] Scan Results for:"+Name[0])
except:
print ("\n[+] Scan Results for:"+tgtIP)
setdefaulttimeout(1)
for Port in tgtPorts:
t = Thread(target=connScan,args=(tgtHost,int(Port)))
t.start()
def main():
usage="usage %prog -H <target host> -p/-P <target ports>"
parser=optparse.OptionParser(usage)
parser.add_option('-H',dest='Host',type='string',help='target host')
parser.add_option('-P','-p',dest='Ports',type='string',help='target ports')
(options,args)=parser.parse_args()
Host=options.Host
Ports=str(options.Ports).split(',')
if (Host==None)|(Ports[0]==None):
print(parser.usage)
exit(0)
portScan(Host,Ports)
if __name__=='__main__':
main()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)