[Revert from backup]对Android最新fakesms漏洞的分析

注:原文发表于 2012-11-08并同时发表于freebuf,后来在博客地震中消失了,现在的是根据freebuf上的恢复而来的。
近期Android爆出SMS smishing vuln, 首先来源于http://www.csc.ncsu.edu/faculty/jiang/smishing.html, 然后github上给出了poc,具体来说是任意一个app没有write_sms权限下可以伪造任意发件人的任意短信。
20121108123649823

影响平台可上至Android 1.6下至4.1。由于很多以android2.3为主的手机已经不能再升级,此漏洞的危害不可小视。一个攻击场景是malicious app首先向ISP发送一条申请业务的短信,然后伪造ISP发送一条用户需要确认的短信。当用户确认时就中招了。
首先感谢各位大神的贡献。在github上给出poc后,我根据代码进行了一些分析。前面构造pdu的代码非常重要,但不是本文分析的重点。此次分析的POC代码在于
 

Intent intent = new Intent();
intent.setClassName("com.android.mms",
                "com.android.mms.transaction.SmsReceiverService");
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
intent.putExtra("pdus", new Object[] { pdu });
intent.putExtra("format", "3gpp");
context.startService(intent);

 
这里启动了com.android.mms.transaction.smsreceiverService,这个service的代码在这里. 当service启动时,调用链如下:
 

onStartCommand->mServiceHandler.sendMessage(msg);

 
消息进入ServiceHandler的消息队列中,在handleMessage中得到处理。由于Action是SMS_RECEIVED,所以进入handleSmsReceived函数:
 

public void handleMessage(Message msg) {
159            int serviceId = msg.arg1;
160            Intent intent = (Intent)msg.obj;
161            if (intent != null) {
162                String action = intent.getAction();
163
164                if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
165                    handleSmsSent(intent);
166                } else if (SMS_RECEIVED_ACTION.equals(action)) {
167                    handleSmsReceived(intent);
168                } else if (ACTION_BOOT_COMPLETED.equals(action)) {
169                    handleBootCompleted();
170                } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
171                    handleServiceStateChanged(intent);
172                }
173            }
174            // NOTE: We MUST not call stopSelf() directly, since we need to
175            // make sure the wake lock acquired by AlertReceiver is released.
176            SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
177        }
178    }

 
handleSmsReceived
 

private void handleSmsReceived(Intent intent) {
279        SmsMessage[] msgs = Intents.getMessagesFromIntent(intent);
280        Uri messageUri = insertMessage(this, msgs);
281
282        if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
283            SmsMessage sms = msgs[0];
284            Log.v(TAG, "handleSmsReceived" + (sms.isReplace() ? "(replace)" : "") +
285                    " messageUri: " + messageUri +
286                    ", address: " + sms.getOriginatingAddress() +
287                    ", body: " + sms.getMessageBody());
288        }
289
290        if (messageUri != null) {
291            MessagingNotification.updateNewMessageIndicator(this, true);
292        }
293    }

 
在291段用户得到通知,即一般大家看到的toast和短信提示框,再来看insertMessage,
 

private Uri insertMessage(Context context, SmsMessage[] msgs) {
331        // Build the helper classes to parse the messages.
332        SmsMessage sms = msgs[0];
333
334        if (sms.getMessageClass() == SmsMessage.MessageClass.CLASS_0) {
335            displayClassZeroMessage(context, sms);
336            return null;
337        } else if (sms.isReplace()) {
338            return replaceMessage(context, msgs);
339        } else {
340            return storeMessage(context, msgs);
341        }
342    }

 
其中replaceMessage最后调用storeMessage, storeMessage负责将短信存入数据库。这样一个fake message就成功以假乱真。
那为什么会出现这样的问题?对/system/app/Mms.apk进行反编译,获得AndroidManifest.xml,在其中可以看到:
 

<application android:label="@string/app_label" android:icon="@drawable/ic_launcher_smsmms" android:name="MmsApp" android:taskAffinity="android.task.mms" android:allowTaskReparenting="true">
<service android:name=".transaction.TransactionService" android:exported="true" />
<service android:name=".transaction.SmsReceiverService" android:exported="true" />
<activity android:theme="@android:style/Theme.NoTitleBar" android:label="@string/app_label" android:name=".ui.MmsTabActivity" android:launchMode="singleTop" android:configChanges="keyboardHidden|orientation" android:windowSoftInputMode="stateAlwaysHidden|adjustPan">

 
SmsReceiverService被export出去后没有使用permission声明signature或signatureOrSystem或Dangerous,甚至也没有Normal声明。在代码中也没有显式调用checkPermission,这违反了android开发规范,造成了事实上的permission-redelegation漏洞。由于Mms属于系统程序,存在于所有android-platform中,后果更加严重。
以上是对android的最新短信漏洞做的分析。由于水平所限,如果有所疏误请不吝赐教。

Leave a Reply

Your email address will not be published. Required fields are marked *