本帖最后由 新手427192 于 2017-11-10 10:59 编辑
TCP 空闲扫描(-sI) 1998年,安全研究员Antirez (本书中hping2工具的作者)在Bugtraq邮件列表上,提到了一个巧妙的端口扫描技术--空闲扫描。众所周知,它允许进行端口完全欺骗扫描。使得攻击者能够不使用自己的IP向目标主机发送数据包。它的巧妙之处在于,利用不活跃的“僵尸主机”反弹给攻击者一个旁通信道,从而使得攻击者可以进行端口扫描。入侵检测系统(IDS--Intrusion detection system)也就会把无辜的僵尸主机当成攻击者。除了异常隐蔽外,该种扫描还可以用于发现基于IP的机器间的信任关系。 因为空闲扫描比目前任何一种扫描技术都要复杂(笔者注:该文献时间是1998年,有必要注意一下),所以要理解它,你不必成为TCP/IP专家。总而言之可以概括为以下几个方面: l 判断一个TCP端口是否开放,其中一种方法是向该端口发送SYN(会话建立)包。若端口开放,则目标主机会返回一个SYN/ACK(会话建立确认)包;若端口关闭,则目标主机会返回RST(重置)包。这就是前面所讨论的半开扫描基本概念。 l 机器收到SYN/ACK包后会返回一个RST包,而收到的RST包则会被忽略掉。 l 互联网上的每个IP数据包都有一个分段身份识别号(IP ID)。许多操作系统只是简单的把该识别号递增,因此分析最后一次的IPID就可以告诉攻击者已经发送了多少数据包。 结合这些特征,通过伪造你的身份,就可以扫描一个目标网络,而看起来就像无辜的僵尸主机在扫描。 逐步说明空闲扫描 本质上,空闲扫描在扫描每个端口时都由以下三步组成: 1. 探测僵尸主机的IP ID并记录。 2. 向需要扫描的目标主机端口发送一个伪造成来自僵尸主机的SYN包。根据目标主机端口状态的不同,目标主机返回的数据包会使得僵尸主机的IP ID递增或否。 3. 再次探测僵尸主机的IP ID。并对比第一步记录的IP ID就可以确定目标主机端口的状态。 每次扫描后,僵尸主机数据包的IP ID应该增加1或2。增加1说明僵尸主机没有发送任何数据包,只有攻击者探测时导致的加1。而未发送任何数据包则说明目标端口是未打开的(目标主机向僵尸主机发送了RST包,该包会被忽略,或者什么也没发送)。增加2说明僵尸主机在两次探测之间发送了一个额外的数据包。这个额外的数据包表明目标端口是开放的(即目标主机收到伪造的SYN包后向僵尸主机发送SYN/ACK包,僵尸主机向目标主机回复一个RST包)。增加数大于2则说明我们选择的中间层不适合做僵尸主机。它可能含有不可预测的IP ID,或者说在进行空闲扫描时该端口有其他的通讯。 (笔者注:空闲扫描利用的是空闲的端口,如果该端口有其他的通讯,就会导致扫描程序误判目标主机的端口状态。建议选择打印机、考勤机或者不活跃的web服务器做僵尸主机) 尽管被过滤的端口与关闭的端口有少许的不同,但是攻击者会得到相同的结果,即IPID都增加1。因此利用空闲扫描技术不能区分关闭的端口或被过滤掉的端口。所以,当nmap收到增长为1的IPID后就会把该端口标记为closed|filtered(关闭的或者被过滤的)。 为了更详细的描述,用下面三张图来解释端口开放、关闭、被过滤间的探测原理。三个角色分别用以下图标代表: Figure 5.1. Idlescan of an open port Figure 5.2. Idlescan of a closed port [img=553,188][/img] Figure 5.3. Idlescan of a filtered port 空闲扫描是种终级隐秘扫描。虽然Nmap提供欺骗扫描技术(-D)来帮助用户保护自己的身份,但是这种扫描(不像空闲扫描)仍需要攻击者使用自己真实的IP发送一些数据包以便获取扫描结果。空闲扫描的结果之一是,入侵检测系统若发出警报,则会报告僵尸机已开始对他们扫描。因此可以用该种扫描技术给其他主机栽赃。当你的IDS发出警报时,你要首先考虑这种扫描方式。 空闲扫描的好处之一是,可以用来突破防火墙及路由的的包过滤。IP源地址包过滤技术是一种常用(尽管很弱)的安全机制,用于限制机器可能连接到敏感的主机或网络。例如,一个公司的数据库服务器可能仅允许发布网站的服务器进行访问。或者一个家庭办公人员可能仅允许来自它办公机器的SSH(交互式登陆)连接。 有一种比较让人棘手的情况是:老板让网络管理员在防火墙上打开一个端口,以便他可以使用家里的IP地址来访问公司内部的网络资源。这经常发生在高管不想或不会用VPN(或类似产品)的情况下。 空闲扫描有时候能够映射出这种信任关系。因为空闲扫描列出的开放端口是相对于僵尸主机而言。若对上述数据库服务器进行一次常规的扫描,可能显示未开放任何端口,但是使用web服务器的IP作为僵尸主机,进行空闲扫描却显示该数据库相关的服务端口是开放的,由此可以断定他们之间存在信任关系。 若能映射出他们之间的信任关系,将对攻击者非常有用,可以优先把它当成攻击目标。如果不能注意到连带的数据库访问,那么上述讨论的web服务器对于攻击者而言就是一个非常普通服务器。 空闲扫描的劣处是它比其他大多数类型的扫描花费的时间都要长。虽然已经对该算法进行了优化(在【空闲扫描实现算法】一章中有相关描述),但是一个耗时15秒的半开(SYN)扫描操作,用空闲扫描的话可能花费15分钟还多。另外,你必须确认伪造成来自僵尸主机的数据包能够到达目标主机。因为很多的ISP(互联网服务提供商、和宽带提供商)会过滤掉这种欺骗包。高层服务(像托管服务和T1服务)一般是不会过滤这种包的。如果你伪造的僵尸机数据包被过滤了,那么nmap会立即打印一个错误信息。如果无法更换ISP,可以尝试使用同一个ISP网络下的其他IP做僵尸机。因为很多时候包过滤仅针对非ISP提供的IP地址范围内的数据包。使用空闲扫描另外一个难点是,你必须找到一个工作良好的僵尸主机,将会在下一章讨论。 找到一个运行良好的僵尸主机 进行IP ID空闲扫描的第一步是找到一台合适的僵尸主机。这需要标记的IP ID在全局(不是与僵尸机通讯的每一台主机)基础上递增。所以僵尸机必须是空闲的(也就是名称的由来),因为夹杂其他的数据包会破坏IP ID序列,使得扫描逻辑混乱不堪。僵尸机与攻击者、以及僵尸机和目标机器间的延迟越低,扫描也就会越快。 一种常用的方法是用nmap对一个网络进行简单的ping扫描。当然你也可以用nmap的IP随机选择模式(-iR),但是有时很可能由于路径较远,使得僵尸主机的延迟非常大。选择一个离目标主机、或离本地主机较近的网络,结果会更好一点。你可以用ping扫描得到的可用主机进行挨个尝试,直到该主机可以用于空闲扫描。通常,用他人的机器进行某些不太被希望的操作前,最好获取他人的许可,如:空闲扫描。 我们选择打印机的图标作为僵尸主机不仅仅为了好玩—通常简单的网络设备更有可能成为僵尸机,因为他们通常未被使用(闲置),并且内嵌了网络栈结构,使得IP ID传输更易检测。 在网络上搜索僵尸机时,执行端口扫描和OS(操作系统)探测(-O)要比只用ping扫描更易找到好的僵尸机。只要开启了详细模式(-v),OS检测通常检测IP ID序列生成方法并打印类似这样的一行“IP ID Sequence Generation: Incremental”(IPID序列生成:递增的)。如果类型是Incremental(递增)或Broken little-endian incremental(损坏的小字节序递增),那么就可以作为一台良好的备用僵尸机。但还是不能保证可以良好运行,比如Solaris和其他系统会为每个与其通讯的主机生成新的IP ID序列。或者主机非常繁忙。OS检查结果和开放的端口列表在确定系统是否为空闲主机时会非常有用。 (译者注:little-endian 即小字节序,当数据长度超过一个字节后,低端字节放到内存的低端地址高端字节存入内存的高端地址。 相关词 big-endian) 另外一种确认备用僵尸机的常用方法是使用ipidseqNSE。该脚本探测某个主机并归类其IP ID的生产方法,然后打印出IP ID的归类名称,就像检测OS一样。像大部分NSE脚本一样,ipidseq.nse同样能够对多台主机进行平行扫描,可以把它当作在整个互联网上搜寻合适僵尸机的另外一种方法。 (译者注:NSE-Nmap ScriptingEngine—nmap的脚本引擎) 找到一台合适的僵尸主机的确会花费一番功夫,所以你可以重复使用已经找到的某台较好的僵尸机。 执行空闲扫描 找到合适的僵尸机后,扫描就好办了。只需要为-sI选项指定僵尸主机地址就行了,剩下的事情nmap会替你做。示例 5.1 为Ereet的一个扫描示例,利用Adobe的一台名叫Kiosk的空闲主机作跳板,去扫描美国唱片协会(RIAA)的主机。 示例5.1. 对RIAA进行空闲扫描 Idlescan using zombie kiosk.adobe.com(192.150.13.111:80); Class: Incremental Nmap scan report for 208.225.90.120 (The 65522 ports scanned but not shown beloware in state: closed) Port State Service 21/tcp open ftp 25/tcp open smtp 80/tcp open http 111/tcp open sunrpc 135/tcp open loc-srv 443/tcp open https 1027/tcp open IIS 1030/tcp open iad1 2306/tcp open unknown 5631/tcp open pcanywheredata 7937/tcp open unknown 7938/tcp open unknown 36890/tcp open unknown Nmap done: 1 IP address (1 host up) scanned in2594.47 seconds 从上面的结果可以看出,RIAA并没有考虑到太多的安全因素(注意开放的pcanywhere端口,端口映射,和Legato nsrexec端口)。显然没有防火墙,也就不太可能有IDS。但是如果有的话,他会把kiosk.adobe.com当成扫描者。 -Pn选项是防止nmap初始化时向RIAA主机发送ping探测包。避免暴露Ereet的真实地址。这次扫描将会花费较长的时间,因为-p-选项要求扫描所有的65K个端口。最后不要用kiosk作为你的扫描目标,因为他早就不存在了。 (译者注:pcanywhere--5631端口,一款远程控制软件;Legato(公司名) nsrexec--7937为nsrexecd进程的服务端口,7938为EMC NetWorker portmapper的服务端口,第一次会试图与111端口建立连接。相关知识请自行查找。65K—65535,两个字节最大值,即计算机所有的端口。) Nmap默认使用僵尸机的80端口向目标主机发送探测包。若要使用另外的端口,可以在僵尸机后面添加一个冒号和端口号(比如–sI kiosk.adobe.com:113)。但是你选择的端口必须不能被攻击者或目标主机过滤掉。可以对僵尸机进行SYN扫描,来探测端口是处于开放还是关闭(open | closed )状态。 空闲扫描算法实现 尽管“逐步说明空闲扫描”章节已经对空闲扫描的基本原理进行了描述,但是nmap的实现却要复杂得多。关键不同是并行快速执行及冗余检查,以达到减少误报的目的。 由于并行扫描是种间接地推测端口状态的扫描方法,所以比任何其他的扫描方法都要棘手。Nmap向目标机发送许多端口探测包,然后检测僵尸机生成的IP ID,生成的IP ID号仅能显示有多少端口是开放的,但不能确定是哪些端口。这个问题倒是不大,因为大部分的端口是关闭的或被过滤的(closed|filtered)。Nmap可以并行的以每组100个端口的方式进行扫描。假如nmap探测了一组端口,发现僵尸机的IP ID增长了<N>次,那么就可以断定这组端口中有<N>个开放的端口。然后nmap用二分法查找这些开放的端口。首先把这组端口分成两段,然后进行独立的探测。如果一个子分组显示零个开放端口,就不该组端口标记为关闭的或被过滤的(closed|filtered)。如果一个子分组显示有一个或多个开放端口,就把该组端口进行拆分并处理,直到可以确定这些开放的端口。尽管增加了复杂度,花费的时间却可以比每次扫描一个端口的方式少上一个数量级。 可靠性是空闲扫描时的另外一个重要问题。如果僵尸机在扫描期间向其他不相关的主机发送了数据包,将会导致他的IPID递增。这将导致nmap认为找到了一个开放的端口。幸运的是,并行扫描此时也能起到作用。假如nmap探测了一组100个端口,根据IPID的增长值发现了两个开放的端口,nmap把这组端口分成两个各含50个端口的子分组。当namp在两个子分组上进行IP ID扫描后,除非僵尸机IP ID恰好增加二,否则,namp就会对前后不匹配的组进行重新扫描。同时根据僵尸机的可靠性调整分组的大小以及扫描的时间。如果nmap检测到太多的不可靠结果,他会立即退出并提示用户提供一个较好的僵尸机。 有时用包追踪的方式可能会更好理解复杂的算法和技术。这时就要用到nmap的--packet-trace 选项了。以下的章节我们对7个实际的端口,进行了相关的包追踪。真实IP地址已用Attacker、Zombie和Target代替了,其他的与包追踪不太相关的因素(如TCP窗口的大小),为了描述清晰均已清除。 Attacker# nmap -sI Zombie -Pn -p20-25,110 -r--packet-trace -v Target -Pn 在隐身攻击中是必须的,否则ping包将会把攻击者真实的地址发送给目标。版本探测同样也会暴露真实地址,并且–sV 也不是必须的。-r选项(关闭随机端口扫描)只是为了使示例更简单些。 Namp首先向僵尸主机发送六个SYN/ACK包,通过分析返回的数据包来确定僵尸机IP ID序列的生成方式。这使得nmap快速排除劣质的僵尸机。这部是必须的,因为有些系统(通常是微软系列的机器,但不是所有的微软机器)每次发送数据包IPID都会递增256,而不是递增1 。这通常发生在小字节序机器上,因为他们通常不将IPID转换为网络字节顺序(big-endian大字节序)。Nmap用这些基本的推测来解决这个问题。 SENT (0.0060s) TCP Attacker:51824 >Zombie:80 SA id=35996 SENT (0.0900s) TCP Attacker:51825 >Zombie:80 SA id=25914 SENT (0.1800s) TCP Attacker:51826 >Zombie:80 SA id=39591 RCVD (0.1550s) TCP Zombie:80 >Attacker:51824 R id=15669 SENT (0.2700s) TCP Attacker:51827 >Zombie:80 SA id=43604 RCVD (0.2380s) TCP Zombie:80 >Attacker:51825 R id=15670 SENT (0.3600s) TCP Attacker:51828 >Zombie:80 SA id=34186 RCVD (0.3280s) TCP Zombie:80 >Attacker:51826 R id=15671 SENT (0.4510s) TCP Attacker:51829 >Zombie:80 SA id=27949 RCVD (0.4190s) TCP Zombie:80 >Attacker:51827 R id=15672 RCVD (0.5090s) TCP Zombie:80 >Attacker:51828 R id=15673 RCVD (0.5990s) TCP Zombie:80 >Attacker:51829 R id=15674 Idlescan using zombie Zombie (Zombie:80);Class: Incremental 这个测试说明是个很好的僵尸机。每个IPID都比上一个增加了一。通过IPID间的通信,很容易确定该主机是台空闲主机。结果不错,但我们仍需要进行下一步检查,即nmap向僵尸机发送四个伪造成Target的数据包。然后探测僵尸机的IPID是否增加。如果没有增加,很可能攻击者的ISP过滤了这种伪造的数据包,或者僵尸机对每个与其通信的主机都使用不同的IPID序列。这两种情况都有可能发生,所以nmap每次都进行这步操作。上面最后的IPID是15674 。 SENT (0.5990s) TCP Target:51823 > Zombie:80SA id=1390 SENT (0.6510s) TCP Target:51823 > Zombie:80SA id=24025 SENT (0.7110s) TCP Target:51823 > Zombie:80SA id=15046 SENT (0.7710s) TCP Target:51823 > Zombie:80SA id=48658 SENT (1.0800s) TCP Attacker:51987 >Zombie:80 SA id=27659 RCVD (1.2290s) TCP Zombie:80 >Attacker:51987 R id=15679 四个伪造的数据包加上攻击者的探测数据包,恰好使得僵尸机的IPID从15674增长到15679 。太好了!现在开始真正的扫描。记住僵尸机的最后一个IPID是15679 。 Initiating Idlescan against Target SENT (1.2290s) TCP Zombie:80 > Target:20 Sid=13200 SENT (1.2290s) TCP Zombie:80 > Target:21 Sid=3737 SENT (1.2290s) TCP Zombie:80 > Target:22 Sid=65290 SENT (1.2290s) TCP Zombie:80 > Target:23 Sid=10516 SENT (1.4610s) TCP Attacker:52050 >Zombie:80 SA id=33202 RCVD (1.6090s) TCP Zombie:80 >Attacker:52050 R id=15680 Nmap探测20-23端口。然后探测僵尸机发现新的IPID为15680,比上个值15679只增加了1。在两次已知的包之间没有IPID的增长,说明端口20-23很可能是closed|filtered。也有可能是来自目标端口的SYN/ACK数据包还没有到达。这种情况下,僵尸机还没有返回RST包,因此它的IPID还没有增加。为了确认这种情况,nmap将稍后再尝试这些端口。 SENT (1.8510s) TCP Attacker:51986 >Zombie:80 SA id=49278 RCVD (1.9990s) TCP Zombie:80 >Attacker:51986 R id=15681 从上次探测后,等待四十分之一秒nmap再探测一次。僵尸机(不确定是真的空闲)在这段时间内可能已经与其他主机进行了通讯,这将可能导致后续的探测不准确。幸运的是,僵尸机没有通信:下一个IPID是15681,与期望的一致。 SENT (2.0000s) TCP Zombie:80 > Target:24 Sid=23928 SENT (2.0000s) TCP Zombie:80 > Target:25 Sid=50425 SENT (2.0000s) TCP Zombie:80 > Target:110 Sid=14207 SENT (2.2300s) TCP Attacker:52026 >Zombie:80 SA id=26941 RCVD (2.3800s) TCP Zombie:80 >Attacker:52026 R id=15684 Nmap 探测端口24,25和110然后查询僵尸机的IPID。他从15681跳到了15684 。跳过了15682和15683,说明三个端口中有两个端口很可能是开放的。 Nmap 不能够确认是哪两个,也有可能根本不正确。所以nmap进行更深入的检查,把这这次的扫描分成两个子分组。 SENT (2.6210s) TCP Attacker:51867 >Zombie:80 SA id=18869 RCVD (2.7690s) TCP Zombie:80 >Attacker:51867 R id=15685 SENT (2.7690s) TCP Zombie:80 > Target:24 Sid=30023 SENT (2.7690s) TCP Zombie:80 > Target:25 Sid=47253 SENT (3.0000s) TCP Attacker:51979 >Zombie:80 SA id=12077 RCVD (3.1480s) TCP Zombie:80 >Attacker:51979 R id=15687 第一个子分组的端口是24和25 。 IPID从15685跳到15687,说明这两个端口中有一个是打开的。 Nmap 依法尝试再次分成两份,独立的探测每个端口。 SENT (3.3910s) TCP Attacker:51826 > Zombie:80SA id=32515 RCVD (3.5390s) TCP Zombie:80 >Attacker:51826 R id=15688 SENT (3.5390s) TCP Zombie:80 > Target:24 Sid=47868 SENT (3.7710s) TCP Attacker:52012 >Zombie:80 SA id=14042 RCVD (3.9190s) TCP Zombie:80 >Attacker:52012 R id=15689 端口24的探测结果显示IPID没有跳跃。所以该端口未开放。从目前的结果来看,nmap可以初步确定: 端口20-23 是 closed|filtered
看了这么久的这个问题,你会发现一个问题:端口25和110是打开的而其他5个端口是关闭的或被过滤的。根据这个逻辑,nmap可以停止扫描然后数据结果了。如果这么做的话,当不能肯定僵尸机是空闲的时候,将会有很多端口误判为开放的。所以nmap继续扫描来确认他的结果: SENT (4.1600s) TCP Attacker:51858 >Zombie:80 SA id=6225 RCVD (4.3080s) TCP Zombie:80 >Attacker:51858 R id=15690 SENT (4.3080s) TCP Zombie:80 > Target:25 Sid=35713 SENT (4.5410s) TCP Attacker:51856 >Zombie:80 SA id=28118 RCVD (4.6890s) TCP Zombie:80 > Attacker:51856R id=15692 Discovered open port 25/tcp on Target SENT (4.6900s) TCP Zombie:80 > Target:110 Sid=9943 SENT (4.9210s) TCP Attacker:51836 >Zombie:80 SA id=62254 RCVD (5.0690s) TCP Zombie:80 >Attacker:51836 R id=15694 Discovered open port 110/tcp on Target 探测端口25和110显示他们是打开的,与我们先前的推测一致。 SENT (5.0690s) TCP Zombie:80 > Target:20 Sid=8168 SENT (5.0690s) TCP Zombie:80 > Target:21 Sid=36717 SENT (5.0690s) TCP Zombie:80 > Target:22 Sid=4063 SENT (5.0690s) TCP Zombie:80 > Target:23 Sid=54771 SENT (5.3200s) TCP Attacker:51962 >Zombie:80 SA id=38763 RCVD (5.4690s) TCP Zombie:80 >Attacker:51962 R id=15695 SENT (5.7910s) TCP Attacker:51887 >Zombie:80 SA id=61034 RCVD (5.9390s) TCP Zombie:80 >Attacker:51887 R id=15696 为了确认, nmap 再次尝试20-23端口。查询僵尸机的IPID,结果显示没有任何跳跃。万一从目标发送到僵尸机的SYN/ACK延迟到达,那么nmap将再次尝试IPID查询。结果再次说明没有开放的端口。现在nmap将有很大的把握来输出他的结果。 The Idlescan took 5 seconds to scan 7 ports. Nmap scan report for Target PORT STATE SERVICE 20/tcp closed|filtered ftp-data 21/tcp closed|filtered ftp 22/tcp closed|filtered ssh 23/tcp closed|filtered telnet 24/tcp closed|filtered priv-mail 25/tcp open smtp 110/tcp open pop3 Nmap finished: 1 IP address (1 host up)scanned in 5.949 seconds 想要了解更详细的nmap空闲扫描实现方法,请阅读nmap发布的源代码中idle_scan.cc文件。 尽管可预测的IPID序列被滥用在了端口扫描上,他们也可以用于其他许多目的。示例贯彻全书,尤其是在【章节10,防火墙和入侵检测系统的检测及欺骗】 |