安全渗透测试的常见模块
一、Socket模块
1.概念
A.Socket模块的主要目的是帮助在网络上的两个程序之间建立信息通道。
B.在Python中提供了两个基本的Socket模块:
a.服务端Socket
b.客户端Socket。
C.当创建了一个服务端Socket 之后,这个Socket就会在本机的一个端口上等待连接
D.客户端Socket会访问这个端口,当两者完成连接之后,就可以进行交互了。
2.实例化Socket类
在Python中,使用Socket进行编程的时候,首先实例化一个Socket类,需要三个参数:
第一个参数是地址族
第二个参数是流
第三个参数是使用的协议
格式:
family是要使用的地址族。
常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX、UNIX域Socket)、AF_ROUTE等。 默认值为socket.AF_INET,通常使用这个默认值即可。
type用来指明Socket类型, 这里可以使用的值有三个:
SOCK_STREAM,这是TCP类型,保证数据顺序及可靠性;这个是默认值
SOCK_DGRAM,用于UDP类型
SOCK_RAW,这是原始类型,允许对底层协议如IP或ICMP进行直接访问,基本不会用到
第三个参数指使用的协议,这个参数是可选的。通常赋值“0”,由系统自动选择。
注释:1.如果希望初始化一个TCP类型的Socket,就可以使用如下语句。
s=socket.socket()
2.这条语句实际上相当于 socket.socket(socket.AF_INET,socket.SOCK_STREAM)。 这里因为使用的都是默认值,所以可以省略掉。
3.如果希望初始化一个UDP类型的Socket,则可以使用如下语句。
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
3.服务端和客户端
A.使用Socket建立服务端的思路主要是首先实例化一个Socket类 ,然后开始循环监听, 一直可以接收来自客户端的连接。
B.成功建立连接之后,接收客户端发来的数据,并再向客户端发送数据,传输完毕之后,关闭这次连接。
C.使用Socket建立客户端则要简单得多,在实例化一个Socket类之后,连接一个远程的地址,这个地址由IP和端口组成。
D.成功建立连接之后,开始发送和接收数据,传输完毕之后,关闭这次连接。
4.常用的函数——服务端函数
A.bind():这个函数由服务端Socket调用,会将之前创建Socket与指定的IP地址和端口进行绑定。如果之前使用了AF_INET初始化Socket,那么这里可以使用元组(host,port)的形式表示地址。
例如,要将刚才创建的Socket套接字绑定到本机的2345端口,可以使用如下语句。
s.bind(('127.0.0.1',2345))
B.listen():这个函数用于在使用TCP的服务端开启监听模式。 可以使用一个参数来指定可以挂起的最大连接数量。 这个参数的值最小为1,一般设置为5。
例如,要在服务端开启一个监听,可以使用如下语句。
s.listen(5)
C.accept():这个函数用于在使用TCP的服务端接收连接,一般是阻塞态。 接受TCP连接并返回(conn,address)其中,conn是新的套接字对象,可以用来接收和发送数据;address是连接客户端的地址。
5.客户端的函数
A.connect():这个函数用于在使用TCP的客户端去连接服务端时使用,使用的参数是一个元组,形式为(hostname,port)。
例如,在客户端程序初始化了一个Socket之后,就可以使用这个函数去连接到服务端。要连接本机的2345端口,可以使用如下语句。
s.connect(("127.0.0.1",2345))
6.服务端和客户端都可以使用的函数
A.send(): 用于在使用 TCP 时发送数据,完整的形式为 send(string[,flag]),利用这个函数可以将string代表的数据发送到已经连接的Socket,返回值是发送字节的数量。但是可能未将指定的内容全部发送。
B.sendall(): 与send()相类似,也是用于在使用TCP时发送数据,完整的形式为 sendall(string[,flag])。 与send()的区别是完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。
例如,使用这个函数发送一段字符到Socket,可以使用如下语句。
s.sendall(bytes("Hello,My Friend!",encoding="utf-8"))
C.recv(): 这个函数用于在使用TCP时接收数据,完整的形式为 recv(bufsize[,flag]), 接收Socket的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量,flag这个参数一般不会使用。
例如,通过这个函数接收一段长度为1024的字符Socket,可以使用如下语句。
obj.recv(1024)
D.sendto(): 这个函数用于在使用UDP时发送数据,完整的形式为 sendto(string[,flag],address), 返回值是发送的字节数。address是形式为(ipaddr,port)的元组,指定远程地址。
E.recvfrom(): UDP专用,接收数据,返回数据远端的IP地址和端口,但返回值是(data,address)。其中,data是包含接收数据的字符串,address是发送数据的套接字地
F.close():关闭socket。
7.使用Socket编写一个简单的服务端和客户端
A.首先使用Socket编写一个服务端程序
B.Socket套接字开始监听后,就会使用accept函数来等待客户端的连接。这个过程使用一个条件永远为真的循环来实现,服务端在处理完和客户端的连接后,会再次调用这个函数,等待下一个连接。
二、Nmap模块
1.Nmap的各种功能
a.主机发现功能。向目标计算机发送信息,然后根据目标的反应来确定它是否处于开机并联网的状态。
b.端口扫描。向目标计算机的指定端口发送信息,然后根据目标端口的反应来判断它是否开放。
c.服务及版本检测。向目标计算机的目标端口发送特制的信息,然后根据目标的反应来检测它运行服务的服务类型和版本。
d.操作系统检测。
2. a.python-nmap是一个可以帮助使用 Nmap功能的 Python 模块文件。
b.在python-nmap模块的帮助下,可以轻松地在自己的程序中使用Nmap扫描的结果,也可以编写程序自动化地完成扫描任务。
c.如果希望在Python中正常使用python-nmap模块,必须先在系统中安装Nmap。因为在这个模块文件中会调用Nmap的一些功能。 Windows操作系统下直接下载安装即可 Linux操作系统中则需要使用如下命令。
1).安装pip
2).
3).
3.基本用法
python-nmap模块的核心就是 PortScanner、PortScannerAsync、PortScannerError、PortScannerHostDict、PortScannerYield等 5个类,其中最为重要的是PortScanner类。
4.python-nmap模块类的实例化
A.最常使用的是PortScanner类,这个类实现Nmap工具功能的封装。对这个类进行实例化很简单,只需要如下语句即可实现。
B.PortScannerAsync类和PortScanner类的功能相似,但是这个类可以实现异步扫描,对这个类的实例化语句如下。
5.python-nmap模块中的函数
A.PortScanner类
a、scan()函数: 这个函数的完整形式为 scan(self, hosts='127.0.0.1', ports=None, arguments='-sV',sudo=False), 用来对指定目标进行扫描,其中需要设置的三个参数包括hosts、ports和arguments。
参数hosts的值为字符串类型,表示要扫描的主机,形式可以是IP地址,例如“192.168.1.1”,也可以是一个域名,例如“www.nmap.org”。
参数ports的值也是字符串类型,表示要扫描的端口。如果要扫描的是单一端口,形式可以为“80”。如果要扫描的是多个端口,可以用逗号分隔开,形式为“80,443,8080”。如果要扫描的是连续的端口范围,可以用横线,形式为“1-1000”。
参数arguments的值也是字符串类型,这个参数实际上就是Nmap扫描时所使用的参数, 如“-sP”“-PR”“-sS”“-sT”“-O”“-sV”等。
“-sP”表示对目标进行Ping主机在线扫描
“-PR”表示对目标进行一个ARP的主机在线扫描
“-sS”表示对目标进行一个TCP半开(SYN)类型的端口扫描
“-sT”表示对目标进行一个TCP全开类型的端口扫描
“-O”表示扫描目标的操作系统类型
“-sV”表示扫描目标上所安装网络服务软件的版本。
如果要对192.168.1.101的1~500端口进行一次TCP半开扫描,可以使用如图所示的命令
对192.168.1.101的1~500端口进行一次TCP半开扫描
b、all_hosts()函数:返回一个被扫描的所有主机列表
c、command_line()函数:返回在当前扫描中使用的命令行,如图所示。
d、csv()函数:返回值是一个CSV(逗号分隔值文件格式)的输出,如图所示。显示一个比较工整的扫描结果
e、has_host(self, host)函数:检查是否有host的扫描结果,如果有则返回True,否则返回False,
f、scaninfo()函数:列出一个扫描信息的结构
g、
B.PortScannerAsync类中最为重要的函数也是scan(), 用法与PortScanner类中的scan()基本一样,但是多了一个回调函数。
完整的scan()函数格式为 scan(self, hosts='127.0.0.1',ports=None, arguments='-sV', callback=None, sudo=False),这里面的callback是以(host, scan_data)为参数的函数
对目标地址进行一次扫描
a、still_scanning():如果扫描正在进行,则返回True,否则返回False
b、wait(self, timeout=None):函数表示等待时间
c、stop():停止当前的扫描
三、Scapy模块文件
1.概念
Scapy是一个由Python语言编写的强大工具,它是大量程序编写人员最喜爱的一个网络模块。目前很多优秀的网络扫描和攻击工具都使用了这个模块。 也可以在自己的程序中使用这个模块来实现对网络数据包的发送、监听和解析。
这个模块相比起Nmap来说,更为底层。可以更为直观地了解到网络中的各种扫描和攻击行为,例如,要检测某一个端口是否开放,只需提供给Nmap一个端口号,而Nmap就会给出一个开放或者关闭的结果,但是并不知道Nmap是怎么做的。
如果想对网络中的各种问题进行深入研究,Scapy无疑是一个更好的选择,可以利用它来产生各种类型的数据包并发送出去,Scapy也只会把收到的数据包展示给你,而并不会告诉你这意味着什么,一切都将由你来判断。
2.基本用法
Scapy提供了和Python一样的交互式命令行。Scapy可以作为Python的一个模块存在,但是Scapy本身就是一个可以运行的工具,它自己具备一个独立的运行环境,因而可以不在Python环境下运行。
3.基本操作
A.在Scapy中,每一个协议就是一个类。 只需要实例化一个协议类,就可以创建一个该协议的数据包。
例如,如果要创建一个IP类型的数据包,就可以使用如下命令。
B.IP数据包最重要的属性就是源地址和目的地址,这两个属性可以使用src和dst来设置。
例如,要构造一个发往“192.168.1.101”的IP数据包,可以使用如下语句。
C. 这个目标dst的值可以是一个IP地址,也可以是一个IP范围,例如192.168.1.0/24,这时产生的就不是1个数据包,而是256个数据包。
如果要查看其中的每一个数据包,可以使用
4.Scapy采用分层的形式来构造数据包
A.通常最下面的一个协议为 Ether,然后是IP,再之后是TCP或者是UDP。
IP( )函数无法用来构造ARP请求和应答数据包,可以使用Ether(), 这个函数可以设置发送方和接收方的MAC地址。
产生一个广播数据包,执行的命令如下。
B.Scapy中的分层通过符号“/”实现,一个数据包是由多层协议组合而成,这些协议之间就可以使用“/”分开,按照协议由底而上的顺序从左向右排列
例如,可以使用 Ether()/IP()/TCP() 来完成一个TCP数据包
C.如果要构造一个HTTP数据包,也可以使用如下这种方式。
D.用ls()函数来查看一个类所拥有的属性
使用ls(IP())来查看IP类的属性
E.可以对这里面对应的属性进行设置,例如,将ttl的值设置为32,可以使用如下方式:
5. Scapy模块中的函数
A.send()和sendp()
a.这两个函数的区别在于send()工作在第三层,而sendp()工作在第二层。 send()是用来发送IP数据包的,而sendp()是用来发送Ether数据包的。
例如,构造一个目的地址为“192.168.1.101”的ICMP数据包,并将其发送出去,可以使用如下语句。
注意,如果这个数据包发送成功,下方会有一个“Sent 1 packets.”的显示。
b.这两个函数的特点是只发不收,只会将数据包发送出去,但是没有能力处理该数据包的回应包!!
B.fuzz()函数
如果希望发送一个 内容是随机填充 的数据包,而且又要保证这个 数据包的正确性,那么可以是 fuzz( ) 函数。
例如,可以使用如下命令来创建一个发往192.168.1.101的TCP数据包。
C.sr()、sr1()和srp()
a.在网络的各种应用中,需要做的不仅是将创建好的数据包发送出去,也需要接收这些数据包的应答数据包,这一点在网络扫描中尤为重要。
b.在Scapy中提供了三个用来发送和接收数据包的函数,分别是sr()、sr1()和srp(),其中,sr()和sr1()主要用于第三层,例如IP和ARP等。而srp()用于第二层。
c.当产生的数据包发送出去之后,Scapy就会监听接收到的数据包,并将其中对应的应答数据包筛选出来,显示在下面。Reveived表示收到的数据包个数,answers表示对应的应答数据包。
d.sr()函数是Scapy的核心,它的返回值是两个列表,第一个列表是收到了应答的包和对应的应答,第二个列表是未收到应答的包。所以可以使用两个列表来保存 sr() 的返回值
使用ans和unans来保存sr()的返回值,因为发出去的是一个ICMP的请求数据包,而且也收到了一个应答包,所以这个发送的数据包和收到的应答包都被保存到了ans列表中,使用ans.summary()可以查看两个数据包的内容,而unans列表为空。
e.sr1()函数跟sr()函数作用基本一样,但是只返回一个应答的包。只需要使用一个列表就可以保存这个函数的返回值。
例如,使用p来保存sr1(IP(dst="192.168.26.6")/ICMP())的返回值,如图所示。
f.可以利用sr1()函数来测试目标的某个端口是否开放,采用半开扫描(SYN)的办法。
192.168.26.101回应了发出的设置了SYN标志位的TCP数据包,这表明这台主机的80端口是开放的
D.sniff()
这个函数可以在自己的程序中捕获经过本机网卡的数据包
比如先在终端 开一个 sniff() ,scapy就处于一个捕获网卡数据包的状态.如果有流量经过网卡(比如 在另一个终端上 ping一下别的主机) 在 ctrl+c的时候 获取 sniff()的结果
E.iface、count 参数:
四、情报收集
1.概念
这里的“情报”指的是目标网络、服务器、应用程序的所有信息。
渗透测试人员需要使用资源尽可能地获取要测试目标的相关信息。
信息收集获得信息的方法可以分成两种:被动扫描和主动扫描。
被动扫描主要指的是在目标无法察觉的情况下进行的信息收集,例如,如果想了解一个远在天边的人,你会怎么做呢?显然可以选择在搜索引擎中去搜索这个名字。其实这就是一次对目标的被动扫描。
主动扫描一般都是针对目标发送特制的数据包,然后根据目标的反应来获得一些信息。 扫描之后将会获得的信息包括:目标网络的结构,目标网络所使用设备的类型,目标主机上运行的操作系统,目标主机上所开放的端口,目标主机上所提供的服务,目标主机上所运行的应用程序。
2.工具的使用方法十分简单,只需要在终端中输入nmap加上参数即可完成
3.主机状态扫描
A.基于ARP的活跃主机发现技术
ARP的中文名字是“地址解析协议”,主要用在以太网中。 需要明确的是,所有的主机在互联网中通信的时候使用的是IP地址,而在以太网中通信时使用的却是硬件地址(也就是常说的MAC地址)。
其核心思想就是要产生一个ARP请求,首先查看Scapy库中ARP类型数据包中需要的参数
注释:这里面的大多数参数都有默认值,其中,hwsrc和psrc分别是源硬件地址和源IP地址。
这两个地址不用设置,发送的时候会自动填写本机的地址。
唯一需要设置的是目的IP地址pdst,将这个地址设置为目标即可
查看一下Ether的格式
注释:这一层只有三个参数:
dst是目的硬件地址,
src是源硬件地址,这里面src会自动设置为本机地址。
所以只需要将dst设置为ff:ff:ff:ff:ff:ff即可将数据包发到网络中的各个主机上
B.基于ICMP的活跃主机发现技术
1)ICMP位于TCP/IP协议族中的网络层,它的目的是用于在IP主机、路由器之间传递控制消息。
2)ICMP中提供了多种报文,这些报文又可以分成两大类:差错报文和查询报文。其中,查询报文都是由一个请求和一个应答构成的。
3)ICMP查询报文有4种,分别是响应请求或应答、时间戳请求或应答、地址掩码请求或应答、路由器询问或应答。
4)Ping命令就是响应请求或应答的一种应用,我们经常会使用这个命令来测试本地与目标之间的连通性。
例如我们所在的主机IP为192.168.1.1,而通信的目标IP地址为192.168.1.2,如果要判断192.168.1.2是否为活跃主机,就需要向其发送一个ICMP请求,这个请求的格式如下。
C.基于TCP的活跃主机发现技术
1)TCP(Transmission Control Protocol,传输控制协议)是一个位于传输层的协议。它是一种面向连接的、可靠的、基于字节流的传输层通信协议。
2)TCP的特点是使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答TCP的三次握手SYN+ACK,并最终对对方的SYN执行ACK确认。这种建立连接的方法可以防止产生错误的连接.
3)TCP三次握手的过程
在这一层中出现了“端口”的概念。“端口”是英文port的意译,可以认为是设备与外界通信交流的出口。端口可分为虚拟端口和物理端口,这里使用的就是虚拟端口,指的是计算机内部或交换机路由器内的端口,例如计算机中的80端口、21端口、23端口等。 这些端口可以被不同的服务所使用来进行各种通信,例如Web服务、FTP服务、SMTP服务等,这些服务都是通过“IP地址+端口号”来区分的
如果检测到一台主机的某个端口有回应,也一样可以判断这台主机是活跃主机。 如果一台主机处于活跃状态,那么它的端口即使是关闭的,在收到请求时,也会给出一个回应,只不过并不是一个“SYN+ACK”数据包,而是一个拒绝连接的“RST”数据包。
D.基于UDP的活跃主机发现技术
UDP全称是用户数据报协议,在网络中它与TCP一样用于处理数据包,是一种无连接的协议。在OSI模型中位于第4层——传输层,处于IP的上一层。
但基于UDP的活跃主机发现技术和TCP不同,UDP没有三次握手。 当向目标发送一个UDP数据包之后,目标是不会发回任何UDP数据包的。 不过,如果目标主机是处于活跃状态的,但是目标端口是关闭的时候,可以返回一个ICMP数据包,这个数据包的含义为“unreachable” 如果目标主机不处于活跃状态,这时是收不到任何回应的。
4.端口扫描
A.基于TCP全开的端口扫描技术
TCP全开扫描:如果目标端口是开放的,那么在接到主机端口发出的SYN请求之后,就会返回一个SYN+ACK回应,表示愿意接受这次连接的请求,然后主机端口再回应一个ACK,这样就成功地和目标端口建立了一个TCP连接
如果目标端口是关闭的,那么在接到主机端口发出的SYN请求之后,就会返回一个RST回应,表示不接受这次连接的请求,这样就中断了这次TCP连接
目标端口不开放还有另外一种情况,就是当主机端口发出SYN请求之后,没有收到任何的回应。
多种原因都可能造成这种情况,例如,目标主机处于非活跃状态,这时当然无法进行回应,不过这也可以认为端口是关闭的。
另外一些网络安全设备也会屏蔽掉对某些端口的SYN请求,这时也会出现无法进行回应的情况
B.基于TCP半开的端口扫描技术
基于TCP全开的端口扫描技术还有一些不完善的地方
例如,这次连接可能会被目标主机的日志记录下来, 而且最为主要的是建立TCP连接三次握手中的最后一次是没用的, 在目标返回一个SYN+ACK类型的数据包之后,已经达到了探测的目的,最后发送的ACK类型数据包是不必要的,所以可以考虑去除这一步。
扫描的思想: 如果目标端口是开放的,那么在接到主机端口发出的SYN请求之后,就会返回一个SYN+ACK回应,表示愿意接受这次连接的请求,然后主机端口不再回应一个ACK,而是发送一个 RST 表示中断这个连接。这样实际上并没有建立好完整的TCP连接,所以称为半开。
如果目标端口是关闭的,半开扫描和全开扫描没有区别
半开扫描实例中,考虑一种更为复杂的情况,那就是目标端口的filtered状态。 这种状态往往是由包过滤机制造成的,过滤可能来自专业的防火墙设备、路由器规则或者主机上的软件防火墙。这种情况下会让扫描工作变得很难,因为这些端口几乎不提供任何信息。不过有时候它们也会响应ICMP错误消息,但更多时候包过滤机制不做出任何响应
将没有收到回应数据包的端口归于“filtered”状态
5.服务扫描
A.平时所使用的软件除了操作系统之外,还有大量的其他应用程序。有些个人开发的应用软件大都也存在着漏洞,它们更是网络安全的重灾区。 如果目标使用这些软件对外提供网络服务,攻击者就有可能利用这个网络服务的漏洞入侵。
B.因此,在对目标进行渗透测试的时候,要尽量地检测出目标系统运行的各种服务。 对于入侵者来说,发现这些运行在目标上的服务,就可以利用这些软件上的漏洞入侵目标; 对于网络安全的维护者来说,也可以提前发现系统的漏洞,从而预防这些入侵行为。
C.服务扫描的思路
常见的服务都会运行在指定的端口上
例如,FTP服务上总会运行在21号端口上,而HTTP服务总会运行在80端口上。因为这些端口都是公知端口,所以只需要知道目标上哪个端口是开放的,就可以猜测出目标上运行着什么服务。
这样做有两个明显的缺点: 一是很多人会将服务运行在其他端口上,例如,将本来运行在23号端口上的Telnet运行在22号端口上,这样就会误以为这是一个SSH服务;
二是这样得到的信息极为有限,即使知道目标80端口上运行着HTTP服务,但是完全不知道是什么软件提供的这个服务,也就无从查找这个软件的漏洞了。
D.有一些扫描工具采用了抓取软件banner的方法,因为很多的软件都会在连接之后提供一个表明自身信息的banner,可以编写程序来抓取这个banner从中读出目标软件的信息
最后也是最为优秀的一种方法,就是向目标开放的端口发送探针数据包,然后根据返回的数据包与数据库中的记录进行比对,找出具体的服务信息。
Nmap扫描工具就是采用了这种方法,它包含一个十分强大的Nmap-service-probe数据库,这个库中包含世界上大部分常见软件的信息,而且这个库还在完善中