• 【Python脚本进阶】2.1、端口扫描器(上):TCP全连接扫描


    目录

    一、简介

    1.1、基础:

    1.2、TCP:

    二、TCP全连接扫描

    2.1、简介:

    2.2、函数:

    2.3、实现:

     第一步:获得主机名和端口

     第二步: connScan和portScan函数

     第三步:抓应用的Banner

     第四步:线程扫描

     第五步:加锁

    2.4、合体:


    一、简介

    1.1、基础:

    扫描目标主机开放的TCP 端口的侦查脚本。当然, 为了与TCP 端口进行交互, 要建立TCP 套接字。


    Python 也提供了访问BSD 套接字的接口。BSD 套接字提供了一个应用编程接口(API) , 使程序员能编写在主机之间进行网络通信的应用程序。通过一系列的套接字API 函数, 我们可以创建、绑定、监听、连接, 或在TCP/IP 套接字上发送数据。在这一点上, 为了进一步开发我们自己的攻击程序, 必须对TCP/lP 套接字有一个更深入的了解。

    1.2、TCP:

    大多数能访问互联网的应用使用的都是TCP 协议。例如, Web 服务器可能位于TCP 80 端口, 电子邮件服务器在TCP25 端口, FTP 服务器在TCP21 端口。要连接目标组织中的任一服务器, 攻击者必须知道与服务器相关联的IP 地址和TCP 端口。


    网络攻击一般都是以端口扫描开始。有一种类型的端口扫描会向一系列常用的端口发送TCP SYN 数据包, 并等待TCP ACK 响应一一这能让我们确定这个端口是开放的。相反,TCP 连接扫描是使用完整的三次握手来确定服务器或端口是否可用的



    二、TCP全连接扫描

    2.1、简介:

    用TCP 全连接扫描来识别主机的TCP 端口的扫描器。

    要导入Python 的BSD 套接字API 实现。套接字API 会为我们提供一些在实现TCP 端口扫描程序时有用的函数。要更深入地了解Python 标准库文档

    2.2、函数:

    socket.gethostbyname(hostname)

    此功能以主机名这样如www.syngress.com并返回IPv4地址格式69.163.177.2


    socket.gethostbyaddr(ip address)

    此功能采用IPv4地址并重新添加一个包含HOS名称的三倍,替代名称。主机名和同一接口的IPv4/V6地址列表在主机上。


    socket.socket(\[family\[, type\[, proto]]])

    此功能创建一个一个新socket的实例给定family。socket的选项family为af_inet,af_inet6或af_unix。此外,socket可以指定为tcp套接字或sock_dgram的sock_streamUDPsocket。最后,协议编号通常为零,并且在大多数情况下被省略。


    socket.create_connection(address\[, timeout\[, source_address]])

    这个功能采用2核(主机,端口),并返回一个实例网络socket。此外,它还可以选择超时和源地址。

    2.3、实现:

     第一步:获得主机名和端口

    从用户那里获得主机名和端口。为了做到这一点, 我们在程序中使用optparse 库解析命令行参数。调用optparse.OptionPaser ([usage message])会生成一个参数解析器(option parser) 类的实例。接着, 在parser.add_option 中指定这个脚本具体要解析哪个命令行参数。下面的例子显示了一个快速解析要扫描的目标主机名和端口的方法。

    1. import optparse
    2. parser = optparse.OptionParser('usage %prog - H' + ' -p ')
    3. parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    4. parser.add_option('-p', dest='tgtPort', type='int', help='specify target port')
    5. (options, args) = parser.parse_args()
    6. tgtHost = options.tgtHost
    7. tgtPort = options.tgtPort
    8. if (tgtHost == None) | (tgtPort == None) :
    9. print(parser.usage)
    10. exit(0)

     第二步: connScan和portScan函数

    两个函数: connScan和portScan

    portScan函数以参数的形式接收主机名和目标端口列表。它首先会尝试用gethostbyname()函数确定主机名对应的IP地址。


    使用connScan函数输出主机名(或IP地址), 并使用connScan()函数尝试逐个连接我们要连接的每个端口。connScan 函数接收两个参数: tgtHost 和tgtPort, 它会去尝试建立与目标主机和端口的连接。如果成功, connScan将打印出一个端口开放的消息。如果不成功,它会打印出端口关闭的消息。

    1. import optparse
    2. from socket import *
    3. def connScan(tgtHost, tgtPort):
    4. try:
    5. connSkt = socket(AF_INET, SOCK_STREAM)
    6. connSkt.connect((tgtHost,tgtPort))
    7. print('[+] %d/tcp open' % tgtPort)
    8. connSkt.close()
    9. except:
    10. print('[-] %d/tcp closed' % tgtPort)
    11. def portScan(tgtHost, tgtPorts):
    12. try:
    13. tgtIP = gethostbyname(tgtHost)
    14. except:
    15. print('[-] Cannot resolve ' %s ':Unknown host' %tgtHost)
    16. return
    17. try:
    18. tgtName = gethostbyaddr(tgtIP)
    19. print('\n[+] Scan Results for: '+ tgtName[0])
    20. except:
    21. print('\n[+] Scan Results for: '+ tgtIP)
    22. setdefaulttimeout(1)
    23. for tgtPort in tgtPorts:
    24. print('[+] Scanning port ' + tgtPort)
    25. connScan(tgtHost,int(tgtPort))

     第三步:抓应用的Banner

    为了抓取目标主机上应用的Banner, 先在connScan 函数中插入一些新增的代码。找到开放的端口后, 向它发送一个数据串并等待响应。跟进收集到的响应,推断出在目标主机和端口上运行的应用

    1. import optparse
    2. import socket
    3. from socket import *
    4. def connScan(tgtHost, tgtPort):
    5. try:
    6. connSkt = socket(AF_INET, SOCK_STREAM)
    7. connSkt.connect((tgtHost,tgtPort))
    8. connSkt.send(bytes('ViolentPython\r\n',"utf8"))
    9. results = connSkt.recv(100)
    10. print('[+] %d/tcp open' % tgtPort)
    11. print( '[+] ' + str( results ) )
    12. connSkt.close()
    13. except:
    14. print('[-] %d/tcp closed' % tgtPort)
    15. def portScan(tgtHost, tgtPorts):
    16. try:
    17. tgtIP = gethostbyname(tgtHost)
    18. except:
    19. print('[-] Cannot resolve ' %s ':Unknown host' %tgtHost)
    20. return
    21. try:
    22. tgtName = gethostbyaddr(tgtIP)
    23. print('\n[+] Scan Results for: '+ tgtName[0])
    24. except:
    25. print('\n[+] Scan Results for: '+ tgtIP)
    26. setdefaulttimeout(1)
    27. for tgtPort in tgtPorts:
    28. print('Scanning port ' + tgtPort)
    29. connScan(tgtHost,int(tgtPort))
    30. def main():
    31. parser = optparse.OptionParser("usage%prog " + "-H -p ")
    32. parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    33. parser.add_option('-p', dest='tgtPort', type='string',help='specify target port[s] separated by comma')
    34. (options, args) = parser.parse_args()
    35. tgtHost = options.tgtHost
    36. tgtPorts = str(options.tgtPort).split (', ')
    37. if (tgtHost == None) | (tgtPorts[0] == None):
    38. print('[一] You must specify a target host and port[s].')
    39. exit(0)
    40. portScan(tgtHost,tgtPorts)
    41. if __name__ == '__main__':
    42. main()

     第四步:线程扫描

    根据套接字中timeout变量的值, 每扫描一个套接字都会花费几秒钟。 但如果我们要扫描多个主机或端口, 时间总量就会成倍增加。同时扫描多个套接字进行扫描。必须引入Python线程, 线程是一种能提供这类同时执行多项任务的方法。具体到我们这个扫描器, 我们要修改的是portScan()函数中迭代循环里的代码

    1. for tgtPort in tgtPorts:
    2. t = Thread(target=connScan, args=(tgtHost, int(tgtPort)))
    3. t.start()

     第五步:加锁

    速度显著提升, 但connScanO函数在屏幕上打印一个输出。如果多个线程同时打印输出, 就可能会出现乱码和失序。


    为了让一个函数获得完整的屏幕控制权, 需要使用一个信号量(semaphore)。一个简单的信号量就能阻止其他线程运行。注意, 在打印输出前, 我们用screenLock.acquire()执行一个加锁操作。如果信号量还没被锁上, 线程就有权继续运行, 并输出打印到屏幕上。如果信号量已经被锁定, 只能等待, 直到持有信号量的线程释放信号量。通过利用信号量, 能够确保在任何给定的时间点上只有一个线程可以打印屏幕。在异常处理代码中, 位千fmally关键字前面的是在终止阻塞(其他线程)之前需要执行的代码

    1. screenLock = Semaphore(value=1)
    2. def connScan(tgtHost, tgtPort):
    3. try:
    4. connSkt = socket(AF_INET, SOCK_STREAM)
    5. connSkt.connect((tgtHost,tgtPort))
    6. connSkt.send(bytes('ViolentPython\r\n',"utf8"))
    7. results = connSkt.recv(100)
    8. screenLock.acquire()
    9. print('[+] %d/tcp open' % tgtPort)
    10. print( '[+] ' + str( results ) )
    11. except:
    12. screenLock.acquire()
    13. print('[-] %d/tcp closed' % tgtPort)
    14. finally:
    15. screenLock.release()
    16. connSkt.close()

    2.4、合体:

    把所有的函数放入同一个脚本中, 并添加一些参数解析代码, 这就有了我们最终的端口扫描器脚本。

    1. import optparse
    2. import socket
    3. from socket import *
    4. screenLock = Semaphore(value=1)
    5. def connScan(tgtHost, tgtPort):
    6. try:
    7. connSkt = socket(AF_INET, SOCK_STREAM)
    8. connSkt.connect((tgtHost,tgtPort))
    9. connSkt.send(bytes('ViolentPython\r\n',"utf8"))
    10. results = connSkt.recv(100)
    11. screenLock.acquire()
    12. print('[+] %d/tcp open' % tgtPort)
    13. print( '[+] ' + str( results ) )
    14. except:
    15. screenLock.acquire()
    16. print('[-] %d/tcp closed' % tgtPort)
    17. finally:
    18. screenLock.release()
    19. connSkt.close()
    20. def portScan(tgtHost, tgtPorts):
    21. try:
    22. tgtIP = gethostbyname(tgtHost)
    23. except:
    24. print('[-] Cannot resolve ' %s ':Unknown host' %tgtHost)
    25. return
    26. try:
    27. tgtName = gethostbyaddr(tgtIP)
    28. print('\n[+] Scan Results for: '+ tgtName[0])
    29. except:
    30. print('\n[+] Scan Results for: '+ tgtIP)
    31. setdefaulttimeout(1)
    32. for tgtPort in tgtPorts:
    33. t = Thread( target=connScan, args=(tgtHost, int( tgtPort )) )
    34. t.start()
    35. def main():
    36. parser = optparse.OptionParser("usage%prog " + "-H -p ")
    37. parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    38. parser.add_option('-p', dest='tgtPort', type='string',help='specify target port[s] separated by comma')
    39. (options, args) = parser.parse_args()
    40. tgtHost = options.tgtHost
    41. tgtPorts = str(options.tgtPort).split (', ')
    42. if (tgtHost == None) | (tgtPorts[0] == None):
    43. print(parser.usage)
    44. exit(0)
    45. portScan(tgtHost,tgtPorts)
    46. if __name__ == '__main__':
    47. main()

  • 相关阅读:
    Java 序列化和反序列化为什么要实现 Serializable 接口?
    Kotlin中循环语句
    外贸出口迷你车载冰箱亚马逊UL2089测试标准
    招募 AIGC 训练营助教 @上海
    java计算机毕业设计技术交流网站源码+数据库+系统+lw文档+mybatis+运行部署
    Java面试题-为什么重写equals就一定要重写hashCode方法呢?
    css的布局方式
    【Python基础】Python文件操作介绍
    Java中如何将String类型的2023年09月21日这个值变成DATE相关的类型
    Python 使用executemany批量向mysql插入数据
  • 原文地址:https://blog.csdn.net/qq_53079406/article/details/126026565