forked from Trietptm-on-Security/WooYun-2
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Android uncovers master-key 漏洞分析.html
217 lines (138 loc) · 120 KB
/
Android uncovers master-key 漏洞分析.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
<html>
<head>
<title>Android uncovers master-key 漏洞分析 - livers</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>原文地址:<a href="http://drops.wooyun.org/papers/219">http://drops.wooyun.org/papers/219</a></h1>
<p>
<h3>0x00 背景</h3>
<hr />
<p>Bluebox的CTO Jeff Forristal在其官⽅方blog爆出一个漏洞叫做UNCOVERING ANDROID MASTER KEY,大致是不篡改签名修改android代码。</p>
<p>Link:<a href="http://bluebox.com/corporate-blog/bluebox-uncovers-android-master-key/">http://bluebox.com/corporate-blog/bluebox-uncovers-android-master-key/</a></p>
<h5>blog:关于细节并没有讲太多,只有discrepancies in how Android applications are cryptographically verified & installed(安卓应⽤用签名验证和安装的不⼀一致)essentially allowing a malicious author to trick Android into believing the app is unchanged even if it has been(让andriod系统本⾝身认为应⽤用没有修改)这两条重要的信息。</h5>
<p><!--more--> 剩下就是放出来一张更改基带字串的图:</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394530853.png" alt="enter image description here" /></p>
<p>具体细节7月底的blackhat放出。</p>
<p>没多少天7月8号国外已经有人放出poc来。微博上看到rayh4c说已经搞定。就分析了一下。</p>
<h3>0x01 分析</h3>
<hr />
<p>POC还没出来之前,先是看了下android的签名机制和安装机制。</p>
<p>签名机制: 用简单的话来讲就是android把app应用的所有文件都做了sha1(不可逆)签名,并对这签名用RSA(非对称加密算法)的私钥进行了加密,客户端安装验证时用公钥进行解密。</p>
<p>从逻辑上看,这签名机制对完整性和唯一性的校验是完全没问题的。主流的很多加密都类似这样。</p>
<p>安装机制:</p>
<p>安装机制则较为复杂。</p>
<pre><code>1.系统应用安装――开机时完成,没有安装界面
2.网络下载应用安装――通过market应用完成,没有安装界面
3.ADB⼯工具安装――没有安装界面。
4.第三⽅方应用安装――通过SD卡⾥里的APK⽂文件安装,有安装界面,由packageinstaller.apk应⽤用处理安装及卸载过程的界面。
</code></pre>
<p>安装过程:复制APK安装包到data/app目录下,解压并扫描安装包,把dex⽂文件(Dalvik字节码) 保存到dalvik-cache目录,并data/data目录下创建对应的应⽤用数据目录。</p>
<p>到这里看出在安装机制上的问题可能性比较大。</p>
<p>回头看⽼老外的POC:<a href="https://gist.github.com/poliva/36b0795ab79ad6f14fd8">https://gist.github.com/poliva/36b0795ab79ad6f14fd8</a></p>
<p><img src="http://static.wooyun.org/20140918/2014091811394551470.jpeg" alt="enter image description here" /></p>
<p>在linux执⾏行了一遍,出现错误。可能是apk的原因。</p>
<p>索性把这poc移植到windows下,先是⽤用apktool 把要更改的apk给反编译出来到一个目录apk_test</p>
<p>然后⼜又把apk_test打包成⼀一个新的apk</p>
<p>把原先的apk解压出来apk_old</p>
<p>把apk_old所有⽂文件以zip压缩的⽅方式加⼊入新的apk中。我本机以weibo.apk为例:</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394657069.png" alt="enter image description here" /></p>
<p>可见两者大小发生了变化,apktool在反编译过程不可避免的出现差异。并且重编译的apk不含有签名文件。</p>
<p>按照poc的做法我用批处理导出目录的文件名到1.txt修改了poc.py</p>
<pre><code>import zipfile
import sys
f=open('1.txt','r')
line=f.readline()
test=[]
while line:
test1=line.replace("\n","")
test.append(test1)
if not line:
break
line=f.readline()
f.close()
z = zipfile.ZipFile("livers.apk", "a")
for i in range(0,len(test)):
print test[i]
z.write(str(test[i]))
z.close()
</code></pre>
<p><img src="http://static.wooyun.org/20140918/2014091811394686712.png" alt="enter image description here" /></p>
<p>差不多增大了一倍,放在手机上安装了一下,成功安装。查看了下:</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394685963.png" alt="enter image description here" /></p>
<p>出现了多对同名文件。CRC校验不同,查看了一下,基本上是两个字节便产生不同。</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394680771.png" alt="enter image description here" /></p>
<p>这里我又测试了只添加签名文件,或者dex文件等,均不能通过验证。</p>
<p>可证明其在scan list扫描目录或者复制文件时候对同名文件处理不当。</p>
<h3>0x02 验证</h3>
<hr />
<p>证明是否可以进行更改源码,并能使用原生签名。我把apk图标进行了更改。</p>
<p>顺便讲下一般的反编译修改:</p>
<pre><code>1. apktool或者其他工具进行反编译包含smalijava字节码汇编和xml图片文件。
2. apkzip解压。
3. 反编译dex成java文件。
4. 查找对应修改的smali文件或者xml(一般广告链接)
5. Apktool打包成apk文件
6. 用autosign进行签名。
这里没有进行签名直接借用原来的签名。
</code></pre>
<p><img src="http://static.wooyun.org/20140918/2014091811394776790.png" alt="enter image description here" /></p>
<p><img src="http://static.wooyun.org/20140918/2014091811394768100.png" alt="enter image description here" /></p>
<h3>0x03 查找根源</h3>
<hr />
<p>我这里下载的android 2.2的源码,查找到获取签名信息安装位于<code>frameworks\base\core\java\android\content\pm\PackageParser.java</code>这个文件,<code>public boolean collectCertificates(Package pkg, int flags)</code>和<code>private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)</code>这个方法是用来获取签名信息的。</p>
<pre><code> Enumeration entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry je = (JarEntry)entries.nextElement();
if (je.isDirectory()) continue;
if (je.getName().startsWith("META-INF/")) continue;
Certificate[] localCerts = loadCertificates(jarFile, je,
readBuffer);
。。。。。。
} else {
// Ensure all certificates match.
for (int i=0; i<certs.length; i++) {
boolean found = false;
for (int j=0; j<localCerts.length; j++) {
if (certs[i] != null &&
certs[i].equals(localCerts[j])) {
found = true;
break;
}
}
。。。。。
</code></pre>
<p>前面通过黑盒方式,大致推断出安装机制就是把重命名文件同时处理了,没有覆盖而是:</p>
<pre><code>if (certs[i] != null &&certs[i].equals(localCerts[j])) {
found = true;
break;
}
</code></pre>
<p>两个重名文件都做了验证,只要有一个通过验证,就返回验证通过。</p>
<h3>0x04 后继</h3>
<hr />
<p>我android研究不多,大多以前玩逆向的底子。大家可以多讨论。 欢迎大家留言探讨~!</p>
<p>======================================================================================================</p>
<h4>7月11日21点更新:</h4>
<p>没看到看雪上已经讨论的热火朝天,读下来来源于看雪的zmworm的原理分析应该是更准确的。</p>
<h4>原理简述
</h4>
<p>由于ZIP格式允许存在两个或以上完全相同的路径,而安卓系统没有考虑这种场景。</p>
<p>在该情况下,android包管理器校验签名取的是最后一个文件的hash,而运行APK加载的dex文件却是zip的第一个dex文件。
</p>
<p>包管理器验证签名验的是最后一个(名字相同情况下)文件。</p>
<p>1. 解析zip的所有Entry,结果存到HashMap(key为路径,value为Entry)。</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394857404.jpeg" alt="enter image description here" /></p>
<p>2. 由于HashMap.put在相同key的情况下,会把value更新,导致上述的HashMap在相同路径下,存储的一定是最后一个文件的Entry。</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394884839.jpeg" alt="enter image description here" /></p>
<p>
系统加载dex文件,加载的是第一个dex。
</p>
<p>
1. 查找dex的Entry用的是dexZipFindEntry。
</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394838477.jpeg" alt="enter image description here" /></p>
<p>2. dexZipFindEntry的实现是只要match就返回,所以返回的都是第一个文件。</p>
<p><img src="http://static.wooyun.org/20140918/2014091811394964103.jpeg" alt="enter image description here" /></p>
<p>Zip 可以包含两个同名文件或者路径,而其自身的unzip 默认方式是后一个覆盖前一个。</p>
<p>HashMap.put 的写法应该文件也直接覆盖(hash表的冲突处理不当果真出大问题)才算是算是符合zip 的标准。</p>
<p>就是加载dex的方式则是先加载第一个,这样确实信息不一致。</p>
<p>而我之前黑盒测出来认为android 默认把两个都加载在签名验证顺序上出现问题的,未分析到上一层的类。</p>
<p>看雪上也是讨论很多帖子得到准确的原理分析,大家共同讨论,集思广益。Hack it, know it too.</p>
<p>持续跟新中。</p> </p>
</body>
</html>