【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 中指定这个脚本具体要解析哪个命令行参数。下面的例子显示了一个快速解析要扫描的目标主机名和端口的方法。

import optparse
parser = optparse.OptionParser('usage %prog - H' + '<target host> -p <targe port>')
parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
parser.add_option('-p', dest='tgtPort', type='int', help='specify target port')
(options, args) = parser.parse_args()
tgtHost = options.tgtHost
tgtPort = options.tgtPort
if (tgtHost == None) | (tgtPort == None) :
    print(parser.usage)
    exit(0)

 第二步: connScan和portScan函数

两个函数: connScan和portScan

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


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

import optparse
from socket import *

def connScan(tgtHost, tgtPort):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost,tgtPort))
        print('[+] %d/tcp open' % tgtPort)
        connSkt.close()
    except:
        print('[-] %d/tcp closed' % tgtPort)


def portScan(tgtHost, tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print('[-] Cannot resolve ' %s ':Unknown host' %tgtHost)
        return

    try:
        tgtName = gethostbyaddr(tgtIP)
        print('\n[+] Scan Results for: '+ tgtName[0])
    except:
        print('\n[+] Scan Results for: '+ tgtIP)
    setdefaulttimeout(1)
    for tgtPort in tgtPorts:
        print('[+] Scanning port ' + tgtPort)
        connScan(tgtHost,int(tgtPort))

 第三步:抓应用的Banner

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

import optparse
import socket
from socket import *


def connScan(tgtHost, tgtPort):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost,tgtPort))
        connSkt.send(bytes('ViolentPython\r\n',"utf8"))
        results = connSkt.recv(100)
        print('[+] %d/tcp open' % tgtPort)
        print( '[+] ' + str( results ) )
        connSkt.close()
    except:
        print('[-] %d/tcp closed' % tgtPort)


def portScan(tgtHost, tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print('[-] Cannot resolve ' %s ':Unknown host' %tgtHost)
        return

    try:
        tgtName = gethostbyaddr(tgtIP)
        print('\n[+] Scan Results for: '+ tgtName[0])
    except:
        print('\n[+] Scan Results for: '+ tgtIP)
    setdefaulttimeout(1)
    for tgtPort in tgtPorts:
        print('Scanning port ' + tgtPort)
        connScan(tgtHost,int(tgtPort))

def main():
    parser = optparse.OptionParser("usage%prog " + "-H <target host> -p <target port>")
    parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    parser.add_option('-p', dest='tgtPort', type='string',help='specify target port[s] separated by comma')
    (options, args) = parser.parse_args()
    tgtHost = options.tgtHost
    tgtPorts = str(options.tgtPort).split (', ')
    if (tgtHost == None) | (tgtPorts[0] == None):
        print('[一] You must specify a target host and port[s].')
        exit(0)
    portScan(tgtHost,tgtPorts)



if __name__ == '__main__':
    main()

 第四步:线程扫描

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

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

 第五步:加锁

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


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

screenLock = Semaphore(value=1)
def connScan(tgtHost, tgtPort):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost,tgtPort))
        connSkt.send(bytes('ViolentPython\r\n',"utf8"))
        results = connSkt.recv(100)
        screenLock.acquire()
        print('[+] %d/tcp open' % tgtPort)
        print( '[+] ' + str( results ) )
    except:
        screenLock.acquire()
        print('[-] %d/tcp closed' % tgtPort)
    finally:
        screenLock.release()
        connSkt.close()

2.4、合体:

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

import optparse
import socket
from socket import *


screenLock = Semaphore(value=1)
def connScan(tgtHost, tgtPort):
    try:
        connSkt = socket(AF_INET, SOCK_STREAM)
        connSkt.connect((tgtHost,tgtPort))
        connSkt.send(bytes('ViolentPython\r\n',"utf8"))
        results = connSkt.recv(100)
        screenLock.acquire()
        print('[+] %d/tcp open' % tgtPort)
        print( '[+] ' + str( results ) )
    except:
        screenLock.acquire()
        print('[-] %d/tcp closed' % tgtPort)
    finally:
        screenLock.release()
        connSkt.close()


def portScan(tgtHost, tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print('[-] Cannot resolve ' %s ':Unknown host' %tgtHost)
        return

    try:
        tgtName = gethostbyaddr(tgtIP)
        print('\n[+] Scan Results for: '+ tgtName[0])
    except:
        print('\n[+] Scan Results for: '+ tgtIP)
    setdefaulttimeout(1)
    for tgtPort in tgtPorts:
        t = Thread( target=connScan, args=(tgtHost, int( tgtPort )) )
        t.start()


def main():
    parser = optparse.OptionParser("usage%prog " + "-H <target host> -p <target port>")
    parser.add_option('-H', dest='tgtHost', type='string', help='specify target host')
    parser.add_option('-p', dest='tgtPort', type='string',help='specify target port[s] separated by comma')
    (options, args) = parser.parse_args()
    tgtHost = options.tgtHost
    tgtPorts = str(options.tgtPort).split (', ')
    if (tgtHost == None) | (tgtPorts[0] == None):
        print(parser.usage)
        exit(0)
    portScan(tgtHost,tgtPorts)


if __name__ == '__main__':
    main()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑色地带(崛起)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值