分类目录归档:Stack

修改scrapy-selenium支持docker-selenium

scrapy-selenium是一个Scrapy的中间件,用于让Scrapy支持通过selenium driver访问网页。但默认情况下只支持本地的WebDriver。

scrapy-selenium在和selenium的会话管理上相对完善和稳定,所以,派生一个SeleniumMiddleware的子类,重写即可。

More

逍遥模拟器adb配置参考

最近为了减少一些工作量以及完成自动化的需求,对Android模拟器进行了一些测试。通过测试,逍遥模拟器的性能、兼容性、Xposed稳定性方面满足需求。但默认情况下adb连接略微麻烦。可以进行如下调整解决。

本地adb连接

由于逍遥模拟器自带的adb版本较老,使用platform-tools的adb连接会出现不兼容。因此,复制platform-tools的adb替换即可。替换文件: More

切换VPS服务器记录

终于下定决心买一台VPS。原因有两个,一来总是白嫖FlowerCode的服务器,实在不好意思;二来最近三年都在键值成都办公室网管和部门IT的角色,一来二去的折腾,竟感觉还有那么些意思。所以,趁着休假的时机,正好有时机安静的折腾。 More

连接AWVS 11的PostgreSQL数据库

最近有些需求,需要在AWVS 11的基础上进行一些自动化,AWVS 11的API接口不能完全满足需求,所以需要直接操作数据库完成。

读取配置文件

配置文件位于C:\ProgramData\Acunetix 11\settings.ini,数据库相关的字段如下:

外部访问PostgreSQL

修改C:\ProgramData\Acunetix 11\db目录下的PostgreSQL配置文件pg_ident.confpostgresql.conf可以让PostgreSQL外部访问,但升级的时候会出问题。Windows下,使用netsh进行端口转发,并且加入防火墙例外即可:

QQ拼音for Android v4.9.1 so劫持/感染

Intro

QQ拼音for Android v4.9.1的导出组件com.tencent.qqpinyin.voice.DownloadApkService没有对传入的下载地址进行过滤,导致任意文件下载,且没有对传入的文件名进行合法性校验,导致目录遍历。加上其本身Apk的特点,可以使用该组件感染/劫持so文件。
之前没注意QQ拼音已经归属搜狗,2015-04-27提交到了TSRC,告知已转交搜狗。至今漏洞依然存在,但从v4.9.2开始lib目录有所变化,无法感染/劫持。

漏洞细节

查看AndroidManifest.xml文件,发现com.tencent.qqpinyin.voice.DownloadApkService导出:

DownloadApkService关键代码如下:

所以,绑定了该服务即可通过mBinder进行远程调用。mBinder是DownloadApkService$3,实现的接口如下:

DownloadApkService$3的startDownload实际上调用的是DownloadApkService的download函数:

download函数如下:

所以,实际上调用的是DownloadApkService$DownLoadTask进行下载。程序预期在/storage/emulated/0/Tencent/QQInput/Apk/目录下写入文件,由于没有处理”../”,导致目录遍历,可以将文件写入任意位置。

利用方法

和其他Service的利用有点差别,远程调用Binder需要在绑定后使用transact进行调用,通过Parcel传递返回值和参数。每一个函数的对应调用号可以在IDownloadApkService$Stub中找到:

然后利用起来就十分简单了:

关于感染/劫持

在QQ拼音for Android v4.9.1这个版本中,apk运行时所需的so文件并没有保存在apk的lib目录下,而是保存在了Apk的/res/raw/目录下,运行的时候释放到/data/data/com.tencent.qqpinyin/app_lib/目录并加载运行。在Android系统中,App自身无法写入/data/data/[PACKAGE_NAME]/lib/目录,只可读取。QQ拼音for Android v4.9.1的这种设计则绕过这种设计,并且在加载时只做了文件是否存在的校验,并没有其他完整性校验。利用如下代码可以感染libsecurity.so文件:

伪造的libsecurity.so被加载的时候会drop原始的so,并调用原始的JNI_Onload。效果如图所示:
0ce82ad83ec2664e30ef2ec318ea00c5
完整代码请参考QQPinyinExp

其他

4.9.2后的版本,所用的so文件放在了lib目录下,无法直接写入。然而,com.tencent.connect.auth.AuthDialog会尝试加载的/data/data/com.tencent.qqpinyin/files/libwbsafeedit.so:

看起来这是腾讯SSO的一个SDK,但目前没发现能触发的操作。如果其他App也用了这个SDK,配合额其他类似的漏洞,也可以达到劫持和感染的目的。

QQ邮箱 for Android <= 4.0.4手势密码绕过

漏洞描述

对于一个Android程序来说,没有一个统一的入口,任何导出的Activity都可以作为程序的入口。所以,如果在写程序的时候,没有考虑到每一个入口进入时的状态,就有可能出现逻辑上的漏洞。
比如QQ邮箱的这个,连续启动两次某些Activity就可以绕过手势密码。最初把PoC代码和描述都提交到了TSRC,结果那边回复说这是by design的,之后的沟通不了了之。

PoC

完整代码见:https://github.com/TheCjw/QQMailPatternLockBypass

半自动Fuzz

结合Drozer,并针对导出Activity进行一些逆向分析,可以轻松找到类似的漏洞。这类漏洞并不适合Fuzz,因为很大程度上涉及到了业务逻辑,初始化环境和检测结果免不了人工干预,但我们当初还是进行了一些尝试。大体的步骤是这样的:

  • 安装一些App,并登录帐号,进行设置。
  • 编写了个drozer的插件,目的是获取导出的Activity,然后对Activity进行排列组合,产生不同的调用顺序。当时最多好像设置了3个。
  • 之后,插件按照生成的顺序进行startActivity,每次startActivity设置一定的间隔。每组走完之后,获取顶层Activity,和之前启动的Activity进行对比,如果不是这两个Activity以及桌面的话,记录组合。
  • 重放步骤3中记录到的组合,人工进行观测。最后,靠肉眼识别。
  • More

    CVE-2014-3153笔记

    CVE-2014-3153可以说是相当经典的漏洞,影响范围相当广泛。这实际上是一个Linux内核的Use-After-Free漏洞,利用得当可以转化为任意内核地址写入。Geohot的TowelRoot也利用了这个漏洞,在当时(以及现在)能够Root(或Crash)绝大多数Android设备。由于工作的需要,收集了该漏洞的一些资料,并且对漏洞原理和利用方法进行了一些学习和分析。

    参考资料

    以下是收集的资料:

    http://blog.nativeflow.com/the-futex-vulnerability
    http://blog.nativeflow.com/escalating-futex
    http://blog.nativeflow.com/pwning-the-kernel-root
    http://blog.topsec.com.cn/ad_lab/cve2014-3153/
    https://github.com/timwr/CVE-2014-3153

    https://github.com/android-rooting-tools/libfutex_exploit More

    360加固保ELF脱壳总结

    Intro

    360加固保可以针对ELF和DEX进行保护,360某些产品的ELF文件基本都使用了自家产品进行加壳,而这些正是我们感兴趣的东西。由于文件比较多,为了能够快速的拿到Payload,最近稍微总结了一些较为通用的方法。

    大体流程

    壳整个流程的目的是解密核心ELF文件到内存中,关键解密的地方有3处,均使用RC4。

    INIT_ARRAY

    壳填充了结构,Linker在so加载完毕后会调用这个回调。这个函数被重命名为__gnu_armfini_26。其功能是进行一些反调试,并且解密JNI_Onload的代码。

    JNI_Onload

    JNI_OnLoad负责解密核心ELF并加载。此时解密的ELF文件的入口代码没有解密。

    __gnu_Unwind_0

    最后的步骤,解密核心ELF的入口代码。在不同的版本中解密入口代码的地方有所不同,一般的产品中在壳调用原始JNI_OnLoad之前会进行解密,360的某些产品则会通过Hook库函数的方式,在调用库函数之前再进行解密。

    关键函数

    外壳大部分函数名被修改成了伪库函数的名字,如图:
    shell_functions
    通过调试得到了一些关键函数的功能,对这些函数下断点可以快速的脱壳:

    __gnu_arm_message

    rc4_decode

    __arm_aeabi_6

    rc4_init

    __gnu_Unwind_0 

    解密入口
    脱壳流程
  • 找到__gnu_armfini_26函数。修改入口代码为FE FF FF EA,即死循环;
  • 加载so并使用调试器附加,将原始代码修改回去,一般是PatchDword(GetRegValue(“PC”), 0xe92d0001)
  • __gnu_arm_message进行下断,然后开始跑;
  • 第一次是JNI_Onload的解密,第二次是ELF文件的解密,记录下解密数据保存的地址和大小,RC4解密完之后还会有些处理,此时可以先不Dump;
  • 第三次略有不同,如果是解密一个8字节的数据,则需要手工设置PC为__gnu_Unwind_0。如果大于8字节,则是在解密入口代码。解密完成后Dump出Step 4中的数据以及入口代码。
  • 把入口代码写回ELF中。ELF头部magic可能被修改为lfx,这种情况把lfx替换为ELF即可。
  • More

    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/