Here is the slide of my talk on Security Bsides Delaware 2017.
DDoS Types
网上DDoS攻击类型的说明七零八落,没有一个成体系的类型划分。DDoS攻击,目的都是毁掉“可用性”,那第一考量维度应该就是毁掉的“可用性资源”是什么。其次,攻击发起的位置,也就是协议层次,很重要,这决定了,我们在什么样的位置可以更好的发现对应类型的攻击。任何一个DDoS攻击,一定要能说明白这两个问题,才能说“看到了”这个攻击。
因此,做个表格,从如下两个维度来给常见的DDoS一个合适的位置
- 协议层次: 各种不同网络层级的不同协议
- 耗费的资源: 带宽,CPU,还是连接,甚或是特定应用的特定弱点?
LayerProto \ Resources | Bindwidth | CPU | Session/Connection | Application Specified Weakness |
---|---|---|---|---|
GRE | GRE_Flood | GRE_Flood | ||
ICMP | Ping_Flood; Smurf_Attack | Ping_of_Death | ||
UDP | AMP_Flood; UDP_Plain; Fraggle_Attack | UDP_Plain; Small_Package_Flood | ||
TCP | SYN_Flood; ACK_Flood | ACK_Flood | SYN_Flood; Slow_Read_Attack; | Teardrop_Attack |
DNS | DNS_Flood; RSD_Attack | DNS_Flood; RSD_Attack | ||
HTTP | CC_Flood; SSL_Flood | Slowloris; RUDY | CC_Flood; SSL_Flood | |
VoIP | INVITE_of_Death |
一句话注释:
- AMP_Flood: 反射放大,DNS/NTP/CharGen等等,伪造源IP为受害者IP,发送请求流量到反射节点,响应流量就涌向受害者IP,响应包大小远大于请求包大小,是为“放大”
- SYN_Flood: 半连接状态,受害者协议栈需要保存大量状态信息,同时,很多会带有payload,顺道消耗带宽
- UDP_Plain: 大量UDP包瞬间发往目的IP,阻塞目的链路,包一般很大,当前存在两组攻击者,一组喜欢填充500字节左右,一组喜欢填充1k以上,也有超过1500的,会导致产生0端口Fregment碎片
- Small_Package_Flood: 类似UDP_Plain, 不过包一般很小,基本都在50字节以下
- ACK_Flood: TCP版本的UDP_Plain, 包大小分布非常相似,但是,除了耗费带宽外,还耗费TCP协议栈针对ack包的的查表操作
- DNS_Flood: 伪造大量DNS请求包,发送给DNS cache 服务器或者DNS权威,以期拖垮DNS服务
- RSD_Attack: 目的类似DNS_Flood,不过攻击手法是伪造大量随机子域名,响应都是NXDOMAIN,因此就算请求到cache服务器,也可以穿透cache服务器的TTL,间接攻击到权威服务器
- CC_Flood: HTTP Flood的别称,具有业务针对性,基本都是找受害者的http响应中最耗费性能的那个链接,比如计算密集的,或者数据库查询比较重的,以此来拖垮服务器
- SSL_Flood: SSL协议协商对计算要求较高,因此大量的SSL连接请求,可以直接将SSL接入服务器CPU耗尽
- GRE_Flood: GRE是封包协议,大量GRE包,一方面可以消耗带宽,一方面可以耗费解包CPU资源
- Ping_Flood: 大量的ping,硬干
- Slowloris: 大量HTTP长连接,GET请求但是永远不发送\r\n结束,耗尽服务端连接池
- RUDY: 类似Slowloris, 不过是通过设置一个超大的content-length header来构造一个永不停止的POST请求,进而耗费目标服务的连接池
- Ping_of_Death: ping的畸形包或者超大包,目标系统重组的时候会由overflow引起的crash
- Smurf_Attack: 伪造源IP为要攻击的目标IP,给广播地址发ping,所有的echo就涌向了受害者IP
- Fraggle_Attack: UDP版本的Smurf, 使用UDP的端口7(echo)和端口19(CharGEN)
- Slow_Read_Attack: 和受害者建立长连接,把TCP receive buffer设置的很小,慢慢读,耗费受害者连接池
- Teardrop_Attack: 利用某些操作系统IP碎片重组的bug来使目标系统crash
- INVITE_of_Death: 构造SIP INVITE畸形请求包来使目标系统crash
上面的分类,是站在“看到攻击”的角度。如果站在“防御攻击”的角度,那下一个DDoS攻击精细化的分类维度应该是“攻击路径”: 是脚本直接发包?还是借助proxy?还是借助反射点?还是通过服务穿透?还是利用Bot?确定了攻击路径,才能找到最合适的防御位置。
DDoS检测 - 骨干网与企业安全边界的差异
当前我们在做骨干网的DDoS实时检测,用以积累我们security visibility的能力。
同样是DDoS检测,在大网上来看和在防护安全边界来来,情况差异比较大,总结一下备忘。
数据
检测基于数据,先说数据差异。
数据类型
安全边界,几乎可以做全流量分析,而大网上,可获取的几乎只能是流量摘要数据。因此,安全边界可以做更细致的单包深度检测,或者会话重组找渗透,但是大网只能看统计特征。
Point View vs. Scape View
企业看到针对自己这个点的数据,大网看的是整体。设定两个数量集规模M和N,M比N大2个数量级,安全边界看到的是M:N, 大网看到的是M:M。
因此,大网背景流量大很多,意味着噪音大很多,意味着很多即便是大攻击,但是淹没在更巨大的背景流量下,反而很小了,需要耗费更大的精力来定位分析。
但是大网的大背景流量在某些场景下也有优势,比如企业很难发现或者确认scanner,但是大网上由于自己的Scape View,确认Scanner反而简单。
Full Data vs. Partial Data
企业安全边界对应Full Data很容易理解。大网上,Partial Data有两层含义:
1, 大网上看到针对一个IP的流量,只能是整体数据的一部分:很多我们采集点之外的数据我们是看不到的,更多大网采集点层级之下的数据我们也是看不到的
2,是进出数据的一边:在大网骨干路由上,来去的流量不一定是经过同一个地方,因此大网上某个点常常会看到单向流量
由于DDoS攻击流量基本上是全网窜,因此1带来的困难只是检测精细化的工程难度,2带来的更难处理,因为单向流量直接影响到了判定,看到一个IP只接受RST包,怎么确定这是RST Flood还是它是被Spoofed IP来SYN_ACK Flood攻击别人呢?
业务
Manage Object/管理对象/资源/业务对象
企业都会有自己的资源/业务梳理,大网是没有的,我们当前可用的只有PDNS带给我们的domain-IP的映射关系,但是由于有CDN的存在,这个也存在部分问题。
Baseline
企业既然可以梳理出MO,那也就可以根据MO来确定一个baseline,流量大小的也好,访问态势的也好,总有能力刻画一个常态的profile,但是大网监控,第一不可能有一个可梳理的baselien,第二,大网上异常太多,业务故障/业务调整/网络异常/攻击等等情况时刻都在发生,就算有baseline,那超出baseline部分的异常,仍旧是多到难以处理,所以有了baseline也要丢掉,直接去看数据中的强特征更靠谱。
目标
看到 vs. 防住
企业安全防护,工作的衡量标准就是自己保护对象的可用性,当攻击发生时能不能防住。
既然以保护对象的可用性作为最终衡量标准,那基本上都是抓大放小,告警基线可以根据自己资源能力来调整一个比较高的阈值,小攻击,探测性的攻击,能忽略就忽略,毕竟这些事情的处理也是要耗费安全运营的资源,大到可能影响业务的攻击一旦发生,那势必立即响应,以求安全。
我们做大网上的监控,更多的是想“看到”,大小都想看到。而且,更普遍的情况是,我们看到的小,只是因为我们的数据不全,只是在我们可见的范围内小,而实际攻击并不小。因此,我们看攻击没有“大小”的区别,只有“看到和看不到”的区别,我们要尽可能的“全看到”。
于此带来的一个最典型的工程处理方法上的区别就是,安全边界的TopN更重要,而大网监控的SpikeRate更重要,TopN突出的是当前面对的最大的是谁,SpikeRate表达的是变化最大的是谁。
大数据,机器学习,网络安全
一些阶段性的看法:
- 大数据,大在两个方面: 数量 和 维度
- 单单数量大,不算真正的大数据,数据简单,特征简单,量的问题可以通过硬件资源的堆叠和各种优化算法的提升来解决
- 维度的爆炸,带来的问题是数据特征难以被人把握,特定数据对应的特征的组合更隐蔽,更难以被人发现,需要更深入的专家知识和经验
- 机器学习是为了应对维度的爆炸,顺带要搞定数据量的大,单单因为数据量大就上机器学习是错误的
- 机器学习是黑箱,只能告诉我们是什么,而不能告知为什么,网络安全是非黑即白,必须要有为什么,有天然的矛盾存在
- 情况0: 机器学习学习正常,作为数据过滤通道,而不是异常检测方式
- 情况1: 机器学习解决大数据中初筛的功能,作为前置探测存在,产出各种可疑数据,但不是结果数据,后续还是有专家验证
- 情况2:机器学习只作用在特定场景,产出有专家验证的可控的漏报误报,直接产出最终结果
- 对信息安全行业整体而言,当前的壁垒还没到大数据,信息采集监控还没做好,基础做的差的很远,机器学习PR需求强于实际需求
- 对信息安全特定方向而言,机器学习已经开始发挥作用
- 机器学习应用到网络安全大数据的关键点: 去噪 & 可验证。去噪好坏体现工程难度,决定后续工程难度,决定最终产出;验证是落地的必须环节。没法去噪,可以小步試错;没法验证,不要做
- 机器学习,一方面解决的是人对大数据的无力,另一方面解决的是专家的知识壁垒。有些行业的专家要小心了
crontab notes
为了监控系统,在crontab里设置了几条命令,自己测试怎么都好使,但是放在crontab里就是不执行。
查看/var/log/cron可以看到执行记录,但是结果不是期望的,都要怀疑操作系统了。请教了一个运维老司机,原来知道是环境变量的原因。
我的监控命令用到了一个lsof,手动执行ok,但是crontab里面执行的时候是找不到的,需要设置PATH或者使用绝对路径。
搜索“cron 环境变量 坑爹”有好多结果,我就不重复了。
另外一个需要注意的是,crontab执行命令会默认将执行输出发用户邮箱,日积月累邮箱也会爆,所以命令一定记得 >/dev/null 2>&1 重定向。
c++ 通过 frind 来获取一个类的 private 成员变量
有个朋友问到一个给定的不可变的类,且是安装好的三方库,不能改代码,不能重新编译,想获取其私有变量,有什么方法?
答案是友元~
lib头文件 t.h
lib代码 t.cc
上面两个文件编译为libt。注意这时候上面friend是屏蔽掉的,因为我们假定原始给定的头文件没有友元。
我们自己的测试代码m.cc
此时如果不把上述friend行打开,直接编译会报错:
这是符合预期的,因为就是要测试friend行代码的效用嘛~打开后就能正常编译执行。
我的测试环境是mac+clang,如果是linux+g++,最后编译可执行文件时需要增加运行期lib查找路径 -Wl,-rpath=./
总结:
- class的private/protected权限是编译期的行为,提供的是编译期的内存获取权限的检查,编译完成后就没有任何约束了
- 因此,我们想要获取一个给定对象的私有变量,是我们自己代码编译时期的权限检查,只要保证自己代码编译时有friend来放开权限即可
如果给定一个类,对于其私有成员变量,直接get有时候可以理解,绝不要直接set,在不知道原本class实现的前提下,极有可能会破坏其内部实现的逻辑
劫持tshark使其更方便的和我们自有系统交互
劫持tshark解包接口
wireshark是一款伟大的工具,tshark是wireshark的命令行工具,具有丰富的功能。
但是tshark只能将数据包抓取解析并按照既定格式打印出来,没办法做更自由的数据格式,比如把特定数据形成Porotobuf格式,也没法对外交互,比如发送到某个socket等。
So,let‘s make it.
简单说一下环境:
- Centos6
- wireshark-1.10.8 源码
要劫持接口,那就追代码,hark源码的结构可以在其他地方找到更详细的剖析,我们只需要知道以下几个点:
- 各种协议包的解析在wireshark-1.10.8/epan/dissectors/ 下面
- 根据协议解包是个顺序的调用的过程,比如epan/dissectors/packet-ip.c中解析完IP协议,然后调用epan/dissectors/packet-udp.c来解析UDP协议,依次往后,直至没有新协议数据需要解析为止
- 协议包数据解析完是一个proto_tree结构,这棵树的添加构造在epan/proto.c中,上面的dissector都会掉用proto.c中的方法来将解析出来的数据添加到树中
- 注意一个header_field_info结构,内部成员name是展示的名字, abbrev是解析包过程中用到的过滤名字,比如ip.src udp.dstport等,还有一个type标识对应的value应该是什么数据
- proto.c设置数据的时候,会调用5个基本类型的数据设置方法 fvalue_set fvalue_set_sinteger fvalue_set_uinteger fvalue_set_integer64 fvalue_set_floating,代码在epan/ftypes/ftypes.c
数据流收缩的最小的口径就是在ftypes.c中,从这里入手才能最小代码的改动来劫持到所有数据。但是这里的函数获取到的只有value,而我们需要key和value都能一一对应上,因此还需要在调用者proto.c上动点手脚。
方法1
- 创建如下文件shark_hijack.h
|
|
- 将上述文件放在epan/ftypes/文件夹下,然后在epan/proto.c原文件最后一行include之后添加,如下行
|
|
- 这样,将原始的5个设置方法以宏的形式替换,在原始操作之后,调用hijack_call,将整个field_info指针传递过去,这里我们就能获取到name abbrev value,就可以根据自己的需求做些想做的事情了。这样的完整的样例可以在 https://github.com/xuy1202/xylibs/tree/master/tshark_wrap 看到
方法2
上面的方法最简单,但是需要在hijack_call中做类型判断,我们可以将修改面扩大一点,但是整体上更简单
- 将上述shark_hijack.h修改为如下,还是用宏劫持的方式
|
|
- 原始的fvalue_set等5个函数返回类型为void,我们要修改为接受value的类型,并将valuereturn出来,比如修改fvalue_set为如下
|
|
这样,我们就将value直接分类型转给了我们自己声明的shark_id_dispatch_string等5个方法, 我们可以在另外一个动态库中实现这5个方法,然后修改Makefile链接起来,这样以后只需要修改我们自己的so就能达到修改逻辑的目的
tricky的地方注意到了么,我们没有name,没有abbrev,而只有一个fi->hfinfo->id。这个id其实是thark编译的时候根据各个解包器生成的固定的id,如果在proto.c的proto_register_field_init函数return之前添加一行
|
|
编译执行开始,总能看到id和abbrev的固定映射关系,比如:
|
|
因此,这样的映射表只需要知道,然后就完全可以根据id来做自己的逻辑了。
Wish you happy, go nuts!
hexo+next主题的markdown示范样例备忘
|
|
这篇blog没有干货,所以一上来就得有点趣味
|
|
|
|
!!!: hexo tag doc
Do not just seek happiness for yourself. Seek happiness for all. Through kindness. Through mercy.
Every interaction is both precious and an opportunity to delight.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque hendrerit lacus ut purus iaculis feugiat. Sed nec tempor elit, quis aliquam neque. Curabitur sed diam eget dolor fermentum semper at eu lorem.
Head1
This is an H2
Head2
sub title
sub title
This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
default
primary
success
info
warning
danger
|
|