第三章 端口扫描(三)
作者:Justin Hutchens 译者:飞龙 协议:CC BY-NC-SA 4.0
3.13 Dmitry 连接扫描
另一个可以对远程系统执行 TCP 连接扫描的 替代工具就是 Dmitry。不像 Nmap 和 Metasploit,Dmitry 是个非常简单的工具,我们可以使用它来执行简单快速的扫描,而不需要任何配置。这个秘籍展示了如何使用 Dmitry 来自执行 TCP 连接扫描。
准备
为了使用 Dmitry 执行 TCP 连接扫描,你需要一个运行 TCP 网络服务的远程服务器。这个例子中我们使用 Metasploitable2 实例来执行任务。配置 Metasploitable2 的更多信息请参考第一章中的“安装 Metasploitable2”秘籍。
操作步骤
Dmitry 是个多用途的工具,可以用于执行目标系统上的 TCP 扫描。它的功能十分有限,但是它是个简单的工具,快速而高效。为了查看 Dmitry 的可用选项,我们在终端中不带任何参数来启动这个程序:
代码语言:javascript复制root@KaliLinux:~# dmitry
Deepmagic Information Gathering Tool
"There be some deep magic going on"
Usage: dmitry [-winsepfb] [-t 0-9] [-o %host.txt] host
-o Save output to %host.txt or to file specified by -o file
-i Perform a whois lookup on the IP address of a host
-w Perform a whois lookup on the domain name of a host
-n Retrieve Netcraft.com information on a host
-s Perform a search for possible subdomains
-e Perform a search for possible email addresses
-p Perform a TCP port scan on a host
* -f Perform a TCP port scan on a host showing output reporting filtered ports
* -b Read in the banner received from the scanned port
* -t 0-9 Set the TTL in seconds when scanning a TCP port ( Default 2 )
*Requires the -p flagged to be passed
就像输出中所说的那样,-p
选项用于执行 TCP 端口扫描。为了实现它,我们以被扫描系统的 IP 地址来使用这个选项。Dmitry 拥有 150 个常用的预配置端口,它会扫描这些。在这些端口中,它会展示任何发现的开放端口。考虑下面的例子:
root@KaliLinux:~# dmitry -p 172.16.36.135
Deepmagic Information Gathering
Tool "There be some deep magic going on"
ERROR: Unable to locate Host Name for 172.16.36.135
Continuing with limited modules
HostIP:172.16.36.135
HostName:
Gathered TCP Port information for 172.16.36.135
--------------------------------
Port State
21/tcp open
22/tcp open
23/tcp open
25/tcp open
53/tcp open
80/tcp open
111/tcp open
139/tcp open
Portscan Finished: Scanned 150 ports, 141 ports were in state closed
Dmitry 中的 TCP 端口扫描并不能自定义。但是它是个简单高效的方法来访问单个主机上的常用服务。我们也可以使用-o
选项,并通过指定文件名称,将 DMitry 扫描结果输出到文本文件中。
root@KaliLinux:~# dmitry -p 172.16.36.135 -o output
root@KaliLinux:~# ls Desktop output.txt
root@KaliLinux:~# cat output.txt
ERROR: Unable to locate
Host Name for 172.16.36.135
Continuing with limited modules
HostIP:172.16.36.135
HostName:
Gathered TCP Port information for 172.16.36.135
--------------------------------
Port State
21/tcp open
22/tcp open
23/tcp open
25/tcp open
53/tcp open
80/tcp open
111/tcp open
139/tcp open
Portscan Finished: Scanned 150 ports, 141 ports were in state closed
工作原理
定义如何执行 TCP 连接扫描的底层机制和之前讨论的其它工具一样。和其他工具相比,Dmitry 的使用性主要源于简洁,并不需要管理多个配置项,像我们使用 Nmap 和 Metasploit 那样。我们可以轻易通过指定响应模式,以及将 IP 地址传递给他来启动 Dmitry。它能够快读扫描常用的 150 个端口,以及其中所有开放端口的值。
Netcat TCP 端口扫描
由于 Netcat 是个网路哦套接字连接和管理工具,它可以轻易转换为 TCP 端口扫描工具。这个秘籍展示了如何使用 Netcat 执行 TCP 连接扫描。
准备
为了使用 Netcat 执行 TCP 连接扫描,你需要一个运行 TCP 网络服务的远程服务器。这个例子中我们使用 Metasploitable2 实例来执行任务。配置 Metasploitable2 的更多信息请参考第一章中的“安装 Metasploitable2”秘籍。
操作步骤
Netcat 是个非常易用,功能多样的网络工具,可以用于多种目的。Netcat 的一种非常高效的使用方式就是执行端口扫描。为了确定使用选项,nc
应该以-h
选项调用,像这样:
root@KaliLinux:~# nc -h
[v1.10-40]
connect to somewhere: nc [-options] hostname port[s] [ports] ...
listen for inbound: nc -l -p port [-options] [hostname] [port]
options:
-c shell commands as `-e'; use /bin/sh to exec [dangerous!!]
-e filename program to exec after connect [dangerous!!]
-b allow broadcasts
-g gateway source-routing hop point[s], up to 8
-G num source-routing pointer: 4, 8, 12, ...
-h this cruft
-i secs delay interval for lines sent, ports scanned
-k set keepalive option on socket
-l listen mode, for inbound connects
-n numeric-only IP addresses, no DNS
-o file hex dump of traffic -p port local port number
-r randomize local and remote ports
-q secs quit after EOF on stdin and delay of secs
-s addr local source address
-T tos set Type Of Service
-t answer TELNET negotiation
-u UDP mode
-v verbose [use twice to be more verbose]
-w secs timeout for connects and final net reads
-z zero-I/O mode [used for scanning]
port numbers can be individual or ranges: lo-hi [inclusive]; hyphens in port names must be backslash escaped (e.g. 'ftp-data').
正如输出所表示的那样,-z
选项可以高效用于扫描。为了扫描目标系统上的 TCP 80 端口,我们使用-n
选项来表明所使用的 IP 地址,-v
选项用于详细输出,-z
选项用于扫描,像这样:
root@KaliLinux:~# nc -nvz 172.16.36.135 80
(UNKNOWN) [172.16.36.135] 80 (http) open
root@KaliLinux:~# nc -nvz 172.16.36.135 443
(UNKNOWN) [172.16.36.135] 443 (https) : Connection refused
开放端口上的扫描尝试执行会返回 IP 地址,端口地址,以及端口状态。对活动主机的关闭端口执行相同扫描会显式简介被拒绝。我们可以在寻呼哪种自动化这个过程,像这样:
代码语言:javascript复制root@KaliLinux:~# for x in $(seq 20 30); do nc -nvz 172.16.36.135 $x; done
(UNKNOWN) [172.16.36.135] 20 (ftp-data) : Connection refused
(UNKNOWN) [172.16.36.135] 21 (ftp) open
(UNKNOWN) [172.16.36.135] 22 (ssh) open
(UNKNOWN) [172.16.36.135] 23 (telnet) open
(UNKNOWN) [172.16.36.135] 24 (?) : Connection refused
(UNKNOWN) [172.16.36.135] 25 (smtp) open
(UNKNOWN) [172.16.36.135] 26 (?) : Connection refused
(UNKNOWN) [172.16.36.135] 27 (?) : Connection refused
(UNKNOWN) [172.16.36.135] 28 (?) : Connection refused
(UNKNOWN) [172.16.36.135] 29 (?) : Connection refused
(UNKNOWN) [172.16.36.135] 30 (?) : Connection refused
通过将输出传递给STDOUT
,之后过滤输出,我们能够分离出提供开放端口细节的行。我们甚至可以更加简明,通过仅仅提取我们需要的信息。如果单个主机被扫描了,我们可能能够利用第三和第四个字段;
root@KaliLinux:~# for x in $(seq 20 30); do nc -nvz 172.16.36.135 $x; done 2>&1 | grep open | cut -d " " -f 3-4
21 (ftp)
22 (ssh)
23 (telnet)
25 (smtp)
通过从输出提取这些字段,cut
函数可以用于以空格分隔符,之后通过指定要输出的字段分离这些行。但是,还有另一种高效的方法,就是在 Netcat 中指定端口范围,而不需要将工具传递金循环中。通过向nc
中传入端口地址值的序列,Netcat 会自动展示其中的开放端口:
root@KaliLinux:~# nc 172.16.36.135 -nvz 20-30
(UNKNOWN) [172.16.36.135] 25 (smtp) open
(UNKNOWN) [172.16.36.135] 23 (telnet) open
(UNKNOWN) [172.16.36.135] 22 (ssh) open
(UNKNOWN) [172.16.36.135] 21 (ftp) open
但是,像之前那样,我们需要将它的输出传给STDOUT
,以便将其传递给cut
函数。通过展示 2 到 4 的字段,我们可以限制 IP 地址、端口号以及相关服务的输出,像这样:
root@KaliLinux:~# nc 172.16.36.135 -nvz 20-30 2>&1 | cut -d " " -f 2-4
[172.16.36.135] 25 (smtp)
[172.16.36.135] 23 (telnet)
[172.16.36.135] 22 (ssh)
[172.16.36.135] 21 (ftp)
我们可以在 bash 中使用loop
函数来使用 Netcat 扫描多个主机地址序列,之后提取相同的细节来确定不同的被扫描 IP 地址中,哪个端口是开着的。
root@KaliLinux:~# for x in $(seq 0 255); do nc 172.16.36.$x -nvz 80 2>&1 | grep open | cut -d " " -f 2-4; done
[172.16.36.135] 80 (http)
[172.16.36.180] 80 (http)
工作原理
执行 TCP 连接扫描的同居通过执行完整的三次握手,和远程系统的所有被扫描端口建立连接。端口的状态取决于连接是否成功建立。如果连接建立,端口被认为是开放的,如果连接不能成功建立,端口被认为是关闭的。
3.15 Scapy 僵尸扫描
我们可以识别目标系统的开放端口,而不留下和系统交互的证据。这种机器隐蔽的扫描形式就是僵尸扫描,并且只能在网络中存在其他拥有少量网络服务和递增 IPID 序列的主机时执行。这个秘籍展示了如何使用 Scapy 执行僵尸扫描。
准备
为了使用 Scapy 执行僵尸扫描,你需要拥有运行 TCP 服务的远程系统,以及另一个拥有 IPID 递增序列的远程系统。在所提供的例子中,Metasploitable2 用作扫描目标,WindowsXP 用作 IPID 递增的僵尸。关于如何在本地实验环境下配置系统的更多信息,请参考第一章的“安装 Metasploitable2”和“安装 Windows 服务器”秘籍。此外,这一节也需要使用文本编辑器将脚本写到文件系统,例如 VIM 或 Nano。如何编写脚本的更多信息,请参考第一章中的“使用文本编辑器(VIM 或 Nano)”秘籍。
操作步骤
所有 IP 封包中都存在的值是 ID 号。取决于系统,ID 号会随机生成,可能始终从零开始,或者可能在每个发送的 IP 封包中都递增 1。如果发现了 IPID 递增的主机,并且这个主机并不和其它网路系统交互,它就可以用作识别其它系统上开放端口的手段。我们可以通过发送一系列 IP 封包,并分析响应,来识别远程系统的 IPID 序列模式。
代码语言:javascript复制>>> reply1 = sr1(IP(dst="172.16.36.134")/TCP(flags="SA"),timeout=2,verbo se=0)
>>> reply2 = sr1(IP(dst="172.16.36.134")/TCP(flags="SA"),timeout=2,verbo se=0)
>>> reply1.display()
###[ IP ]###
version= 4L
ihl= 5L
tos= 0x0
len= 40
id= 61
flags=
frag= 0L
ttl= 128
proto= tcp
chksum= 0x9938
src= 172.16.36.134
dst= 172.16.36.180
options
###[ TCP ]###
sport= http
dport= ftp_data
seq= 0
ack= 0
dataofs= 5L
reserved= 0L
flags= R
window= 0
chksum= 0xe22
urgptr= 0
options= {}
###[ Padding ]###
load= 'x00x00x00x00x00x00'
>>> reply2.display()
###[ IP ]###
version= 4L
ihl= 5L
tos= 0x0
len= 40
id= 62
flags=
frag= 0L
ttl= 128
proto= tcp
chksum= 0x992d
src= 172.16.36.134
dst= 172.16.36.180
options
###[ TCP ]###
sport= http
dport= ftp_data
seq= 0
ack= 0
dataofs= 5L
reserved= 0L
flags= R
window= 0
chksum= 0xe22
urgptr= 0
options= {}
###[ Padding ]###
load= 'x00x00x00x00x00x00'
如果我们向 Windows 独立系统发送两个 IP 封包,我们可以检测响应中的 ID 属性的整数值。要注意第一个请求的回复的 ID 是 61,第二个是 62。这个主机确实存在递增的 IPID 序列,并假设它保持独立。它可以用作高效的僵尸,来进行僵尸扫描。为了执行僵尸扫描,必须向僵尸系统发送初始的 SYN ACK 请求,来判断返回的 RST 中的当前 IPID 值。之后,向扫描目标发送伪造的 SYN 扫描,带有僵尸系统的 IP 原地址。如果端口是打开的,扫描目标会发送 SYN ACK 响应给僵尸。由于僵尸没有实际发送初始的 SYN 请求,它会将 SYN ACK 解释为来路不明,并且项目表发送 RST 封包。因此将 IPID 增加 1。最后,应该向僵尸发送另一个 SYN ACK 封包,它会返回 RST 封包并将 IPID 再次增加 1。IPID 比起初始响应增加了 2,折表示所有这些时间都发生了,并且被扫描系统的目标端口是开放的。
反之,如果端口是关闭的,会发生不同的系列时间,这仅仅会导致最后的 RST 响应早呢更加 1。如果被扫描系统的目标端口是关闭的,RST 封包会发给僵尸系统,作为初始的伪造的 SYN 封包的响应。由于 RST 封包没有任何回应,僵尸系统的 IPID 值无变化。所以,作为 SYN ACK 封包的响应,返回给扫描系统的最后的 RST 封包的 IPID 值只会增加 1。
为了简化这个过程,下面的脚本以 Python 编写,它能识别可用僵尸系统,也对扫描目标执行了僵尸扫描。
代码语言:javascript复制#!/usr/bin/python
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
def ipid(zombie):
reply1 = sr1(IP(dst=zombie)/TCP(flags="SA"),timeout=2,verbose=0)
send(IP(dst=zombie)/TCP(flags="SA"),verbose=0)
reply2 = sr1(IP(dst=zombie)/TCP(flags="SA"),timeout=2,verbose=0)
if reply2[IP].id == (reply1[IP].id 2):
print "IPID sequence is incremental and target appears to be idle. ZOMBIE LOCATED"
response = raw_input("Do you want to use this zombie to perform a scan? (Y or N): ")
if response == "Y":
target = raw_input("Enter the IP address of the target system: ")
zombiescan(target,zombie)
else:
print "Either the IPID sequence is not incremental or the target is not idle. NOT A GOOD ZOMBIE"
def zombiescan(target,zombie):
print "nScanning target " target " with zombie " zombie print "n---------Open Ports on Target--------n"
for port in range(1,100):
try:
start_val = sr1(IP(dst=zombie)/TCP(flags="SA",dport=port),tim eout=2,verbose=0)
send(IP(src=zombie,dst=target)/TCP(flags="S",dport=port),verbose=0)
end_val = sr1(IP(dst=zombie)/TCP(flags="SA"),timeout=2,verbo se=0)
if end_val[IP].id == (start_val[IP].id 2):
print port
except:
pass
print "-----------Zombie Scan Suite------------n"
print "1 - Identify Zombie Hostn"
print "2 - Perform Zombie Scann" ans = raw_input("Select an Option (1 or 2): ")
if ans == "1":
zombie = raw_input("Enter IP address to test IPID sequence: ")
ipid(zombie)
else:
if ans == "2":
zombie = raw_input("Enter IP address for zombie system: ")
target = raw_input("Enter IP address for scan target: ")
zombiescan(target,zombie)
在执行脚本过程中,用户会收到量个选项的提示。通过选项选项 1,我们可以扫描或评估目标的 IPID 序列来判断是否主机是个可用的僵尸。假设主机是独立的,并拥有递增的 IPID 序列,主机就可以用作僵尸。并且用户会被询问是否使用僵尸来执行扫描。如果执行了扫描,会对 TCP 端口前 100 个地址的每个地址执行前面讨论的过程。像这样:
代码语言:javascript复制root@KaliLinux:~# ./zombie.py
-----------Zombie Scan Suite-----------
1 - Identify Zombie Host
2 - Perform Zombie Scan
Select an Option (1 or 2): 1
Enter IP address to test IPID sequence: 172.16.36.134
IPID sequence is incremental and target appears to be idle. ZOMBIE LOCATED
Do you want to use this zombie to perform a scan? (Y or N): Y
Enter the IP address of the target system: 172.16.36.135
Scanning target 172.16.36.135 with zombie 172.16.36.134
---------Open Ports on Target-------
21
22
23
25
53
80
工作原理
僵尸扫描是个枚举目标系统开放端口的隐秘方式,不需要留下任何交互的痕迹。将伪造请求的组合发给目标系统,以及将正常请求发给僵尸系统,我们就可以通过评估僵尸系统的响应的 IPID 值来映射目标系统的开放端口。
3.18 Nmap 僵尸扫描
就像上一个秘籍,在编程自定义脚本对于理解僵尸扫描背后的工作原理很有帮助。Nmap 中还有另一种高效的扫描模式,可以用于执行僵尸扫描。这个秘籍展示了如何使用 Nmap 执行僵尸扫描。
准备
为了使用 Nmap 执行僵尸扫描,你需要拥有运行 TCP 服务的远程系统,以及另一个拥有 IPID 递增序列的远程系统。在所提供的例子中,Metasploitable2 用作扫描目标,WindowsXP 用作 IPID 递增的僵尸。关于如何在本地实验环境下配置系统的更多信息,请参考第一章的“安装 Metasploitable2”和“安装 Windows 服务器”秘籍。此外,这一节也需要使用文本编辑器将脚本写到文件系统,例如 VIM 或 Nano。如何编写脚本的更多信息,请参考第一章中的“使用文本编辑器(VIM 或 Nano)”秘籍。
操作步骤
僵尸扫描可以在 Nmap 中带参数执行。但是,我们可以使用 Metasploit 快速发现任何可用的僵尸候选项,通过扫描整个地址范围和评估 PIPD 序列,而不是使用 Nmap 僵尸扫描。为了这样做,我们需要使用msfconsole
命令打开 Metasploit,并选项 IPID 序列辅助模块,像这样:
root@KaliLinux:~# msfconsole
-------------------------------------------------------
| METASPLOIT by Rapid7 |
--------------------------- ---------------------------
| __________________ | |
| ==c(______(o(______(_() | |""""""""""""|======[*** |
| )= | | EXPLOIT |
| // \ | |____________________ |
| // \ | |==[msf >]============ |
| // \ | |______________________ |
| // RECON \ | (@)(@)(@)(@)(@)(@)(@)/ |
| // \ | ********************* |
--------------------------- ---------------------------
| o O o | '///'/ |
| o O | )======( |
| o | .' LOOT '. |
| |^^^^^^^^^^^^^^|l___ | / _||__ |
| | PAYLOAD |""___, | / (_||_ |
| |________________|__|)__| | | __||_) | |
| |(@)(@)"""**|(@)(@)**|(@) | " || " |
| = = = = = = = = = = = = | '--------------' |
--------------------------- ---------------------------
Using notepad to track pentests? Have Metasploit Pro report on hosts, services, sessions and evidence -- type 'go_pro' to launch it now.
=[ metasploit v4.6.0-dev [core:4.6 api:1.0]
-- --=[ 1053 exploits - 590 auxiliary - 174 post
-- --=[ 275 payloads - 28 encoders - 8 nops
msf > use auxiliary/scanner/ip/ipidseq
msf auxiliary(ipidseq) > show options
Module options (auxiliary/scanner/ip/ipidseq):
Name Current Setting Required Description
---- --------------- -------- ----------
INTERFACE no The name of the interface
RHOSTS yes The target address range or CIDR identifier
RPORT 80 yes The target port
SNAPLEN 65535 yes The number of bytes to capture
THREADS 1 yes The number of concurrent threads
TIMEOUT 500 yes The reply read timeout in milliseconds
这个辅助模块可以用于在主机地址序列或网络范围中执行扫描,可以使用 CIDR 记法来定义。为了使扫描速度增加,我们可以将THREADS
变量设为合理的并发任务数量,像这样:
msf auxiliary(ipidseq) > set RHOSTS 172.16.36.0/24
RHOSTS => 172.16.36.0/24
msf auxiliary(ipidseq) > set THREADS 25
THREADS => 25
msf auxiliary(ipidseq) > show options
Module options (auxiliary/scanner/ip/ipidseq):
Name Current Setting Required Description
---- --------------- -------- ---------- INTERFACE no The name of the interface
RHOSTS 172.16.36.0/24 yes The target address range or CIDR identifier
RPORT 80 yes The target port
SNAPLEN 65535 yes The number of bytes to capture
THREADS 25 yes The number of concurrent threads
TIMEOUT 500 yes The reply read timeout in milliseconds
一旦为所需变量设置了合理的值,我们可以使用show options
来再次验证扫描配置。IPID 序列扫描之后可以使用run
命令来执行。
msf auxiliary(ipidseq) > run
[*] 172.16.36.1's IPID sequence class: Randomized
[*] 172.16.36.2's IPID sequence class: Incremental!
[*] Scanned 026 of 256 hosts (010% complete)
[*] Scanned 052 of 256 hosts (020% complete)
[*] Scanned 077 of 256 hosts (030% complete)
[*] Scanned 103 of 256 hosts (040% complete)
[*] Scanned 128 of 256 hosts (050% complete)
[*] 172.16.36.134's IPID sequence class: Incremental!
[*] 172.16.36.135's IPID sequence class: All zeros
[*] Scanned 154 of 256 hosts (060% complete)
[*] Scanned 180 of 256 hosts (070% complete)
[*] Scanned 205 of 256 hosts (080% complete)
[*] Scanned 231 of 256 hosts (090% complete)
[*] Scanned 256 of 256 hosts (100% complete)
[*] Auxiliary module execution completed
由于 IPID 序列扫描模块会遍历所提供的网络范围,它会识别被发现主机的 IPID 序列模式,并且表示出哪些是 0,随机或递增的。用于僵尸扫描的理想候选项必须拥有递增的 IPID,并且不会被网络上的其它主机严重影响。一旦识别了递增的独立主机,我们可以在 Nmap 中使用-sI
选项并且传入僵尸主机的 IP 地址来执行僵尸扫描。
root@KaliLinux:~# nmap 172.16.36.135 -sI 172.16.36.134 -Pn -p 0-100
Starting Nmap 6.25 ( http://nmap.org ) at 2014-01-26 14:05 CST I
dle scan using zombie 172.16.36.134 (172.16.36.134:80); Class: Incremental
Nmap scan report for 172.16.36.135
Host is up (0.045s latency).
Not shown: 95 closed|filtered ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
23/tcp open telnet
25/tcp open smtp
53/tcp open domain
80/tcp open
http MAC Address: 00:0C:29:3D:84:32 (VMware)
Nmap done: 1 IP address (1 host up) scanned in 2.75 seconds
上面的例子中,僵尸扫描执行在扫描目标172.16.36.135
的前 100 个 TCP 端口上。独立主机172.16.36.134
用作僵尸,-Pn
选项用于阻止 Nmap 尝试 ping 扫描目标。这个示例中,我们识别并枚举了所有列出的开放端口,而不会直接和被扫描主机交互。反之,伪造了来源的封包会发给扫描目标,并且只有扫描系统和僵尸主机之间才有直接的交互。