首页
论坛
课程
招聘
雪    币: 353
活跃值: 活跃值 (27)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝

[原创]从p0sixspwn源码看越狱流程、原理、目的

2014-10-31 13:00 19317

[原创]从p0sixspwn源码看越狱流程、原理、目的

2014-10-31 13:00
19317
本文word版本: 从p0sixspwn源码看越狱流程、原理、目的.docx.7z

p0sixspwn的源码在:
https://github.com/p0sixspwn/p0sixspwn
这个工具可以实现iOS6.1.3~6.1.6的越狱。

本文的目的在于针对p0sixspwn源码,分析越狱操作的流程、然后理解原理,最终总结出通用的东西例如目的、理念等。

流程和原理:
1.        首先检查iOS设备是可以越狱。
检查产品类型,固件版本。不支持,结束。
2.        检查iOS设备是否已经越狱。
检查是否可以启动afc2、检查是否/Applications目录是一个符号连接、检查是否存在/private/etc/launchd.conf文件
已越狱,结束。
Note1:越狱前/Applications目录是一个正常目录,当Cydia第一次运行完之后就成了符号链接。
Applications -> /var/stash/_.k0EtTL/Applications/
这是因为/Applications目录下的文件被移动到了用户分区下,这样做是为了给系统分区节省空间,来放别的东东。
参考:http://theiphonewiki.com/wiki//private/var/stash
Note2:launchd.conf是越狱后写入的,目的是让iOS版本的init程序(/sbin/launchd)来加载执行内核内存补丁程序:/private/var/untether/untether,该程序主要目的是去掉内核对执行文件的完整性检查(Apple Mobile File Integrity),可写的内存区域就不会有执行权限,等限制。
这里要注意的是用户分区是挂接在/private/var目录下的:
/dev/disk0s1s2 on /private/var
在没有越狱的情况下/etc目录也是一个符号连接到/private/etc
/etc -> /private/etc/
所以/private/etc/launchd.conf就是/etc/launchd.conf,但这个文件又是只读的,因为他属于root分区,fstab定义root分区是只读的:
/dev/disk0s1s1 / hfs ro 0 1
Note3:检查有没有越狱只要看能不能开启afc2就够了。至于Cydia有没有运行过,或者untether程序有没有放置只是辅助。
3.        越狱的第一步,利用com.apple.mobilebackup2漏洞,创建文件:/var/db/launchd.db/com.apple.launchd/overrides.plist,内容如下:
char* overrides_plist = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
"<plist version=\"1.0\">\n"
"<dict>\n"
"    <key>com.apple.syslogd</key>\n"
"    <dict>\n"
"        <key>Disabled</key>\n"
"        <true/>\n"
"    </dict>\n"
"</dict>\n"
"</plist>\n";
字面上看是要关闭syslog服务。
Note1:com.apple.mobilebackup2漏洞利用的方法类似于在游戏上经常使用的存档漏洞。
流程是:首先生成备份。在PC端对备份文件进行修改。通过恢复修改后的备份文件触发漏洞。
这个漏洞的原理并不是堆栈溢出,而是恢复备份时对存在的符号链接的情况没有做安全过滤。
例如创建/var/db/launchd.db/com.apple.launchd/overrides.plist的流程:
a.        Create backup
b.        backup_mkdir("Media/Recordings")
c.        backup_symlink("Media/Recordings/.haxx", "/var/db/launchd.db/com.apple.launchd")        也就是/var/db/launchd.db/com.apple.launchd -> Media/Recordings/.haxx
d.        backup_add_file("Media/Recordings/.haxx/overrides.plist")
e.        restore backup
Note2:使用afc对文件操作的范围仅限于:/private/var/mobile/Media,而且只能是普通用户(501、mobile)的权限
/usr/libexec/afcd --xpc -d /private/var/mobile/Media
com.apple.mobilebackup2程序,也就是/usr/libexec/BackupAgent2,虽然是root权限,但也不能写只读的分区,例如/private/etc/launchd.conf。
/System/Library/Lockdown/Services.plist:
        <key>com.apple.mobilebackup2</key>
        <dict>
                <key>InstanceLimit</key>
                <integer>5</integer>
                <key>Label</key>
                <string>com.apple.mobilebackup2</string>
                <key>ProgramArguments</key>
                <array>
                        <string>/usr/libexec/BackupAgent2</string>
                        <string>--lockdown</string>
                </array>
        </dict>
Note3:我不明白关闭com.apple.syslogd有什么实质意义。
4.        越狱的第二步,利用漏洞DeveloperDiskImage race condition
先交代背景:
把iPhone同你的Mac连上, 打开Xcode, 点击 “User For Development”, 一个磁盘映像就会上传到你的iPhone中。它就是所谓的 DevelopeerDiskImage.dmg
这个DMG可以在你的Mac机器上找到, 比如
/Developer/Platforms/iPhoneOS.platform/DeviceSupport/3.1.3/DeveloperDiskImage.dmg
通过SSH登录到iPhone上,运行mount命令
#mount
/dev/disk1 on /Developer (hfs, local, read-only) Note1:这个/Developer目录是iOS系统原始情况下就有的
扩展应用就是:可以挂接任何dmg到这个/Developer目录,只要同时具有这个dmg文件的有效签名。
例如:http://appldnld.apple.com/iOS6/041-8518.20121029.CCrt9/iOSUpdater.ipa
解开获取:iOSUpdaterHelper.dmg、iOSUpdaterHelper.dmg.signature
运行下面命令同样可以完成挂接:
$ ideviceimagemounter.exe -t Developer ./iOSUpdaterHelper.dmg
Uploading ./iOSUpdaterHelper.dmg --> afc:///PublicStaging/staging.dimage
done.
Mounting...
Done.
Status: Complete
这个race condition是说,按正常流程将dmg和其签名,通过lockdown告诉了com.apple.mobile.mobile_image_mounter之后的某个时刻,如果用另外一个dmg的内容替换了afc:///PublicStaging/staging.dimage,会怎么样?
结果是,如果这个时间点拿捏的比较好的话,另一个dmg(hax.dmg)会取代iOSUpdaterHelper.dmg被挂接到/Developer目录!
而这个时间点就是com.apple.mobile.mobile_image_mounter完成了dmg完整性校验,但还没有开始挂接dmg文件。
从程序上看,这个时间点是1000 ~ 3900(1000+29*100)us,程序会以100us为步长,通过29轮来尝试这个碰撞。
我印象中race condition都很短,有的甚至用FPGA之类的硬件来实现,例如xbox360。估计现在的版本apple不会再留这么多的时间间隔了吧...

这个hax.dmg hfs文件系统镜像里面只有2个plist文件:

貌似/usr/libexec/lockdownd程序非常关注这个"/Developer/Library/Lockdown/ServiceAgents"目录。


5.        越狱的第三步,通过lockdown运行r.plist和com.apple.afc2.plist
简单说就是通过root权限执行下面两条命令,第一条remount让root分区具有写权限(android的root,:-)),第二条启动熟悉的afc2服务
/sbin/mount –u –o rw,suid,dev /
/usr/libexec/afcd --lockdown -d /

r.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>r</string>
        <key>ProgramArguments</key>
        <array>
                <string>/sbin/mount</string>
                <string>-u</string>
                <string>-o</string>
                <string>rw,suid,dev</string>
                <string>/</string>
        </array>
</dict>
</plist>

com.apple.afc2.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>com.apple.afc2</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/libexec/afcd</string>
                <string>--lockdown</string>
                <string>-S</string>
                <string>-d</string>
                <string>/</string>
        </array>
</dict>
</plist>
6.        越狱的第四步,类似于第一步继续使用com.apple.mobilebackup2漏洞上传untether payload和Cydia安装包(当然afc2都起来,没有必要一定需要利用这个漏洞了)
例如/etc/launchd.conf、/private/var/untether/_.dylib、/private/var/untether/untether
# cat /etc/launchd.conf
unload /System/Library/LaunchDaemons/com.apple.MobileFileIntegrity.plist
bsexec .. /sbin/mount -u -o rw,suid,dev /
load /System/Library/LaunchDaemons/com.apple.MobileFileIntegrity.plist
setenv DYLD_INSERT_LIBRARIES /private/var/untether/_.dylib
bsexec .. /private/var/untether/untether
unsetenv DYLD_INSERT_LIBRARIES
bsexec .. /bin/rm -f /var/untether/sock
bsexec .. /bin/ln -f /var/tmp/launchd/sock /var/untether/sock
        目的是每次系统启动后,都可以通过/sbin/launchd来执行上面这些命令。
7.        到此越狱结束。

其实还要再说几句,因为还有几个漏洞的利用没有登场。
第一个是AMFID_code_signing_evasi0n7
untether本身的目的是在内存上patch掉内核的限制。但_.dylib和untether都是没有签名的程序,在没有被patch之前又如何运行呢?
_.dylib里_TEXT是空的,他也就没有签名,他存在的真实目的告诉动态库加载器dyld,用CoreFoundation里的_CFEqual函数来替换掉libmis.dylib里的_MISValidateSignature
我理解re-export只是一个特征,基于这个特征的确是比较危险,算他是漏洞吧。
    $ dyldinfo -export _.dylib
    export information (from trie):
    [re-export] _kMISValidationOptionValidateSignatureOnly (_kCFUserNotificationTokenKey from CoreFoundation)
    [re-export] _kMISValidationOptionExpectedHash (_kCFUserNotificationTimeoutKey from CoreFoundation)
[re-export] _MISValidateSignature (_CFEqual from CoreFoundation)
参考CoreFoundation的源码:
www.opensource.apple.com/tarballs/CF/CF-855.17.tar.gz
Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
    if (NULL == cf1) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT; }
    if (NULL == cf2) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT; }
    if (cf1 == cf2) return true;
    CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf1, isEqual:, cf2);
    CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1);
    __CFGenericAssertIsCF(cf1);
    __CFGenericAssertIsCF(cf2);
    if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false;
    if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) {
        return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2);
    }
    return false;
}
libmis.dylib里的_MISValidateSignature是这样的:
int __fastcall MISValidateSignature(int a1, int a2)
{
  return MISValidateSignatureAndCopyInfo(a1, a2, 0);
}
因为a1和a2是不同的东西,所以CFEqual一定返回false也就是0。对于MISValidateSignature,0就是校验通过!

虽然
setenv DYLD_INSERT_LIBRARIES /private/var/untether/_.dylib
bsexec .. /private/var/untether/untether
这两句看样子是说在untether执行的时候做这个符号替换,但实际这个_.dylib真不是为他准备的。untether根本就不会去调用MISValidateSignature函数!
事实上_.dylib是给amfid这个程序准备的。因为内核在加载untether做校验时,启动了用户态程序amfid来判断是否合法,不知道apple为什么这样设计,但事实就是这样。
这样amfid总会告诉内核,他在加载的程序是合法的,于是untether就运行了。
这里摘录《D2T1 - Pod2g, Planetbeing, Musclenerd and Pimskeks aka Evad3rs - Swiping Through Modern Security Features.pdf》说明amfid的调用关系:

Note: lauchd加载untether程序流程
1. lauchd调用fork(spawn)
2. 在fork的子进程里调用execv
3. 内核装载器调用amfid检查untether有效性,通过后进行装载
4. 内核装载器发现untether是要用到动态库的,就顺便装载dyld,把返回用户态后的fork出来的进程的pc指向dyld的入口函数
5. dyld完成剩下dylib的加载(包括执行dylib里的init函数),最后执行untether的入口函数。

剩下的漏洞利用在于untether执行起来之后如何去找到对应的指令进行patch,据说因为ASLR的存在,这个事情很难办到。
目前还没有看到这部分,无法确认细节,据说是下面这两个:
posix_spawn kernel information leak (by i0n1c)
posix_spawn kernel exploit (CVE-2013-3954) (by i0n1c)

最后做下小结
越狱的目的是什么?或者说越狱对iOS设备造成了什么影响?
目的就是突破iOS上的限制。
1.        Remount rootfs获取写权限
2.        启动afc2访问所有文件
3.        Patch内核,去除执行文件完整性检查机制(unsigned code to run)、可写的内存区域没有执行权限(MobileSubstrate可以工作)、…
4.        安装Cydia(Appstore不是唯一来源)

2020,给你一个诚意满满的夏令营!

上传的附件:
最新回复 (12)
雪    币: 325
活跃值: 活跃值 (24)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
地狱怪客 活跃值 2 2014-10-31 13:12
2
0
顶。。。
雪    币: 7830
活跃值: 活跃值 (109)
能力值: ( LV8,RANK:137 )
在线值:
发帖
回帖
粉丝
雪衫 活跃值 2014-10-31 13:22
3
0
前排留名,以后有时间再学习下..感谢楼主分享
雪    币: 4
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whliuwei 活跃值 2014-10-31 13:54
4
0
嗯!写的不错,有机会是否可以共同交流一下。
雪    币: 114
活跃值: 活跃值 (14)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
gamehacker 活跃值 1 2014-10-31 15:21
5
0
求交往,楼主求联系方式
雪    币: 235
活跃值: 活跃值 (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
piratelzs 活跃值 2014-10-31 15:57
6
0
不明觉厉~~!致谢一个先
雪    币: 494
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
鬼谷子c 活跃值 1 2014-10-31 16:26
7
0
前排支持。。不过现在一般用盘古的直接越,自己写工具,太纠结了。。
雪    币: 213
活跃值: 活跃值 (14)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
冰冻冷咖啡 活跃值 2014-10-31 16:27
8
0
支持楼主科普帖子~学习mark!
雪    币: 10891
活跃值: 活跃值 (1046)
能力值: ( LV15,RANK:870 )
在线值:
发帖
回帖
粉丝
obaby 活跃值 20 2014-11-3 17:14
9
0
顶~~~~
雪    币: 5257
活跃值: 活跃值 (78)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
FlashK 活跃值 2014-11-6 22:26
10
0
分析不错。支持。
雪    币: 246
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
airbus 活跃值 2014-11-18 15:58
11
0
人好少啊...好好努力了哈.
雪    币: 74
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chengyang 活跃值 2016-3-23 14:37
12
0
认真的拜读了下楼主的分析,收获很大!
可惜最后的untether内核patch部分没有看到细节,这方面有相关的源码吗?
雪    币: 43
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tangxp 活跃值 2016-4-15 09:17
13
0
这个强大,花一些时间来学习。
游客
登录 | 注册 方可回帖
返回