0x04编写程序分析流量
检测ddos攻击
1使用dpkt发现下载loic的行为
LOIC,即Low Orbit Ion Cannon低轨道离子炮,是用于压力测试的工具,通常被攻击者用来实现DDoS攻击。
我们要编写py脚本来解析http流量,并检查其中有无通过http get获取压缩过的loic二进制可执行文件的情况。为了检查http流量,我们必须先把数据包的以太网部分、ip层以及tcp层部分分解出来,注意http协议是位于tcp协议层之上的。如果http层中使用了get方法,则解析http get所要获取的统一资源标识符(uri)。如果该uri所指向的文件的文件名中包含有 .zip 和loic,则在屏幕上输出一条某个ip正在下载loic的消息。
注意:这个程序在windows下运行可能会报这样的错误(溢出了)
“OverflowError: Python int too large to convert to C long”
所以这里我在kali下执行了
这里的 download.pcap 是下载loic时捕获的压缩包(是http的,不是https的,若为https的则无法直接通过抓包来进行请求头的分析,因为https加密了)
因为后来怕大家不能够理解这个脚本,所以后来我决定写一些基础知识上来
直接上截图(在这个例子当中我已经尽可能详细地说明了~~)
用wireshark打开数据包是这个样子的(以第一个数据包为例分析)
中的arrive time--------》对应的是
可以看出来,wireshark和python的dpkt库对这个时间的解析是存在一定的差异的,不过这个问题不大
----》
其中type:ipv4(0x0800) 对应的是 2048
Ip的对应很容易找
Len=488----->total length:488
Ttl=64----------->time to live=64
DF---------------->对应flags标识中的Don’t fragment
MF----------------->对应flags标识中的More fragments
Offset=0---------------->对应fragment offset:0
分析到这里已经非常清楚了,其实dpkt这个模块在这里就是对数据包进行了解析。
再看一个结构图(用---来表示各层协议的分层情况)
这个也是用dpkt模块解析出来的数据包中各层协议之间一些分布情况
就像一些类中的属性值一样,例如解析出ip包会用ip=eth.data,可以这样去理解,ip包中的数据是eth类的一个属性的值,这个属性的名字是data,然后会得到一个ip类,然后ip类中又存在一个data属性,他的值为tcp包中的数据,所以解析tcp包就使用 tcp=ip.data ,这种说法确实不严谨,但是可以这样去辅助理解一下下~~
现在我们再回来理解一下这个程序
(好吧~说的有点多了~其实说基础知识不是我这次分享的本意~~)
2
解析Hive服务器上的IRC命令
findHivemind()函数--主要用于检测僵尸网络流量中的IRC命令
实现思路分析:
要发起攻击,“匿名者”成员需要登录到指定的irc服务器上发出一条攻击指令,例如
!lazor targetip=66.211.169.66 message=test_test port 80 method=tc wait=false random=true start
通常irc服务器使用的是tcp 6667端口,在编写我们的findHivemind()函数时就可以利用这一点,我们先把数据包中的以太网部分、ip层、tcp层分解出来,在获得tcp层部分的数据后,我们检查它的源端口和目标端口是不是6667,如果我们看到 !lazor 指令的目标端口是6667,则可以确定某个成员提交了一个攻击指令,如果我们看到了 !lazor 指令的源端口为6667,则可以认为这是服务器在向hive中的成员发布攻击的消息。
3
检测DDoS攻击
实现思路:
要识别攻击,需要设置一个不正常的数据包数量的阀值。如果某个用户发送到某个地址的数据包的数量超过了这个阀值,就把它认为是发动了攻击。
整合脚本:
实现能检测到下载行为,监听到hive指令并检查出攻击行为
在这个例子中流量包的总量是29246个,而在实际应用中流量包的总量要比这个还要大得多,我们基本是不可能人工分析出来的,这时候学会编写脚本来分析就显得十分重要了。
4
工具源代码
代码语言:js复制#!/usr/bin/python
#coding=utf-8
import dpkt
import socket
import optparse
#设置阈值为1000
THRESH = 1000
#检测下载loic行为
def findDownload(pcap):
for (ts, buf) in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
src = socket.inet_ntoa(ip.src)
# 获取TCP数据
tcp = ip.data
# 解析TCP中的上层协议HTTP的请求
http = dpkt.http.Request(tcp.data)
# 若是GET方法,且请求行中包含“.zip”和“loic”字样则判断为下载LOIC
if http.method == 'GET':
uri = http.uri.lower()
if '.zip' in uri and 'loic' in uri:
print "[!] " src " Downloaded LOIC."
except:
pass
#监听hive指令
def findHivemind(pcap):
for (ts, buf) in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
src = socket.inet_ntoa(ip.src)
dst = socket.inet_ntoa(ip.dst)
tcp = ip.data
dport = tcp.dport
sport = tcp.sport
# 若目标端口为6667且含有“!lazor”指令,
#则确定是某个成员提交一个攻击指令
if dport == 6667:
if '!lazor' in tcp.data.lower():
print '[!] DDoS Hivemind issued by: ' src
print '[ ] Target CMD: ' tcp.data
# 若源端口为6667且含有“!lazor”指令,
#则确定是服务器在向HIVE中的成员发布攻击的消息
if sport == 6667:
if '!lazor' in tcp.data.lower():
print '[!] DDoS Hivemind issued to: ' src
print '[ ] Target CMD: ' tcp.data
except:
pass
#检查出攻击行为
def findAttack(pcap):
pktCount = {}
for (ts, buf) in pcap:
try:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
src = socket.inet_ntoa(ip.src)
dst = socket.inet_ntoa(ip.dst)
tcp = ip.data
dport = tcp.dport
# 累计各个src地址对目标地址80端口访问的次数
if dport == 80:
stream = src ':' dst
if pktCount.has_key(stream):
pktCount[stream] = pktCount[stream] 1
else:
pktCount[stream] = 1
except:
pass
for stream in pktCount:
pktsSent = pktCount[stream]
# 若超过设置检测的阈值,则判断为进行DDoS攻击
if pktsSent > THRESH:
src = stream.split(':')[0]
dst = stream.split(':')[1]
print '[ ] ' src ' attacked '
dst ' with ' str(pktsSent) ' pkts.'
def main():
parser = optparse.OptionParser("[*]Usage python findDDoS.py "
"-p <pcap file> -t <thresh>")
parser.add_option('-p', dest='pcapFile',
type='string',
help='specify pcap filename')
parser.add_option('-t', dest='thresh',
type='int',
help='specify threshold count ')
(options, args) = parser.parse_args()
if options.pcapFile == None:
print parser.usage
exit(0)
if options.thresh != None:
THRESH = options.thresh
pcapFile = options.pcapFile
# 若用f = open(pcapFile)
#则这里的pcap文件解析只能调用一次,
#而这里需要多次调用,所以应该使用with open
with open(pcapFile, 'r') as f:
pcap = dpkt.pcap.Reader(f)
findDownload(pcap)
with open(pcapFile, 'r') as f:
pcap = dpkt.pcap.Reader(f)
findHivemind(pcap)
with open(pcapFile, 'r') as f:
pcap = dpkt.pcap.Reader(f)
findAttack(pcap)
if __name__ == '__main__':
main()