分类目录归档:Stack

WIFI万能钥匙Python查询脚本

最近声讨WIFI万能钥匙的声音越来越越多。这东西带来的安全性不必多说,但研究这个App还是十分有意思的。

其实在去年10月份左右,Hao Liu就已经把接口分析完毕。当时还没有iOS的非越狱版,Hao Liu猜测到了WIFI万能钥匙团队一定会通过大量的Android用户提供的密码,然后以LBS的形式出现在Apple App Store上。 More

CVE-2012-1875 UAF Analysis

Intro

大牛ga1ois在《关于泄漏的艺术》一文中提到CVE-2012-1875是一个可以从脚本层面直接访问的UAF。以前没分析过这种类型的UAF,这两天趁着年后不忙看了一下漏洞成因。

POC

POC来自看雪,按照惯例添加了一些代码方便跟踪整个过程:

调试的IE版本:

崩溃信息

打开POC之后崩溃信息如下:

看起来是某个CElement(实际上是CImgElement,后文会提到)的UAF。根据栈中的调用信息,发现这个CElement来自下面的代码:

635E7AA4的CElementAryCacheItem::MoveTo以及635E7AAB的CElementAryCacheItem::GetNext是通过调试得到的。可以看到,这个CElement保存在一个类型为CElementAryCacheItem的对象里。

CElementAryCacheItem&CImplPtrAry

根据调试分析,在这个版本的IE中,CElementAryCacheItem的虚表地址是6363b284:

显然这有点像一个vector。通过进一步的分析,发现是CImplPtrAry的一个子类,对象中部分偏移所代表的含义如下:

如此看来,这个UAF的原因是某个CElement被保存在一个CElementAryCacheItem对象里,但这个CElement被释放之后,并没有从这个数组中移除,之后的代码直接取出对象并使用,导致UAF。
因此,通过监视CElementAryCacheItem添加和删除对象的情况,可以得知是哪一个CElementAryCacheItem对象以及哪一个CElement出的问题。经过测试,IE中只使用了CElementAryCacheItem::AppendElement(CElement *)进行添加对象,CElementAryCacheItem创建之初并没有分配Buffer,而是在第一次Append的时候分配空间,之后每一次Append会检查是否超过了当前的容量,如果超过则分配新的空间,然后复制原始数据,并且Append新的对象,最后释放掉旧的空间,这一点上很像vector;释放的时候使用的是CElementAryCacheItem::ResetContents(void),ResetContents只是重置了个数,并没有清除掉数组Buffer中的内容。

对象跟踪

需要说明的是,通过调试可以发现,那个UAF的CElement对象实际上的类型是CImgElement,是CElement的子类。最初我是通过CElement::CElement以及CElement::~CElement进行监视,这样的Log比较多,后来通过KK的文章以及调试,确定了对象是CImgElement,所以,用于监视的WinDbg脚本应该是这样的:

分段列出Log,便于分析:

上述代码是执行x[0].fireEvent(“onMouseOver”);前的Log,可以看到,创建的CImgElement对象是00215ae8,被插入到了00226950和00225d38两个CElementAryCacheItem中。

这里是触发onMouseOver后执行crash函数中的Log,可以看到CImgElement对象00215ae8被加入到了02de91a0这个CElementAryCacheItem中。

这一段是执行testfaild.innerHTML = testfaild.innerHTML;时的Log,KK的文章中说这一段代码会导致对象被释放并且重新创建,这个Log展示的和描述相符。其中,CImgElement对象00215ae8已经被释放。
现在,00215ae8被加入到了三个CElementAryCacheItem中,分别是00226950、00225d38以及02de91a0,通过最后一段日志,可以看到发生问题的:

可以看到,出问题的对象确实是00215ae8的那个CImgElement,而由于00225d38和00226950已经reset。所以,目前可以确定,第一次进入crash函数的时候创建的CElementAryCacheItem中残留了已经释放的CImgElement。

另一个CElementAryCacheItem

然而,实际情况有些不太一样。我尝试着调试crash函数中的Append相关的代码,发现被Append到这个CElementAryCacheItem中的元素,是HTML代码中包含了相同名字的元素,在上一层代码,也就是CCollectionCache::BuildNamedArray函数中,会遍历另外一个CElementAryCacheItem,然后进行比较Id,只有Id为imgTest才会被Append。CCollectionCache::BuildNamedArray完毕之后,会返回CCollectionCache::GetDisp,然后执行到这个地方:

这段代码会分配一个新的CElementAryCacheItem,然后使用CImplPtrAry::Copy将之前监视到的那个CElementAryCacheItem复制到新的CElementAryCacheItem中,之前的那个只是一个局部变量。之后,这个CElementAryCacheItem会保存在CCollectionCache中。构造完毕的结构如下(由于是另外一个快照的,所以CImgElement的地址变成了001f8850,新的CElementAryCacheItem地址是001ebf50):

解释一下,CCollectionCache偏移0xC处,是一个数组的Buffer地址。这个数组元素的结构未知,这里延续KK文章中的描述,称之为CACHE_ITEMS。CACHE_ITEMS的大小是0x3C,总共有0xF个,发生UAF的元素保存在最后一项也就是下标为0xE。CACHE_ITEMS的偏移0x8处是一个CElementAryCacheItem结构,这个结构之前已经给出,偏移0x14处是数组的Buffer,里面保存着CImgElement和CDivElement,也就是001f8850和001d8228。内存Dump展示如下:

此时,可以通过硬件断点,跟踪这个CACHE_ITEMS的访问,最后可以发现,确实是这个数组中的CElementAryCacheItem被取出,进而读取里面已经释放的CImgElement。

成因分析

有了对CElementAryCacheItem的理解,以及对象释放后对三个包含了CElementAryCacheItem的观察,发现在CImgElement释放后,这些CElementAryCacheItem中依然保存着CImgElement的指针。不同的是,另外两个CElementAryCacheItem在使用前检查了某个标志,然后调用CElementAryCacheItem::ResetContents避免了UAF的发生。所以猜测这个UAF的原因是某处代码忘记调用CElementAryCacheItem::ResetContents所致。
为了证明这个观点,我企图通过调试补丁后的程序得到答案。然而,通过修改WinDbg脚本监视ResetContents并没有得到我想要的结果,在补丁后的IE中,并不会Reset那个CElementAryCacheItem::ResetContents。此时,可以确定是某处标志设置或检查不严格导致了这个UAF。
经过漫长的对比调试,得到了最终的结果。最后出现不同的代码位于此处:

在这里,ebx是CCollectionCache,所以eax就是CACHE_ITEMS的Buffer,而esi是0xE,也就是读取最后一个元素。此时,最后一个元素内存是这样的:

之后,会从CACHE_ITEMS的偏移0x24读出另外一个Index,再用这个Index去索引另外一个CACHE_ITEMS。可以看到偏移0x24处的值是8。也就是说,这里会用CACHE_ITEMS[0xE]和CACHE_ITEMS[0x8]的最后一个元素做对比。Patch前两个值的内容一样,均为0,跳转不会实现。而补丁后的值则不同,跳转不会实现。以下是在mshtml_8.00.6001.23580中得到的结果对比:

可见,两个的值不同,0x8的是2,0xE的是1。在补丁后的版本,也就是mshtml_8.00.6001.23580中,修改CACHE_ITEMS[0x8]标志位1,使得跳转失败,该POC还是会导致UAF。所以,可以确定,导致该UAF的原因是某处忘记设置了CACHE_ITEMS的标志。
有了这个地方,通过硬件断点即可找到补丁后的代码更新标志的地方:

而使用硬件断点监视补丁前的的程序,没有看到更新这个标志的地方。

结语

Coming soon…

参考文章

1. CVE-2012-1875:mshtml.dll Use-After-Free漏洞分析,http://bbs.pediy.com/showthread.php?t=152240
2. CVE-2012-1875:Microsoft IE SAME_ID UAF,http://zenhumany.blog.163.com/blog/static/1718066332013926101149471/

CVE-2013-3893 UAF Analysis

Intro

前段时间工作中一直在干一些乱七八糟的事情,重心基本都是在Android上,掐指一算大概也有几个月没在Windows上用过调试器了。昨天心血来潮分析了一下IE的CVE-2013-3893漏洞。

POC

POC来自这里,使用XP下的IE8作为调试对象:

调试过程
定位出错对象

IE加载原始的POC,异常中断时的信息如下:

CallStack:

异常的地址位于CElement::Doc函数的第一句:

显然,尝试在获取当前CElement对象的虚表时,发生了内存访问异常错误,当前的对象即ECX的值为feeefeee,即包含了这个CElement的对象在释放后被使用,该对象的内存已经被设为feeefeee,尝试从该对象中取出的CElement对象是一个不存在的对象。
往上一层看代码,当前属于CTreeNode的代码:

根据代码,该CTreeNode偏移0处保存了一个CElement对象的地址,ESI为CTreeNode对象,查看当前对象的内存:

所以,产生异常的对象是CTreeNode。

跟踪对象释放情况

修改POC代码,按照惯例加入Math.atan2

调试器载入IE后,使用sxe ld JScript.dll下断点。接下来载入POC页面,此时由于IE加载JScript.dll,调试器会中断,然后利用如下断点进行整体流程和对象的跟踪:

结果如下:

根据上述Log,可以看到,产生UAF的CTreeNode是最初分配的,姑且称之为Root_0,因为我发现之后Append的两个对象的父节点都是它。CTreeNode +0处是该节点对应的CElement,+4是父节点。
之前的流程都比较清晰,由于id_0设置了onlosecapture回调,id_1调用setCapture()时会导致id_0的onlosecapture回调被调用。而onlosecapture中的document.write(“”);则会导致之前的对象被释放。从逻辑上来看,应该是setCapture内部没有对CTreeNode处理完善,在id_1调用setCapture的某个环节,id_0的onlosecapture被执行,document.write把最初的CTreeNode被释放,之后回到setCapture中,继续使用了该对象,导致UAF。

UAF原因分析

setCapture对应的处理代码位于CDoc::SetMouseCapture,第二次进入CDoc::SetMouseCapture也就是id_1调用的时候,走到的关键代码是这里:

635F3F68的时候,eax是最初创建的CElement对象,+14是对应的CTreeNode,此时,两个对象都还没有被释放。之后调用了CDoc::ReleaseDetachedCaptures。在ReleaseDetachedCaptures函数中,会重新进入CDoc::SetMouseCapture,并走到调用CDoc::ClearMouseCapture,该函数会导致onlosecapture回调的触发:

之后就是进入onlosecapture,执行document.write,CTreeNode被释放。然而,PumpMessage在ReleaseDetachedCaptures之后的代码中,直接使用了保存在栈中的CTreeNode对象,最终通过635F3FDF处调用CTreeNode::NodeAddRef访问到了已经释放的CTreeNode对象。
大体上,触发UAF的原因是:

  1. 保存CTreeNode到栈中;
  2. 调用ReleaseDetachedCaptures导致栈中的对象被释放;
  3. 没有做详细检查直接使用该对象。
未完待续

这次注意到了一些有意思的地方,如:

  • 元素被加入到DOM树的时候,需要用CTreeNode表示各个结点,每个CTreeNode都有其对应的元素(即CElement)和父节点的CTreeNode。
  • document.write导致原始的DOM树失效,并重新建立一个。
  • id_0[‘outerText’]=””;导致了两个元素对应的节点都被摘除。
  • More

    稳定利用CVE-2012-4220的方法

    CVE-2012-4220 原理分析中简单的描述了一下libdiagexploit存在的问题,经过实际的测试,android-rooting-tools使用libdiagexploit是没法将值修改正确的。下面给出一种修正的方案,经过测试可以在ZTE N798 (CT_CN_N798+V1.0.0B09)上获取到了Root权限。

    注意事项

    利用之前需要清楚这个漏洞的功能和限制。
    1. 使用该漏洞可以向任意地址写入一个16位的值,范围是2~0xFFFF
    2. 修改为特定值需要循环调用该漏洞直到delayed_rsp_id的值是目标值。
    所以,就是要控制好写入值,以及循环的次数。
    由于对Linux不熟悉,获取Root权限方法沿用了libexploit中的方法。看起来,其获取Root权限的核心代码是在内核执行commit_creds_address(prepare_kernel_cred_address(0))。为了实现这一目标,libexploit企图利用各种漏洞修改ptmx_fops的结构体中+0x38处的一个函数地址,然后打开设备/dev/ptmx并调用fsync以获得在内核执行代码的权限。为了写入32位的地址,需要分别将目标地址的高位和地位写入。而且,高位和低位中不能出现0或者1。

    利用代码

    根据上述几点分析,更新的代码如下:
    循环次数控制
    为了准确的计算循环次数,每次都将计数重置为2,而且,为了防止将值修改到一半的时候由于其他程序调用,递增的时候使用了局部变量,最后再传入真正要写入的地址:

    地址分配
    一般来说用户态的elf都会加载到比较低的地址,高16bit是0。libexploit直接写入低16位会导致poc的稳定性很差,或者说肯定无法使用,从某个Bootloader来看内核会被加载到0xC0000000以上的地址。为了解决这个问题,目前的解决办法是预分配一块固定地址的内存,然后在里面写入跳转代码,让其跳回当前的模块中。
    分配地址:

    然后从这里抄一个hook:

    完成上述准备工作,就可以开始root了:

    执行的结果:

    这样,这个漏洞的利用就相对稳定了许多。当然,是在有符号、能获取到那些函数、结构体地址的情况下。

    最后

    不太理解的是,Android的内核居然可以直接执行用户空间的代码…

    CVE-2012-4220 原理分析

    漏洞信息

    该漏洞的一些相关连接:
    CodeAurora
    NVD
    上述连接中对该漏洞的描述:

    漏洞分析

    造成该漏洞的主要代码如下:

    这代码两个问题:
    1. 对于用户态传递的参数ioarg没有检验直接使用。传递一个无效指针即可造成拒绝服务。
    2. 对delay_params中的rsp_ptr以及num_bytes_ptr两个用户态的指针仅做了非空判断就直接使用。传递无效指针可造成拒绝服务,传递其他地址可以造成任意地址写入攻击。

    利用思路

    先看一下相关的代码:

    完成有效的攻击需要注意几点。

    delay_params->rsp_ptr More

    ARM和Thumb模式下的断点总结

    脱壳或者调试SO的时候,需要在恰当的时机让进程停下来,以便于附加调试器到该进程上。被无视的壳虐待之后,总结出以下几种断点的方法。

    死循环

    ARM Mode
    ARM Mode下每条指令长度为4个字节,对应跳转自身的Opcode是FE FF FF EA,对应的助记符是:

    Thumb Mode
    Thumb Mode下每条指令长度为2个字节,对应跳转自身的Opcode是FE E7,对应的助记符是:

    断点

    来自Github,代码片段:

    某版本360加固保动态调试&DEX静态脱壳

    Intro

    360加固保是360针对Android app推出的加固服务。本文针对其DEX加密技术进行分析。

    动态调试

    动态调试过程略过。

    文件结构&静态脱壳

    这个版本的加固保中,加密后的DEX文件被附在了壳DEX的文件尾部,如图所示:
    qihoo_dex_unpack
    感谢QQ6.4提供的马赛克功能。
    这块数据有个明显的文件头标志:

    之后的关键数据从偏移0x10C开始到文件尾部的数据,由长度为0x10的key和压缩、加密的DEX组成。在加壳的时候,加固保没有对原始的DEX做结构上的变形和处理,处理的流程如下:

  • 首先会生成8字节8 bit的随机数,对原始的DEX Header,即头部大小0x70的数据进行异或处理。
  • 接下来使用标准lzma压缩DEX文件。
  • 最后随机生成长度为0x10的key,使用标准RC4对压缩后的数据进行加密。
  • More

    某国产DEX加固原理

    Intro

    这个加固是来自国内某个公司的作品,虽然在强度不是太高,但思路却不错,很好的平衡了性能和保护效果。目前看来,分析的这个版本只是一个很初级的框架,如果再此之上进行更多的防护和保护,强度会更好。

    加固效果

    加固之后,其效果是DEX中某些函数被加上ACC_NATIVE标志,原始的DEX代码已经消失,使得反编译、二次打包等功能失效。而加固之后新增的Libt**.so则负责在运行的时候,还原那些被抽取的Dalvik虚拟机代码。

    相关结构

    了解一下相关的结构有助于分析:

    DexClassData描述了DEX文件中的某个类的相关信息,DexMethod则描述的是这个类的函数的信息。DexMethod的methodIdx是method在method_id_item中的Index,accessFlags描述了这个method的Access Control以及其他的信息,code_off是一个偏移,偏移之后的结构是DexCode结构,这个DexCode描述了method具体的信息。更多的信息可以参考Google的官方文档
    以上是DEX文件中相关的结构,而DVM运行的时候,会用上述的信息构造Method,DVM使用这个结构来执行:

    如果Method.accessFlags没有ACC_NATIVE标志,则insns指向Dalvik虚拟机代码,反之,表明该Method的实现在Native层,insns应该为空。

    加固原理

    上面说到,加固的效果是抽取了原始的Dalvik虚拟机代码,并且Method被加上了ACC_NATIVE标志。libt**.so在加载的时候,会获取这些method对应的Method结构,去掉accessFlags中的ACC_NATIVE标志,并且将insns写回这个结构。另外,DVM对insns是有要求的,代码如下:

    可见insns指向的是DexCode中的insns结构,也就是有了Method.insns,就可以得到原始的DexCode结构。

    脱壳

    进一步分析发现,被这个加固抽取掉的DexCode信息还原封不动的保存在Data section中,而在dex的尾部,新增了一个结构用于描述DexCode和原始函数的关系。libt**.so运行的时候,就是通过这个结构来还原Method中的insns信息。
    最后,在smali中加了10来行代码,成功脱掉。

    总结

    这个加固实现的效果有:
    1. 反静态分析
    即便是原始的虚拟机代码仍然保存在文件中,但是二者的关系已经被模糊,不经过修改的工具无法得知原始代码的位置。
    2. 防止内存Dump
    由于针对修复的对象是Method,是DVM内存中的结构体,而原始的odex并没有被修改。
    3. 防止二次打包
    由于这个加固在DEX尾部添加了一个自定义的结构,baksmali二次打包的时候会导致这些信息丢失,原始函数和虚拟机代码的代码也因此丢失,所以编译之后的程序无法运行。
    最后,我分析的这个libt**.so有一处越界的Bug,可能会导致程序崩溃,或者直接篡改任意代码——这有点搞笑……

    The End Of An Era

    P40429-102642_1
    It’s the end of an era. Kevin邮件的第一句。
    这次的主角不是Tarja,是我们。毕业后来到SRC,近两年,如今说没了就没了。太匆匆啊太匆匆。
    这一段时间的经历对我影响至深,感谢SRC的每一位同事,感谢大家的贡献和努力。
    两年的时间,我才明白如何才能做好,可惜现在没有机会再继续。这是我目前最大的遗憾。
    多的不说了,祝各位以后顺利。

    RDB文件格式分析

    RDB文件常见于腾讯的客户端软件,大多数与UI资源相关,包括了各种图片、XML等。

    Layout

    文件头包含了文件基本结构的信息,File Description Table描述了文件名、大小和偏移,最后就是实际文件的数据,没有加密或者压缩。

    File Header

    File Header由四个域组成,C语言描述如下:

    各个字段的描述如下:

    File Description Table

    FDT描述了当前RDB中所有文件的信息,其中的每一项是一个变长的结构,里面的三个字段分别是FileName、OffsetToData以及SizeOfData。

    File Data

    紧挨着的文件数据。

    实例分析

    以下是一个文件头的Dump:

    可知,FDT位于0x24,FileData位于0x24 + 0x01CC16 = 0x1CC3A。
    查看FDT的前两个Items:

    得到的两个文件信息如下:

    查看GIF的信息,偏移为0x1CC3A + 0x1F185 = 0x3BDBF,对应的数据如下:

    End

    这种文件结构有点类似于游戏使用的pak文件,上一次在仙剑的某个版本中看到过类似的结构,只不过多了对文件数据的加密。