F5售后服务“一点通”专栏,是由F5售后工程师主笔,收集和总结客户在实际工作中遇到的常见多发性问题,汇编成小技巧和知认点,通过F5官方号定期进行分享,希望有相同问题的客户从中得到解决问题的指导。“一点通”栏目的口号是“一点就通,痛并快乐的学习并解决问题!”。
武斌
F5 ENE | SIRT安全事件响应团队成员
2011年加入F5售后技术团队,从事通信和安全领域工作超过十年。F5 安全事件应急响应团队(SIRT)成员。获得安全领域OSCP (OffensiveSecurity Certified Professiona)和 GCIH (GIACCertified Incident Handler |)证书。
F5 的众多产品可以提供丰富多样的应用层服务, 在客户的使用环境中由于业务的多样性,所面临的问题也是多种多样的。 这也给问题复现带来了很多的困难, 因为我们处理的可能是从1层到7层任何一个层面的问题。 这里总结了一些F5产品问题在数据包问题相关问题复现的方法和工具,希望可以对代理商和客户在定位问题的过程中有所帮助。问题复现的黄金法则
在复现问题的时候, 最理想的情况一定是用同样的硬件平台, 软件版本,配置,业务环节和同样的测试步骤来复现问题。 这样应该是最容易复现问题的。但是实际情况中可能很难实现所有都一样。 但是至少我们应该在问题出发条件不明朗的时候尽量保证相似的环境。
UCS安装
在我们的工作中, 经常需要安装客户的ucs来尽量保证同样的配置。 但是客户的配置并不是一定能很顺利的安装到另外一个设备上。比如因为没有客户的master key,从而各种加密的密码无法解开。 这里总结一下小技巧:
1. 解压ucs命令: tar zxvfcustomer.ucs
2. 在解压后的config目录中可以删除掉bigip_user.conf中root和admin账户的加密行,之后loaducs的时候相当于重置了root和admin的密码(default和admin)
3. 最好修改bigip_base.conf 中的管理ip, 以免在loaducs后因为管理ip改变丢失ssh连接
4. 因为没有master key 可以删除掉所有配置里面加密的密码,ssl profile 的passphrase部分可以删除掉cert, key, passphrase来使用默认的证书
5. 在修改完成后可以用命令(tar cvf - * | gzip -c > /var/local/ucs/repro.ucs)来把修改后的文件打包成ucs文件尝试load。
6. 如果load不成功, 可以根据报错信息在/config目录中继续修改然后 tmsh load sys config,无需修改原来的ucs文件
NC工具介绍
NC 由于可以方便的建立tcp或udp的连接, 发送各种数据,非常合适用于发送流量来复现7层的问题。如下的列子可以在pcap文件中选定相应的数据包的payload 部分,分别存储, 然后用nc同时模拟client 和 server,来达到发送和抓取的数据包一致的效果
Reading from and writing to network connections(using clear text):
1)Copy the request from packetcapture(.pcap) and save it in text format on a client machine. i.e. request.out
2)Copy the response from packetcapture(.pcap) and save it in text format on a server machine. i.e. response.out
Server – listen on tcp port 8085:
[root@ws2tmp]# nc -k -l 196.168.1.100 8085 <response.out
Client – connect to vs:
[root@centos-client1 tmp]#nc192.168.1.25 8085 <request.out
HTTP/1.1 200 OK
Date: Sat, 11 Apr 2015 10:59:15 GMT
Server: Apache/2.2.3 (Red Hat)
Last-Modified: Tue, 10 Feb 2015 12:28:08GMT
ETag: "38014-73-4ef0600"
Accept-Ranges: bytes
Content-Length: 115
Connection: close
Content-Type: text/html; charset=UTF-8
<<<<<snipped>>>>>
也可以和其他命令结合比如复制16进制码流然后通过16进制转ascii然后nc发送。比如
echo -en
f70726ffc2ef312e310d0a486f73743ae2e66352e636f6d0d0ad436f6e74726f6c3a206e6f2dd0ade743adc69656e740d0a436f6e6ef6e3a20436c6f73650d0a0d0a|xxd-r -p |nc 127.0.0.1 80
Hping3 工具Hping3 可以发送tcp,udp,icmp, 而且还可以设置其中的标志位, 对于简单的4层问题是非常好的工具。比如常见的synflood命令
root@centos-client1 tmp]# hping3 -S192.168.1.25 -p 80 -s 1025 –flood
部分其他参数我们还可以拓展来完成一些复杂的工作, 比如下面用三个命令发送ip分片的包
[root@centos-client1 tmp]# hping3192.168.1.25 --file fragment1.bin -p 1812 -s 1024 --ipproto 17 -d 104 -c 1 -0--morefrag --id 17; hping3 192.168.1.25 --file fragment2.bin -p 1812 -s 1024--ipproto 17 -d 1376 -c 1 -0 --morefrag --fragoff 104 --id 17; hping3192.168.1.25 --file fragment3.bin -p 1812 -s 1024 --ipproto 17 -d 359 -c 1 -0--fragoff 1480 --id 17
Scapy介绍Scapy是python的一个库,支持发送任意数据包。 通过python的编程可以实现任何想要模仿的通信工程, 从2层到7层。 一些有用的介绍文档如下:
http://www.secdev.org/projects/scapy/doc/usage.html
https://theitgeekchronicles.files.wordpress.com/2012/05/scapyguide1.pdf
简单实例send() 功能发送3层数据包,让当前系统来根据当前的路由环境选择interface发送.
sendp() 是2层发送功能,可以指定发送的interface,mac地址.
在上面的例子中向10.238.2.67 发送了payload为 “icmp test”的icmp包
刚接触的时候最大的困难可能是不知道怎么各个标记位应该如何定义。 其实scapy提供了简单的方法,可以通过读取现有的pcap文件, 将指定的数据包转成命令, 方便我们参考和修改
pkts = rdpcap("lab_ipsec.pcap")--- 读取文件
pkts.show() --- 显示数据包
pkts[2].command() --- 将其中一个数据包转成命令
交互式脚本举例:在下面的脚本中模拟了clienttcp三次握手, 在三次握手的最后一个ack中, client置位ack和push并且发送了data。 在实际环境中很难用真实的应用程序控制第4层。 但是用scapy就很容易做到。 (注意: scapy模拟的连接在linux的内核中是不存在的, 所以在类似的脚本使用中需要用iptables命令比如(iptables -A INPUT -p tcp -s172.24.111.174 -j DROP) 将相关的数据包在进入内核之前过滤掉,否则linux内核会发送reset导致连接中断。 Scapy会在iptable之前接受到数据包,所以iptables对scapy没有影响)
#!/usr/bin/python
import sys
from scapy.all import *
source="172.24.111.180"
dest="172.24.111.174"
destport=443
seq_nr=random.randint(,)
source_port=random.randint(1025,64000)
#build the IP layer
ip = IP(src=source,dst=dest)
#build the TCP layer, then send SYN andreceive SYN/ACK
tcp =TCP(sport=source_port,dport=destport,flags="S",seq=seq_nr)
synack = sr1( ip / tcp )
#update the TCP layer, then send FIN/ACK
my_ack = synack.seq + 1
tcp =TCP(sport=source_port,dport=destport,flags="AP",seq=seq_nr+1,ack=my_ack)/Raw(load=\x16\x03\x01\x00\xa8\x01\x00\x00\xa4\x03\x03\x83\x0d\xdc\xd6\x63\x05\xa7\x07\x81\xcd\x33\x3b\x08\x25\x21\x77\xd2\x54\x4d\x72\x66\xe7\x90\xd8\x0a\x2f\x0e\xc5\x75\x80\x75\xd9\x00\x00\x1a\xc0\x2b\xc0\x2f\xcc\xa9\xcc\xa8\xc0\x0a\xc0\x09\xc0\x13\xc0\x14\x00\x33\x00\x39\x00\x2f\x00\x35\x00\x0a\x01\x00\x00\x61\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\x0a\x00\x08\x00\x06\x00\x17\x00\x18\x00\x19\x00\x0b\x00\x02\x01\x00\x00\x23\x00\x00\x33\x74\x00\x00\x00\x10\x00\x17\x00\x15\x02\x68\x32\x08\x73\x70\x64\x79\x2f\x33\x2e\x31\x08\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x0d\x00\x16\x00\x14\x04\x01\x05\x01\x06\x01\x02\x01\x04\x03\x05\x03\x06\x03\x02\x03\x04\x02\x02\x02)
send ( ip / tcp )
print ("Sent last ACK")
http client toolscurl是常见的命令, 举例常见用法
curl 172.24.111.100 –c cookie –b cookie ---- save cookie and load cookie
curl 172.24.111.100 –L ---- follow redirect
curl 172.24.111.100 –d <data><@filename> ---- post data
浏览器在开启了调试模式之后, 支持在network 菜单下面直接转化http请求为curl命令,方便用curl命令发送同样的请求
ab 命令可以并发http请求,比如 ab: ab -n 100 -c10 http://172.24.111.172/
Burp SuitBurp suit 是有名的代理软件, 通过将浏览器设置代理直到burp suit 后可以通过burp suit 重放, 修改, 爬虫, 爆破等等功能。用法非常丰富, 不在这里详细讨论。
Key features are
Proxy interception
Repeater
Scanner
Spider
Intruder
Iptables
Iptables 防火墙在问题复现的过程中可以帮我们模拟丢包的情况。 比如丢弃掉特定标记位,长度的包,比如
iptables -A INPUT -p tcp -s 11.0.0.150--tcp-flags ALL PSH,ACK -j DROP -- 丢弃psh,ack同时置位的包
iptables -A FORWARD -p tcp --syn -m limit--limit 1/s -j ACCEPT--- 每秒forward一个syn包
DNS工具
1. Dnsperf是dns性能测试工具用了发送大量的dns请求。
2. Dnschef可以用了当做dns server 来回复dns请求, 比如如下一条命令可以返回一条假的A记录。
模拟http服务器
如果问题是和客户的server应用层数据有关系的, 那么拥有和客户一样的服务器显然是最理想的测试条件。但是常常是不可能实现的。 模拟http服务器, 可以让客户用fiddler抓取流量然后用fiddler的重放功能模拟服务器。
如果有pcap文件,我自己写了一个脚本可以从pcap文件中读取request和response,然后模拟一个http serve,客户端可以通过浏览器看到和数据包中一样的页面内容
https://github.com/ufo009e/pcap-http-replay-
Python
Python简单灵活,可以方便的帮我们实现数据的发送。 下面的例子个有一个client端和server端, 利用socket库模拟了client和server的通信
服务器脚本#!/usr/bin/python
import os
import sys
import time
import socket
import threading
response = "server data"
server = socket.socket()
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEPORT, 1)
server.bind((0.0.0.0, 50001))
server.listen(32)
def handler():
while True:
client, clientaddr =server.accept()
while 1:
request =client.recv(4096)
print request
client.send(response)
client.close()
thread.exit()
threads = []
for i in range(0, 100):
thread = threading.Thread(target=handler, args=())
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
Client脚本#!/usr/bin/python
import socket
HOST=10.154.159.171
PORT=50001
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((HOST,PORT))
for i in range(1,10000):
while 1:
cmd="GET /MakeTransaction.phpHTTP/1.1\r\nHost: 10.154.159.171\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1;Win64; x64; rv:56.0) Gecko/ Firefox/56.0\r\nConnection:keep-alive\r\n\r\n"
s.sendall(cmd)
data=s.recv(1024)
print data
s.close()
更多的工具Kalilinux是渗透测试的工具集, 里面有非常多的工具。 其中有很多可以当做我们复现问题的工具来使用。
关于F5售后服务
最强服务指南!不止365天,我们提供的是20年如一的出色保障