执
执着
Unregistered / Unconfirmed
GUEST, unregistred user!
局域网里截获别人的通讯和阻止别人的通讯
TCP KILL 阻断的协议层次分析和实验
这里是RFC793的TCP 连接例子,可以看到RST的一种使用情况
seq= 对方的 ack
ack=0
CTL =RST
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> ...
3. (duplicate) ... <SEQ=90><CTL=SYN> --> SYN-RECEIVED
4. SYN-SENT <-- <SEQ=300><ACK=91><CTL=SYN,ACK> <-- SYN-RECEIVED
5. SYN-SENT --> <SEQ=91><CTL=RST> --> LISTEN
6. ... <SEQ=100><CTL=SYN> --> SYN-RECEIVED
7. SYN-SENT <-- <SEQ=400><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
8. ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK> --> ESTABLISHED
对方发送数据的情况
TCP A TCP B
1. (CRASH) (send 300,receive 100)
2. (??) <-- <SEQ=300><ACK=100><DATA=10><CTL=ACK> <-- ESTABLISHED
3. --> <SEQ=100><CTL=RST> --> (ABORT!!)
TCP A TCP B
1. LISTEN LISTEN
2. ... <SEQ=Z><CTL=SYN> --> SYN-RECEIVED
3. (??) <-- <SEQ=X><ACK=Z+1><CTL=SYN,ACK> <-- SYN-RECEIVED
4. --> <SEQ=Z+1><CTL=RST> --> (return to LISTEN!)
5. LISTEN LISTEN
RST的情况描述1
1. If the connection does not exist (CLOSED) then a reset is sent
in response to any incoming segment except another reset. In
particular, SYNs addressed to a non-existent connection are rejected
by this means.
如果一个连接并不存在,那么一个RST将会被发送,通常情况下一个发给不存在的连接的SYN会受到 RST
If the incoming segment has an ACK field, the reset takes its
sequence number from the ACK field of the segment, otherwise the
reset has sequence number zero and the ACK field is set to the sum
of the sequence number and segment length of the incoming segment.
The connection remains in the CLOSED state.
对于返回的RST数据来说 它的ack 和seq 是这样的 如果一个连入的数据有ACK 字段的话,将从对方的ACK拿出 数字,并当作seq 返回给对方
否则的话, 会有返回一个seq 为 0 , ack 字段为对方的 seq 和数据段的长度的和的RST 数据
if(packet has ack)
{
seq=ack
ack=0
ctl=rst
}
else
{
seq=0
ack=seq+packetlength
}
if(ack)
{
seq=seg.ack
ack=0
ctl=rst
}
else
{
seq=0
ack=seg.seq+seg.len
ctl=rst ack
}
If the ACK bit is on,
<SEQ=SEG.ACK><CTL=RST>
If the ACK bit is off, sequence number zero is used,
<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
对于一个截获的数据包来说
如果他是TCp 的数据段则为了阻断这个连接
首先要假冒它的目的给他发送一个RST包
这个包除了要源IP, 目的IP,源端口,目的端口都符合他期待的数值以外,还有这样的
要求
if(ack)
{
seq=seg.ack
ack=0
ctl=rst
}
else
{
seq=0
ack=seg.seq+seg.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
}
那反过来如何告诉目的Ip要rst这个连接呢?
我们需要知道目的ip下一次将要发送的ACK 和 SEQ
首先 SEQ 应该 SELF.LASTSEQ+SELF.LAST.LEN
同时在接受到 之后的第一个 SEQ = 对方LASTACK
我们在这里可以知道它的目的ip返还的tcp 的 SEQ 一定是 这次截获的数据的ACK 了
那么它的下下一个SEQ 有可能是 SEQ + ??
在分析 httP 的数据。,可以看到使用每次发送1460 字节,那么这个1460是从和得到的呢?
Source port = 4110 (Unassigned) - [34-35]
Destination port = 80 (www-http (World Wide Web HTTP)) - [36-37]
Sequence number = 3895578463 - [38-41]
Acknowledgement number = 0 - [42-45]
Header length = 28 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 002h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.0 .... = No acknowledgement - {46-47}
0000 00.. 0... = No push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..1. = SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 16384 - [48-49]
Checksum = F901h - [50-51]
Urgent pointer = 0 - [52-53]
Options = 8 bytes - [54-61]
Code = 2 (MSS)
Required MSS: 1460
Other Options
我们可以看到
是在tcp 握手阶段的时候,使用的mss tcP 选项定下来的
那么有一个问题,就是当要发送的数据不足1460字节的时候,怎么办?比如 http 请求,这里并没有超过 1046字节
----- IPv4 Header ----- [14-33]
Version = 4 - {14-14}
Header length = 20 bytes - {14-14}
Type of service = 00h - [15-15]
000. .... = priority 0: routine - {15-15}
...0 .... = normal delay - {15-15}
.... 0... = normal throughput - {15-15}
.... .0.. = normal reliability - {15-15}
.... ..0. = normal monetary cost - {15-15}
.... ...0 = Reserved bit, for future usage, which has to be 0 - {15-15}
Total length = 730 bytes - [16-17]
Identification = 35859 - [18-19]
Flags = 4h - {20-20}
0... .... = must be 0 - {20-20}
.1.. .... = do not fragment - {20-20}
..0. .... = last fragment - {20-20}
Fragment offset = 0 bytes - {20-21}
Time to live = 128 seconds/hops - [22-22]
Protocol = 6 (TCP [Transmission Control Protocol]) - [23-23]
Header checksum = E9DCh - [24-25]
Source address = [192.168.0.1] - [26-29]
Destination address = [192.168.0.220] - [30-33]
No IP options - [14-14]
----- TCP Header ----- - [34-53]
Source port = 4110 (Unassigned) - [34-35]
Destination port = 80 (www-http (World Wide Web HTTP)) - [36-37]
Sequence number = 3895578464 - [38-41]
Acknowledgement number = 1124946225 - [42-45]
Header length = 20 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 018h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.1 .... = Acknowledgement - {46-47}
0000 00.. 1... = Push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..0. = No SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 17520 - [48-49]
Checksum = FA0Fh - [50-51]
Urgent pointer = 0 - [52-53]
No TCP options
----- HTTP Client Request ----- - [54-743]
[690 byte(s) of data]
GET /bbs/FORUM.asp?FORUM_ID=55&CAT_ID=7&Forum_Title=ASP%C2%DB%CC%B3 HTTP/1.0 - [54-129]
Accept: */* - [132-142]
Referer: http://wwh/bbs/topic.asp?TOPIC_ID=305&FORUM_ID=55&CAT_ID=7&Topic_Title=%CB%F9%D3%D0%B5% ... - [145-288]
Accept-Language: zh-cn - [291-312]
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) - [315-376]
Host: wwh - [379-387]
Pragma: no-cache - [390-405]
Cookie: Snitz00User=Cookies=&Pword=cc&Name=cceye; ASPSESSIONIDGGGGQMEK=HDJJLABCNOIGOCFCGHMMHJPG; ... - [408-715]
Connection: Keep-Alive - [718-739]
看来并没有使用添冲,而是全部发送。本来嘛,这个mss就是最大的传输字段,并没有限制是多少。
在这里试图截断连接 我尽量不去纪录状态,因为可能涉及到的数据量很大。我要从任何一个包里得到全部的信息
从这里看我不可能得到mss 因为mss 仅仅在数据连接状态的时候才出现,然后各自就纪录到各自的TCP连接状态中了
那么在初始握手阶段有没有用呢? 还是不要叉开话题了,现在是如何发送RST给这个数据包的目的Ip
好吧 mss 和window 由什么关系吗?
看到 17520 是 mss 的12 倍
而在 server 端接受到 client发送的 690字节的请求以后他的window 就变成了 16830(16830+690正好是 17520)
但是 client 尽管接受了很多字节 它的window 的值还是没有改变。
在数据截获的时候很难区分那一段在使用什么规则,而且各个操作系统实现起来不一样。
还与握手阶段有很大关系。目的IP 的下下一个 seq 是多少就判断不出了。
但是有了下一个 seq 就可以了
"那反过来如何告诉目的Ip要rst这个连接呢?
我们需要知道目的ip下一次将要发送的ACK 和 SEQ
首先 SEQ 应该 SELF.LASTSEQ+SELF.LAST.LEN
同时在接受到 之后的第一个 SEQ = 对方LASTACK
我们在这里可以知道它的目的ip返还的tcp 的 SEQ 一定是 这次截获的数据的ACK 了
那么它的下下一个SEQ 有可能是 SEQ + ??"
它的下一个ACK 应该是多少呢?
应该是我的这次数据包的 seq + seq.len
那么现在可以确定这个数据包的目的Ip在接受到这个数据包之后的操作了
seq=this.ack
ack=this.seq+this.len
根据前面的发送RST 的要求发送
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
发送给目的主机
seq=0
ack=this.ack+0(因为首先会返回一个回应,但是如果它使用 PUSH就没有办法知道它的可能的数值了)
}
哦因为没有ack 所以根本不可能有下一次的ack因为他还没有发送 syn 呢.所以
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
}
好了,现在只不过是确定了要RST 目的IP 将来的数据段,如果我的RST包在他还没有。来得及发送回应就发出去了,应该是没有什么效果的,
因为本身的状态还没有更新,自然也就无可RST嘛。
如果能RST他接收到的数据包就好了,状态就好了。
这要求我知道它的上一次的数据包的 seq 和 ack
好,我们来再玩一次游戏
根据上面推出的结果
可得到
seq=last.ack
ack=last.seq+last.len
推出 last.ack=this.seq
last.seq=this.ack-last.len
我可能知道上一次的len 吗?不可能
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
seq=this.seq
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
发送给目的主机
seq=0
ack=this.ack
ctl=rst ack
}
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
}
现在经过实验上面的逻辑可使连接断开,但是一旦停止运行,其连接自动又恢复了,
对于某些连接比如 http来说,是不可会恢复的。
但是对于比如象 netant 这样的 自动重新尝试的连接,就不行了。
现在实验这样断开逻辑
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
seq=this.seq
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
发送给目的主机
seq=0
ack=this.ack
ctl=rst ack
}
没有问题,发现很容易切断连接,于是实验把ack 的值更改看看能不能断开,发现还是可以。
于是启动sniffer 观察断开之后的情形。
从开始可看出不断的请求连接被断开的情形。
----- TCP Header ----- - [34-61]
Source port = 1632 (pammratc (PAMMRATC)) - [34-35]
Destination port = 1021 (Unassigned) - [36-37]
Sequence number = 1035563504 - [38-41]
Acknowledgement number = 0 - [42-45]
Header length = 28 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 002h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.0 .... = No acknowledgement - {46-47}
0000 00.. 0... = No push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..1. = SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 16384 - [48-49]
Version = 4 - {14-14}
Header length = 20 bytes - {14-14}
Type of service = 00h - [15-15]
000. .... = priority 0: routine - {15-15}
...0 .... = normal delay - {15-15}
.... 0... = normal throughput - {15-15}
.... .0.. = normal reliability - {15-15}
.... ..0. = normal monetary cost - {15-15}
.... ...0 = Reserved bit, for future usage, which has to be 0 - {15-15}
Total length = 40 bytes - [16-17]
Identification = 23561 - [18-19]
Flags = 0h - {20-20}
0... .... = must be 0 - {20-20}
.0.. .... = may fragment - {20-20}
..0. .... = last fragment - {20-20}
Fragment offset = 0 bytes - {20-21}
Time to live = 44 seconds/hops - [22-22]
Protocol = 6 (TCP [Transmission Control Protocol]) - [23-23]
Header checksum = 8956h - [24-25]
Source address = [202.113.29.123] - [26-29]
Destination address = [192.168.0.220] - [30-33]
No IP options - [14-14]
----- TCP Header ----- - [34-53]
Source port = 1021 (Unassigned) - [34-35]
Destination port = 1632 (pammratc (PAMMRATC)) - [36-37]
Sequence number = 0 - [38-41]
Acknowledgement number = 1035563505 - [42-45]
Header length = 20 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 014h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.1 .... = Acknowledgement - {46-47}
0000 00.. 0... = No push - {46-47}
0000 00.. .1.. = Reset - {46-47}
0000 00.. ..0. = No SYN - {46-47}
下面我们来看已经建立的连接如何被打断的
看到netant 开始建立syn 请求握手了,
受到了相应之后,netant 开动了5个 syn 同时请求握手(这算不算是syn flood )
都受到了相应了,现在他们开始亲密而默锲的交谈了。好了,现在开始找我的RST
这里看到
202.204.24.12 --> 192.168.0.220 seq 4193832849 ack 179135224
192.168.0.220_--> 202.204.24.12 seq 179135224 ack 4193837229
这里的 ack 是上一次的 seq + 4380而上一起实际传输的数据是 1460, 因此可知这里使用了慢启动算法和滑动窗口
这里的 window 是 17520 看来tcpkill.c 中使用
tcp->th_seq = htonl(ack + (i * win)); 是有道理的。
这个时候我的RST 出现了 seq 为 4193832849 和 4193834309
的阻断包。这个是来自
规则:
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
seq=this.seq
ack=0
ctl=rst
为了测试效果,我把发往源主机的阻断包都关闭了。
下面我看看这两台主机互相又 发送了什么
202.204.24.12 --> 192.168.0.220 seq 4131598001 1774271156
在此之后没有出现任何 seq 在4193832849之后的 TCp数据,因此可以肯定,此RST 已经成功了.
----- Packet Details -----
----- General Information -----
Item number 10, position in dumpfile 2%
Item type: Partial frame, 744 bytes available
Frame size is 744 (2E8x) bytes
Timestamp: 11h:41m:42s:777667us
----- Ethernet v.2.0 MAC Header ----- [0-13]
Destination = Computer 00E04C-482B51 (Universal; Vendor: ???) - [0-13]
Source = Computer 00E04C-3C04D8 (Universal; Vendor: ???) - [6-11]
Ethertype = 0800h (DOD Internet Protocol (IP) Xerox) - [12-13]
----- IPv4 Header ----- [14-33]
Version = 4 - {14-14}
Header length = 20 bytes - {14-14}
Type of service = 00h - [15-15]
000. .... = priority 0: routine - {15-15}
...0 .... = normal delay - {15-15}
.... 0... = normal throughput - {15-15}
.... .0.. = normal reliability - {15-15}
.... ..0. = normal monetary cost - {15-15}
.... ...0 = Reserved bit, for future usage, which has to be 0 - {15-15}
Total length = 730 bytes - [16-17]
Identification = 35859 - [18-19]
Flags = 4h - {20-20}
0... .... = must be 0 - {20-20}
.1.. .... = do not fragment - {20-20}
..0. .... = last fragment - {20-20}
Fragment offset = 0 bytes - {20-21}
Time to live = 128 seconds/hops - [22-22]
Protocol = 6 (TCP [Transmission Control Protocol]) - [23-23]
Header checksum = E9DCh - [24-25]
Source address = [192.168.0.1] - [26-29]
Destination address = [192.168.0.220] - [30-33]
No IP options - [14-14]
----- TCP Header ----- - [34-53]
Source port = 4110 (Unassigned) - [34-35]
Destination port = 80 (www-http (World Wide Web HTTP)) - [36-37]
Sequence number = 3895578464 - [38-41]
Acknowledgement number = 1124946225 - [42-45]
Header length = 20 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 018h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.1 .... = Acknowledgement - {46-47}
0000 00.. 1... = Push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..0. = No SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 17520 - [48-49]
Checksum = FA0Fh - [50-51]
Urgent pointer = 0 - [52-53]
No TCP options
----- HTTP Client Request ----- - [54-743]
[690 byte(s) of data]
GET /bbs/FORUM.asp?FORUM_ID=55&CAT_ID=7&Forum_Title=ASP%C2%DB%CC%B3 HTTP/1.0 - [54-129]
Accept: */* - [132-142]
Referer: http://wwh/bbs/topic.asp?TOPIC_ID=305&FORUM_ID=55&CAT_ID=7&Topic_Title=%CB%F9%D3%D0%B5% ... - [145-288]
Accept-Language: zh-cn - [291-312]
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) - [315-376]
Host: wwh - [379-387]
Pragma: no-cache - [390-405]
Cookie: Snitz00User=Cookies=&Pword=cc&Name=cceye; ASPSESSIONIDGGGGQMEK=HDJJLABCNOIGOCFCGHMMHJPG; ... - [408-715]
Connection: Keep-Alive - [718-739]
2. If the connection is in any non-synchronized state (LISTEN,
SYN-SENT, SYN-RECEIVED), and the incoming segment acknowledges
something not yet sent (the segment carries an unacceptable ACK), or
if an incoming segment has a security level or compartment which
does not exactly match the level and compartment requested for the
connection, a reset is sent.
当一个非同步的连接存在的时候,而且进入的数据段可能还没有相应的字段发出的时候
也有可能是对方的数据段要求的安全等级并不能被接受的时候,会发送RST.
If our SYN has not been acknowledged and the precedence level of the
incoming segment is higher than the precedence level requested then
either raise the local precedence level (if allowed by the user and
the system) or send a reset; or if the precedence level of the
incoming segment is lower than the precedence level requested then
continue as if the precedence matched exactly (if the remote TCP
cannot raise the precedence level to match ours this will be
detected in the next segment it sends, and the connection will be
terminated then). If our SYN has been acknowledged (perhaps in this
incoming segment) the precedence level of the incoming segment must
match the local precedence level exactly, if it does not a reset
must be sent.
If the incoming segment has an ACK field, the reset takes its
sequence number from the ACK field of the segment, otherwise the
reset has sequence number zero and the ACK field is set to the sum
of the sequence number and segment length of the incoming segment.
The connection remains in the same state.
3. If the connection is in a synchronized state (ESTABLISHED,
FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT),
any unacceptable segment (out of window sequence number or
unacceptible acknowledgment number) must elicit only an empty
acknowledgment segment containing the current send-sequence number
and an acknowledgment indicating the next sequence number expected
to be received, and the connection remains in the same state.
If an incoming segment has a security level, or compartment, or
precedence which does not exactly match the level, and compartment,
and precedence requested for the connection,a reset is sent and
connection goes to the CLOSED state. The reset takes its sequence
number from the ACK field of the incoming segment.
Reset Processing
In all states except SYN-SENT, all reset (RST) segments are validated
by checking their SEQ-fields. A reset is valid if its sequence number
is in the window. In the SYN-SENT state (a RST received in response
to an initial SYN), the RST is acceptable if the ACK field
acknowledges the SYN.
除了syn 的情况,所有的 RST会被根据 seq 的数值检验是否合法,如果seq 的数值在 window 的内部的话,将被看作是合法的
如果是在 syn 阶段的话则 这个RST 的 ACK 将是对方的SYN
The receiver of a RST first validates it, then changes state. If the
receiver was in the LISTEN state, it ignores it. If the receiver was
in SYN-RECEIVED state and had previously been in the LISTEN state,
then the receiver returns to the LISTEN state, otherwise the receiver
aborts the connection and goes to the CLOSED state. If the receiver
was in any other state, it aborts the connection and advises the user
and goes to the CLOSED state.
如果一个RST 被收到的话,首先验证他,然后改变状态,如果这个接受方是在listen的状态的话,
将会忽略这个RST.
如果这个接受方是在刚刚从listen阶段转到 SYN阶段,那么这个listen 将会转到listen 状态
其他的情况,这个接受方将会断开连接,并转向closed 状态.
资料整理:编程先锋 http://wlbookwl.myrice.com 站长:小黑侠
TCP KILL 阻断的协议层次分析和实验
这里是RFC793的TCP 连接例子,可以看到RST的一种使用情况
seq= 对方的 ack
ack=0
CTL =RST
TCP A TCP B
1. CLOSED LISTEN
2. SYN-SENT --> <SEQ=100><CTL=SYN> ...
3. (duplicate) ... <SEQ=90><CTL=SYN> --> SYN-RECEIVED
4. SYN-SENT <-- <SEQ=300><ACK=91><CTL=SYN,ACK> <-- SYN-RECEIVED
5. SYN-SENT --> <SEQ=91><CTL=RST> --> LISTEN
6. ... <SEQ=100><CTL=SYN> --> SYN-RECEIVED
7. SYN-SENT <-- <SEQ=400><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED
8. ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK> --> ESTABLISHED
对方发送数据的情况
TCP A TCP B
1. (CRASH) (send 300,receive 100)
2. (??) <-- <SEQ=300><ACK=100><DATA=10><CTL=ACK> <-- ESTABLISHED
3. --> <SEQ=100><CTL=RST> --> (ABORT!!)
TCP A TCP B
1. LISTEN LISTEN
2. ... <SEQ=Z><CTL=SYN> --> SYN-RECEIVED
3. (??) <-- <SEQ=X><ACK=Z+1><CTL=SYN,ACK> <-- SYN-RECEIVED
4. --> <SEQ=Z+1><CTL=RST> --> (return to LISTEN!)
5. LISTEN LISTEN
RST的情况描述1
1. If the connection does not exist (CLOSED) then a reset is sent
in response to any incoming segment except another reset. In
particular, SYNs addressed to a non-existent connection are rejected
by this means.
如果一个连接并不存在,那么一个RST将会被发送,通常情况下一个发给不存在的连接的SYN会受到 RST
If the incoming segment has an ACK field, the reset takes its
sequence number from the ACK field of the segment, otherwise the
reset has sequence number zero and the ACK field is set to the sum
of the sequence number and segment length of the incoming segment.
The connection remains in the CLOSED state.
对于返回的RST数据来说 它的ack 和seq 是这样的 如果一个连入的数据有ACK 字段的话,将从对方的ACK拿出 数字,并当作seq 返回给对方
否则的话, 会有返回一个seq 为 0 , ack 字段为对方的 seq 和数据段的长度的和的RST 数据
if(packet has ack)
{
seq=ack
ack=0
ctl=rst
}
else
{
seq=0
ack=seq+packetlength
}
if(ack)
{
seq=seg.ack
ack=0
ctl=rst
}
else
{
seq=0
ack=seg.seq+seg.len
ctl=rst ack
}
If the ACK bit is on,
<SEQ=SEG.ACK><CTL=RST>
If the ACK bit is off, sequence number zero is used,
<SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
对于一个截获的数据包来说
如果他是TCp 的数据段则为了阻断这个连接
首先要假冒它的目的给他发送一个RST包
这个包除了要源IP, 目的IP,源端口,目的端口都符合他期待的数值以外,还有这样的
要求
if(ack)
{
seq=seg.ack
ack=0
ctl=rst
}
else
{
seq=0
ack=seg.seq+seg.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
}
那反过来如何告诉目的Ip要rst这个连接呢?
我们需要知道目的ip下一次将要发送的ACK 和 SEQ
首先 SEQ 应该 SELF.LASTSEQ+SELF.LAST.LEN
同时在接受到 之后的第一个 SEQ = 对方LASTACK
我们在这里可以知道它的目的ip返还的tcp 的 SEQ 一定是 这次截获的数据的ACK 了
那么它的下下一个SEQ 有可能是 SEQ + ??
在分析 httP 的数据。,可以看到使用每次发送1460 字节,那么这个1460是从和得到的呢?
Source port = 4110 (Unassigned) - [34-35]
Destination port = 80 (www-http (World Wide Web HTTP)) - [36-37]
Sequence number = 3895578463 - [38-41]
Acknowledgement number = 0 - [42-45]
Header length = 28 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 002h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.0 .... = No acknowledgement - {46-47}
0000 00.. 0... = No push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..1. = SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 16384 - [48-49]
Checksum = F901h - [50-51]
Urgent pointer = 0 - [52-53]
Options = 8 bytes - [54-61]
Code = 2 (MSS)
Required MSS: 1460
Other Options
我们可以看到
是在tcp 握手阶段的时候,使用的mss tcP 选项定下来的
那么有一个问题,就是当要发送的数据不足1460字节的时候,怎么办?比如 http 请求,这里并没有超过 1046字节
----- IPv4 Header ----- [14-33]
Version = 4 - {14-14}
Header length = 20 bytes - {14-14}
Type of service = 00h - [15-15]
000. .... = priority 0: routine - {15-15}
...0 .... = normal delay - {15-15}
.... 0... = normal throughput - {15-15}
.... .0.. = normal reliability - {15-15}
.... ..0. = normal monetary cost - {15-15}
.... ...0 = Reserved bit, for future usage, which has to be 0 - {15-15}
Total length = 730 bytes - [16-17]
Identification = 35859 - [18-19]
Flags = 4h - {20-20}
0... .... = must be 0 - {20-20}
.1.. .... = do not fragment - {20-20}
..0. .... = last fragment - {20-20}
Fragment offset = 0 bytes - {20-21}
Time to live = 128 seconds/hops - [22-22]
Protocol = 6 (TCP [Transmission Control Protocol]) - [23-23]
Header checksum = E9DCh - [24-25]
Source address = [192.168.0.1] - [26-29]
Destination address = [192.168.0.220] - [30-33]
No IP options - [14-14]
----- TCP Header ----- - [34-53]
Source port = 4110 (Unassigned) - [34-35]
Destination port = 80 (www-http (World Wide Web HTTP)) - [36-37]
Sequence number = 3895578464 - [38-41]
Acknowledgement number = 1124946225 - [42-45]
Header length = 20 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 018h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.1 .... = Acknowledgement - {46-47}
0000 00.. 1... = Push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..0. = No SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 17520 - [48-49]
Checksum = FA0Fh - [50-51]
Urgent pointer = 0 - [52-53]
No TCP options
----- HTTP Client Request ----- - [54-743]
[690 byte(s) of data]
GET /bbs/FORUM.asp?FORUM_ID=55&CAT_ID=7&Forum_Title=ASP%C2%DB%CC%B3 HTTP/1.0 - [54-129]
Accept: */* - [132-142]
Referer: http://wwh/bbs/topic.asp?TOPIC_ID=305&FORUM_ID=55&CAT_ID=7&Topic_Title=%CB%F9%D3%D0%B5% ... - [145-288]
Accept-Language: zh-cn - [291-312]
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) - [315-376]
Host: wwh - [379-387]
Pragma: no-cache - [390-405]
Cookie: Snitz00User=Cookies=&Pword=cc&Name=cceye; ASPSESSIONIDGGGGQMEK=HDJJLABCNOIGOCFCGHMMHJPG; ... - [408-715]
Connection: Keep-Alive - [718-739]
看来并没有使用添冲,而是全部发送。本来嘛,这个mss就是最大的传输字段,并没有限制是多少。
在这里试图截断连接 我尽量不去纪录状态,因为可能涉及到的数据量很大。我要从任何一个包里得到全部的信息
从这里看我不可能得到mss 因为mss 仅仅在数据连接状态的时候才出现,然后各自就纪录到各自的TCP连接状态中了
那么在初始握手阶段有没有用呢? 还是不要叉开话题了,现在是如何发送RST给这个数据包的目的Ip
好吧 mss 和window 由什么关系吗?
看到 17520 是 mss 的12 倍
而在 server 端接受到 client发送的 690字节的请求以后他的window 就变成了 16830(16830+690正好是 17520)
但是 client 尽管接受了很多字节 它的window 的值还是没有改变。
在数据截获的时候很难区分那一段在使用什么规则,而且各个操作系统实现起来不一样。
还与握手阶段有很大关系。目的IP 的下下一个 seq 是多少就判断不出了。
但是有了下一个 seq 就可以了
"那反过来如何告诉目的Ip要rst这个连接呢?
我们需要知道目的ip下一次将要发送的ACK 和 SEQ
首先 SEQ 应该 SELF.LASTSEQ+SELF.LAST.LEN
同时在接受到 之后的第一个 SEQ = 对方LASTACK
我们在这里可以知道它的目的ip返还的tcp 的 SEQ 一定是 这次截获的数据的ACK 了
那么它的下下一个SEQ 有可能是 SEQ + ??"
它的下一个ACK 应该是多少呢?
应该是我的这次数据包的 seq + seq.len
那么现在可以确定这个数据包的目的Ip在接受到这个数据包之后的操作了
seq=this.ack
ack=this.seq+this.len
根据前面的发送RST 的要求发送
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
发送给目的主机
seq=0
ack=this.ack+0(因为首先会返回一个回应,但是如果它使用 PUSH就没有办法知道它的可能的数值了)
}
哦因为没有ack 所以根本不可能有下一次的ack因为他还没有发送 syn 呢.所以
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
}
好了,现在只不过是确定了要RST 目的IP 将来的数据段,如果我的RST包在他还没有。来得及发送回应就发出去了,应该是没有什么效果的,
因为本身的状态还没有更新,自然也就无可RST嘛。
如果能RST他接收到的数据包就好了,状态就好了。
这要求我知道它的上一次的数据包的 seq 和 ack
好,我们来再玩一次游戏
根据上面推出的结果
可得到
seq=last.ack
ack=last.seq+last.len
推出 last.ack=this.seq
last.seq=this.ack-last.len
我可能知道上一次的len 吗?不可能
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
seq=this.seq
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
发送给目的主机
seq=0
ack=this.ack
ctl=rst ack
}
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
}
现在经过实验上面的逻辑可使连接断开,但是一旦停止运行,其连接自动又恢复了,
对于某些连接比如 http来说,是不可会恢复的。
但是对于比如象 netant 这样的 自动重新尝试的连接,就不行了。
现在实验这样断开逻辑
if(ack)
{
发送给源主机
seq=this.ack
ack=0
ctl=rst
发送给目的主机
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
seq=this.seq
ack=0
ctl=rst
}
else
{
发送给源主机
seq=0
ack=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ctl=rst ack
发送给目的主机
seq=0
ack=this.ack
ctl=rst ack
}
没有问题,发现很容易切断连接,于是实验把ack 的值更改看看能不能断开,发现还是可以。
于是启动sniffer 观察断开之后的情形。
从开始可看出不断的请求连接被断开的情形。
----- TCP Header ----- - [34-61]
Source port = 1632 (pammratc (PAMMRATC)) - [34-35]
Destination port = 1021 (Unassigned) - [36-37]
Sequence number = 1035563504 - [38-41]
Acknowledgement number = 0 - [42-45]
Header length = 28 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 002h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.0 .... = No acknowledgement - {46-47}
0000 00.. 0... = No push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..1. = SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 16384 - [48-49]
Version = 4 - {14-14}
Header length = 20 bytes - {14-14}
Type of service = 00h - [15-15]
000. .... = priority 0: routine - {15-15}
...0 .... = normal delay - {15-15}
.... 0... = normal throughput - {15-15}
.... .0.. = normal reliability - {15-15}
.... ..0. = normal monetary cost - {15-15}
.... ...0 = Reserved bit, for future usage, which has to be 0 - {15-15}
Total length = 40 bytes - [16-17]
Identification = 23561 - [18-19]
Flags = 0h - {20-20}
0... .... = must be 0 - {20-20}
.0.. .... = may fragment - {20-20}
..0. .... = last fragment - {20-20}
Fragment offset = 0 bytes - {20-21}
Time to live = 44 seconds/hops - [22-22]
Protocol = 6 (TCP [Transmission Control Protocol]) - [23-23]
Header checksum = 8956h - [24-25]
Source address = [202.113.29.123] - [26-29]
Destination address = [192.168.0.220] - [30-33]
No IP options - [14-14]
----- TCP Header ----- - [34-53]
Source port = 1021 (Unassigned) - [34-35]
Destination port = 1632 (pammratc (PAMMRATC)) - [36-37]
Sequence number = 0 - [38-41]
Acknowledgement number = 1035563505 - [42-45]
Header length = 20 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 014h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.1 .... = Acknowledgement - {46-47}
0000 00.. 0... = No push - {46-47}
0000 00.. .1.. = Reset - {46-47}
0000 00.. ..0. = No SYN - {46-47}
下面我们来看已经建立的连接如何被打断的
看到netant 开始建立syn 请求握手了,
受到了相应之后,netant 开动了5个 syn 同时请求握手(这算不算是syn flood )
都受到了相应了,现在他们开始亲密而默锲的交谈了。好了,现在开始找我的RST
这里看到
202.204.24.12 --> 192.168.0.220 seq 4193832849 ack 179135224
192.168.0.220_--> 202.204.24.12 seq 179135224 ack 4193837229
这里的 ack 是上一次的 seq + 4380而上一起实际传输的数据是 1460, 因此可知这里使用了慢启动算法和滑动窗口
这里的 window 是 17520 看来tcpkill.c 中使用
tcp->th_seq = htonl(ack + (i * win)); 是有道理的。
这个时候我的RST 出现了 seq 为 4193832849 和 4193834309
的阻断包。这个是来自
规则:
seq=this.seq+this.len(如果这个数据包有 syn 的话,则应该再加1)
ack=0
ctl=rst
seq=this.seq
ack=0
ctl=rst
为了测试效果,我把发往源主机的阻断包都关闭了。
下面我看看这两台主机互相又 发送了什么
202.204.24.12 --> 192.168.0.220 seq 4131598001 1774271156
在此之后没有出现任何 seq 在4193832849之后的 TCp数据,因此可以肯定,此RST 已经成功了.
----- Packet Details -----
----- General Information -----
Item number 10, position in dumpfile 2%
Item type: Partial frame, 744 bytes available
Frame size is 744 (2E8x) bytes
Timestamp: 11h:41m:42s:777667us
----- Ethernet v.2.0 MAC Header ----- [0-13]
Destination = Computer 00E04C-482B51 (Universal; Vendor: ???) - [0-13]
Source = Computer 00E04C-3C04D8 (Universal; Vendor: ???) - [6-11]
Ethertype = 0800h (DOD Internet Protocol (IP) Xerox) - [12-13]
----- IPv4 Header ----- [14-33]
Version = 4 - {14-14}
Header length = 20 bytes - {14-14}
Type of service = 00h - [15-15]
000. .... = priority 0: routine - {15-15}
...0 .... = normal delay - {15-15}
.... 0... = normal throughput - {15-15}
.... .0.. = normal reliability - {15-15}
.... ..0. = normal monetary cost - {15-15}
.... ...0 = Reserved bit, for future usage, which has to be 0 - {15-15}
Total length = 730 bytes - [16-17]
Identification = 35859 - [18-19]
Flags = 4h - {20-20}
0... .... = must be 0 - {20-20}
.1.. .... = do not fragment - {20-20}
..0. .... = last fragment - {20-20}
Fragment offset = 0 bytes - {20-21}
Time to live = 128 seconds/hops - [22-22]
Protocol = 6 (TCP [Transmission Control Protocol]) - [23-23]
Header checksum = E9DCh - [24-25]
Source address = [192.168.0.1] - [26-29]
Destination address = [192.168.0.220] - [30-33]
No IP options - [14-14]
----- TCP Header ----- - [34-53]
Source port = 4110 (Unassigned) - [34-35]
Destination port = 80 (www-http (World Wide Web HTTP)) - [36-37]
Sequence number = 3895578464 - [38-41]
Acknowledgement number = 1124946225 - [42-45]
Header length = 20 bytes - {46-46}
6 Reserved bits & 6 bits Flags = 018h - {46-47}
0000 00.. .... = 6 Reserved bits, for future usage, which have to be 0 - {46-47}
0000 000. .... = No urgent pointer - [46-47]
0000 00.1 .... = Acknowledgement - {46-47}
0000 00.. 1... = Push - {46-47}
0000 00.. .0.. = No reset - {46-47}
0000 00.. ..0. = No SYN - {46-47}
0000 00.. ...0 = No FIN - {46-47}
Window = 17520 - [48-49]
Checksum = FA0Fh - [50-51]
Urgent pointer = 0 - [52-53]
No TCP options
----- HTTP Client Request ----- - [54-743]
[690 byte(s) of data]
GET /bbs/FORUM.asp?FORUM_ID=55&CAT_ID=7&Forum_Title=ASP%C2%DB%CC%B3 HTTP/1.0 - [54-129]
Accept: */* - [132-142]
Referer: http://wwh/bbs/topic.asp?TOPIC_ID=305&FORUM_ID=55&CAT_ID=7&Topic_Title=%CB%F9%D3%D0%B5% ... - [145-288]
Accept-Language: zh-cn - [291-312]
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) - [315-376]
Host: wwh - [379-387]
Pragma: no-cache - [390-405]
Cookie: Snitz00User=Cookies=&Pword=cc&Name=cceye; ASPSESSIONIDGGGGQMEK=HDJJLABCNOIGOCFCGHMMHJPG; ... - [408-715]
Connection: Keep-Alive - [718-739]
2. If the connection is in any non-synchronized state (LISTEN,
SYN-SENT, SYN-RECEIVED), and the incoming segment acknowledges
something not yet sent (the segment carries an unacceptable ACK), or
if an incoming segment has a security level or compartment which
does not exactly match the level and compartment requested for the
connection, a reset is sent.
当一个非同步的连接存在的时候,而且进入的数据段可能还没有相应的字段发出的时候
也有可能是对方的数据段要求的安全等级并不能被接受的时候,会发送RST.
If our SYN has not been acknowledged and the precedence level of the
incoming segment is higher than the precedence level requested then
either raise the local precedence level (if allowed by the user and
the system) or send a reset; or if the precedence level of the
incoming segment is lower than the precedence level requested then
continue as if the precedence matched exactly (if the remote TCP
cannot raise the precedence level to match ours this will be
detected in the next segment it sends, and the connection will be
terminated then). If our SYN has been acknowledged (perhaps in this
incoming segment) the precedence level of the incoming segment must
match the local precedence level exactly, if it does not a reset
must be sent.
If the incoming segment has an ACK field, the reset takes its
sequence number from the ACK field of the segment, otherwise the
reset has sequence number zero and the ACK field is set to the sum
of the sequence number and segment length of the incoming segment.
The connection remains in the same state.
3. If the connection is in a synchronized state (ESTABLISHED,
FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK, TIME-WAIT),
any unacceptable segment (out of window sequence number or
unacceptible acknowledgment number) must elicit only an empty
acknowledgment segment containing the current send-sequence number
and an acknowledgment indicating the next sequence number expected
to be received, and the connection remains in the same state.
If an incoming segment has a security level, or compartment, or
precedence which does not exactly match the level, and compartment,
and precedence requested for the connection,a reset is sent and
connection goes to the CLOSED state. The reset takes its sequence
number from the ACK field of the incoming segment.
Reset Processing
In all states except SYN-SENT, all reset (RST) segments are validated
by checking their SEQ-fields. A reset is valid if its sequence number
is in the window. In the SYN-SENT state (a RST received in response
to an initial SYN), the RST is acceptable if the ACK field
acknowledges the SYN.
除了syn 的情况,所有的 RST会被根据 seq 的数值检验是否合法,如果seq 的数值在 window 的内部的话,将被看作是合法的
如果是在 syn 阶段的话则 这个RST 的 ACK 将是对方的SYN
The receiver of a RST first validates it, then changes state. If the
receiver was in the LISTEN state, it ignores it. If the receiver was
in SYN-RECEIVED state and had previously been in the LISTEN state,
then the receiver returns to the LISTEN state, otherwise the receiver
aborts the connection and goes to the CLOSED state. If the receiver
was in any other state, it aborts the connection and advises the user
and goes to the CLOSED state.
如果一个RST 被收到的话,首先验证他,然后改变状态,如果这个接受方是在listen的状态的话,
将会忽略这个RST.
如果这个接受方是在刚刚从listen阶段转到 SYN阶段,那么这个listen 将会转到listen 状态
其他的情况,这个接受方将会断开连接,并转向closed 状态.
资料整理:编程先锋 http://wlbookwl.myrice.com 站长:小黑侠