谈谈物理服务器的安全

随着虚拟技术与云计算的火热,越来越多的人将注意力放在了虚拟机与虚拟网络的安全上面。当然确实也是目前一个趋势与发展方向,但虚拟化的安全与物理设备的安全就如同一个天平的两端,过于重视一端就可能遗漏了另一端的问题。今天我想聊聊物理服务器层面的安全问题。

为什么大家容易忽视物理服务器的安全问题?

我认为有以下几个可能的原因:

  • 服务器设备通常放置于相对安全的机房当中,通常在企业防火墙后面
  • 能接触到设备的人员比较有限
  • 对于物理设备上发现的问题通常用户无法解决,或是无法通过安装防御软件来解决
  • 不容易被攻击,毕竟这个时代能攻击到物理设备的方式远没攻击虚拟设备的多

所以用户不关心,运维人员也不关心,厂家也省事。但这样真的没问题了吗?显然不是。俗话说“外贼易防,家贼难防”,假设某个运维人员偷偷的植入了一段BIOS启动代码,可以说市面上所有的安全软件都是无法检测出来的。这也是为什么要有Secure Boot技术,一种在系统的启动阶段进行保护,使得操作系统运行在一个可信的物理环境上的技术。这里只举一个例子来说明物理设备的安全问题,尽管没那么明显但是一般都是非常严重并且难以处理的问题。

物理服务器安全的方方面面

大家都知道服务器有一部分部件与PC相似,如CPU,内存,磁盘,网卡,显卡,风扇等,但还有一部分是特有的,如传感器,PSU,RAID卡,固件芯片等。另外服务器也有一些内嵌的软件模块,如BIOS,BMC以及厂家自己研发的嵌入式软件。所有的这些都可能存在漏洞问题,如内存的Row Hammer漏洞,CPU的S3读取PCH模块脚本未被保护问题等。还有一部分涉及到的是嵌入式软件的问题,通常服务器是需要以24×7的强度来运行的,这对服务器的稳定性提出了很高的要求。因此服务器内有大量的传感器来监视服务器的健康状态,如温度传感器,风扇传感器,PSU传感器等,所以厂家通常会开发一些嵌入式软件来监控这类的设备,这里最出名的莫过于板载控制器(BMC)了,基本上主流两路以上的服务器都会具有BMC。此外还有其他外围的设备如显卡,RAID卡,网卡等板卡设备。在进行更细致的分析前,请大家看一下与服务器安全相关的全景图:


物理服务器安全之硬件部分

对于硬件层面的安全问题主要集中在可信计算方面,建立一个安全可信的运行环境是可信计算的主要目的。TPM安全芯片是目前业界的主流解决方案,也是很多上层安全技术的基础。它解决以下几个问题:

  • 存储,管理秘钥,如BIOS密码,硬盘加密密码等
  • 生成秘钥,使用不同的加密算法来创建
  • 磁盘加密,为上层提供磁盘加密功能,如Windows的Bitlocker
  • 以及其他加解密相关的支持,如生成随机数

TPM本质上是一个安全的协处理器。服务器上CPU众多,为什么还需要一个这样的协处理器呢?加解密工作是一个非常耗CPU的任务,如果你的程序里有进行加解密运算,你一定要警惕它的性能问题。记得早前的一个做信用卡卡号处理的项目,当数据量少时一切正常,一旦数据量大到一定程度,CPU就是100%。当时我们分析了各种原因,有人说是内存太小导致频繁磁盘交换,有人说线程太多,任务切换过于频繁等。最后拿性能剖析工具一查,才知道是加解密模块吃掉了所有CPU计算资源。因此对于服务器来说,尽管CPU很多但是还是需要一个专业干加解密的硬件设备。

说到TPM就不得不提TCG(可信计算组),这是一个由主流设备生产厂商发起的组织,主要的目的是解决当时业界已经面临的个人计算平台安全问题。具体的历史可以查看维基百科,但也不是所有人都认同可信计算的,主要的争论点是采用可信计算方案相当于个人的信息对这些厂家来说是公开的,也就是一个对厂家公开的后门。所以在国内,政府的要求是采用TCM而不是TPM,TCM与TPM功能类似,唯一不同是加密算法是采用国内研究机构开发的。安全嘛,只有自己人才可信:)。

物理服务器安全之嵌入式软件部分

说起来软件程序面临的安全问题基本都很类似,不管是嵌入式软件,应用软件,web系统,你所面临的安全问题大多有以下几种:

  • 加解密算法是否足够安全
  • 网络连接是否安全
  • 数字签名与证书相关的安全
  • 存储是否安全
  • 程序越界问题
  • 注入攻击问题
  • 代码漏洞问题
  • 权限控制问题

BIOS作为现代计算机的基础软件,几十年来地位就没变过。但与它相关的技术倒是发生了一些变化,从早期的汇编,C,EFI到现在的UEFI,从功能角度来说丰富了不少。嵌入式软件终于也可以画出一些相对漂亮的界面来给用户了。也正是由于它比较基础对于它的保护是必不可少的,了解病毒历史的读者可能还记得90年代的CIH病毒,这个病毒影响意义深远。而Secure boot技术的目的就是让BIOS在引导系统启动的时候具备足够安全性。看一下Secure Boot的过程:

由于BIOS程序对外没有网络访问的能力,所以安全问题相对来说简单一些,主要是UEFI的漏洞问题。

而BMC就不一样了,这个功能强大的家伙问题也是最多的。可以这么说物理服务器涉及到的安全问题有一大半是出在BMC身上。你可能会问都有哪些问题?我只能说几乎上面提到的所有问题,因为它就是一个用于处理硬件问题的web应用。BMC有哪些功能,看看这张截图:

它使用一个微型的嵌入式Linux内核,并通常带有一个web栈。BMC对外支持多种协议,如HTTP,IPMI,SNMP,CIM等等。而这里面用的最多的,并且安全性最差的就是IPMI协议了。IPMI协议是一个事实上的服务器管理标准协议,几乎所有的服务器都会支持它(当然有的服务器如果没有BMC,通常也会有AMT技术做替代)。而被广为诟病的是IPMI协议中RAKP使用的SHA1进行秘钥哈希运算问题,这是一个已知的并且广泛存在的问题。我们只能通过禁用IPMI的远程访问来绕过它,但是如果没有远程的能力,对于具有成千上万台服务器的数据中心来说,单单是关机/重启这样简单的操作就是一个恶梦。因此各大厂商采用HTTP协议来替代IPMI的远程访问(有些厂商采用CIM接口,但是CIM的兼容性是很大的问题)。那么引入HTTP就引入了所有HTTP可能遇到的安全问题,如中间人攻击,证书伪造,跨站攻击,脚本注入,DDOS等,安全问题也变得日益严峻。为了解决这些问题,引入HTTPS是最好的方案。在大多数情况下,HTTPS可以避免中间人与证书伪造等问题。说到这里又不得不提OpenSSL,作为业内著名的开源安全库已经有很长的历史了。它是实现SSL的主要模块,也可以说HTTPS实现的基础。但是在最近的一年里OpenSSL接连报出几个大的漏洞问题,如Heart Bleeding,Freak Attack等,给广大厂商和用户带来了很多麻烦。虽然OpenSSL的补丁不断,但是官方已经声明在2015年年底停止对0.9.8分支的支持,2016年底停止对1.0.0和1.0.1分支的支持。这是好事也是坏事,好事是我们不需要再为旧版本漏洞担忧了,而坏事是你不得不为升级库比进行大量测试。

BIOS与BMC是服务器上嵌入式软件的两个主要部分,当然还有其他的如厂商自行研发的部署软件等,还有驱动的问题等不一而足。另外遇到的挑战是通常更新这些补丁需要重启服务器,而对于需要持续运行的服务器来说重启是比较困难的。因此现实的情况是很多服务器都是带着大量的安全漏洞在跑的,幸运的是服务器管理网络与业务网络是物理隔离的,被外部攻击的可能性比较低。

物理服务器安全之其他内容

从概览图里可以看出来,与服务器安全相关的内容有很多。如标准,美国有美国的标准,中国有中国的标准。通常来说美国的标准比中国的全面而且严格一些,如美国标准对固件更新就有明确的安全规定。所以大家在采购服务器的时候可以询问一下所符合的标准。另外还有测试方法与工具,测试原则,漏洞管理等。目前来说对于物理服务器安全问题的解决,还是以厂家提供的补丁为主,建议用户对严重的问题进行及时的更新,并密切关注各个厂家的安全响应页面(可以搜索PSIRT关键字来了解)。

最后,个人觉得安全问题归根到底还是人的意识问题。单有工具没有安全意识也是白扯,就像一个全副武装战士,掉进敌人挖的坑里也是没救的。所以提高安全防范意识是人们的首要任务。

  • 如果是开发团队,引入安全验证过程,采用漏洞扫描工具Nessus,AppScan进行安全检测。
  • 如果是运维团队,关注业界安全漏洞网站,采用工具进行定期的扫描,增加审计过程
  • 如果是个人用户,除了安装杀毒软件外,就是不要登陆不了解的网站。下载程序时注意网站提供的哈希码,这是防止程序被篡改的关键。

谈谈物理服务器的安全,首发于博客 – 伯乐在线

你以为服务器关了这事就结束了? – XcodeGhost截胡攻击和服务端的复现,以及UnityGhost预警

0×00 序


截胡,麻将术语,指的是某一位玩家打出一张牌后,此时如果多人要胡这张牌,那么按照逆时针顺序只有最近的人算胡,其他的不能算胡。现也引申意为断别人财路,在别人快成功的时候抢走了别人的胜利果实。

虽然XcodeGhost作者的服务器关闭了,但是受感染的app的行为还在,这些app依然孜孜不倦的向服务器(比如init.icloud-analysis.com,init.icloud-diagnostics.com等)发送着请求。这时候黑客只要使用DNS劫持或者污染技术,声称自己的服务器就是”init.icloud-analysis.com”,就可以成功的控制这些受感染的app。具体能干什么能,请看我们的详细分析。

另外,有证据表明unity 4.6.4 – unity 5.1.1的开发工具也受到了污染,并且行为与XcodeGhost一致,更恐怖的是,还有证据证明XcodeGhost作者依然逍遥法外,具体内容请查看第三节。

PS:虽然涅槃团队已经发出过攻击的demo了2,但很多细节并没有公布。所以我们打算在这篇文章中给出更加详细的分析过程供大家参考。

0×01通信协议分析


在受感染的客户端App代码中,有个Response方法用于接收和处理远程服务器指令。

Response方法中根据服务器下发的不同数据,解析成不同的命令执行,根据我们分析,此样本大致支持4种远程命令,分别是:设置sleep时长、窗口消息、url scheme、appStore窗口。

通过4种远程命令的单独或组合使用可以产生多种攻击方式:比如下载安装企业证书的App;弹AppStore的应用进行应用推广;弹钓鱼页面进一步窃取用户信息;如果用户手机中存在某url scheme漏洞,还可以进行url scheme攻击等。

其通信协议是基于http协议的,在传输前用DES算法加密http body。Response方法拿到服务器下发送的数据后,调用Decrypt方法进行解密:

如果解密成功,将解密后的数据转换成JSON格式数据:

然后判断服务器端下发的数据,执行不同的操作。如下面截图是设置客户端请求服务端器sleep时长的操作:

0×2恶意行为分析及还原


在逆向了该样本的远程控制代码后,我们还原了其服务端代码,进一步分析其潜在的危害。

首先我们在服务端可以打印出Request的数据,如下图:

红色框标记的协议的头部部分,前4字节为报文长度,第二个2字节为命令长度,最后一个2字节为版本信息,紧跟着头部的为DES的加密数据。我们在服务端将数据解密后显示为:

这里有收集客户端信息上传到控制服务器。

同样我们返回加密数据给客户端:

明文信息为:

客户端根据App的运行状态向服务端提供用户信息,然后控制服务器根据不同的状态返回控制数据:

恶意行为一 定向在客户端弹(诈骗)消息

该样本先判断服务端下发的数据,如果同时在在“alertHeader”、“alertBody”、“appID”、“cancelTitle”、“confirmTitle”、“scheme”字段,则调用UIAlertView在客户端弹框显示消息窗口:

消息的标题、内容由服务端控制

客户端启动受感染的App后,弹出如下页面:

恶意行为二 下载企业证书签名的App

当服务端下发的数据同时包含“configUrl”、“scheme”字段时,客户端调用Show()方法,Show()方法中调用UIApplication.openURL()方法访问configUrl:

通过在服务端配置configUrl,达到下载安装企业证书App的目的:

客户端启动受感染的App后,目标App将被安装:

demo地址:http://v.youku.com/v_show/id_XMTM0MTQyMzM1Ng==.html

恶意行为三 推送钓鱼页面

通过在服务端配置configUrl,达到推送钓鱼页面的目的:

客户端启动受感染的App后,钓鱼页面被显示:

demo地址:http://v.youku.com/v_show/id_XMTM0MTQyMjkyOA==.html

恶意行为四 推广AppStore中的应用

通过在服务端配置configUrl,达到推广AppStore中的某些应用的目的:

phishing1.html页面内容:

客户端启动受感染的App后,自动启动AppStore,并显示目标App的下载页面:

demo地址:http://v.youku.com/v_show/id_XMTM0MTQyNTk0MA==.html

0×03 UnityGhost?


在大家以为一切都完结的时候,百度安全实验室称已经确认”Unity-4.X的感染样本”。并且逻辑行为和XcodeGhost一致,只是上线域名变成了init.icloud-diagnostics.com。这意味,凡是用过被感染的Unity的app都有窃取隐私和推送广告等恶意行为。

Unity是由Unity Technologies开发的一个让玩家创建诸如三维视频游戏、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。很多有名的手机游戏比如神庙逃亡,纪念碑谷,炉石传说都是用unity进行开发的。

更令人恐怖的是,在百度安全实验室确认后没多久,大家就开始在网上寻找被感染的Unity工具,结果在我搜到一个Unity3D下载帖子的时候发现”codeFun与2015-09-22 01:18编辑了帖子”!?要知道codeFun就是那个自称XcodeGhost作者的人啊。他竟然也一直没睡,大半夜里一直在看大家发微博观察动静?随后发现大家知道了Unity也中毒的事情,赶紧去把自己曾经投毒的帖子删了?

现在再去看那个帖子已经被作者删的没有任何内容了。。。 http://game.ceeger.com/forum/read.php?tid=21630&fid=8

但根据XcodeGhost作者没删之前的截图表明,从unity 4.6.4 – unity 5.1.1的开发工具都有可能被投毒了!

0×04 总结


虽然病毒作者声称并没有进行任何广告或者欺诈行为,但不代表别人不会代替病毒作者进行这些恶意行为。并且作者依然还在逍遥法外!所以立刻!马上!删掉那些中毒的app吧!

0×05 参考资料


  1. 涅槃团队:Xcode幽灵病毒存在恶意下发木马行为 http://drops.wooyun.org/papers/8973
  2. XcodeGhost 源码 https://github.com/XcodeGhostSource/XcodeGhost

你以为服务器关了这事就结束了? – XcodeGhost截胡攻击和服务端的复现,以及UnityGhost预警,首发于博客 – 伯乐在线

让微信等知名 APP 都中招的 XcodeGhost 事件全面详细回顾

9月18日,我们在「iOS大全」(iOShub)微信已做过首次汇总。19日晚,「程序员的那些事」主页君根据当前网上相关信息,按照时间线,再次做一次更全面汇总。

 

2015-09-14

国家互联网应急中心 发布预警

不过这个公告,绝大多数开发者,也是昨天开始才知道的。

2015-09-16

腾讯安全响应中心称,「发现 App Store上的 TOP5000 应用有 76 款被感染,于是我们向苹果官方及大部分受影响的厂商同步了这一情况。」

 

2015-09-17

XcodeGhost 事件在网上升温发酵

【9:45】唐巧 发了一条微博:

随后很多留言的小伙伴们纷纷表示中招,@谁敢乱说话表示:”还是不能相信迅雷,我是把官网上的下载URL复制到迅雷里下载的,还是中招了。我说一下:有问题的Xcode6.4.dmg的sha1是:a836d8fa0fce198e061b7b38b826178b44c053a8,官方正确的是:672e3dcb7727fc6db071e5a8528b70aa03900bb0,大家一定要校验。”另外还有一位小伙伴表示他是在百度网盘上下载的,也中招了。

 

【16:00】国外安全公司 paloalto 发现了 XcodeGhost 问题,并发布第一版分析报告

【17:43】阿里的蒸米、迅迪发布了他们文章:《 XCode 编译器里有鬼,XCodeGhost 样本分析

@程序员的那些事 主页君注:内容为节选,有删减)

虽然 XCodeGhost 并没有非常严重的恶意行为,但是这种病毒传播方式在iOS上还是首次。也许这只是病毒作者试试水而已,可能随后还会有更大的动作,请开发者务必要小心。

这个病毒让我想到了UNIX 之父 Ken Thompson 的图灵奖演讲 “Reflections of Trusting Trust”。他曾经假设可以实现了一个修改的 tcc,用它编译 su login 能产生后门,用修改的tcc编译“正版”的 tcc 代码也能够产生有着同样后门的 tcc。也就是不论 bootstrap (用 tcc 编译 tcc) 多少次,不论如何查看源码都无法发现后门,真是细思恐极啊。

根据热心网友举报,投毒者网名为『coderfun』。他在各种iOS开发者论坛或者weibo后留言引诱iOS开发者下载有毒版本的Xcode。并且中毒的版本不止Xcode 6.4,还有6.1,6.2和6.3等等。

 

2015-09-18

第一批受感染的 APP 陆续被曝光

【14:14 】开始,@图拉鼎  在微博持续发布了由他测试验证受感染的 APP,至少包括如下:

  • 网易云音乐
  • 滴滴出行
  • 12306
  • 中国联通手机营业厅
  • 高德地图
  • 豌豆荚的开眼
  • 网易公开课
  • 下厨房
  • 51卡保险箱(金融应用)
  • 同花顺
  • 中信银行动卡空间

这个列表出来后,令人震惊。

【15:43】网易云音乐发公告

摘几个网友对该公告的评论:

@吴明prfc :

这公告,用被小偷改造的工具,导致被偷。给你说小偷走了,没威胁了,大家放心

@祝佳音:

翻译:虽然我们愚蠢又无能,也不知如何收拾残局,但不知道为什么,好像敌人暂时没动静了。这件事就当没发生,就当没发生!

【19:17】@Saic 童鞋发布《XcodeGhost 实际用途猜测分析》,给出了 XG  木马的逻辑:

在用户安装了目标应用后,木马会向服务器发送用户数据。

服务器根据需要返回模拟弹窗。

弹窗可以是提示支付失败,请到目标地址付款,也可以是某个软件的企业安装包。

用户被诱导安装未经审核的安装包后,程序可以调用系统的私有 API,实现进一步的攻击目的。

 

木马中还有一些调用应用内购的攻击逻辑,就不展开说明了。

如果之前有遇到任何程序弹出非系统需要输入 Apple ID 或密码的网站,并输入过密码的,还请尽早修改。

全文:http://weibo.com/p/1001603888503866975286

 

【21:02】微博上曝光了第二份受感染的 APP 列表:


(右侧是版本信息)

 

【21:43】中招的@腾讯微信团队 在微博发声明,里面提到:

1.该问题仅存在iOS 6.2.5版本中,最新版本微信已经解决此问题,用户可升级微信自行修复,此问题不会给用户造成直接影响。

全文:http://weibo.com/p/1001603888540667758451

 

2015-09-19

【凌晨 4:39】自称 XcodeGhost 作者的网友在微博发声明,称只是实验项目,无任何威胁

以下引用部分微博上针对该声明的评论:

@唐巧_boy:我刚刚看了一下作者放出的源码,和逆向出来的代码行为一致,应该是真的。

@南非蜘蛛:你有点小调皮,想进监狱了是吧?

@Daniel_K4:作者是实验么?持续传播了半年,我不太相信。。。现在才出来发布说明,应该是被定位到吓坏了吧。

@Livid:一个程序员出于试验目的做的修改版 Xcode.dmg 能够通过自然分发的方式装到那么多重要 App 的开发环境里,也是一件挺不可思议的事情。

@Easy:翻一下就是「我就配了把你家钥匙。还没开始偷东西呢,当然是无害了」。

@tombkeeper 事闹大了,就会变成公安部督办案件,就几乎一定能破案,几乎一定能抓到人。这时候无论自首还是跑路都比发“澄清”有意义得多。

@onevcat:算个账,微信用户总数 5 亿日活70%。每天每人就算5个POST请求,每个请求300Byte,日流入流量就接近500G,以及17.5亿次请求。据说服务器扔在亚马逊,那么资费算一下每个月应该是存储$450,请求$260K。这还只是单单一个微信,再算上网易云音乐等等,每月四五十万刀仅仅是苦逼iOS开发者的个人实验?

2015-09-19  上午

为避免给更多用户造成可能是伤害,苹果公司开始下架受感染的 APP,并给相应开发商发邮件

图来自@小小小小_灿,可能看不清。在邮件中,苹果也说明了重新上架的条件:

  1. 从官方下载 Xcode;
  2. 重新编译打包;
  3. 提交等待审核;

 


【开发圈和安全圈的事后讨论】

(不分时间顺序)

@Saic:

苹果以审核严格著称,为何会允许应用上架???

 

恶意代码加载到程序中后,将收集到的用户信息加密,发送到远程服务器。

收集的信息包括系统版本,程序名称,用户的唯一识别 ID,语言等非敏感信息。

对苹果来说,这段代码与普通的第三方统计代码并没有区别,甚至你在使用一些程序内的微博登陆或微信分享功能时,微博和微信都可能会收集这些信息到自己的服务器。

因为没有涉及到苹果禁止开发者使用的接口,一切看起来都很正常,所以带有恶意代码的应用可以正常发布到 App Store。

 

对我有什么影响???

根据目前的研究进展以及自称是开发者公布的恶意代码源码,代码主要做了以下事情:

在用户安装了目标应用后,木马会向服务器发送用户数据。

服务器会返回一些可以让程序弹出提示的控制代码,例如:

  • 用户名密码错误,请到以下地址修改,用户确认后跳转到一个伪造的钓鱼网站
  • 弹出 App Store 官方的应用下载页面,诱导用户下载
  • 程序有升级,用户确认后可以利用非官方渠道、修改过的应用替换掉当前应用
  • 其他非官方应用程序的推广和下载

因为弹窗是从用户信任的应用里弹出,很多时候不会多做怀疑就会授权或确认下载。

另外根据相关研究,代码可能存在多种变种 [ 3 ],可能存在直接窃取用户 Apple ID 的版本,模拟系统登陆框在技术上是可行的。

Via: http://weibo.com/p/1001603888803550000430

 

@图拉鼎:

对于 iOS 开发者的建议,立即删除从不明来源下载的 Xcode,即使你是用官方地址然后在迅雷上下载的,最后从 App Store 安装最新版本的 Xcode。有条件的公司应该在今天开始专门设置一台有专人管理的 Build Server,所有发布至 App Store 的 App 只能从该台电脑 Build 并发布,以防止未来此类事件的再现。

 

@sunny_THU:

2. 这件事情是不是很严重

可以说很严重,也可以说不严重。说这件事情很严重,是因为我们把程序的控制权分享分享给了第三个人,他可以做任何程序内部的操作,包括监控输入,支付,跳转,用户的内容等行为(但也仅限于单个中毒的app内部,系统层的内容和别的app的内容是拿不到的,这里就不得不感谢苹果的沙盒机制,在机制上保护了一定的安全性),并且这次攻击证明根本上苹果软件的开发和提交机制是有漏洞的,更严重的问题是会不会已经有了一些别的病毒在软件中,只是没有被发现。 不严重是因为这次的病毒如果按照木马作者披露的源码,并没有做严重损害用户隐私的事情(一些安全机构逆向了源码,基本和作者公开的代码符合 http://security.tencent.com/index.php/blog/msg/96 )。

3. 怎么避免这种事情

“程序最大的bug不是程序自身,而是人”。这次事件是各种因素一起影响的结果,开发者根本没有意识到Xcode都会被攻击,国内网络环境太差,公司不配备VPN等等。而开发者作为软件的开发者和安全的负责人以及直接责任人更需要去规范和争取,因为你比其他人知道的更多,也更清楚问题有多严重。

 

@TK 教主:

2015 年 3 月 10 日的这篇文章透露:美国圣地亚国家实验室在 2012 年 CIA 的秘密会议“Jamboree”上提出被称作“Strawhorse”的攻击方式:通过修改 Xcode 使开发商不知情地发布带有后门的 APP。“codefun” 开始散布修改后的 Xcode 是在 3 月中旬,不知道是不是受了这个启发。

 

@月光博客:

迅雷的回应如下:对于Xcode被植入恶意代码一事,有猜测称迅雷服务器受到感染,导致使用迅雷会下载到含有恶意代码的Xcode。迅雷第一时间安排工程师进行检测,并对比了离线服务器上的文件,结果都与苹果官方下载地址的文件信息一致。也就是说,官方链接的Xcode经迅雷下载不会被植入恶意代码。

XcodeGhost事件并不表明苹果iOS的安全性相比安卓有什么问题,实际上,就开发环境来说,安卓实际上也是一样的,苹果的开发软件下载速度慢,而安卓的开发软件不翻墙根本无法从官网下载,大量安卓开发者都不是从官网下载的开发环境,很多开发工具来路不明,因此安卓很可能也存在类似问题。

 

@唐巧:

XcodeGhost 这件事情,苹果自己也有责任,Mac App Store下载速度慢得要死,每次下Xcode花个几十分钟非常正常,这才造成大家都用迅雷和百度网盘这种非官方渠道。就说现在吧,我的Mac系统更新了一上午,还是处于卡顿无进度状态。[泪]

 

@腾讯玄武实验室:

虽然目前 init.icloud-analysis.com 等 XcodeGhost 相关域名已经不可访问,XcodeGhost 的始作俑者可能也不会再利用其干坏事,但这并不代表其他人不会。

有心干坏事的人,可以通过 DNS 投毒、伪造 WiFi 接入点等手段,控制或大或小的一个地区对 init.icloud-analysis.com 等域名的解析,从而变成 XcodeGhost 的控制者。所以受影响的 APP 开发商还是应该尽快发布干净的版本让用户升级。

 

 


【主页君留言】:今天这篇耗时 2+ 小时。如果各位觉得不错,请分享给其他朋友。

微信号:iProgrammer

(长按上图,可自动识别二维码)

其他媒体和公号若转载

必须保留全文完整内容,包括本段声明和二维码图片

 

让微信等知名 APP 都中招的 XcodeGhost 事件全面详细回顾,首发于博客 – 伯乐在线

内存寻址原理

在做网络安全事件分析的时候,都会遇到内存寻址的知识,例如上次跟大家分享的《 空指针漏洞防护技术》,就涉及到非法访问内存地址的问题。如果这个坎儿迈不过去,你就会迷失在代码中,更无从分析了。今天绿盟科技的安全技术专家就讲讲这个内存寻址的原理,文章分为上下两篇《内存寻址原理》及《内存寻址方式》。

随着信息化发展和数据处理能力需求的提高,对计算机硬件产品的性能和容量也提出了新的挑战,要求计算机处理能力也要能随实际情况需求的变动而提升、改变。

当下,一台普通的电脑硬盘容量也要200多G,内存也有4G;如此大容量的硬盘和内存,在处理大量数据或是大型游戏面前还是显得力不从心,需要通过扩容来满足需求,比如将内存由4G提升到8G或是16G不等。扩容后对个人体验确实提升不少。对于内存容量的提升需要有相应的硬件基础支撑,需要有能消化掉这么多内存的寻址地址。比如说如果一8位单片机如果要装载16G的内存,那就是暴殄天物。

哪里有需求哪里就有市场 ;计算机从8位的51单片机,20位8086寻址,发展到32位 win2003,64位win10,都是由于信息化需求的膨胀推动着计算机一代又一代的改革创新。

对于内存的扩容,很多人都不是很清楚应用程序如何使用的物理内存地址。远了不说,单说现在常用计算机中的32位、64系统;系统是怎么样将虚拟地址转化成线性地址,线性地址又是怎样转换成物理地址的,其中又用到了哪些寄存器或是数据结构,相信很多人对此也是一知半解;也像我一样,想结合实例从地址转换的本质来掌握其精髓之处。接下来就一起学习从逻辑地址到物理地址的整个转换过程。

1.实模式与保护模式简介

CPU常见三种工作模式:实模式与保护模式,虚拟8086模式。

实模式 :CPU复位(reset)或加电(power on)的时候以实模式启动,处理器以实模式工作。在实模式下,内存寻址方式和8086相同,由16位段寄存器的内容乘以16(10H)当做段基地址,加上16位偏移地址形成20位的物理地址,最大寻址空间1MB。在实模式下,所有的段都是可以读、写和可执行的。实模式下没有分段或是分页机制,逻辑地址和物理地址相等。

由此得知:

  1. 在实模式下最大寻址空间时1M,1M以上的内存空间在实模式下不会被使用。
  2. 在实模式所有的内存数据都可以被访问。不存在用户态、内核态之分。
  3. 在BIOS加载、MBR、ntdlr启动阶段都处在实模式下。

保护模式 :对于保护模式大家并不陌生;是目前操作系统的运行模式,利用内存管理机制来实现线性地址到物理地址的转换,具有完善的任务保护机制。

保护模式常识:

  1. 现在应用程序运行的模式均处于保护模式。
  2. 横向保护,又叫任务间保护,多任务操作系统中,一个任务不能破坏另一个任务的代码,这是通过内存分页以及不同任务的内存页映射到不同物理内存上来实现的。
  3. 纵向保护,又叫任务内保护,系统代码与应用程序代码虽处于同一地址空间,但系统代码具有高优先级,应用程序代码处于低优先级,规定只能高优先级代码访问低优先级代码,这样杜绝用户代码破坏系统代码。

虚拟8086 模式: 简称V86模式是运行在保护模式中的实模式,为了在32位保护模式下执行纯16位程序。可以把8086程序当做保护模式的一项任务来执行。虚拟8086允许在不退出保护模式的情况下执行8086程序。

虚拟8086常识:

  1. 寻址的地址空间是1M字节.
  2. 可以在虚拟8086模式下运行16位DOS程序。
  3. 在V86模式下,代码段总是可写的;这与实模式相同,同理,数据段也是可执行的。
  4. 32系统编写V86模式的程序:

2. 保护模式寻址基础知识

接下来就以32位系统为例,介绍保护模式下,内存中一些地址转换相关的寄存机和数据结构。

2.1 内存地址概念

逻辑地址 :在进行C语言编程中,能读取变量地址值(&操作),实际上这个值就是逻辑地址,也可以是通过malloc或是new调用返回的地址。该地址是相对于当前进程数据段的地址,不和绝对物理地址相干。只有在Intel实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或分页机制,CPU不进行自动地址转换)。应用程序员仅需和逻辑地址打交道,而分段和分页机制对一般程序员来说是完全透明的,仅由系统编程人员涉及。应用程序员虽然自己能直接操作内存,那也只能在操作系统给你分配的内存段操作。一个逻辑地址,是由一个段标识符加上一个指定段内相对地址的偏移量,表示为 [段标识符:段内偏移量]。

线性地址 :是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,或说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址能再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4G(2的32次方即32根地址总线寻址)。

物理地址(Physical Address) 是指出目前CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了,比如在实模式下。

2.2 虚拟地址,线性地址,物理地址关系

对于保护模式下地址之间的转换,对程序员来说是透明的。那么物理内存通过内存管理机制是如何将虚拟地址转换为物理地址的呢?当程序中的指令访问某一个逻辑地址时,CPU首先会根据段寄存器的内容将虚拟地址转化为线性地址。如果CPU发现包含该线性地址的内存页不在物理内存中就会产生缺页异常,该异常的处理程序通过是操作系统的内存管理器例程。内存管理器得到异常报告后会根据异常的状态信息。特别是CR2寄存器中包含的线性地址,将需要的内存页加载到物理内存中。然后异常处理程序返回使处理器重新执行导致页错误异常的指令,这时所需要的内存页已经在物理内存中,所以便不会再导致页错误异常。

2.3 段式机制及实例分析

前面说到在线性地址转换为物理地址之前,要先由逻辑地址转换为线性地址。系统采用段式管理机制来实现逻辑地址到线性地址的转换。保护模式下,通过”段选择符+段内偏移”寻址最终的线性地址。

CPU的段机制提供一种手段可以将系统的内存空间划分为一个个较小的受保护的区域,每个区域为一个段。相对32位系统,也就是把4G的逻辑地址空间换分成不同的段。每个段都有自己的起始地址(基地址),边界和访问权限等属性。实现段机制的一个重要数据结构就是段描述符。

下面是个程序实例中显示除了各个段的值:

图中给出了代码段CS,堆栈段SS,数据段DS等段寄存器的值;从得到的值可知,SS=DS=ES是相等的,至于为什么有些段的值相等,后面会说到。 以实例中给出的地址0x83e84110 为例,哪里是段描述符,哪里是段内偏移, 又是如何将该逻辑地址转换为线性地址的呢?相信很多人都迫不及待的想知道整个转换过程,接下来就要看看逻辑地址到线性地址详细转换过程。

上面说到段式管理模式下有段选择符+段内偏移寻址定位线性地址,其实际转换过程如下图所示

从图中可知,逻辑地址到线性地址的转换,先是通过段选择符从描述符表中找到段描述符,把段描述符和偏移地址相加得到线性地址。也就是说要想得到段描述符需要三个条件:

  1. 得到段选择符。
  2. 得到段描述符表
  3. 从段描述符表中找到段描述符的索引定位段描述符。

前面我们提到了段描述符 + 偏移地址,并没有提段选择符和段描述符表。所以我们要弄清楚这几个观念段选择符,段描述符表,段描述符,以及如何才能得到这几个描述符?

2.3.1 段描述符基础知识

从上图可知,通过段选择符要通过段描述符表找到段描述符,那么段描述符表是什么,又是怎么得到段描述符表呢?

在保护模式下,每个内存段就是一个段描述符。其结构如下图所示:

图中看出,一个段描述符是一个8字节长的数据结构,用来描述一个段的位置、大小、访问控制和状态等信息。段描述符最基本内容是段基址和边界。段基址以4字节表示(图中可看出3,4,5,8字节)。4字节刚好表示4G线性地址的任意地址(0×00000000-0xffffffff)。段边界20位表示(1,2字节及7字节的低四位)。

2.3.2 段描述符表实例解析

在现在多任务系统中,通常会同时存在多个任务,每个任务会有多个段,每个段需要一个段描述符,段描述符在上面一小节已经介绍,因此系统中会有很多段描述符。为了便于管理,需要将描述符保存于段描述符表中,也就是上图画出的段描述符表。IA-32处理器有3中描述符表:GDT,LDT和IDT。

GDT是全局描述符表。一个系统通常只有一个GDT表。GDT表也即是上图中的段描述符表,供系统中所以程序和任务使用。至于LDT和IDT今天不是重点。

那么如何找到GDT表的存放位置呢?系统中提供了GDTR寄存器用了表示GDT表的位置和边界,也就是系统是通过GDTR寄存器找到GDT表的;在32位模式下,其长度是48位,高32位是基地址,低16位是边界;在IA-32e模式下,长度是80位,高64位基地址,低16位边界。

位于GDT表中的第一个表项(0号)的描述符保留不用,成为空描述符。如何查看系统的GDT表位置呢?通过查看GDTR寄存器,如下图所示

从上图看出GDT表位置地址是0×8095000,gdtl值看出GDT边界1023,总长度1024字节。前面知道每一项段描述符占8字节。所以总共128个表项。图中第一表项是空描述符。

2.3.3 段选择符结构

前面我们介绍了段描述符表和段描述符的格式结构。那么如何通过段选择符找到段描述符呢,段选择符又是什么呢?

段选择符又叫段选择子,是用来在段描述符表中定位需要的段描述符。段选择子格式如下:

7

段选择子占有16位两个字节,其中高13位是段描述在段描述表中的索引。低3位是一些其他的属性,这里不多介绍。使用13位地址,意味着最多可以索引8k=8192个描述符。但是我们知道了上节GDT最多128个表项。

在保护模式下所有的段寄存器(CS,DS,ES,FS,GS)中存放的都是段选择子。

2.3.4 逻辑地址到线性地址转换实例解析

已经了解了逻辑地址到虚拟地址到线性地址的转换流程,那就看看在前面图中逻辑地址0x83e84110对应的线性地址是多少?

首先,地址0x83e84110对应的是代码段的一个逻辑地址,地址偏移已经知道,也就是段内偏移知道,通过寄存器EIP得到是0x83e34110。段选择符是CS寄存器CS=0008,其高13位对应的GDT表的索引是1,也就是第二项段描述符(第一项是空描述符)。GDT表的第二项为标红的8个字节

通过段描述的3,4,5,8个字节得到段基址。

如上图所示第二项段描述符的3,4,5,8字节对应的值为0×00000000。由此我们得到了段机制和段内偏移。最后的线性地址为段基址+段内偏移=0×0+0x83e34110=0x83e34110。

由此我们知道在32系统中逻辑地址就是线性地址。

其实通过观察其他的段选择子会发现,所有段选择子对应的基地址都是0×0,这是因为在32系统保护模式下,使用了平坦内存模型,所用的基地址和边界值都一样。既然基地址都是0,那么也就是线性地址就等于段内偏移=逻辑地址。

总之:

  1. 段描述符8字节
  2. GDTR是48位
  3. 段选择子2个字节。

2.4 页式机制及实例分析

前面介绍了由逻辑地址到线性地址的转换过程,那么接下来就要说说地址是如何将线性地址转为物理地址。需要先了解一些相关的数据结构。

前面说到如果CPU发现包含该线性地址的内存页不在物理内存中就会产生缺页异常,该异常的处理程序通过是操作系统的内存管理器例程。内存管理器得到异常报告后会根据异常的状态信息。特别是CR2寄存器中包含的线性地址,将需要的内存页加载到物理内存中。然后异常处理处理返回使处理器重新执行导致页错误异常的指令,这时所需要的内存页已经在物理内存中,所以便不会再导致也错误异常。

32位系统中通过页式管理机制实现线性地址到物理地址的转换,如下图:

2.4.1 PDE结构及如何查找内存页目录

从上图中我们知道通过寄存器CR3可以找到页目录表。那么CR3又是什么呢?在32系统中CR3存放的页目录的起始地址。CR3寄存器又称为页目录基址寄存器。32位系统中不同应用程序中4G线性地址对物理地址的映射不同,每个应用程序中CR3寄存器也不同。也就是说每个应用程序中页目录基址也是不同的。

从上图知道页目录表用来存放页目录表项(PDE),页目录占一个4kb内存页,每个PDE长度为4字节,所以页目录最多包含1KB。没启用PAE时,有两种PDE,这里我们只讨论使用常见的指向4KB页表的PDE。

页目录表项的高20位表示该PDE所指向的起始物理地址的高20位,该起始地址的低12位为0,也就是通过PDE高20位找到页表。由于页表低12位0,所以页表一定是4KB边界对齐。 也就是通过页目录表中的页目录表项来定位使用哪个页表(每一个应用程序有很多页表)。

以启动的calc程序为例,CR3寄存器是DirBase中的值,如下图

Calc.exe程序对应的CR3寄存器值为0x2960a000,下面是对应PDT结构

2.4.2页表结构解析

页表是用来存放页表表项(PTE)。每一个页表占4KB的内存页,每个PTE占4个字节。所以每个页表最多1024个PTE。其中高20位代表要使用的最终页面的起始物理地址的高20位。所以4KB的内存页也都是4KB边界对齐。

内存寻址原理,首发于博客 – 伯乐在线

空指针漏洞防护技术(提高篇)

在《空指针漏洞防护技术-初级篇》中我们介绍了空指针及空指针漏洞的概念,在这次高级篇中介绍空指针利用及相应的防护机制。

1 提高篇之:空指针的利用

前面主要介绍了空指针的一些概念和相关的知识,了解了什么是空指针,对于由野指针导致的空指针漏洞不是今天的重点。接下来主要就针对指向零页内存的空指针漏洞做详细的介绍。

此类漏洞利用主要集中在两种方式上:

  1. 利用NULL指针。
  2. 利用零页内存分配可用内存空间

对于第一种情况可以利用NULL指针来绕过条件判断或是安全认证。比如X.0rg空指针引用拒绝访问漏洞(CVE-2008-0153 ),如下图对比修改补丁前后的对比:

从代码补丁可以看出该漏洞利用NULL指针改变程序流程来触发漏洞。

针对第二种情况,在某些情况下零页内存也是可以被使用,比如下面两种情况:

  1. 在windows16系统或是windows16虚拟系统中,零页内存是可以使用的;在windows 32位系统上运行DOS程序就会启动NTVDM进程,该进程就会使用到零页内存。
  2. 通过ZwAllocateVirtualMemory等系统调用在进程中分配零页内存(win7系统之前)。

接下来结合ZwAllocateVirtualMemory API函数的调用直观感受在win7与win8系统中零页内存分配的差异。

1.1 ZwAllocateVirtualMemory基本介绍

zwAllocateVirtualMemory函数在指定进程的虚拟空间中申请一块内存,那是不是只要在内存申请空间就会调用zwAllocateVirtualMemory函数呢?调用zwAllocateVirtualMemory需要根据实际的情况。

堆的分配、使用、回收都是通过微软的API来管理的,最常见的API是malloc和new。在底层调用是HeapAlloc,同时通过HeapCreate来创建堆。对zwAllocateVirtualMemory函数的调用情况是:

. HeapCreate->RtlCreateHeap->ZwAllocateVirualMemory,这里会直接申请一大块内存,至于申请多大的内存,由进程PEB结构中的字段决定,HeapSegmentReserve字段指出要申请多大的虚拟内存,HeapSegmentCommit指明要提交多大内存。

图中看出默认申请大小是0×100000,默认提交大小是0×2000。下图是利用Heapcreate函数调用zwAllocatevirtualMemory时的函数调用栈关系。

图中展示了函数的调用过程。

  1. HeapAlloc->RtlAllocateHeap-> ZwAllocateVirualMemory,这里的内存申请是由Heapcreate已经提交的内存中申请。堆管理器从这片内存中划分一块出来以满足申请的需要,仅当申请的内存不够的时候,才会再次调用ZwAllocateVirualMemory函数。 **也就是说,我们平时使用**** malloc ****或是**** new *\*在堆上申请一块小的内存是不会调用该函数的。** 这点大家要注意。下图中展示了利用HeapAlloc调用ZwAllocateVirualMemory的过程:

c. 直接利用zwAllocateVirtualMemory分配内存,对于zwAllocateVirtualMemory函数,微软没有给出公开的文档,但是可以通过相关资料或是逆向来了解该函数的使用方式。直接利用zwAllocateVirtualMemory函数分配内存首先加载函数所在模块,同时获取该函数的符号地址。由于该函数提供了比较全面的参数,利用此函数来分配内存空间更加灵活多变。

1.2 ZwAllocateVirtualMemory函数知识

zwAllocateVirtualMemory该函数在指定进程的虚拟空间中申请一块内存,该块内存默认将以64kb大小对齐。

NTSYSAPI NTSTATUS NTAPI **ZwAllocateVirtualMemory** (
IN HANDLE *ProcessHandle*,
IN OUT PVOID **BaseAddress*,
IN ULONG *ZeroBits*,
IN OUT PULONG *RegionSize*,
IN ULONG *AllocationType*,
IN ULONG *Protect*
);

两个主要参数:

返回值

如果内存空间申请成功会返回0,失败会返回各种NTSTATUS码。

从zwAllocateVirtualMemory说明来看,本想利用BaseAddress参数在零页内存中分配空间,但是当BaseAdress指定为0时,系统会寻找第一个未使用的内存块来分配,而不是在零页内存中分配。那么如何才能分配到零页内存呢?

1.3 零页内存分配之实例win7 vs win8

了解了zwallocatevirtualmemory的用法,就结合实例来看看如何利用该函数进行零页内存分配。前面介绍将BaseAdress设置为0时,并不能在零页内存中分配空间,就需要利用其它方式在零页内存分配空间。在AllocateType参数中有一个分配类型是MEM_TOP_DOWN,该类型表示内存分配从上向下分配内存。那么此时指定 BaseAddress为一个 低地址,例如 1,同时指定分配内存的大小 大于这个值 ,例如8192(一个内存页),这样分配成功后 地址范围就是 0xFFFFE001(-8191) 到 1把0地址包含在内了,此时再去尝试向 NULL指针执行的地址写数据,会发现程序不会异常了 。通过这种方式我们发现在0地址分配内存的同时,也会在高地址(内核空间)分配内存(当然此时使用高地址肯定会出错,因为这样在用户空间)。

下面就举个例子看如何在零页分配内存

了解windows编程的情况下,对上面的代码不难理解,获取模块句柄,获取zwAllocateVirtualMemory函数地址,并传递参数调用该函数,其中baseaddress的值为4,参数类型中包含了MEM_TOP_DOWN,即内存由上向下分配。所以如果成功的话,将把零页内存中的地址4-0都会分配出去;函数返回0表示内存分配成功。然后再给0地址赋值打印,对0地址重新赋值后再次打印,查看结果。

为了能对比win7与win8系统运行结果的差异,需要准备两个干净的系统win7和win8,这里采用的都是32位系统。

在win7系统中直接编译运行该程序,运行结果如下

从显示结果来看,利用zwAllocateVirtualMemory函数,确实在零内存页分配了4-0地址的空间,也就是说我们可以利用zwAllocateVirtualMemory在零页内存中成功分配空间。

同时在win8系统中同时编译该程序,如果F5调试运行结果如下图:

或是CTRL+F5非调试运行,其结果如下图:

在win8系统中在调用zwallocatevirtualmemory后,函数返回了非0,返回值为0Xc00000f0。最终没能在零页内存分配空间。也就是说在win8系统中对零页内存做了安全防护,导致在零页地址分配内存时失败。

接下来看看win8系统中到底对NULL Pointer也就是零页内存做了哪些防护。

2 提高篇:windows零页内存防护机制

win8系统对零页内存防护机制通过搜索引擎可以查到: **在**** WIN8 ****系统中利用了内核进程结构**** EPROCESS ****中的**** flags ****字段的**** Vdmallowed *\*标志来判断是否允许访问零页内存。** 但是知其然而不知其所以然不是我们追求的目标。我们要做的就是在不依靠其他文献的条件下通过逆向和动态调试技术来剖析win8对零页内存的防护机制。

2.1 搭建内核调试环境

探索Win8的零页内存保护机制在内核中的实现,首先需要搭建一个能调试内核的环境。利用上面给出的例子结合内核调试来分析安全机制。关于如何搭建内核环境在之前的文章中已经介绍过,这里再累赘一下。

5.1.1 虚拟机及调试环境

搭建内核调试环境,采用双机调试模式,在虚拟机中安装win8系统同时配置win8调试模式。

Vmware安装win8系统就不在详解。系统启动后:

管理员权限打开CMD

按照上面的步骤配置好后,关闭虚拟机,打开win8虚拟机配置选项,删除并行端口,添加串行端口,同时配置串行端口,如下图:

配置好vmware后启动虚拟机进入调试模式,如下图:

5.1.2 配置启动windbg

双机模式调试内核需要配置windbg工具,现在主机中安装windbg;创建一个windbg的快捷方式,并在属性->目标中填入如下内容:

"C:\program file\WinDbg(x64)\windbg.exe" -b -k com:pipe,port=\.\pipe\com_1,baud=115200,resets=0,pipe

Windbg路径根据安装路径不同而调整。

启动windbg,由于我的主机是win7系统如果直接双击windbg快捷方式启动

这是缺少必要的权限,所以在启动windbg快捷方式时,需要以管理员的权限启动,启动完成后就可以和虚拟机中的win8系统进行内核级调试,启动之后的结果如下图:

到此内核调试的基本环境创建好了,为了能够更加直观的查看windows系统函数及调用关系需要为windbg配置符号表,这样windbg可以识别出windows标准的导出符号,同时为了能够更方便的调试nullpointer,也需要加载该程序的符号表。

到此内核调试环境搭建完成。

2.2 用户态及内核态跨栈调试

该部分是动态调试的关键部分,也是注意事项最多的一节。

5.2.1 内核调试用户态程序

在上面配置好环境后,在windbg中运行G命令,启动调试。启动程序后,同时在windbg中按住CRTL+BREAK断到调试器中。此时win8系统处于中断状态,不会再运行任何指令。

调试器断下来

我们知道在win7与win8中调用zwallocatevirtualmemory时由于零页内存保护机制的原因,win8系统不能在零页内存分配空间。那么就从调试nullpointer入手,通过调用zwallocatevirtualmemory调试内核态程序来剖解安全机制。

但是现在windbg处于内核调试状态,查看所有启动的进程

需要切换到nullpointer进程中。加载了nullpointer符号表。查看main函数的反汇编如下图所示:

5.2.2 用户态进入内核态

跟进该函数,最后进入

进入了sysenter指令之前,对windows系统有所了解的话,就知道该函数利用该调用进入快速系统调用也就是说此时将由用户态进入内核态。

SYSENTER用来快速调用一个0层的系统过程。SYSENTER是SYSEXIT的同伴指令。该指令经过了优化,它可以使将由用户代码(运行在3层)向操作系统或执行程序(运行在0层)发起的系统调用发挥最大的性能。

在调用SYSENTER指令前,软件必须通过下面的MSR寄存器,指定0层的代码段和代码指针,0层的堆栈段和堆栈指针:

  1. IA32_SYSENTER_CS:一个32位值。低16位是0层的代码段的选择子。该值同时用来计算0层的堆栈的选择子。

2.IA32_SYSENTER_EIP:包含一个32位的0层的代码指针,指向第一条指令。

3.IA32_SYSENTER_ESP:包含一个32位的0层的堆栈指针。

MSR寄存器可以通过指令RDMSR/WRMSR来进行读写。寄存器地址如下表。这些地址值在以后的intel 64和IA32处理器中是固定不变的。

为了能保证我们调试的**** NT!NtAllocatevirtualMemory ****函数刚好是**** nullpointer ****调用的,需要给**** NT!NtAllocatevirtualMemory ****函数下断点,意思是只在指定进程调用该函数时才断下来。** 待函数断下来后,同时查看函数调用栈如下图 **:

从图中调用栈可知,此时断下来的NT!NtAllocatevirtualMemory刚好是nullpointer引用的内核函数。此时已经进入内核调试状态。

5.3 逆向分析nt!NtAllocateVirtualMemory

进入win8内核调试,就要结合静态分析和动态调试来挖掘有用的信息。首先找到win8内核文件。 **需要注意的是此时分析的是虚拟机中**** win8 ****系统的内核文件,不是**** win7 *\*主机的内核文件。**

5.3.1 NtAllocatevirtualMemory参数确认

在前面的调试中,windbg断在了NT! NtAllocatevirtualMemory函数的入口处。对比NtAllocatevirtualMemory函数在windbg和IDA反编译的结果:

可知,在运行完指令call __SEH_prolog4_GS,后EBP+8为第一个参数,EBP+C为第二个参数,那就看看在调用call __SEH_prolog4_GS后EBP的值,如下图:

第一个参数是进程句柄,本进程句柄刚好是-1,第二个参数基地址指针,之前我们在程序中基地址是4,也就是0×00000004,查看基地址指针的值:

刚好是0×00000004,用户态传入的第三个参数是0,这里的第三个参数也刚好是0。其他参数不在一一列举;也就是是说内核函数NtAllocatevirtualMemory与用户态函数zwallocatevirtualmemory参数是一致的。

5.3.2 查找NtAllocatevirtualMemory 零页内存安全机制

到了最重要的时刻,接下来动态调试NtAllocatevirtualMemory, 一路单步执行,看到eax=0xc00000f0时停下:

从图中可知并EAX来自于ESI的赋值。那就继续往上看,看ESI的值是从哪里来的

从图中看出,在执行test[edi+0C4],1000000h指令后,如果相等就执行了mov esi,0xc00000f0。

5.3.3 确认NtAllocatevirtualMemory零页内存安全机制

前面已经找到了返回0xc00000f0的地方,接下来就要看看条件判断的地方, EDI=0x84b2ac80是EPROCESS进程的地址,查看EPROCESS结果可知:

在结构eprocess偏移0xc4的位置刚好是标志Vdmallowed,该值是0,并且[edi=0xc4] 与上1000000后刚好是零。导致ESI=0xc00000f0,进而导致EAX=0xc00000f0。

**到此基本上已经确认了**** NtAllocateVirtualMemory ****中对**** NULLPage ****的安全机制,就是检查**** EPROCESS ****中的**** VdmAllowed *\*的标志位。**

确定条件判断确定位置

从判断语句来看V76应该是参数中的基地址,V14应该是EPROCESS的地址。看一下这两个值的来源

从上图可知v76就是baseaddress; V14追溯到keGetCurrentThread,在内核模式下FS却指向KPCR(Kernel’s Processor Control Region)结构。即FS段的起点与KPCR结构对齐。看一下KPCR结构偏移124的位置

图中可知偏移124的位置刚好的当前线程的结构地址。通过查看函数KeGetCurrentThread的实现也能证实这一点,如下图:

线程结构地址+128(0×80)的位置刚好是当前进程的内核地址,如下图所示:

之后NtAllocateVirtualMemory函数在将进程结构地址偏移0xC4值与0×1000000做比较判断做安全检查。

到目前为止,NtAllocateVirtualMemory函数对零页内存的保护机制剖析完成。总结一下:

  1. 判断基地址是否小于**** 0×1000000,
  2. 判断内核结构**** EPROCESS ****的**** Vdmallowed ****标志是否为**** 0

5.3.4 查找内核中其他对零页内存保护的函数

通过对NtAllocateVirtualMemory逆向分析和动态跟踪了解了win8中对零页内存的保护机制;那么除了NtAllocateVirtualMemory函数,在内核中是否还有其他的函数也对零页内存进行了安全检查呢?

通过在整个NT内核文件中查找零页内存保护机制,又发现了几个包含零页内存包含的函数,搜索结果如下图:

也就是说在内核文件中除了NTAllocateVirtualMemory外,还有四个函数对零页内存做检测:

  1. MiIsVaRangeAvailable:
  2. MiMapViewOfPhySicalSection
  3. MiMapLockedPagesInUserSpace
  4. MiCreatePebOrTeb

这四个函数不都是导出函数,也就是说在内核编程中有可能我们使用的一些导出函数中内部调用了这四个函数中的某一个,其内部已经做了零页内存检测。

6 总结

本文先是介绍了什么是空指针漏洞,之后对windows系统的零页内存保护机制做了剖析。

空指针漏洞:

对零页内存的安全防护:

  1. 检测分配页是否在零页内存。
  2. **检测**** EPROCESS ****结构中的**** VdmAllowed *\*标志。**

Win8**** 以后的零页内存防护也只是保证了不会在零页内存分配空间,缓解分配零页内存空间来利用漏洞;从上图可知,利用零页内存分配导致的空指针漏洞也只是众多空指针漏洞类型中的一种。通过零页内存保护机制并不能缓解所有的空指针漏洞。

空指针漏洞防护技术(提高篇),首发于博客 – 伯乐在线

空指针漏洞防护技术(初级篇)

安全历史上由于空指针所带来的漏洞及攻击数不胜数,但由于其对利用者的编程能力有要求,对分析及防护者来说有更高的要求,所以国内对空指针漏洞及相关技术的讨论不是很多。今天这篇《空指针漏洞防护技术》,由绿盟科技威胁响应安全专家坐堂讲解,大家可以从中了解空指针漏洞的基础知识,并结合Windows 8的内存防护机制实例,动手实践空指针漏洞的防护技术。

1 背景

指针对于绝大部分的编程人员来说都不陌生,说起C/C++中指针的使用既带来了编程方面的方便;同时对编程人员来说,也是对个人编程能力的一种考验,不正确的使用指针会直接导致程序崩溃,而如果是内核代码中对指针的错误使用,会导致系统崩溃,后果也是相当严重。

一般情况下我们使用指针时,错误用法集中在三个方面:

  1. 由指针指向的一块动态内存,在利用完后,没有释放内存,导致内存泄露
  2. 野指针(悬浮指针)的使用,在指针指向的内存空间使用完释放后,指针指向的内存空间已经归还给了操作系统,此时的指针成为野指针,在没有对野指针做处理的情况下,有可能对该指针再次利用导致指针引用错误而程序崩溃。
  3. Null Pointer空指针的引用,对于空指针的错误引用往往是由于在引用之前没有对空指针做判断,就直接使用空指针,还有可能把空指针作为一个对象来使用,间接使用对象中的属性或是方法,而引起程序崩溃,空指针的错误使用常见于系统、服务、软件漏洞方面。

对于第一和第二种情况,我们可以通过一些代码审计工具在发布之前就能确定导致内存泄露或是野指针存在的地方。比如常见的工具有fority,valgrind等及时发现指针错误引用导致的问题。

对于第三种情况,空指针(Null Pointer)引用导致的错误,依靠代码审计工具很难发现其中的错误,因为空指针的引用一般不会发生在出现空指针然后直接使用空指针情况。往往是由于代码逻辑比较复杂空指针引用的位置会比较远,不容易发现;并且在正常情况下不会触发,只有在特定输入条件下才会引发空指针引用。对于排查此类错误也就更加困难。

本文不会重点讨论内存泄露和野指针的内容,而是通过一些现有的漏洞和实例来分析一下Null Pointer 空指针。从NULL Pointer概念、本质结合静态逆向及内核动态调试技术来了解在win7 32位和win8 32位下系统对Null Pointer处理情况有什么不同;Win8 32位针对Null Pointer添加了哪些防护机制。

本文从浅入深,循序渐进的讲述了NULL Pointer,结合静态逆向分析和内核级动态调试技术深入剖析win8系统对零页内存的保护机制,其中还涉及到了一些内核调试的技巧,对于对NULL Pointer的概念、使用比较模糊的人员值得一读,对于从事安全研究和学习的人员也是巩固、加深、拓展的好素材。

2 空指针由Null Pointer引发的漏洞

首先来看看近年来由于空指针的错误使用导致的系统、服务漏洞:

  • Microsoft windows kernel ‘win32k.sys’本地权限提升漏洞(CVE-2015-1721)(MS15-061)

该漏洞影响了windows Server 2003 SP2和R2 SP2,Windows Vista SP2, Windows Server 2008 SP2 和R2 SP1,Windows7 SP1,Windows8 ,Windows8.1,Windows Server2012 Gold和R2,Windows RT Gold and 8.1 。利用内核驱动程序 win32k.sys漏洞可以提升权限或是引起拒绝访问服务,主要原因是空指针的错误引用导致。

  • PHP空指针引用限制绕过漏洞(CVE-2015-3411)

PHP存在安全漏洞,由于程序多个扩展中缺少路径或某些函数的路径参数的空字节检查,允许远程攻击者利用漏洞可绕过目标文件系统访问限制,访问任意文件。

  • 0rg空指针引用拒绝访问漏洞(CVE-2008-0153 )

X.Org是X.Org基金会运作的一个对X Window系统的官方参考实现,是开源的自由软件。libXfont是一个用于服务器和实用程序的X字体处理库。 X.Org libXfont 1.4.9之前版本和1.5.1之前1.5.x版本的bitmap/bdfread.c文件中的’bdfReadCharacters’函数存在安全漏洞,该漏洞源于程序未能正确处理不能读取的字符位图。远程攻击者可借助特制的BDF字体文件利用该漏洞造成拒绝服务(空指针逆向引用和崩溃),执行任意代码。

  • Paragma TelnetServer空指针引用拒绝服务漏洞(BID-27143)

Pragma TelnetServer是一款远程访问和控制Telnet服务器。Pragma TelnetServer处理协议数据时存在漏洞,远程攻击者可能利用此漏洞导致服务器不可用。TelnetServer服务器对每个入站连接启动一个telnetd.exe进程,该进程在处理TELOPT PRAGMA LOGON telnet选项(138号)期间存在空指针引用,导致进程终止。尽管终止单个进程不会影响其他进程,但终止某些进程会导致拒绝访问服务器。

  • OpenSSL SSLv2客户端空指针引用拒绝服务漏洞(CVE-2006-4343)

OpenSSL是一种开放源码的SSL实现,用来实现网络通信的高强度加密,现在被广泛地用于各种网络应用程序中。OpenSSL的协议实现在处理连接请求时存在问题,远程攻击者可能利用此漏洞导致服务器拒绝服务。SSLv2客户端的get_server_hello()函数没有正确地检查空指针。使用OpenSSL的受影响客户端如果创建了到恶意服务器的SSLv2连接,就会导致崩溃。

  • Linux Kernel空指针间接引用本地拒绝服务漏洞(CVE-2014-2678)

Linux kernel 3.14版本内,net/rds/iw.c中的函数rds_iw_laddr_check在实现上存在本地拒绝服务漏洞,本地用户通过盲系统调用没有RDS传输的系统上的RDS套接字,利用此漏洞可造成空指针间接引用和系统崩溃。

  • ISC BIND named拒绝服务漏洞(CVE-2015-5477)

ISC BIND 9.9.7-P2之前版本、9.10.2-P3之前版本,named存在安全漏洞,远程攻击者通过TKEY查询,利用此漏洞可造成拒绝服务(REQUIRE断言失败及程序退出,指针未初始化)。

此类漏洞还有很多,从给出的几个漏洞来看,空指针漏洞主要是以拒绝服务访问漏洞为主,空指针错误引用自然会到底程序出现错误,严重者会崩溃,从而引起拒绝服务访问。

3 基础篇:空指针验证方式

由空指针的错误引用导致的漏洞,其原理本身很简单:错误引用空指针,导致非法访问内存地址。

那到底什么是空指针漏洞呢?在计算机编程过程中使用指针时有两个重要的概念:空指针和野指针。那么在前面我们提到的空指针漏洞是不是就是我们在编程时所说的空指针呢?要弄清这个问题,首先需要知道编程领域中空指针和野指针分别是什么,还要弄清楚什么是空指针漏洞。

3.1 概念性验证

假如 char p,那么p是一个指针变量,该变量还没有指向任何内存空间,如果p = 0; p = 0L; p = ”; p = 3 – 3; p = 0 * 5; 中的任何一种赋值操作之后(对于 C 来说还可以是 p = (void)0;), p 都成为一个空指针,由系统保证空指针不指向任何实际的对象或者函数。反过来说,任何对象或者函数的地址都不可能是空指针。(比如这里的(void)0就是一个空指针。当然除了上面的各种赋值方式之外,还可以用 p = NULL; 来使 p 成为一个空指针。因为在很多系统中#define NULL (void)0。

3.1.1 内存管理之空指针

空指针指向了内存的什么地方呢?标准中并没有对空指针指向内存中的什么地方这一个问题作出规定,也就是说用哪个具体的地址值(0×0 地址还是某一特定地址)表示空指针取决于系统的实现。我们常见的 空指针一般指向 0 地址,即空指针的内部用全 0来表示 (zero null pointer,零空指针)。

对于NULL能表示空指针,是否还有其他值来表示空指针呢?在windows核心编程第五版的windows内存结构一章中,表13-1有提到NULL指针分配的分区,其范围是从0×00000000到0x0000FFFF。这段空间是空闲的,对于空闲的空间而言,没有相应的物理存储器与之相对应,所以对这段空间来说,任何读写操作都是会引起异常的。

从图中看出,对NULL指针分配的区域有0×10000之多,为什么分配如此大的空间?在定义NULL的时候,只使用了 0×00000000这么一个值,而在表13-1有提到NULL指针分配的分区包含了0×00000000-0x0000FFFF,是不是有点浪费空间了;这是和操作系统地址空间的分配粒度相关的,windows X86的默认分配粒度是64KB,为了达到对齐,空间地址需要从0×00010000开始分配,故空指针的区间范围有那么大。

3.1.2知识拓展之野指针

“野指针”又叫”悬浮指针”不是NULL指针,是指向”垃圾”内存的指针。

“野指针”的成因主要有三种:

1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如: char *p = NULL; char *str = (char *) malloc(100);

2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。

free和delete只是把指针所指的内存给释放掉,但并没有把指针本身干掉。free以后其地址仍然不变(非NULL),只是该地址对应的内存变成垃圾内存,p成了”野指针”。如果此时不把p设置为NULL,会让人误以为p是个合法的指针。如果程序比较长,我们有时记不住p所指的内存是否已经被释放,在继续使用p之前,通常会用语句if (p != NULL)进行防错处理。很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。

用free或delete释放了内存之后,就应立即将指针设置为NULL,防止产生”野指针”。内存被释放了,并不表示指针会消亡或者成了NULL指针。

3)指针操作超越了变量的作用范围。例如不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放,这种情况让人防不胜防,示例程序如下:

另外需要注意的是如果程序定义了一个指针,就必须要立即让它指向一个我们设定的空间或者把它设为NULL,如果没有这么做,那么这个指针里的内容是不可预知的,即不知道它指向内存中的哪个空间(即野指针),它有可能指向的是一个空白的内存区域,可能指向的是已经受保护的区域,甚至可能指向系统的关键内存,如果是那样就糟了,也许我们后面不小心对指针进行操作就有可能让系统出现紊乱,死机了。所以必须设定一个空间让指针指向它,或者把指针设为NULL。

3.2源码级验证

接下来就结合两个小的实验例子看看空指针,及使用空指针的后果。

3.2.1指针使用前期对比

本例是要验证指针变量在初始化前后的状况,下图是一段代码:

代码很简单只是验证指针变量在赋值与未赋值分别指向的空间。代码中要打印的值:

  1. 指针变量初始化之前的地址
  2. 指针变量初始化之前的值
  3. 指针变量初始化之后的地址
  4. 指针变量初始化之后的值

编译之后,运行三次程序看运行的结果:

从三次运行结果来看:

  1. 每次打印指针变量的地址都不同,因为每次运行程序,P指针变量的地址都在变动。
  2. 同一次打印中指针变量在初始化之前与初始化之后的地址没有变化。因为指针变量也是变量,变量在其生命周期中值可以变动,但是地址不会改变。
  3. 每次打印中指针变量在初始化之前的值发生了变化。指针变量的值本身也是指向一块内存地址,在初始化之前该变量不指向任何内存地址,所以该变量的值就是一个随机值(也就是指向随机内存地址)。
  4. 每次打印中指针变量在初始化之后的值没有发生变化,在指针变量初始化之后P=0,所以在内存初始化的指针变量指向了内存地址都为0×00000000的位置。在每次打印中指针变量在初始化之后的值就不会发生变化。

3.2.2指针使用后期对比

针对指针变量在使用完毕后,内存释放之后的情况对比,其源码如下:

代码没什么复杂逻辑,只是想验证一下在指针变量释放后, P=NULL之前的野指针与P=NULL之后的指针状况,打印的内容:

  1. 指针变量P开始的地址与值
  2. 指针变量P在分配内存空间之后的地址与值
  3. 指针变量P在释放内存空间之后的地址与值
  4. 指针变量P在P=NULL之后的地址与值

下图是在编译之后运行的结果:

a. 指针变量在声明之后一直到最后的程序结束,指针变量的地址一直没有变动为0x35f778。 b. 定义指针变量时其值为0×00000000 c. 在申请新的内存之后,指针变量的值为申请内存的地址0x6e7a78 d. 在内存释放后,P变成野指针,但是此时P的值仍然是申请的内存地址0x6e7a78,但是此时P指针已经不能再使用。 e. 在P=NULL,p重新指向了地址0×00000000处。

由此可见,我们在释放指针变量后,指针变量会变成野指针,如果此时引用该指针会出现非法访问,因此需要在释放指针变量后将指针变量指向空。

3.3可视化内存验证

为了能够更加直观的查看指针变量在内存中的变化,下面就结合动态调试的技术看看指针变量在整个使用过程中的变化情况。下面是一段程序代码:

在这里,我们使用OD动态调试器,来看看调用printf函数的情况:

a. 第一条打印语句

printf("p address :%p, value :%08x\n", &p, p);

在调用printf前其内存情况:

可知指针变量P的值为EAX=[EBP-4],P的地址ECX=EBP-4,此时的寄存器值:

调用printf之后的值刚好是这两个值

b.第二条打印语句printf(“p intialized address :%p, value :%08x\n”, &p, p);在调用printf前其内存情况:

可知指针变量P的值为EDX=[EBP-4],P的地址EAX=EBP-4,此时的寄存器值:

image013

调用printf之后的值刚好是这两个值:

c. 第三条打印语句printf(“p free address :%p, value :%08x\n”, &p, p);在调用printf前其内存情况:

可知指针变量P的值为EAX=[EBP-4],P的地址ECX=EBP-4,此时的寄存器值:

image016

调用printf之后的值刚好是这两个值:

d. 第四条打印语句printf(“p ultimate address :%p, value :%08x\n”, &p, p);在调用printf前其内存情况:

可知指针变量P的值为EDX=[EBP-4],P的地址EAX=EBP-4,此时的寄存器值:

调用printf之后的值刚好是这两个值:

3.4 概念总结之空指针漏洞

前面对什么是空指针,什么是野指针做了讲解和验证。

在编程领域的空指针是指向NULL的指针,也就是说指向零页内存的指针叫空指针。对于未初始化的指针,释放内存而未将指针置为NULL和指针指向超出范围的情况称为野指针。那么在第二节中列举的空指针漏洞及未列举的空指针漏洞是不是都是由于引用零页内存导致的呢(比如CVE-2014-2678)?其实不然,有些漏洞是由于引用未初始化的指针或是引用超出范围的指针所导致,而这类漏洞应该说是由于错误的引用了野指针。比如最新的BIND漏洞(CVE-2015-5477):

但是到目前为止还没用听说过哪个漏洞命名为野指针漏洞,而更多的是空指针漏洞。也就是说在计算机安全领域中由空指针或是野指针导致的漏洞统一叫做空指针漏洞。

…未完待续 在下一次《空指针漏洞防护技术-高级篇》中,我们将介绍空指针利用及Windows 8中相应的防护机制。

空指针漏洞防护技术(初级篇),首发于博客 – 伯乐在线

一个缓冲区溢出漏洞的简易教程

这篇文章类似于“傻瓜系列之利用缓冲区溢出”。在这类漏洞中,我们的做法是利用网络,程序控制器,输入等等,发送超大的数据缓冲区给程序,覆盖程序内存的重要部分。在这些缓冲区覆盖程序内存之后,我们可以重定向程序的执行流并运行注入代码。

首先,我们需要做的是查明程序的哪一部分可以用来重写内存。处理这个任务的过程叫作“fuzzing”。我们可以为Metasploit框架中的各种协议找到若干个fuzzer(执行fuzzing任务的工具)。

接下来这个例子中,我们用metasploit对一个ftp服务器进行fuzz:

Fuzzer运行几分钟后,程序就崩溃了,见下图:

在Metasploit窗口中,我们可以看到崩溃缓冲区的长度:

在分析所有输出内容之后,我们可以得出:在ftp服务器通过用户命令发送了一个大于250的缓冲区后,程序崩溃了。

我们可以使用python来重现崩溃:

现在,我们重新实施这次攻击,但是首先要将FTP SERVER进程附加到一个调试器上,在这里我们用的调试器是OLLYDBG。

在实施攻击之后,我们可以很直观地看到ESP,EDI和EIP寄存器被覆盖。

稍微研究一下,大家可以发现:EIP控制程序的执行流,如果可以重写EIP,那么就可以手动重定向程序的执行流。EIP指向下一个待执行地址。

在这里,我们需要知道要重写的EIP缓冲区长度。我们可以在metasplpit中用pattern_create创建一种模式,并且作为一个缓冲区使用,来获取重写EIP的4个字节的位置。

把这些命令添加到我们的利用代码中,并再次运行:

现在,我们可以看到程序内存中的模式。

现在需要使用pattern_offset(偏移量模式)来找到那4个字节的准确位置(只要把4个字节作为一个脚本参数粘贴到EIP里面)。

由于在EIP之后ESP就被重写,我们可以写出这样一段利用代码如下:

并且,如果重新加载,在OLLY里面,可以看到它运行得很好。

在EIP之后,是这样改写ESP的:

那么在EIP里面我们需要做什么呢?将我们的恶意代码放到重写EIP的代码后面,然后需要做的只是简单的JMP ESP。

记住,EIP将包含下一条待执行指令的地址,所以此时需要做的是找到包含JMP ESP的地址。我们可以在OLLY(在E标签页)中进行查找。

一个简单的命令检索将会返回给我们一个地址。

现在,我们拷贝这个地址:

最后,我们需要做的是,在实行攻击之后,加入并执行我们的shell代码。我们可以用metasploit生成这些shellcode。

现在我们的利用代码如下。注意一下案例中CPU的ENDIAN,在EIP寄存器中我们会用到小端格式。

现在,如果我们再次实行攻击,将会运行我们的shellcode。

好的,现在我们可以生成另外的shellcode来执行不同的任务。

我们可以生成一段反向连接的shell代码,来访问我们的受害主机。

把这行代码我们的利用代码中,

最后运行利用代码:

我们的利用代码编写完成

提示:注意一些特殊字符。如果在缓冲区中间,利用代码被截断,可能是由于一些特殊字符导致的。特殊字符诸如“xa0″、 “|x00″等,会截断shellcode,你必须通过测试找到这些字符,并且在shellcode中避免用到,可别说我没提醒过你!

一个缓冲区溢出漏洞的简易教程,首发于博客 – 伯乐在线

记一次Linux服务器上查杀木马经历

开篇前言

Linux服务器一直给我们的印象是安全、稳定、可靠,性能卓越。由于一来Linux本身的安全机制,Linux上的病毒、木马较少,二则由于宣称Linux是最安全的操作系统,导致很多人对Linux的安全性有个误解:以为它永远不会感染病毒、木马;以为它没有安全漏洞。所以很多Linux服务器都是裸奔的。其实在这次事件之前,我对Linux的安全性方面的认识、重视程度也是有所不足的。系统的安全性是相对而言的,没有绝对的安全,风险无处不在。

案例描述

我们在云端(中信国际电讯CPC)的一台Linux 应用服务器时不时出现网络中断情况,最开始反馈到系统管理员和网络管理员哪里,以为是网络方面的问题。在监控系统后,发现在一些时间段出现高流量的情况,分析发现这台Linux服务器只安装了Tomcat应用程序,没有任何其它应用程序。产生如此大的流量很不正常,而且出现网络中断的时刻,就是系统产生高流量的时刻。当然这些都是我后来才了解到的一些情况,我没有这台服务器的权限,系统管理员找我看看能分析出啥问题,所以将root账号权限给了我。

案例分析

我连接到服务器后,运行ifconfig命令,检查网卡的发送、接收数据情况,如下所示,网卡eth0累计发送了12.3TB的数据。这明显不太正常,显然有应用程序一直在往外发包。我特意对比了另外一台正常的服务器后,验证了这个事实。

那么是那个应用程序在一直往外发送包呢? 我首先检查了Linux系统日志,发现了一些错误、告警信息。但是作用不大。于是在服务器上安装了NetHogs应用程序,实时监控Linux进程的网络带宽占用情况。

监控过程确实发现了一些异常情况的进程:

1:/home/WDPM/Development/WebServer/apache-tomcat-7.0.61/cmys 一直在往外发包

2:/usr/bin/bsd-port/agent 一直在往外发包。

3:./cmys一直在往外发包

4:不时出现下面大量异常进程

[root@LNX17 /]# ps -ef | grep getty
root      2012     1  0 May22 tty2     00:00:00 /sbin/mingetty /dev/tty2
root      2014     1  0 May22 tty3     00:00:00 /sbin/mingetty /dev/tty3
root      2018     1  0 May22 tty4     00:00:00 /sbin/mingetty /dev/tty4
root      2020     1  0 May22 tty5     00:00:00 /sbin/mingetty /dev/tty5
root      2022     1  0 May22 tty6     00:00:00 /sbin/mingetty /dev/tty6
root     13835 32735  0 01:02 pts/0    00:00:00 grep getty
[root@LNX17 tmp]# ll /usr/bin/bsd-port/
total 2324
-rwxr-xr-x. 1 root root 1135000 Jul 17 08:28 agent
-rwxr-xr-x. 1 root root       4 Jul 17 08:28 agent.conf
-rw-r--r--. 1 root root      27 Jul 21 12:42 cmd.n
-rw-r--r--. 1 root root      73 Aug 21 21:30 conf.n
-rwxr-xr-x. 1 root root 1223123 Aug 21 04:08 getty
-rwxr-xr-x. 1 root root       5 Aug 21 04:08 getty.lock

搜索/usr/bin/bsd-port/agent等进程相关资料,发现很多关于木马、后门方面的文章,严重怀疑服务器被挂马了。手工杀进程或手工删除/home/WDPM/Development/WebServer/apache-tomcat-7.0.61/cmys文件,发现不过一会儿,又会出现相同的进程和文件。于是下载安装了AVG ANTIVIRUS FREE – FOR LINUX这款杀毒软件,但是启动服务失败,不想折腾,于是安装了ClamAV 杀毒软件

ClamAV介绍

ClamAV是一个在命令行下查毒软件,因为它不将杀毒作为主要功能,默认只能查出您计算机内的病毒,但是无法清除,至多删除文件。ClamAV可以工作很多的平台上,但是有少数无法支持,这就要取决您所使用的平台的流行程度了。另外它主要是来防护一些WINDOWS病毒和木马程序。另外,这是一个面向服务端的软件。

下载ClamAV安装包

ClamAV的官方下载地址为http://www.clamav.net/download.html 我直接使用wget下载源码安装文件。

[root@LNX17 tmp]# wget http://nchc.dl.sourceforge.net/project/clamav/clamav/0.97.6/clamav-0.97.6.tar.gz
--2015-08-21 21:58:36--  http://nchc.dl.sourceforge.net/project/clamav/clamav/0.97.6/clamav-0.97.6.tar.gz
Resolving nchc.dl.sourceforge.net... 211.79.60.17, 2001:e10:ffff:1f02::17
Connecting to nchc.dl.sourceforge.net|211.79.60.17|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14765896 (14M) [application/x-gzip]
Saving to: “clamav-0.97.6.tar.gz”
 
100%[==============================================================>] 14,765,896   652K/s   in 71s     
 
2015-08-21 21:59:48 (204 KB/s) - “clamav-0.97.6.tar.gz” saved [14765896/14765896]
 
[root@LNX17 tmp]# wget http://nchc.dl.sourceforge.net/project/libpng/zlib/1.2.7/zlib-1.2.7.tar.gz
--2015-08-21 22:00:24--  http://nchc.dl.sourceforge.net/project/libpng/zlib/1.2.7/zlib-1.2.7.tar.gz
Resolving nchc.dl.sourceforge.net... 211.79.60.17, 2001:e10:ffff:1f02::17
Connecting to nchc.dl.sourceforge.net|211.79.60.17|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 560351 (547K) [application/x-gzip]
Saving to: “zlib-1.2.7.tar.gz”
 
100%[=============================================================>] 560,351      287K/s   in 1.9s    
 
2015-08-21 22:00:26 (287 KB/s) - “zlib-1.2.7.tar.gz” saved [560351/560351]

1、zlib-1.2.7.tar.gz安装

[root@LNX17 tmp]# tar xvzf zlib-1.2.7.tar.gz
[root@LNX17 tmp]# cd zlib-1.2.7
[root@LNX17 zlib-1.2.7]# ./configure 
Checking for gcc...
Checking for shared library support...
Building shared library libz.so.1.2.7 with gcc.
Checking for off64_t... Yes.
Checking for fseeko... Yes.
Checking for strerror... Yes.
Checking for unistd.h... Yes.
Checking for stdarg.h... Yes.
Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf().
Checking for vsnprintf() in stdio.h... Yes.
Checking for return value of vsnprintf()... Yes.
Checking for attribute(visibility) support... Yes.
Looking for a four-byte integer type... Found.
[root@LNX17 zlib-1.2.7]# make && make install
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -c -o example.o test/example.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o adler32.o adler32.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o crc32.o crc32.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o deflate.o deflate.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o infback.o infback.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o inffast.o inffast.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o inflate.o inflate.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o inftrees.o inftrees.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o trees.o trees.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o zutil.o zutil.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o compress.o compress.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o uncompr.o uncompr.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o gzclose.o gzclose.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o gzlib.o gzlib.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o gzread.o gzread.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN   -c -o gzwrite.o gzwrite.c
ar rc libz.a adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o 
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o example example.o -L. libz.a
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -c -o minigzip.o test/minigzip.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o minigzip minigzip.o -L. libz.a
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/adler32.o adler32.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/crc32.o crc32.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/deflate.o deflate.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/infback.o infback.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/inffast.o inffast.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/inflate.o inflate.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/inftrees.o inftrees.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/trees.o trees.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/zutil.o zutil.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/compress.o compress.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/uncompr.o uncompr.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzclose.o gzclose.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzlib.o gzlib.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzread.o gzread.c
gcc -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -DPIC -c -o objs/gzwrite.o gzwrite.c
gcc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map -O3  -fPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o libz.so.1.2.7 adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo  -lc 
rm -f libz.so libz.so.1
ln -s libz.so.1.2.7 libz.so
ln -s libz.so.1.2.7 libz.so.1
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o examplesh example.o -L. libz.so.1.2.7
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o minigzipsh minigzip.o -L. libz.so.1.2.7
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -D_FILE_OFFSET_BITS=64 -c -o example64.o test/example.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o example64 example64.o -L. libz.a
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -I. -D_FILE_OFFSET_BITS=64 -c -o minigzip64.o test/minigzip.c
gcc -O3  -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN -o minigzip64 minigzip64.o -L. libz.a
cp libz.a /usr/local/lib
chmod 644 /usr/local/lib/libz.a
cp libz.so.1.2.7 /usr/local/lib
chmod 755 /usr/local/lib/libz.so.1.2.7
cp zlib.3 /usr/local/share/man/man3
chmod 644 /usr/local/share/man/man3/zlib.3
cp zlib.pc /usr/local/lib/pkgconfig
chmod 644 /usr/local/lib/pkgconfig/zlib.pc
cp zlib.h zconf.h /usr/local/include
chmod 644 /usr/local/include/zlib.h /usr/local/include/zconf.h

2:添加用户组clamav和组成员clamav

[root@LNX17 zlib-1.2.7]# groupadd clamav
[root@LNX17 zlib-1.2.7]# useradd -g clamav -s /bin/false -c "Clam AntiVirus" clamav
[root@LNX17 zlib-1.2.7]#

3:安装Clamav-0.97.6

[root@LNX17 tmp]# tar xvzf clamav-0.97.6.tar.gz
[root@LNX17 tmp]# cd clamav-0.97.6
[root@LNX17 clamav-0.97.6]# ./configure --prefix=/opt/clamav  --disable-clamav
[root@LNX17 clamav-0.97.6]# make
[root@LNX17 clamav-0.97.6]# make install

配置Clamav

1:创建目录

[root@LNX17 clamav-0.97.6]# mkdir /opt/clamav/logs 
 
[root@LNX17 clamav-0.97.6]# mkdir /opt/clamav/updata

2:创建文件

[root@LNX17 clamav-0.97.6]# touch /opt/clamav/logs/freshclam.log
[root@LNX17 clamav-0.97.6]# touch /opt/clamav/logs/clamd.log
[root@LNX17 clamav-0.97.6]# 
 
[root@LNX17 clamav-0.97.6]# cd /opt/clamav/logs
[root@LNX17 clamav]# cd logs
[root@LNX17 logs]# ls
clamd.log  freshclam.log
[root@LNX17 logs]# ls -lrt
total 0
-rw-r--r--. 1 root root 0 Aug 21 22:10 freshclam.log
-rw-r--r--. 1 root root 0 Aug 21 22:10 clamd.log

3:修改属主

[root@LNX17 logs]# chown clamav:clamav clamd.log 
[root@LNX17 logs]# chown clamav:clamav freshclam.log 
[root@LNX17 logs]# ls -lrt
total 0
-rw-r--r--. 1 clamav clamav 0 Aug 21 22:10 freshclam.log
-rw-r--r--. 1 clamav clamav 0 Aug 21 22:10 clamd.log
[root@LNX17 logs]#

4:修改配置文件

#vi /opt/clamav

/etc/clam.conf
# Example 注释掉这一行. 第8 行

LogFile /opt/clamav/logs/clamd.log 删掉前面的注释目录改为/opt/clamav/logs/clamd.log

PidFile /opt/clamav/updata/clamd.pid 删掉前面的注释路径改为/opt/clamav/updata/clamd.pid

DatabaseDirectory /opt/clamav/updata 同上

#vi /opt/clamav

/etc/clamfreshclam.conf , 将Example 这一行注释掉。否则在更新反病毒数据库是就有可能出现下面错误

[root@LNX17 clamav]# /opt/clamav/bin/freshclam

ERROR: Please edit the example config file /opt/clamav/etc/freshclam.conf

ERROR: Can’t open/parse the config file /opt/clamav/etc/freshclam.conf

clip_image005

5:升级病毒库

[root@LNX17 etc]# /opt/clamav/bin/freshclam

ERROR: Can’t change dir to /opt/clamav/share/clamav

出现上面错误,直接创建一个文件夹并授权给clamav用户即可。

[root@LNX17 etc]# mkdir -p /opt/clamav/share/clamav
[root@LNX17 etc]# chown clamav:clamav /opt/clamav/share/clamav
[root@LNX17 etc]# 
 
[root@LNX17 etc]# /opt/clamav/bin/freshclam
ClamAV update process started at Fri Aug 21 22:42:18 2015
WARNING: Your ClamAV installation is OUTDATED!
WARNING: Local version: 0.97.6 Recommended version: 0.98.7
DON'T PANIC! Read http://www.clamav.net/support/faq
nonblock_connect: connect timing out (30 secs)
Can't connect to port 80 of host database.clamav.net (IP: 211.239.150.206)
Trying host database.clamav.net (120.29.176.126)...
nonblock_recv: recv timing out (30 secs)
WARNING: getfile: Download interrupted: Operation now in progress (IP: 120.29.176.126)
WARNING: Can't download main.cvd from database.clamav.net
Trying again in 5 secs...
ClamAV update process started at Fri Aug 21 23:03:32 2015
WARNING: Your ClamAV installation is OUTDATED!
WARNING: Local version: 0.97.6 Recommended version: 0.98.7
DON'T PANIC! Read http://www.clamav.net/support/faq
Downloading main.cvd [100%]
main.cvd updated (version: 55, sigs: 2424225, f-level: 60, builder: neo)
Downloading daily.cvd [100%]
daily.cvd updated (version: 20817, sigs: 1537382, f-level: 63, builder: neo)
Downloading bytecode.cvd [100%]
bytecode.cvd updated (version: 268, sigs: 47, f-level: 63, builder: anvilleg)
Database updated (3961654 signatures) from database.clamav.net (IP: 219.94.128.99)

由于ClamAV不是最新版本,所以有告警信息。可以忽略或升级最新版本。病毒库需要定期升级,例如我第二天升级病毒库

[root@LNX17 ~]# /opt/clamav/bin/freshclam
ClamAV update process started at Mon Aug 24 10:10:25 2015
WARNING: Your ClamAV installation is OUTDATED!
WARNING: Local version: 0.97.6 Recommended version: 0.98.7
DON'T PANIC! Read http://www.clamav.net/support/faq
main.cvd is up to date (version: 55, sigs: 2424225, f-level: 60, builder: neo)
Downloading daily-20818.cdiff [100%]
Downloading daily-20819.cdiff [100%]
Downloading daily-20820.cdiff [100%]
Downloading daily-20821.cdiff [100%]
Downloading daily-20822.cdiff [100%]
Downloading daily-20823.cdiff [100%]
Downloading daily-20824.cdiff [100%]
Downloading daily-20825.cdiff [100%]
Downloading daily-20826.cdiff [100%]
Downloading daily-20827.cdiff [100%]
Downloading daily-20828.cdiff [100%]
Downloading daily-20829.cdiff [100%]
daily.cld updated (version: 20829, sigs: 1541624, f-level: 63, builder: neo)
bytecode.cvd is up to date (version: 268, sigs: 47, f-level: 63, builder: anvilleg)
Database updated (3965896 signatures) from database.clamav.net (IP: 203.178.137.175)

6:ClamAV 使用

可以使用/opt/clamav/bin/clamscan -h查看相应的帮助信息

· 扫描所有用户的主目录就使用 clamscan -r /home

· 扫描您计算机上的所有文件并且显示所有的文件的扫描结果,就使用 clamscan -r /

· 扫描您计算机上的所有文件并且显示有问题的文件的扫描结果,就使用 clamscan -r –bell -i /

执行下面命令扫描根目录下面的所有文件。如下所示:56个文件被感染了。基本上都是Linux.Trojan.Agent和Linux.Backdoor.Gates等。

/opt/clamav/bin/clamscan -r –bell -i

手工删除这些文件。然后重新扫描一下,发现木马已经被清理完成。但是按照网上资料进一步查找发现木马启动程序

[root@LNX17 ~]# cd /etc/init.d/
[root@LNX17 init.d]# ls Db*
DbSecurityMdt  DbSecuritySpt
[root@LNX17 init.d]# ls sel*
selinux
[root@LNX17 init.d]# more selinux 
#!/bin/bash
/usr/bin/bsd-port/getty
[root@LNX17 init.d]# more DbSecuritySpt 
#!/bin/bash
/home/WDPM/Development/WebServer/apache-tomcat-7.0.61/cmys
[root@LNX17 init.d]# more DbSecurityMdt 
#!/bin/bash
/root/cmy6
[root@LNX17 init.d]# more DbSecurityMdt 
#!/bin/bash
/root/cmy6
[root@LNX17 bin]# ls bsd*
 
agent.conf cmd.n conf.n getty.lock
 
[root@LNX17 bin]# cd bsd-port/
 
[root@GETLNX17 bsd-port]# ls
 
agent.conf cmd.n conf.n getty.lock
 
[root@LNX17 bsd-port]# more agent.conf 
 
3341
 
[root@LNX17 bsd-port]# more getty.lock 
 
1013
 
[root@LNX17 bsd-port]# cd ..
 
[root@LNX17 bin]# rm -rf bsd-port

此时在用nethogs监控进程的网络流量,发现已经没有异常进程了,应该算是彻底清除了。

 

关于Linux.Backdoor.Gates,看到一篇介绍资料了相关内容:Linux.BackDoor.Gates.5——又一针对Linux的木马, 具体内容如下所示:

——————————————————————————————————————————

某些用户有一种根深蒂固的观念,就是目前没有能够真正威胁Linux内核操作系统的恶意软件,然而这种观念正在面临越来越多的挑战。与4月相比,2014年5月Doctor Web公司的技术人员侦测到的Linux恶意软件数量创下了新纪录,六月份这些恶意软件名单中又增加了一系列新的Linux木马,这一新木马家族被命名为Linux.BackDoor.Gates。

在这里描述的是恶意软件家族Linux.BackDoor.Gates中的一个木马:Linux.BackDoor.Gates.5,此恶意软件结合了传统后门程序和DDoS攻击木马的功能,用于感染32位Linux版本,根据其特征可以断定,是与Linux.DnsAmp和Linux.DDoS家族木马同出于一个病毒编写者之手。新木马由两个功能模块构成:基本模块是能够执行不法分子所发指令的后门程序,第二个模块在安装过程中保存到硬盘,用于进行DDoS攻击。Linux.BackDoor.Gates.5在运行过程中收集并向不法分子转发受感染电脑的以下信息:

CPU核数(从/proc/cpuinfo读取)。

CPU速度(从/proc/cpuinfo读取)。

CPU使用(从/proc/stat读取)。

Gate’a的 IP(从/proc/net/route读取)。

Gate’a的MAC地址(从/proc/net/arp读取)。

网络接口信息(从/proc/net/dev读取)。

网络设备的MAC地址。

内存(使用/proc/meminfo中的MemTotal参数)。

发送和接收的数据量(从/proc/net/dev读取)。

操作系统名称和版本(通过调用uname命令)。

启动后,Linux.BackDoor.Gates.5会检查其启动文件夹的路径,根据检查得到的结果实现四种行为模式。

如果后门程序的可执行文件的路径与netstat、lsof、ps工具的路径不一致,木马会伪装成守护程序在系统中启动,然后进行初始化,在初始化过程中解压配置文件。配置文件包含木马运行所必须的各种数据,如管理服务器IP地址和端口、后门程序安装参数等。

根据配置文件中的g_iGatsIsFx参数值,木马或主动连接管理服务器,或等待连接:成功安装后,后门程序会检测与其连接的站点的IP地址,之后将站点作为命令服务器。

木马在安装过程中检查文件/tmp/moni.lock,如果该文件不为空,则读取其中的数据(PID进程)并“干掉”该ID进程。然后Linux.BackDoor.Gates.5会检查系统中是否启动了DDoS模块和后门程序自有进程(如果已启动,这些进程同样会被“干掉”)。如果配置文件中设置有专门的标志g_iIsService,木马通过在文件/etc/init.d/中写入命令行#!/bin/bash\n<path_to_backdoor>将自己设为自启动,然后Linux.BackDoor.Gates.5创建下列符号链接:

ln -s /etc/init.d/DbSecuritySpt /etc/rc1.d/S97DbSecuritySpt

ln -s /etc/init.d/DbSecuritySpt /etc/rc2.d/S97DbSecuritySpt

ln -s /etc/init.d/DbSecuritySpt /etc/rc3.d/S97DbSecuritySpt

ln -s /etc/init.d/DbSecuritySpt /etc/rc4.d/S97DbSecuritySpt

如果在配置文件中设置有标志g_bDoBackdoor,木马同样会试图打开/root/.profile文件,检查其进程是否有root权限。然后后门程序将自己复制到/usr/bin/bsd-port/getty中并启动。在安装的最后阶段,Linux.BackDoor.Gates.5在文件夹/usr/bin/再次创建一个副本,命名为配置文件中设置的相应名称,并取代下列工具:

/bin/netstat

/bin/lsof

/bin/ps

/usr/bin/netstat

/usr/bin/lsof

/usr/bin/ps

/usr/sbin/netstat

/usr/sbin/lsof

/usr/sbin/ps

木马以此完成安装,并开始调用基本功能。

执行另外两种算法时木马同样会伪装成守护进程在被感染电脑启动,检查其组件是否通过读取相应的.lock文件启动(如果未启动,则启动组件),但在保存文件和注册自启动时使用不同的名称。

与命令服务器设置连接后,Linux.BackDoor.Gates.5接收来自服务器的配置数据和僵尸电脑需完成的命令。按照不法分子的指令,木马能够实现自动更新,对指定IP地址和端口的远程站点发起或停止DDoS攻击,执行配置数据所包含的命令或通过与指定IP地址的远程站点建立连接来执行其他命令。

此后门程序的主要DDoS攻击目标是中国的服务器,然而不法分子攻击对象也包括其他国家。下图为利用此木马进行的DDoS攻击的地理分布:

参考资料:

http://blog.csdn.net/liukeforever/article/details/38560363

http://vekergu.blog.51cto.com/9966832/1619266

http://blog.csdn.net/liukeforever/article/details/38560363

http://bbs.appstar.com.cn/thread-10205-1-1.html

http://yangrong083.blog.163.com/blog/static/113406097201371235159424/

记一次Linux服务器上查杀木马经历,首发于博客 – 伯乐在线

危险的文件夹上传框

分享一篇老文章。前些年在 ASRC 上的看了一篇文章「Html5新功能上的ui-redressing」后,写的一些改进方案。

文件对话框

文件上传对话框是一直以来就存在的网页控件。

到了 HTML5 时代,增加了更多的功能,例如支持文件多选。Chrome 甚至还支持「上传文件夹」这一私有特征:

<input type="file" webkitdirectory />

在给用户方便的同时,其安全隐患也逐渐出现。用户平时在下载时,理所当然的弹出的是保存对话框,因此常常不仔细看就做出了选择。

这极有可能被攻击者所利用。一些恶意网站在用户点击下载时,故意弹出一个上传对话框。只要用户一疏忽,就把选中的文件夹给上传了!

下载对话框

上传对话框

当然,仅仅依靠默认的上传,这种攻击方式仍有较大难度。因为整个文件夹可能非常大,上传需要很久的时间。

如果用户等了半天也没看见下载进度,或许就会刷新重试,甚至放弃了。

选择即授权

然而,HTML5 带来了一个新的规范 —— File API,允许脚本访问文件。

但由于沙箱限制,脚本无法访问任何一个本地文件,除非用户主动授权。如何授权?最常见的,就是「上传对话框」了。

事实上,如今的上传对话框,早已不是从前「选择哪个文件」的功能,而是「允许脚本访问哪个文件」的权限申请!只不过界面上没有提示罢了。

例如,一个传统的文件上传控件。当用户选中文件后,即可通过 File API 读取文件内容:

<input id="dialog" type="file" />
<script>
    dialog.onchange = function(e) {
        var reader = new FileReader();
        reader.onload = function() {
            console.log(this.result);
        };
        reader.readAsText(this.files[0]);
    };
</script>

或许你已注意到,File 位于files[]而不是file,这正是给文件夹预留的!

在 Chrome 里,上传控件只要加上 webkitdirectory 属性,就变成文件夹选择框。这时一旦用户选中某个文件夹,瞬间就赐予脚本访问整个文件夹的权限!

<input id="dialog" type="file" webkitdirectory />
<script>
    dialog.onchange = function(e) {
        var files = this.files;
        var table = {};

        for (var i = 0; i < files.length; i++) {
            var f = files[i];
            var dt = new Date(f.lastModified);

            table[i] = {
                path: f.webkitRelativePath,
                size: f.size,
                modified: dt.toLocaleString()
            };
        }

        console.table(table);
    };
</script>

演示

于是,用户本想将文件保存在桌面上,结果却将桌面上的所有资料,被攻击者的脚本拿到!

优化上传

一旦脚本可主动访问,我们可以用更灵活的方式处理这些文件,无需再用传统落后的方式上传。我们可以直接在前端分析出「有价值」的文件,例如:

  • 备注文件、脚本、批处理、电子表格等,很可能存有一些敏感信息,而且体积小价值大,优先将其上传;
  • 图片则可通过 canvas 缩放,先传较小的缩略图。当接收端发现有意义时,再传输原文件。
  • 对于一些体积较大但意义不大的文件,则可以直接忽略。

由于 HTTP 上传是没有压缩的,因此在传输文本文件时效率很低。我们可以借助 Flash 内置的LZMA压缩算法,极大提升传输效率。如果不支持 Flash,也可以使用asm.js版的 LZMA 压缩器,配合Worker线程在后台压缩和传输。

同时,将多个小文件合并后再压缩,可进一步提高压缩率。再多开几个连接,上传速度即可大幅提升。

续点上传

不过即使再优化,仍有传不完的可能。因此,我们得将没传完的内容储存起来,当用户再次回来时,继续传输。

得益于 HTML5 的 Storage API,这不难实现。

事实上,当用户授权了某个文件夹时,我们首先要做的不是发送,而是读出文件夹内容,立即备份到 Storage 里。毕竟,文件的读取需要用户主动配合,是非常珍贵的;而访问 Storage 则无需任何条件。

当备份完成后,再从 Storage 里读取、发送、删除。这样,即使中途页面刷新或关闭了,下次回来时,仍能从 Storage 中继续。

考虑到每个域的 Storage 容量有限,我们可以使用iframe嵌入多个不同域的页面,然后通过postMessage进行数据的分发和汇总,这样就不受容量限制了。

当然,能不能无限容量还得看浏览器策略,不然硬盘会被撑满

将数据存放在 Storage 里还有另一个好处,即使用户永不回来,但数据仍持久保存着。只要以后一旦进入其他的站点,只要是我们可控的,仍有机会继续上传。(例如将用户引到我们布置了 XSS 的站点上)

延长上传

在之前《延长 XSS 生命期》 中介绍过,可以使用各种黑魔法来提升脚本有效期。

利用这个原理,即使当前页面关闭,其他关联的页面也能继续上传。事实上,除了文中提到的方法,如今还有一个新的 API —— SharedWorker,它可以让 Worker 共享于多个页面,只要有一个存在,线程就不会停止。可以让续点时丢失的数据更少。

视觉欺骗

由于上传控件有着独特的界面,如何才能让用户主动去点呢?万能的方法是点击劫持(Clickjacking)。

不过本场景无需这么麻烦,只需简单的调用控件的click方法就可以了。

<a href="ed2k://|file|xxxxxxxxxx.avi" id="download">高速下载</a>
<script>
    var uploader = document.createElement('input');
    uploader.type = 'file';
    uploader.webkitdirectory = true;

    download.onclick = function(e) {
        uploader.click();       // 弹出授权对话框
        e.preventDefault();     // 屏蔽下载对话框
    };
</script>

演示

我们将屏蔽超链接的默认行为,将其传递给上传控件,即可召唤出「文件夹授权」对话框了!

同时,为了不让眼亮的人发现对话框上的破绽,我们使用一些第三方的下载方式,例如电驴、迅雷等等,让人们误以为就是这样的。

当然,这只是一个小例子。只要页面做的真实,下载内容引人入胜,用户自然就会中招。

后记

本以为 webkitdirectory 的这个私有属性很快就会放弃,至少是更强的安全提示。不过至少现在也没更新,因此上网时还是要多加留心,看清楚了再做决定。

当然,这篇只是最早的「交互欺骗」探索。事实上,深入挖掘会发现可利用点远不仅此。

如今的浏览器在视觉、音频上的体验已经非常完善,攻击者甚至可以在网页里,高度模拟一个本地应用的交互效果。让用户误以为是浏览器之外的程序弹出的界面,从而进行钓鱼。

危险的文件夹上传框,首发于博客 – 伯乐在线

甲骨文:不行,你不能看我们的源代码!

【伯乐在线导读】:是人写的软件,都不可避免有漏洞。而发现漏洞的,并不只是软件开发商,也有独立第三方机构或个人。所以,业界不少知名公司有对外的漏洞悬赏计划,比如:Facebook谷歌Twitter、微软、Paypal。

咦,为啥小编没听过甲骨文的漏洞悬赏计划呢?各位接着往下看。

8月10日,甲骨文 CSO(首席安全官)Mary Ann Davidson 在企业博客上发布一篇文章,怒斥客户通过逆向工程看源码找漏洞的行为。这篇文章在 Reddit 引发大量讨(tu)论(cao),本文末尾摘录的 3 条。该文因争议太大,后来被删,不过有 谷歌快照 & 时光机存档了。

下面是伯乐在线翻译组黄小非的全文翻译。

Mary Ann Davidson

No, You Really Can’t | 不行,就是不让你看

我最近已经写了很多东西了。其中一些是和我姐姐一起,使用笔名Maddi Davidson写的凶案悬疑小说。最近,我们一直在写一些较短的凶杀故事,尝试用一些新主意来“杀死”故事中的被害者(诚实地说,在现实中我真会去想怎么把这些凶杀情节实践到那些连车距都保持不好的白痴司机身上)。

对于我来说,写悬疑小说真的比我写其他类型的东西要有趣得多。最近我发现,企图通过逆向工程来挑我们毛病的客户人数显著地增加了(诶,大大叹口气吧)。所以你也就不难理解为什么我近来大量给客户写信,都是以这样的内容来开头:“Hi~, Howizt,你好”(译注:看似很友好客套),可是结尾却变成了:“请您遵循许可证协议,不要再对我们进行逆向工程看源码了。”

我能理解,在我们生活的世界上,几乎每天都有人在说数据出了问题,然后还会有超级无敌多的匿名入侵记录,这一定是敌对分子搞破坏造成的。所以,在系统安全技术方面人们总是想再往前多走一步。不过,在你整装待发准备多走这一步之前,你要知道,其实客户已经标定了关键系统,对敏感数据进行了加密,该打的补丁都打上了,而且也配备了各种配套产品,并且还用了工具来锁定配置确保其不会被篡改——总而言之,在你尝试挖掘 0-day 大漏洞之前,系统在常规情况下已经非常安全了。事实上,如果该做的常规措施都做到了,大部分的数据隐患都可以被消除,这个事实听上去一点儿也不性感吧,但事实就是这样,通常情况下那些用 0-day 级别漏洞来产生的“无敌高级持续性系统威胁“的案例并非真的存在!所以无论是你自己去打理服务器,还是说你的云服务供应商帮你去鼓捣,把基本的安全实践工作做好非常必要(,其余的事情你就不用去考虑了)

纵使认为供应商都应该是业界良心(会对他们的开发软件产品的方式负责),你还是有很多东西需要确认,而不能只用漏洞扫描工具一扫了之。客户能做的事情可多着呢,额滴神啊(千万别说你不知道该做什么),客户可以询问供应商,问问他们采用了哪些安全认证规程,或者查查看他们的产品有没有行业认证(例如像 Good Housekeeping 质量担保图印,或者 FIPS-140 认证这样的计算机信息安全通用标准认证)。大多数供应商,至少是我知道的最大的那几个供应商,目前会采用相当完备的安全规程(我之所以知道这些信息,是因为我们在技术大会上会相互交换技术资料并作比较)。作为客户,在安全方面孜孜不倦当然是好事,不过如果客户总是想着:“嘿,我认为我应该帮供应商做点儿什么,所以让我来看看他们的源代码有什么漏洞没有”,这样就不是什么好事了。即使是面对如下的情况,这也不是什么好事:

  • 漏洞扫描工具报警:客户其实没有能力去分析被报警的部分是否是在安全控制范围之内的,更何况这种报警往往还都是“虚假警报“(false positive)
  • 即使发现问题,客户也没有能力去自己给问题开发补丁程序——因为只有供应商才有能力开发补丁程序
  • 客户在使用静态工具分析源代码时,实际上很可能已经触犯了许可证协议条例(条例规定不能对源代码进行任何操作)

我来开门见山地说吧:我认为很多时候说”客户使用逆向工程技术”这句话其实并不准确,因为真正的逆向工程操作是由客户聘用的顾问来做的,这些顾问运行一下逆向工具,逆向出一堆代码,用打印机打印出一大坨,往客户面前一撂,接下来客户就会把这一大坨送给我们。我现在已经注意到,给我们送来的所谓漏洞扫描报告根本就不是“证明这里或者那里有问题”的清晰报告,不管是采用动态分析还是静态分析,漏洞扫描报告完全不体现漏洞存在的真正证据。通常情况下,这些报告就跟一缕蒸汽一样(扑朔迷离又没有价值)。

没事儿找事。(是的,我打算一直这么说:没事找事。) 这就是为什么我们要求客户举报每一个所谓”问题“时,都必须填写服务申请(而不是仅仅把漏洞报告扔给我们就完事儿了),同时还要提供概念性的证据(确实有一些工具能做到这一点)。

通过我们自己的分析,如果我们真的认定扫描报告的结果只可能来自于逆向工程(我们至少遇到过一次以上这种案例,因为报告上“很聪明地”写了:“通过对Oracle XXXXXX 软件的静态分析……”),那么我们就会立刻给“有罪”的客户写信,并同时给为“有罪客户”提供咨询的“有罪顾问”另去一封信件,提醒他们已经触犯了Oracle许可证协议中禁止使用逆向工程的条款,所以不要再这么做了。(用正规的法律语言来说,Oracle许可证协议上的条款是这么写的:“用户不得进行逆向工程,反汇编,反编译,以及任何从程序中获得源代码的尝试”,我们在给客户的警告信中就会引用这个条款)。哦,我们还会要求客户/顾问销毁从逆向工程得来的结果,并要求他们确认他们执行了销毁。

为什么我要强调确认销毁呢?最主要的原因是,我要把这个事情做得板上钉钉。我可不想为了“你们触犯了许可协议”,“不我没有”,“有的,就就是有”,“不,我们没有”这种来回扯皮的话浪费时间。我宁愿花更多我自己的时间,以及团队的时间,去帮助提升开发代码的质量,而不是和人们去讨论用户许可证协议细节问题

现在我需要重申一下,我在这里并不是要用许可证协议来打压用户。我其实更想说的是,“我不让你去分析代码,是因为我自己会去分析。分析代码是我的工作,我们很擅长我们的工作。我们能切实对代码进行分析,并弄清楚真正的情况是什么,而第三方咨询机构或者其他工具软件则做不到。无论在何种级别上,这些工具软件找出来的所谓‘漏洞’几乎 100% 都是‘误报’。所以不要再浪费你的时间了,那些工具里面的小绿人报警帮不了你任何忙。” 我不是要逃避我对客户应尽的运维责任,我仅仅是想避免那些痛苦、烦躁又让双方都非常不爽的过程。

基于上述原因,我想解释一下 Oracle 实施用户许可证条款(尤其是关于逆向工程的条款)的目的,其实这个目的非常符合逻辑也非常符合直觉,那就是:“我们告诉你我们的底线在哪儿,一旦你越过了,我们就对你不客气。”  附注:我在日常与人交谈时偶尔会用到 stare decisis(译注:拉丁文,意思是“照章办事”)这种法律专业词汇(不过我的狗完全不懂拉丁语,它只明白夏威夷语),不过我毕竟不是律师(译注:作者的意思是,他的观点并不能代表Oracle对这些问题的官方司法解释)。所以,当你有什么疑问的时候,参照 Oracle 许可证条款原文就好了,原文比我在这篇文章里写的要准确严格得多。

 

依照上面说的那些原则,我列出一些 FAQ 问答形式的文字,用来做为解释:

问:什么是逆向工程?

答:总的来说,我们(Oracle)的代码都是编译(是的,我知道有些代码是解释型的)以后(以可执行的方式)交付使用的。客户拿到的是可运行的代码,而不是代码在“被开发”时的形式。用户绝大多数时候只需要运行代码,而不需要了解代码是怎么拼凑在一起工作的。这样做的理由很多,例如事实上,我们的源代码是非常宝贵的知识财富,受知识产权法保护(所以我们会对能够接触到源代码的人群设置重重限制,就是为了保护源码的知识产权)。Oracle许可证协议限制了你只能使用交付形式的代码,这一限制隐含着一个事实概念,那就是你不能够反编译,反汇编,不允许把故意做扰乱处理的代码复原,不允许用任何其他形式的将代码从可执行形式转变会原始形式。尽管对于这些限制会有一些特别注释,但是也绝对不会出现“只要你是在寻找代码漏洞就万事大吉”这种例外情况。

所以说,如果你要尝试把我们卖给你的代码转变成与我们卖给你时不同的形式——比如,转变成在我们写这些代码,并且还没有通过对他们进行加工然后卖给你的那种形式,那么你就很可能是在逆向工程了。不!要!这!么!做!

 

问:Oracle关于提交安全漏洞的协议是怎么规定的呢(是不是允许使用工具呢?)

答:我们需要客户针对每一个漏洞做一个上报申请,并提供测试用例,证明你所谓的安全漏洞是可被侦测到的。我们之所以采取这种策略的原因,是为了筛除大量采用安全工具软件扫描得出的不准确的漏洞信息(也就是误判的漏洞信息)。

 

问:为什么你们(Oracle)要去找那些客户的顾问的麻烦呢?客户的顾问又没跟Oracle签什么许可证协议。

答:顾客是同Oracle签订过许可证协议的,那么由顾客雇佣的顾问就因此具有了连带签订许可证协议的法律关系。要不然的话,岂不是每个受雇于客户的顾问都可以说(注意,下面是法律咒语):“甲方甲方能力差,顾问顾问最牛叉,甲方不能我偏能,我想干啥就干啥”。

 

问:如果真的有用户发现了安全漏洞,Oracle会怎么处理的呢?

答:每当被问到这个问题的时候,我的第一反应是拒绝的。因为我想再次重申,用户不应该也不允许对我们交付的代码进行逆向工程。然后,如果真的有客户发现了货真价实的安全漏洞,我们就一定会去修复。我们不喜欢从用户那里发现漏洞(我知道这种说法很可能得罪人),但是如若真的发现了问题,我们也不能熟视无睹。然而,(从另一种角度看)我们去修复错误,也是在保护我们其他的客户,因为一旦我们修复了错误,其他客户的错误也同时得到了修改。不过,我们是不会给上报漏洞的客户(如果他们真的是通过逆向工程来发现漏洞的)提供专门(一次性)补丁的。在发布的公告中,我们也不会(给违规上报者)提供任何赞誉。所以你就不要指望我们会对你说:“感谢你破坏了我们的许可证协议“了。

 

问:现在的反编译产品越做越好,上手也越来越容易,所以说是不是以后的某一天逆向工程就变得OK了?

答:啊,不会的。我们对于逆向工程的反对是基于保护知识产权的立场的, 我们并不是要证明“我们把聪明才智都发挥在阻止我们的客户发现我们安全漏洞上,即使发现了漏洞我们也不修复”。我们鼓励客户在可执行代码上使用工具进行评估,只是说不要去逆向工程就可以了。从这一点来看,用户通过使用第三方工具或者服务来发现问题也是有可能得到我们的优质服务的,只要你跟你的工具开发商或者服务供应商确认一下:a) 工具的工作原理是什么 b) 他们是否实施了逆向工程来达到目的。不管他们说得怎么天花烂坠,你只要记住,问题正确的答案就只有几种情况:“不,我们没有做”;“是的,你做了”;“没做”;“做了”。(译注:其他的答案都是忽悠你的或者是废话)

 

问:不过我的 编码顾问/第三方漏洞扫描软件 真的很牛。你们Oracle就不能把我提交的400页的漏洞扫描报告好好分析一下吗?

答:嘿,哥们儿。我觉得我说这件事情已经说了这么多遍,我都快成说唱歌手了:我们Oracle自己有自己的代码静态分析工具(而且是我们自己开发的),我们自己会分析!外面的那些垃圾工具真的是不准确到离谱啊!(有的时候误判率居然达到了100%,或接近100%),况且用软件工具扫描这件事情本身并不重要。重要的是你要有分析扫描结果的能力,诸如此类。如果我们花时间去判断客户或者他们的顾问的指指点点,分析那些毫无意义的东西,那完全就是一种浪费。我们应该把我们的时间花在刀刃上,也就是说,花在去找那些真正的漏洞上面去。

 

问:是不是一旦有人发现了真正的漏洞存在,你们就会说他们是通过逆向工程才找到的啊?

答:诶,我可是冒着被人骂啰嗦的风险再跟你们说一次:不,不是的。就好比如果有人家里的门或者窗户没锁,那么你直接进入就不算非法闯入。虽然我们不敢说用过市面上每一款的扫描工具。不过我们确实要求开发组(连带包括云端开发和内部开发机构)多用漏洞扫描工具,我们过去几年在工具使用方面已经取得了长足的进步(看看我们的指标数据就知道了),并且我们把跟踪工具的使用纳入到了“Oracle软件安全确认规程”当中。我们强迫——我的意思是“要求”——开发团队使用漏洞扫描工具,是因为我们非常愿意(当然我们的客户也非常愿意)尽可能早地发现并修复各种问题。

业界有云:没有一种工具是万能的。实际上几种工具加起来也达不到万能。我们做不到万能,不过这并不能说用户试图通过逆向工程来找我们的漏洞就是正确的。其实分析一个疑似的漏洞究竟是不是真正的漏洞,最关键的就是对源代码进行分析。坦率地讲,第三方软件是很难做到从源代码的角度进行分析的。随便哪个客户用逆向工程工具粗浅扫描一下,就给我们发漏洞报告,我们自然是不能接受,原因很简单,我们并不需要这样的报告。

 

问:嘿,我有个主意,干嘛不搞个bug悬赏活动呢?如果第三方帮你们找到漏洞,你们给他们奖金不就可以了?

答:诶(再次大口叹气)。Bug悬赏活动是给那些玩票儿的人准备的(玩票儿这个词儿不错吧,是不?)。好多公司把自己和安全研究员都搞得跟神经病一样,让他们来找公司产品代码中的问题,然后还坚持认为:这才是解决Bug的终极之法,就得这么干:如果你不搞Bug悬赏活动,那你就没法做到代码安全。啊,好吧,其实我们87%的安全漏洞都是我们自己找到的,我们的安全研究员会找到约3%的漏洞,剩下的漏洞则是通过用户来发现的。(这里跑个题:我今天发现,一个还挺有名气的安全研究员上报说,在某个特定的技术领域他发现了一堆所谓漏洞,希望我们引起注意——实际上我们早就发现了全部的漏洞,现在已经在着手修补,或者都搞定了。哈哈哈,这件事情笑得我胸围都变大了!)

我并不是要贬低Bug悬赏活动,只是这么做毫不符合经济学逻辑,我为什么要花钱去请一个只能解决我3%问题的人(并且还不能持续性解决问题,基本上就像打田鼠一样看一只打一只),我有这些钱还不如其再聘请一个全职雇员,让他去做一些合规的hacking,然后为我们开发出好用的工具,从而能够自动发现并解决某个特定类型的问题,这样才是正确的做法。其实这个问题就是一个“该信基督教还是该信天主教”的问题,我们当然会包容不同的宗教和文化,但是我们会用我们的方式来包容——其他人怎么做那不关我们的事。祝你们平安!
 

问:如果你不让客户去做逆向工程,万一他们生气了不买你们的东西了咋办?

答:的确我们听到过类似的说法。不过讽刺的是,就是因为他们愿意买我们更多的产品(或者使用我们的云服务),才必须跟我们签使用许可协议啊!所以他们这么想就已经是在违背许可证协议了啊。“亲爱的,如果你不让我再次背叛你的话,那么我们的爱情就能天长地久”,“啊,额,你已经违反了婚姻誓词里面‘无论如何都会天长地久’的誓言了啊,所以我们的婚姻完了”。

同客户沟通更好的方式——通常我也会这么做——就是跟他们解释我们会对我们的产品充分负责,包括我们自己会开发漏洞扫描工具。我希望用户对我们的产品和服务有信心,而不是需要老给他们写信提出警告。

 

问:好吧,你们可以说那些坏人以及竞争对手会去对Oracle的代码进行恶意逆向工程,而且也不会在乎你们的许可协议,不过还是有些客户是出于好意的吧,对于这些人你们也要限制吗?

答:Oracle许可证是为了保护知识产权的目的而存在的。而第三方扫描我们代码的行为被称之为”好意“,我觉得这种观点需要修正,任何为侵犯许可证协议的行为找借口都是不可接受的。就像是你不能跟你的配偶说:“别人家都出轨了”,这完全不是一个正当的理由,因为结婚的时候这些约束都是定好了的。

写到这里,我觉得我可以下个定论了,或者说可以拍板了。我们要求客户不能对我们的代码进行逆向工程,从而找什么安全漏洞。我们自己有源代码,我们自己会运行扫描工具分析自己的源代码(当然我们同时也会分析可执行代码),所以分析代码这件事情真的是我们的事情。我们不需要客户,或者天知道哪儿来的一个第三方机构通过逆向工程来帮我们找漏洞。最后,但是也是最重要的,Oracle许可证协议禁止你这么做。所以你们就不要去做了就对了。


* 我觉得肯定有一部分客户来回地骂我,因为这些客户已经给他们的顾问付了一大笔咨询费了。他们会觉得是因为我们(无能导致漏洞产生)让顾问们敲了他们一大笔(其实是顾问违反了许可证协议在先)。

** 我能想到的唯一的比喻是,我的书架。有的人看了我书架上的书名,就会觉得我是一个好色之人,喜欢看色情小说。并且他们还会让我解释,为什么我要买这么一堆奇奇怪怪的书。比如这些例子(这些真的是我书架上的书的名字哦)

1. 来自下方的雷霆一击(额滴亲娘,一定很劲爆)

2. 裸体经济学(“裸体主义哦!”)

3. 地狱烈火(“哇,一定更劲爆”)

4. 黎明,我们睡去(“你一定是昨天晚上运动过度了才会熬到黎明都不睡吧”)

对于这些,我的回应是,我可没义务给你们解释我对图书的品味,我也不会去真正回应这些怀疑。(不过你们如果真的感兴趣的话,我就告诉你们吧,1. 这是一本传记书籍,书的主人公是 Eugene Fluckey 舰长,第二次世界大战美国海军潜艇舰长,国会荣誉勋章获得者。2. 这真的是一本经济学书籍。3. 这是一本介绍二战期间欧洲剧院的书籍。 4. 这是一本描述珍珠港事件的作品。

***我怎么会讨厌凯恩斯(英国著名现代经济学家——译者注)呢!!! 世界上现存的渡渡鸟(一种珍稀动物,已灭绝——译者注)的数量都比凯恩斯乘数理论的支持者要多。据我所知,“渡渡鸟”和“凯恩斯乘数原理支持者”这两个词汇都能当同义词使用。

****当然,我可能有点夸张了。但也许没有。

 


补充1:摘录 Reddit 网友的吐槽:

gaggra:

这篇博文口气真是傲慢、无礼、假仁假义,我肯定该文要被甲骨文的公关撤下了,因为这真是一篇烂稿。

joeflux:

文章中指出,客户发现的漏洞数量(10%)是他们自己安全人员发现的 3 倍。他们是怎么响应的?给客户发威胁信。

 

willvarfar:

So is Oracle’s packaged-up Linux distro only “Unbreakable” in a legal sense, then? 😉

http://www.oracle.com/technetwork/topics/security/securityfixlifecycle-086982.html says 甲骨文在这篇文章说过

Oracle appreciates and values the members of the independent security research community who find vulnerabilities, bring them to our attention, and work with Oracle so that security fixes can be issued to all customers. 甲骨文赞赏并重视发现漏洞的独立安全研究社区……

So there’s some kind of disconnect going on here anyway.

补充2:

Paypal 的漏洞奖励政策有点奇葩

(曾经)要求提交漏洞的人必须年满 18 岁。2013年5月,有位 17 岁的德国小伙 Robert Kugler 提交了一个 XSS 漏洞,不过因为没满 18 岁,所以……

补充3:

Mary Ann Davidson 这篇文章在 Reddit 引发争议后,后来 Reddit 上又火了另外一篇文章《PostgreSQL: Please, security test our code!》。

甲骨文:不行,你不能看我们的源代码!,首发于博客 – 伯乐在线

亮瞎眼的特斯拉线圈

之前发过一篇用于产生电弧的马克思发生器, 那个玩意儿跟特斯拉线圈相比,就是小巫见大巫了。
尼古拉·特斯拉是一百多年前的一位发明家,他发明了交流电、无线电,制造过小型的地震,搞过巨型的人造闪电。总之他的传奇故事很多,据说是被奸商爱迪生打压以至于默默无闻,著名的电动汽车特斯拉就是为了纪念这个疯狂的科学家。

有传闻说特斯拉玩的闪电,可见范围达到几百英里,不知道真假。我等凡夫俗子,顶多利用特斯拉原理来产生个小型闪电就好了。

 

Step 1: 准备和注意事项

我们的目标是做一个1000w的中型特斯拉线圈,放电距离超过120cm,特斯拉线圈的放电距离和功率成正比。
主要材料及大概成本:
1:高压变压器 1000W 输入220V 输出 10KV
2:大量无极电容 如用0.047uf 1000v~(1600v-)的cbb电容需要准备100只左右,有大容量的高压电容请自己换算
3:直径13厘米长1米的聚氯乙烯管(壁厚0.6-1厘米),pvc管材也将就,厚0.8厘米的绝缘板材(不能是木头!最好塑料)大约2.5平米,厚0.5厘米的绝缘板材(非木!)大约1.5平米,这些都可在家庭装饰城(就是那些买涂料,板材,工具等的那种大市场里)买到
4:导线,多芯铜导线,1000v50A大约6米;10kv1A导线3米
5:耐压漆包线 内径0.5mm 900米长
6:直径0.8厘米的铜管(壁厚1mm以上)长8米,直径3厘米厚>1mm长1米的铜管可在汽车配件或五金等地买到
7:电手钻,螺丝刀,手锯,钳子等工具,普通螺丝,塑料螺丝,环氧树脂胶,钢尺等
8:用于燃气热水器的排气管(金属制作,可弯曲,直径在10厘米以上)制作后期计算得到长度.
Step 2: 电路原理图

等等,你特么是在逗我吗?我们是在做一个极其高大上的“雷公电母”设备,它的原理图怎么可能这么简单。

所以感慨一下科学的伟大吧,小小一张图就可以让你拥有神一般的力量……

 

Step 3: 装配示意图

当然,从原理图到真正的装备,还有很多路要走,这个就是装配的示意图。

Step 4: 一些相关的计算公式

1. 电弧长度: 电弧长度 L(单位:英寸); 变压器功率 P (单位 瓦特); L=1.7*sqrt(P)
2. 电容阵容量: 变压器输出电压(交流)E(单位 伏特); 变压器输出电流 I(单位 毫安); 电容器阵列最大容量C(单位 微法) ; 交流频率F(单位赫兹) C=(10^6)/(6.2832*(E/I)*F) [电容的大小涉及到与变压器功率的一个匹配问题,当电容过大时在交流上升到顶点时(即sqrt (2)*V时,电容电压过低无法击穿打火器的空气隙则打火器无法启动就无法工作,整个系统也就无从启动 ]

3. 电容阵的计算就是电容的简单串,并联,初中就学过,在此就不提了.例如当变压器功率为1000瓦时,输出电压为10000伏(交流),那么电容匹配为0.0318uf,手头有电容规格为:0.047uf 1000~,1600-,再取保险一点到 耐压 1500v~则需要电容阵列安排如下:15个电容串联成一个基本链(BC);再10个这样的基本链并联而成(J),共需要电容150个,若每支电容分压降为630v~(这样可以大幅度延长电容寿命),则: 24–BC,16–J,共需384支电容.

4. 其他: 震荡频率:F = 1/(2*Pi*sqrt(L*C))

Step 5: 制作主线圈

在特斯拉线圈的设计中主线圈采用铜管绕制成蚊香状。铜管是用于汽车,供热,中央空调中的那种管壁较厚的承压铜管。直径8毫米大约绕制9-10匝,大约需要9米,最好选用光滑无锈无伤的。

Step 6: 主线圈支架

 

这样盘成的主线圈可以适用于6英寸到8英寸的次极线圈(盘铜管很费时间,也满费劲,但是不要图快,要尽可能盘的圆滑.),还需要5毫米厚的软塑料板(非脆性塑料)做主线圈支架,将其按等距离打眼(要打成9毫米的眼,要不穿不进去) 底座选用普通中密度板就可以了,这个底座还有用,将来底下要放其它东西.也尽可能加工好,接下来把铜管和塑料支架穿起来。

Step 7: 内圈接头

 

内圈接头部分,将中密度底版在相应地方开孔引出一个接头。

再找一截铜管做为接地保险,注意,不能让它闭合!

Step 8: 电容阵列

在特斯拉线圈中,有一堆好的电容非常重要,因为所有电弧的能量都是由电容直接提供的。由于高压电容价格昂贵,所以现在普遍的做法是通过对普通无极性电容进行串联和并联来达到所需的耐压和容量。
需要准备的材料:
1.无极性电容,(聚乙烯,聚丙烯,CBB电容 等)一般常见高压电容规格主要有:1600v-0.047uf、1600v-0.068uf两种
2.电阻10兆欧(1000000ohm)
3.有机玻璃板
4.塑料螺丝

首先计算所需要的电容个数和排列方式,根据以前提到的变压器匹配计算得到电容量为0.0318uf/10kv,手头电容规格为1600v- 0.047uf, (此处注意:电容的耐压标示都是直流 ,而且电容器交流耐压与电容材质等多种因素有关,不能简单认为只要将直流耐压值除以1.414 就得到交流耐压值),从寿命和安全性角度出发,建议将每电容分压值定为450v~ 则得到整个电容阵构成为:22串一链,共14链并联,一共308支电容电阻,电阻的用途是为了当停止使用时对电容中的残留电荷进行放电,使用方法就是每支电容都要并联一支10兆的电阻(1/4~1/2W )

安全提示:若没有放电电阻,则电容阵中储备的能量将可能存在很久而对人身造成伤害!

图中显示了一个电容链,它是蛇行排布的。注意!电容之间不要紧密接触!要留有一定空隙,层与层之间要用4mm厚的有机玻璃隔离,每层包含两个链,固定使用塑料螺丝(尼龙螺丝), 每层都有各自的接口使之成为独立可使用的单元。

Step 9: 次极线圈的制作

特斯拉线圈中的次极线圈是整个特斯拉线圈中制作最耗时耗神的部分。需要如下材料:
1. 高质量漆包线,一定要买好的,尤其是目前我国的漆包线质量普遍低下,线的直径0.51mm ~ 0.57mm。
2. 聚氯乙烯管材,直径15厘米,最少2米,厚度自己感觉结实就好,一般能买到的大约在4-8mm厚。
3. 用木头制作一个绕线架(有绕线设备的土豪请无视)。用两个圆片穿在圆筒两边,再在圆片中间打眼,穿入中心轴,架到线架子里面就可以绕线了。一圈一圈的绕,大约绕900~1000匝就适合本系统了,整个绕线过程大约7-8小时。
中间休息时一定要把已绕好的部分固定好,免得前功尽弃。绕线时要注意不要使线打结,不要用两根线接起来使用。市面上够长度的漆包线不大好找,大约在500m,但是整卷的线似乎比较贵。有兴趣的朋友可以一起买一大卷分着用。

Step 10: 打火器

 

制作打火需要以下材料:
1.200mm直径pvc管材,长400mm
2.90mm长,直径20mm铜管若干
3.双头螺丝 若干(是铜管数目)两倍 

打火器其实相当于一个开关器,未打火时能量由变压器传递到电容阵,当电容阵充电完毕时两极电压达到击穿打火中的缝隙的电压时,打火器打火,此时电容阵与主线圈形成回路,完成L/C振荡进而将能量传递到次极线圈。制作步骤:
1.先将铜管打眼。
2.再在pvc管上打眼后,将铜管固定在pvc管内部 (每个铜管与铜管之间的缝隙大约控制在1mm)
3.组装好

为了根据需要调整放电缝隙,每相邻螺栓代表1mm的放电缝隙(螺栓即为接线柱)这样安装只要变换接线柱就可以很方便的根据你的设计电压进行调整了。
注意:打火器工作时将会产生很大的热量,而且往往集中在很小的面积上,所以散热设备必须很强大!一般采用小型立式风机(就那种吹婚礼拱门的),一般都在几百瓦,风量足。
只要注意在进风口加上简单的空气过滤装置防止大灰尘就可以了。
如果不加风机散热的话,特斯拉线圈工作几十秒后就可能导致打火器高温变形,加入风机后,一般可以把整个特斯拉线圈的工作时间延长至十几分钟。
另外,要经常在使用后对打火进行清理,去掉电渣和灰尘。

Step 11: 放电终端

 

在这部分的制作比较简单和随意,我这里介绍一种比较成熟和简易的制作方法,也就是最常见的圈型放电终端。
主要材料:
1. 4寸直径的燃气热水器通风管,(就是那种全金属的可弯管,家里有燃气热水器的一看便知)
2. 7寸直径的平底金属盘(用来做派的),其他类似金属物也可,关键1.平底 2.金属
3. 包裹金币巧克力的那种较厚的铝箔

首先将平底金属盘底对底用螺丝固定,接着将铝管盘成圈状,使其正好能卡在平底金属盘制作的骨架上,铝管的接口口处用铝箔封口,接线点定位在平底金属盘骨架中心,组装好成品。
至此特斯拉线圈的所有重要部分已经完成。

 

Step 12: 一些补充说明

 

关于特斯拉线圈的制作其实还有不少需要注意的事情,其中:
1:次极线圈的骨架既那个聚乙烯圆桶的饶线部分是有要求的,一般来说,饶线直径和饶线部分桶长比例在1:4左右
2:主线圈的底版可以用一些稍微便宜的材料制作,因为对它的要求不高,当然最好所有的塑料板材都能用雅克力板制作,这样有结实又漂亮
3:打火器的制作其实有很多方法,关键要注意的是a.放电部件要导热快 b.放电部件厚度要足够 c由于打火器更换频率最高,所以设计要以容易更换,价格便宜为主
4:关于高压电容,前些天见到微波炉内部有一种高压电容规格为 2100AC 1uF 且内部集成放电电阻的电容,看来如果使用这种电容也是一个不错的方案
5:关于主变压器,一般难以购买,可以去当地电子市场询问是否可以定做,如果没有,可以购买霓虹灯电源,规格为 15000V AC 50HZ 60mA 样子象个箱子,在国外特斯拉线圈爱好者中使用比较多,还有就是采购日本二手110VACin –6300vACout 变压器两个串联使用
Step 13: 亮瞎双眼的时候到了

世界各地有大量的特斯拉线圈爱好者,搞出很多炫酷的作品。

有的朋友可能又要说“然并卵”了,事实上,很多科技的突破,都是从一些莫名其妙的的发明演化而来。在自然界中,闪电拥有巨大的能量,据说地球每秒钟平均有45次闪电,如果能够抓住这些能量用来发电,那你就发财啦……

视频:

 

亮瞎眼的特斯拉线圈,首发于极客范 – GeekFan.net

DIY修炼:舵机知识扫盲

DIYer: Tod E. Kurt
GEEK指数: ★★★☆☆

1 简介

舵机控制的机器人

● 我猜你肯定在机器人和电动玩具中见到过这个小东西,至少也听到过它转起来时那与众不同的“吱吱吱”的叫声。对,它就是遥控舵机,常用在机器人技术、电影效果制作和木偶控制当中,不过让人大跌眼镜的是,它竟是为控制玩具汽车和飞机才设计的。
● 舵机的旋转不像普通电机那样只是古板的转圈圈,它可以根据你的指令旋转到0至180度之间的任意角度然后精准的停下来。如果你想让某个东西按你的想法运动,舵机可是个不错的选择,它控制方便、最易实现,而且种类繁多,总能有一款适合你呦。
● 用不着太复杂的改动,舵机就可摇身一变成为一个高性能的、数字控制的、并且可调速的齿轮电机。在这篇文章中,我会介绍舵机使用的的一些基础知识以及怎样制作一个连续运转舵机。

 

2 舵机的结构和原理

A.标准舵机图解

● 遥控舵机(或简称舵机)是个糅合了多项技术的科技结晶体,它由直流电机、减速齿轮组、传感器和控制电路组成,是一套自动控制装置,神马叫自动控制呢?所谓自动控制就是用一个闭环反馈控制回路不断校正输出的偏差,使系统的输出保持恒定。我们在生活中常见的恒温加热系统就是自动控制装置的一个范例,其利用温度传感器检测温度,将温度作为反馈量,利用加热元件提输出,当温度低于设定值时,加热器启动,温度达到设定值时,加热器关闭,这样不就使温度始终保持恒定了吗。

B.闭环反馈控制

● 对于舵机而言呢,位置检测器是它的输入传感器,舵机转动的位置一变,位置检测器的电阻值就会跟着变。通过控制电路读取该电阻值的大小,就能根据阻值适当调整电机的速度和方向,使电机向指定角度旋转。图A显示的是一个标准舵机的部件分解图。图B显示的是舵机闭环反馈控制的工作过程。

3   选择舵机

C.大扭力/微型/标准舵机

● 舵机的形状和大小多到让人眼花缭乱,但大致可以如图C所示分类。最右边身材不错的是常见的标准舵机,中间两个小不点是体积最小的微型舵机,左边的魁梧的那个是体积最大的大扭力舵机。它们都是同样的三线控制,因此你可以根据需求换个大个的或小个的。
● 除了大小和重量,舵机还有两个主要的性能指标:扭力和转速,这两个指标由齿轮组和电机所决定。扭力,通俗讲就是舵机有多大的劲儿。在5V的电压下,标准舵机的扭力是5.5千克/厘米(75盎司/英寸),转速很容易理解,就是指从一个位置转到另一个位置要多长时间。在5V电压下,舵机标准转度是0.2秒移动60度。总之,和我们人一样,舵机的个子越大,转的就越慢但也越有劲儿。
● 赶快想好你要做的东西,让我们开始动手吧。确定做什么之后,选择哪种大小的舵机(标准型、微型、绞盘型)就是小case了,你可以绅士般的从中选个最便宜的。在这个项目中,我选的就是微型系列的HexTronik公司生产的HXT500型舵机,额定数值是扭力0.8千克,转速0.10秒,只花不到4美元就搞定了。

4 舵机的支架和连接装置

 

D.多种舵盘

● 想在你的项目中用上舵机,就要满足两个条件:一是需要个能把舵机固定到基座上的支架,二是得有个能将驱动轴和物体连在一起的连接装置。支架一般舵机上就有,而且带有拧螺丝用的安装孔。如果你仅仅是测试的话,用点儿热熔胶或者双面泡沫胶带就能轻松的固定住舵机。
● 怎样连接驱动轴呢,你会发现舵机都附带了一些有孔的小东西,这就是舵盘,它可以套在驱动轴,臂上打上了些小孔。你只要用连接棒或者线把物体连到孔上,就可以将舵机的旋转运动变成物体的直线运动了,当然了,选用不同的舵盘或固定孔就能产生不同的运动啦。
● 图示的是几种不同的舵盘。前面4个白色的是舵机附带的舵盘,右边四个是用激光切割机切割塑料得到的DIY舵盘。最右边的2个是舵盘和支架的组合,如果你想实现两个舵机的组合运动,把这个舵盘的支架固定到另一个舵机的支架上就OK了。

E.普通舵盘设计

F.其他舵盘

● 制作普通舵盘对于童鞋们来说是比较容易的,先用矢量作图软件画一个多边形,这个多边形的半径和顶点数都要和舵机驱动轴匹配,这样它就能连接到驱动轴上了,其他种类的也是这样画出来的。

5   如何控制舵机

G.3线接口

● 像图所示那样,舵机有一个三线的接口。黑色(或棕色)的线是接地线,红线接+5V电压,黄线(或是白色或橙色)接控制信号端。

H.控制信号

● 控制信号(如图H)是一种脉宽调制(PWM)信号,凡是微控制器能轻松的产生这种信号。在此文中,我用的是常用的Arduino开发环境下的微控制器。
● 脉冲的高电平持续1到2毫秒(ms),也就是1000到2000微秒(µs)。在1000µs时,舵机左满舵。在2000µs时,右满舵。不过你可以通过调整脉宽来实现更大或者更小范围内的运动。
● 控制脉冲的低电平持续20毫秒。每经过20毫秒(50次每秒),就要再次跳变为高电平,否则舵机就可能罢工,难以保持稳定。不过你要是想让它一瘸一拐的跳舞,倒可以采取这种方法。

这是一个完整的Arduino设计程序,在这个程序下,舵机始终在正中间位置,控制起来很容易

I.舵机连接Arduino实验板

● 红色和黑色的线分别接到Arduino开发板的5V电源脚和接地脚上。控制线接到Arduino开发板的数字输入/输出脚9脚上。
● 用Arduino控制舵机也有不太给力的地方,就是Arduino程序把绝大部分时间都浪费在等待延迟命令上,不过童鞋们暂时不要失望,Arduino中内置有舵机函数,你可以用它内置的计数器来同时控制两个舵机(分别在9脚和10脚),是不是又豁然开朗了,这样我们不就能把节省下的编程代码干别的事情了吗。

这是一个调用了舵机函数的程序
6 舵机应用:云台网络摄像头

J.舵机控制的云台网络摄像头

● 看了这么多内容了,是不是有点迫不及待练练手的冲动,那就先来个简单的,材料就是下面这些,两个舵机、一个Arduino板、一个用来装摄像头的可转动基座。先用热胶把第一个舵机的舵盘固定到摄像头的底部,然后把第二个舵机固定到基座上,同时把它的舵盘固定到第一个舵机的一侧,最后把舵盘套到各自舵机上,哇塞,一个云台网络摄像头就这样诞生了。
● 图中是一个纯手工打造的云台网络摄像机,它用的是OpenWrt Linux系统的华硕wi-fi路由器。
● 网络摄像头和Arduino控制板都是用USB集线器连接到路由器上的。

通过Arduino的USB口同时控制两个舵机的程序

● 大致的流程是这样滴,当串口上有两个字节到来时,程序开始工作,赋给第一个字节0-180的值,让它调节摇摆舵机(调左右),同样赋给第二个字节0-180的值,让它调节倾斜舵机(调上下)。

7 如何DIY连续旋转的舵机

K.舵机的内部“解剖”结构

● 任何舵机都能变成一个双向、可调速的降速齿轮电机。通常情况下,需要驱动芯片和其他一些零件才能控制电机的转速和方向,这些部件舵机中都会附带,所以要想得到一个用到机器人上的数控连续旋转舵机,最简单也最便宜的的方法就是自己动手改造一个,哈哈,考验动手能力的时候又来了。

L.拿掉金属挡板

● 需要改动的是部分的电路模块和机械模块,电路模块中,我们要找两个阻值相同的电阻来充当电位计,机械模块中,则要去掉防止电机过速的挡板。

M.卸下塑料挡板

● 下面我们就开始吧,首先,卸开舵机外壳,HTX500舵机的外壳由3个塑料部分扣在一起。你可以用个小一字改锥或是类似的片状工具把他撬开,然后从轴上取下齿轮组,(记得标记好各个小齿轮的位置哦),再从下面小心的取出舵机的电路板。
● 舵机上有两个机械制动挡板,用尖嘴钳卸下驱动轴基座上的金属挡板(图L),用斜嘴钳卸下外壳顶部的塑料挡板(图M)。

N.焊上电阻

O.缠上胶带

● 用两个阻值相加约5 kΩ的电阻来替代5 kΩ的电位计,实际制作中,选一对2.2kΩ的电阻就能满足要求了。把电位计上的3根线焊下来,像图N那样焊到电阻上。再把这个重新组装成的家伙用绝缘胶带或是绝缘管缠好(图O),最后再和电路板一起重新塞进舵机外壳中,扣好外壳,一个改造好的舵机就呈现在我们面前了。
● 手工制作阶段到此就结束了,但是现在还能高兴的太早,因为只有找到基准点才能算是大功告成。在理想条件下,如果两个电阻完全相同,舵机就能精确的停到90度的位置上。不过呢,理想和现实总是会差那么一点点,因此舵机就没像理想中那样么精确。为了使舵机控制更精确,我们要找到一个基准点,方法是把上面编的程序灌进电路中,通过实验来看舵机究竟停在哪个角度,这个角度每个舵机都不相同,所以得出结果后要记录下来。
● 我们业余爱好者常用的舵机一般是用电位计来检测驱动轴转动到的角度,而用在工业机器人、电脑数控机床等大型系统中的舵机一般则要用旋转编码器来确定位置。光学旋转编码器的原理是这样的,把一个带有窄缝的圆盘固定在转轴上,然后用一个LED灯和一个光敏元件来记录光通过窄缝照到光敏器件上的次数来计算当前旋转到的位置。其实生活中这种技术也很常见,我们每天都要用的光电鼠标就是用的这个原理制作成的。
注:如果你不想撬开你心爱的舵机,Parallax公司(BASIC Stamp微处理器的制造商)有一款即用型,标准尺寸的连续转动舵机可供你使用。

8 连续旋转舵机的应用:5分钟的绘图机器人

P.安装好的绘图机器人*
● 想做个会画画的的机器人吗,那就去找两个连续旋转舵机来吧,我们这就开始。图O这个绘图机器人中包含了舵机两个, 9V电池,面包板, Arduino电路板,三福记号笔各一个,外加一对塑料轮子。
● 它的电路和云台摄像头一样,我们直接拿来用,而且它的部件都可以用热胶粘到一起。关于轮子的选择,更是简单,只要是直径在1到3英寸的圆东西都能用,比如塑料瓶盖之类的。为了减小摩擦,增大牵引力,我们在车轮上缠上塑料胶带。
● 这样组装阶段就完成了。接下来就是程序了,它的程序用一个包含基准点的变量来制动舵机,这个基准点我们上面已经通过实验测出(你的基准点可能不同)。程序的控制流程为,先让一个舵机朝一个方向运动一段时间,然后换成另一个舵机转动,这样就能得到一个螺线形的图画了。
● 代码在此:
#include
Servo servoL;
Servo servoR;
int servoLZero = 83; // experimentally found to stop L motor
int servoRZero = 91; // experimentally found to stop R motor
boolean turnleft = false;
void setup() {
servoL.attach(9);
servoR.attach(10);
servoL.write(servoLZero); // start out not moving
servoR.write(servoRZero); // start out not moving
}
void loop() {
turnleft = !turnleft;
if( turnleft ) {
servoL.write( servoLZero – 10 );
servoR.write( servoRZero );
delay(1000);
} else {
servoL.write( servoLZero );
servoR.write( servoRZero + 10 );
delay(4000); // turn more one way than the other
}
}

Q.运动中的绘图机器人

● 注意:永久记号笔画的痕迹不好清除,童鞋们千万小心哈,最好让绘图机器人在硬纸板或其他不透水的纸的画画,或者索性换成支水溶性的记号笔。

 

 

DIY修炼:舵机知识扫盲,首发于极客范 – GeekFan.net

【神级DIY】自制无线控制“甲壳虫”机器人

【导读】拥有一个自己会跑会跳的机器人是许多人小时候的一个梦想,如今这个梦想你可以实现了!此次电子元件技术网带来大师级别的DIY,自己动手就能做的机器人,做一个送给家里的小朋友绝对自信心爆棚啊!

话不多说,直接上图。

Solidworks 出图纸和模拟图

机器人身体

机器人头部

机器人漂亮的大腿

 

甲壳虫机器人3D模拟图

camworks 出刀路

甲壳虫机器人3D 模拟图 

 

加工及组装

在自己DIY的数控铣床上进行加工,用的6061 的进口铝板, 3mm厚度 

购买的经典型号舵机MG995,开始组装。 

甲壳虫机器人造型很漂亮吧! 

舵机板和布线已经完成

 

机器人安装完成

功率强劲的8000mah动力电池

机器人安好后摆个POSE

复位后的状态

机器人站起来了

机器人PS手柄和遥控装置

【神级DIY】自制无线控制“甲壳虫”机器人,首发于极客范 – GeekFan.net

DIY:制作曲面感光元件的针孔相机

我们曾介绍不少自制针孔相机,而通常都是使用已经提供好的纸模来制作。而来自加拿大的摄影师 Matt Bechberger,则分享了一个非常完整的针孔相机制作指引,包括了数学上及物理学上的讲解,相机通过弯曲胶卷曝光的办法,令胶卷可以均匀曝光,极大地消除了画面的暗角!很好玩哦~。如果你也想自制一台如此认真的针孔相机,可以来参考参考!

基础概念

针孔相机其实是最原始的相机,光线在物体身上反射出来,然后透过相机上的小孔,聚焦于相机内的底片上,而任何可以遮挡着针孔的东西都可成为快门,手动控制曝光时间。就是这么简单。

数学计算

制作方面,首先你要制造出一个好的针孔,在互联网上都可以买得到,又或你能够自制一个。建议材料是一般的铝罐皮,越薄越好。然后使用小锤及针,轻轻地戳一个洞,在戳的时候最后在底先垫一块橡皮擦,以防止变形。完成后再用砂纸把铝片磨平,并且用显微镜或平板素描器之类 (如果有),去检视针孔的圆度及质素。如果你选用一些硬质金属,则可能要特地使用电钻之类了。
然后你要找出针孔的直径,知道后就可以计算出所需焦距﹐也就是针孔与底片之间的距离。
算式如下︰焦距 = (针孔直径 / 0.03679)^2
例如 针孔0.3mm
焦距 = (0.3mm / 0.03679)^2 = 66.49mm
接下来要计算的就是「视角」(viewing angle),即是光线进入的最大角度,这取决于针孔的直径与物料的厚度。
这个需要动用直角三角形的公式,要用上计数机。d 就是针孔直径,而 t 就是物料厚度,简化版公式如下︰
视角 = tan^-1( (d/2)/(t/2) ) x 2
例如︰
视角 = tan^-1( (0.3/2)/(0.0762/2) ) x 2 = 75.74 x 2 = 151.5 度
视角的重要性,在于让你判断光线能否恰当覆盖到底片,如果覆盖不足的话,就会出现黑角及黑边。例如上图般,底片的对角线不应长于成像圈的直径。而成像圈的直径算式如下︰
成像圈直径 (mm) = 2 x 焦距 x tan ((视角)/2)
例如︰
成像圈直径 (mm) = 2 x 66.49 x tan (151.5/2) = 523.61 mm
在这个例子里,成像圈非常大,所以配合弧面底片的话,就可以在 120 底片上拍出 17cm x 6cm 的超广角影像。

相机制作

完成了数学计算后,就到物理上的实践。弧面底片的就可以让整块底片都与针孔保持相等距离,从而得到均匀曝光。
相机材料方面没太大限制,最重要是能够阻止光线进入。
卷动底片方面,则要使用如下图的扁状金属条 + 结他旋钮的东西,两边各一个,以松开底片及收紧底片之用。
快门方面,丰俭由人,你可以像作者一样,自制一个以弹簧及快门线控制的快门。
在相机背后需要钻一个小孔,以确定底片的使用量,最好在相机内部涂上黑漆,以消除任何杂散光。 

 

曝光计算

接下来要计算的是光圈值,这个会影响你所需要的曝光时间。
算式如下︰光圈值 = 焦距 / 针孔直径
例如︰
光圈值 = 焦距 / 针孔直径 = 66.49mm / 0.3mm = 221
这个世界恐怕没有甚么相机或测光表有 f/221,所以我们要做下一步计算。
根据「标准全级光圈值尺度」,每一级光圈值之间,光线量是减半,亦即是光圈的面积也是每级减半。数字如下︰1.4,2,2.8,5.6,8,11,16,22,32,44,64,88,128,176,256,352。但是超过 f/22 的测光表是不存在的,因此我们可以透过计算自行找出倍数。
不过放心,一般的针孔摄影不是精准的科学,所以也不需要精确的数学。在这情况下 f/221 大概接近 f/256,就当作 f/256 可以了。相比起 f/16 即是有 8 级的差异,也就是说 f/16 的光量是 f/256 的 2^8 倍,也就是 256 倍。
因此你可以透过测光表之类,以相同的 ISO 值但用 f/16 作测量,得快门值后再乘以 256 倍,就是所需的曝光时间了。例如我们测出要曝光 1 秒,那么在此针孔相机上则要曝光 256 秒。
倒易律失效 (Reciprocity Failure)
直至现时为止,所有东西都很直接很数学,但是在摄影上来说,还有一样东西称为「倒易律」。简单说就是在同一感光物料上,曝光时间与曝光量是成正比例上升的,曝光时间两倍,则曝光量也有两倍。但在实际拍摄上,当曝光时间超过一定秒数,就会出现「倒易律失效」,两者不再成正比例,如果想得到正确曝光,则需要额外曝光时间。
下图就是额外曝光简表,很有用,留着它︰
就用 256 秒曝光为例,因为倒易律失效,所以要用上 4 倍曝光时间,即是 1024 秒,由 4 分钟增至 17 分钟,差异当然很大,而且要在曝光环境良好稳定的情况下才是这样。不过放心,其实就算少几分钟也不会很差的,摄影师就曾试过仅用了应有曝光时间的 1/8 来拍摄,结果也不错。
最后提一提,由于针孔摄影往往需要很长曝光时间,所以使用脚架,或放置在稳定的平台上拍摄是很重要的。

 

检验相机成果

接下来让我们看看曲面感光拍出来的效果吧~。

DIY:制作曲面感光元件的针孔相机,首发于极客范 – GeekFan.net

DIY:拆了收录机,做个机器人

我(原作者)是那种会留下所有损坏的电子设备的人,因为我有可能会在某天用到这些东西。我有一张坏了的CD,一个磁带盒和一个别人送我的收音机,它会随机地保持关机状态。事实证明,这不过是因为收音机的某个焊点坏了。把收音机拆开后我才意识到,由于我们已经有了手机,这些年我们已经很少用到它了。如果我再把它组装回来,也不过是放在架子上落灰。

我决定把它身上多余的东西拆掉,用剩下的关键部位组装出一种功能不变但外表新颖的东西。这样起码还能将它作为架子上的装饰品。如果你也喜欢利用废品做机器人,那么你可能会喜欢这样的尝试。这个机器人能够播放CD、磁带,能听收音机,还能通过音频输入线与你的手机相连。

第一步:工具准备

要说出具体需要的工具还真有点困难,以下是必备工具。
1、达美电磨
2、电钻
3、机械螺丝
4、刀具
5、锉刀
6、中心冲头
7、热熔枪
8、钳子
9、螺丝刀
10、卡尺
11、一台3D打印机在定制支架时非常有用,如果你没有的话,你可以用聚氯乙烯这种材料,使用时将其热熔即可。

拆解

要想得到拼接机器人,你必须先将东西都拆开。你可以看到图中的受害者:一台美国无线电公司产的立体声音响。拆开后,我惊讶地发现里面非常空。我把这些东西拆开后,将它们都拼接到了一起,幸运的是这些东西都还能正常工作。这是一个看上去很好玩的立体声音响。当然,这些还不够,如果要做好机器人,我还需要找一些能当支架的废品。

重新组合

要做一个能站立的机器人,必不可少的一部分是它的双脚。我将一张硬盘劈成了两半给它做脚,用大型激光打印机的一些零件给它做了双腿。我发现最难的地方在于,如何将两个不相干的东西结合到一起。我需要一种能支撑这些零件重量的东西,我可不希望我将它拿起来的时候它就散架了。

我的解决办法是将零件对齐,给它们钻孔并用螺丝将其连接起来。对于一些没法钻孔并用螺丝连接的地方,我会先测量尺寸,并用3D打印机定制一些支架。

接着干

另外一个挑战在于如何连接这些扬声器。我想将它们变成机器人的肩膀,但不知道该怎么讲它们连接起来。在切开塑料的时候,我发现收音机外壳上的网很适合做肩膀。由于它们会阻碍其它零件,因此我用3D打印机定制了一些支架,让它们能够上下翻折。

快好了

到目前为止,头是最有挑战性的一部分。我希望机器人的外表在具有复古风格的同时,还能让人在看到它的第一眼就知道它的功能与声音有关。我发现一盒旧磁带的大小与电脑散热片的大小差不多。散热片也可以用来做机器人的头,因为它大部分地方是空的,能够轻易地在里面接线从而给它焊电灯泡。酷酷的机器人怎么可以不亮呢?另外,感谢我的女朋友在此过程中伸出援手。

一些收尾工作

搜寻过废物箱之后,我找到一个废弃的相机电路和一圈花线,并将它们装饰到机器人的头上,给它增加复古感。卷线很容易,只要将它绕在螺栓或者螺丝起子上就行。

整个过程用时比我想象的要长。总共用了50个多小时,不过整个过程很有趣。我还会对这个机器人做一些改进,比如给它身上加一些灯和可移动零件,并给这些灯加上控制开关。我还想知道如何能将机器人的嘴变得能够显示音量大小,并让它根据所播放的声音眨眼。如果你知道,请跟我联系或者在评论中告知我。能变废为宝是一件很棒的事,我会做更多这类大小的机器人。

DIY:拆了收录机,做个机器人,首发于极客范 – GeekFan.net