外卖O2O App安全性分析:App漏洞评估平台技术细节


发布人:admin分类:网络安全浏览量:33发布时间:2017-12-12

本文原创作者:bt0sea

0×00、业务需求

在移动互联网和O2O大潮的席卷下,外卖市场逐渐进入的白领的视野,在BAT三巨头砸钱培育市场的情况下,白领的已经更改就餐习惯。只要是坐班的小白领基本上不会到周边商圈购物中心进餐的习惯。外加这个夏天比较热。

根据权威数据分析:

那么,这个市场到底有多大,目前,根据媒体披露,美团外卖2015年上半年业绩:42.5亿。如果按照1/4市场计算,那么,外卖市场有200亿RMB。 怪不得BAT要抢占这块市场,当然分析用户的饮食习惯也是他们的另外一个目的。

然后,我们再看看中国外卖O2O鼻祖饿了么融资情况。

2015年8月份占市场份额为38.75%,累计投资大约10亿美金。

那么,我们关心的是,这么大笔投资,真正使用在IT基础设施建设上面和业务系统搭建的投入是多少?业务系统搭建中,具体的安全投入是多少?如果按照涉及到IT基础设施业务系统搭建占比1%(总投资额计算),安全投入咱以上IT投资的1%的话,那就是安全相当10万美金的投入。

但是,如果你是一个极客,当然是想通过客户端漏洞用Scrapy 爬出大约每天多少单,每单赚多少钱。存储到Mongodb中,然后使用python脚本写大数据报告,用数据说话麽,大家都信,呵呵。

那么基于业务系统App安全评估如何具体做呢?下面着重描述一下。

0×01、App评估方法论

其实网上有很多方法论的东西,这里我站在自由测评人的角度上分析。

首先确定只对Android App APK进行分析,因为Android系统比较开放,模拟器比较多,业务逻辑ipa和Apk是一样的。

在网络上在线评估网站比比皆是,其实其App漏洞评估平台技术都差不多。

一个Android程序上传后首先要判断其是否可以反编译。如果可以,那么就能分析到更多的数据,包括java写的源代码。

那么怎么判断是是否可以被反编译呢?其实可以通过多种方式实施,静态分析是最直接有效的办法,它主要是利用 apktol、dex2jar、jd-gui、smali2dex 等静态分析工具对应用进行反编译,并对反编译后的 java 文件、xml 文件等文件进行静态扫描分析

具体流程图如下:

当然,如果反静态编译失败,就需要动态分析的方法。动态分析技术是对应用软件安装、运行过程的行为监测和分析。检测的方式使用虚拟机方式通过建立与Android手机终端软件运行环境几乎一样的虚拟执行环境,手机应用软件在其中独立运行,从外界观察应用程序的执行过程和动态,进而记录应用程序可能表现出来的恶意行为。

最后,在通过虚拟机分析线上App程序的时候,可能会遇到模拟器检查、root检测等或者IMEI标识判断等高级防调试的功能,这时候就需要人工去分析,也就是说在真实Android手机上安装App进行实地的安全评估。

那么,下面我们以到家美食汇App作为安全评估对象进行评估:

(1)是否被反编译

测试方法使用含有Apktool开源软件的发编译IDE工具测试,Android killer/ ApkIDE改之理 。本文使用Android killer。

从这张图可以看出apk被编译成smali(java虚拟机文件)然后又被反编译成Java class的源代码。

(2)内置组件和外部第三方SDK评估

通过java Decompiler查看源代码发现:

2.1、内置组件:

Com.alibaba.fastjson 阿里巴巴开源高性能JSON开发包
com.android.volley  Android官方通信框架Volley
com.nostra13.universalimageloader 开源 图片库加载。
com.sina.sso 新浪微博登陆SSO组件
com.squareup.okhttp 高效http客户端 (网络拥堵)
okio 开源基本工具库

使用开源组件包,好处是可以提高开发效率,但是如果是开源组件安全性令人担忧,但是目前为止漏洞库中还没有以上组件安全问题。这时不时的让我想起来去年的AFNetworking组件当时引发的中间人攻击的案例。

2.2、第三方SDK组件

com.baidu.mapapi 百度地图
com.baidu.android.pushservice 百度消息推送服务
com.google.analytics google分析API让我们知道用户如何与我们的应用进行交互
com.tencent 访问腾讯openapi 认证等功能
com.umeng.analytics 应用统计分析

那么,外包第三方组件主要搜索重点是APPKey等,可能被黑客利用:

友盟:

<meta-data android:name="UMENG_APPKEY" android:value="528187ac56240bee3803bc39" />
<meta-data android:name="UMENG_CHANNEL" android:value="daojiaweb" />

百度推送:可以获取到推送服务key值以及推送消息等信息,通过修改源码,使开发商利益受到损失。

<service android:name="com.baidu.android.pushservice.CommandService" android:exported="true" />
<meta-data android:name="api_key" android:value="2qoGQfsfg5CcB9cU9PXHNBGX" />

百度地图:

<meta-data android:name="com.baidu.lbsapi.API_KEY" android:value="jGY5Ft6EuDv9gKWT9dg51UOl" />

(3)不安全的数据存储

3.1、SharedPreferences

首先检查的是SharedPreferences,这是一个可以全局访问的数据结构。经过源码查找发现。

但是,到家使用了混淆类处理:ObscuredSharedPreferences,这个类有对SharedPreferences的加解密函数,但是在源代码被反编译后,没有任何保护力度,黑客可以直接拿解密函数破解其加密数据

public class ObscuredSharedPreferences
  implements SharedPreferences
{
  private static final char[] SEKRIT = { 23, 45, 79, 65, 98, 21, 13, 18, 64, 28 };
  protected static final String UTF8 = "utf-8";
  protected Context context;
  protected SharedPreferences delegate;
 
  protected String decrypt(String paramString)
  {
    if (paramString != null) {}
    for (;;)
    {
      try
      {
        arrayOfByte = Base64.decode(paramString, 0);
        SecretKey localSecretKey = 
SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(new 
PBEKeySpec(SEKRIT)); // 使用java相关加密算法解密,秘钥是SEKRIT
        Cipher localCipher = Cipher.getInstance("PBEWithMD5AndDES");
        localCipher.init(2, localSecretKey, new 
PBEParameterSpec(Settings.Secure.getString(this.context.getContentResolver(),
 "android_id").getBytes("utf-8"), 20)); //UTF-8编码
        return new String(localCipher.doFinal(arrayOfByte), "utf-8");
      }
      catch (Exception localException)
      {
        byte[] arrayOfByte;
        throw new RuntimeException(localException);
      }
      arrayOfByte = new byte[0];
    }
  }
   
  protected String encrypt(String paramString)
  {
    if (paramString != null) {}
    for (;;)
    {
      try
      {
        arrayOfByte = paramString.getBytes("utf-8");
        SecretKey localSecretKey = 
SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(new 
PBEKeySpec(SEKRIT)); // 使用java相关加密算法加密,秘钥是SEKRIT
        Cipher localCipher = Cipher.getInstance("PBEWithMD5AndDES");
        localCipher.init(1, localSecretKey, new 
PBEParameterSpec(Settings.Secure.getString(this.context.getContentResolver(),
 "android_id").getBytes("utf-8"), 20)); //UTF-8编码
        return new String(Base64.encode(localCipher.doFinal(arrayOfByte), 2), "utf-8");
      }
      catch (Exception localException)
      {
        byte[] arrayOfByte;
        throw new RuntimeException(localException);
      }
      arrayOfByte = new byte[0];
    }
  }

3.2、ContentProvider

ContentProvider是android组件之一,可以提供数据的跨应用程序访问,针对其搜索关键字为:ContentResolver。因为这个函数是解析ContentProvider存储的数据的。

但是里面没有什么有价值的数据,pass.

3.3、sqlite

所有的Android数据存储都是使用轻量级的sqlite数据库,在源码中有很多地方都能找到,我就不一一列举了。 同样也没什么有价值的数据 pass.

(4)敏感信息安全评估

4.1、敏感信息检测>>获取设备信息

该app中使用了获取设备信息的权限,窃取用户隐私。

DaojiaApp:
{
      Utils.initSomeThing(); //获取GPS数据
      Globals.instance().currentVersion = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; //获取App程序版本
      Globals.instance().manufacturer = Build.MANUFACTURER;      //Build.MANUFACTURER // 硬件制造商    
      Globals.instance().model = Build.MODEL; // Build.MODEL // 版本  
      Globals.instance().os_version = Build.VERSION.RELEASE;   //获取android系统的版本信息->版本字符串   Build.VERSION.RELEASE 
      WifiInfo localWifiInfo = ((WifiManager)getSystemService("wifi")).getConnectionInfo();
      Globals.instance().mac = localWifiInfo.getMacAddress();  //获取wifi MAC地址
      TelephonyManager localTelephonyManager = (TelephonyManager)getSystemService("phone"); //获得手机号
      Globals.instance().imei = localTelephonyManager.getDeviceId(); //获取IMEI
      DisplayMetrics localDisplayMetrics = new DisplayMetrics(); //屏幕大小
      getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
      Globals.instance().w = localDisplayMetrics.widthPixels;
      Globals.instance().h = localDisplayMetrics.heightPixels;
      Globals.instance().resolution = (localDisplayMetrics.widthPixels + "_" + localDisplayMetrics.heightPixels);
      ObscuredSharedPreferences localObscuredSharedPreferences = new 
ObscuredSharedPreferences(this, getSharedPreferences("daojia", 0));
      if (localObscuredSharedPreferences.getInt("CityID", 0) != 0) {
        Globals.instance().cityID = localObscuredSharedPreferences.getInt("CityID", 0);
    }

4.2、敏感信息检测>>App服务器地址

后来通过http抓包发现,这个地址只是一个获取服务器地址的中间环节,真正的服务器地址是在这个地址中存储,并且检测其连接App的属性。

4.3、敏感信息检测>>字符串初始化检测

//针对服务器提交的翻译命令
  public static final String DELETEHISTORYADDRESSREQUEST = "DeleteHistoryAddress";
  public static final String DELETEHISTORYORDERREQUEST = "DeleteHistoryOrder";
  public static final String DOACTIVEUSER = "DoActiveUser";
  public static final String DOCOMPLAINTREQUEST = "DoComplaint";
  public static final String DOLOGINREQUEST = "DoLogin";
  public static final String DOLOGOUT = "DoLogout";
  public static final String DOREGISTERREQUEST = "DoRegister";
  public static final String DOREGISTERREQUESTRESP = "DoRegisterResp";
  public static final String DOURGENTREQUEST = "DoUrgent";
  public static final String GETADVERTISELISTREQUEST = "GetAdvertiseList";
  public static final String GETAREAANNOUNCEMENTLISTREQUEST = "GetAreaAnnouncementList";
  public static final String GETAREALISTREQUEST = "GetAreaList";
  public static final String GETAUTHORIZATIONCODEREQUEST = "GetAuthorizationCode";
  public static final String GETCARDLISTSREQUEST = "GetCardList";
  public static final String GETCITYLISTREQUEST = "GetCityList";
  public static final String GETCOUPONLISTREQUEST = "GetCouponList";
  public static final String GETFOODCATAGORYLISTREQUEST = "GetFoodCatagoryList";
  public static final String GETFOODLISTREQUEST = "GetFoodList";
  public static final String GETHISTORYADDRESSREQUEST = "GetHistoryAddress";
  public static final String GETHISTORYORDERLISTREQUEST = "GetHistoryOrderList";
  public static final String GETHISTORYRESTAURANTLISTREQUEST = "GetHistoryRestaurantList";
  public static final String GETHOTFOODLISTREQUEST = "GetHotFoodList";
  public static final String GETORDERDETAILSREQUEST = "GetOrderDetails";
  public static final String GETPROFILEREQUEST = "GetProfile";
  public static final String GETPROFILEREQUESTRESP = "GetProfileResp";
  public static final String GETRESTAURANTCATAGORYLISTREQUEST = "GetRestaurantCatagoryList";
  public static final String GETRESTAURANTLISTREQUEST = "GetRestaurantList";
  public static final String GETRESTAURANTMESSAGELISTREQUEST = "GetRestaurantMessageList";
  public static final String GETTODAYORDERLISTREQUEST = "GetTodayOrderList";

4.4、敏感信息检测>>密码管理

登陆密码保存使用ObscuredSharedPreferences同样的数据密码加密形式。

private void doLogin()
  {
    if (Upgrade.hasUpgrade(this.frameActivity)) {
      return;
    }
    new Server(this.frameActivity, getResources().getString(2131034313))
    {
      protected Integer doInBackground(String… paramAnonymousVarArgs)
      {
        ArrayList localArrayList1 = new ArrayList();
        localArrayList1.add("DoLogin");
        int i = Globals.instance().interactWithServer(localArrayList1, null, null);
        if (i != 0) {
          return Integer.valueOf(i);
        }
        ArrayList localArrayList2 = new ArrayList();
        localArrayList2.add("GetHistoryAddress");
        localArrayList2.add("GetProfile");
        localArrayList2.add("GetCardList");
        return Integer.valueOf(Globals.instance().interactWithServer(localArrayList2, null, null));
      }
     
      protected void onPostExecute(Integer paramAnonymousInteger)
      {
        super.onPostExecute(paramAnonymousInteger);
        if (paramAnonymousInteger.intValue() != 0)
        {
          Globals.instance().isLogined = false;
          SharedPreferences.Editor localEditor = DaojiaApplication.getInstance().getSharedPreferences("token", 0).edit();
          localEditor.putString("terminalToken", "");
          localEditor.commit();
          EditText localEditText1 = Login.this.accountEditText;
          Globals.instance().mobile = "";
          localEditText1.setText("");
          EditText localEditText2 = Login.this.passwordEditText;
          Globals.instance().passwd = "";
          localEditText2.setText("");
          new 
AlertDialog.Builder(Login.this.frameActivity).setMessage(Globals.instance().error(paramAnonymousInteger.intValue(),
 
Login.this.frameActivity.getResources())).setNegativeButton(Login.this.frameActivity.getResources().getString(2131034125),
 null).show().setCanceledOnTouchOutside(false);
          return;
        }
        ObscuredSharedPreferences localObscuredSharedPreferences = 
new ObscuredSharedPreferences(Login.this.frameActivity, 
Login.this.frameActivity.getSharedPreferences("daojia", 0));
        localObscuredSharedPreferences.edit().putString("Account", Globals.instance().mobile).commit();
        localObscuredSharedPreferences.edit().putString("Passwd", 
Globals.instance().passwd).commit(); //直接使用ObscuredSharedPreferences 
加密方式处理
        Globals.instance().isStroll = false;
        int i = Globals.instance().todayOrderTotal;
        if (i != 0) {
          Login.this.frameActivity.tabActivity.showBadge(1, i);
        }
        for (;;)
        {
          EasyTracker localEasyTracker = EasyTracker.getInstance(Login.this.frameActivity);
          localEasyTracker.set("&cd", "登录成功");
          localEasyTracker.set(Fields.customDimension(1), "Yes");
          localEasyTracker.send(MapBuilder.createAppView().build());
          try
          {
            Login.this.frameActivity.getSupportFragmentManager().popBackStack();
            return;
          }
          catch (Exception localException)
          {
            Login.this.isBack = true;
            return;
          }
          Login.this.frameActivity.tabActivity.hideBadge(1);
        }
      }
    }.execute(new String[] { "" });
  }

(5)HTTP(s)分析

测试方法,在Android手机,安装到家美食汇App,然后手机上安装Fiddler证书,设置wifi代理获取http(s)数据流量

5.1、登录数据分析

Json值完全没加密

建议在使用工具分析HTTP(s)的数据时,如果可以反编译java源代码的话,就可以更直观的了解其整个登录流程。

由于登录源代码在以上密码分析部分已经说过,这次看注册函数:

在daojia.fragment.Register 下,onClick动作下面。

同时,还发现在输入内容上没有做任何过滤,有SQL injection的风险。

public void onClick(View paramView)
  {
    if (paramView.getId() == 2131492865)
    {
      localView = this.frameActivity.getWindow().getCurrentFocus();
      if (localView != null) {
        ((InputMethodManager)this.frameActivity.getSystemService("input_method")).hideSoftInputFromWindow(localView.getWindowToken(), 0);
      }
      this.frameActivity.getSupportFragmentManager().popBackStack();
    }
    while (paramView.getId() != 2131492906)
    {
      View localView;
      return;
    }
    if ((this.linkman1EditText.getText().toString().trim().length() == 0) && (this.linkman2EditText.getText().toString().trim().length() == 0))
    {
      new AlertDialog.Builder(this.frameActivity).setMessage(getResources().getString(2131034159)).setPositiveButton(getResources().getString(2131034125), null).show().setCanceledOnTouchOutside(false);
      return;
    }
    if (this.mobileEditText.length() == 0)
    {
      new AlertDialog.Builder(this.frameActivity).setMessage(getResources().getString(2131034160)).setPositiveButton(getResources().getString(2131034125), null).show().setCanceledOnTouchOutside(false);
      return;
    }
    if (!this.mobileEditText.getText().toString().matches("^1[3,4,5,8,7]\\d{9}$"))
    {
      new AlertDialog.Builder(this.frameActivity).setMessage(getResources().getString(2131034161)).setPositiveButton(getResources().getString(2131034125), null).show().setCanceledOnTouchOutside(false);
      return;
    }
    if (this.passwdEditText.length() == 0)
    {
      new AlertDialog.Builder(this.frameActivity).setMessage(getResources().getString(2131034162)).setPositiveButton(getResources().getString(2131034125), null).show().setCanceledOnTouchOutside(false);
      return;
    }
    if (this.passwdEditText.length() < 6)
    {
      new AlertDialog.Builder(this.frameActivity).setMessage(getResources().getString(2131034163)).setPositiveButton(getResources().getString(2131034125), null).show().setCanceledOnTouchOutside(false);
      return;
    }
    if (this.passwdEditText.getText().toString().compareTo(this.confirmEditText.getText().toString()) != 0)
    {
      new AlertDialog.Builder(this.frameActivity).setMessage(getResources().getString(2131034164)).setPositiveButton(getResources().getString(2131034125), null).show().setCanceledOnTouchOutside(false);
      return;
    }
    MobclickAgent.onEvent(this.frameActivity, "Step2ForRegistration");
    Log.e("main", "step2ForRegistration");
    Globals.instance().mobile = this.mobileEditText.getText().toString();
    doGetCode();
  }
 
  public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle)
  {
    super.onCreateView(paramLayoutInflater, paramViewGroup, paramBundle);
    this.rootLayout = ((ViewGroup)paramLayoutInflater.inflate(2130903096, paramViewGroup, false));
    this.linkman1EditText = ((EditText)this.rootLayout.findViewById(2131492984));
    this.linkman1EditText.addTextChangedListener(this);
    this.linkman2EditText = ((EditText)this.rootLayout.findViewById(2131492985));
    this.linkman2EditText.addTextChangedListener(this);
    ((InputMethodManager)this.frameActivity.getSystemService("input_method")).toggleSoftInput(2, 0);
    this.mobileEditText = ((EditText)this.rootLayout.findViewById(2131493014));
    this.passwdEditText = ((EditText)this.rootLayout.findViewById(2131492994));
    this.confirmEditText = ((EditText)this.rootLayout.findViewById(2131493035));
    ((TextView)this.rootLayout.findViewById(2131492866)).setText(2131034143);
    ImageView localImageView = (ImageView)this.rootLayout.findViewById(2131492865);
    localImageView.setVisibility(0);
    localImageView.setOnClickListener(this);
    ((Button)this.rootLayout.findViewById(2131492906)).setOnClickListener(this);
    return this.rootLayout;
  }

5.2、下单业务流程

Json没加密是不是就可以刷单了,或者篡改数据了?

5.3、重放攻击

这个问题,先在这里说明一下,如果要抵制App重放攻击,需要在每个请求包总添加包序列号,每次提交自动加一,如果收到的包相同就认为是重放攻击。目前到家美食汇App是做到的,虽然没有后台的源程序,但是从客户端源代码(com.daojia.ds)中可以发现:

private int getUrl()
  {
    Object localObject1 = "";
    for (;;)
    {
      int j;
      try
      {
        JSONObject localJSONObject1 = new JSONObject();
        try
        {
          localJSONObject1.put("Command", "LookupServer");
          localJSONObject1.put("SequenceID", "0");
          localJSONObject1.put("CheckDigit", "0");
          JSONObject localJSONObject3 = new JSONObject();
          localJSONObject3.put("CityID", this.cityID);
          localJSONObject1.put("Body", localJSONObject3);
          JSONArray localJSONArray3 = new JSONArray();
          localJSONArray3.put(localJSONObject1);
          String str3 = localJSONArray3.toString();
          localObject1 = str3;
        }
        catch (JSONException localJSONException)
        {
***  continue;
        }
        localHttpPost = new HttpPost(DAOJIASERVER);
        Log.e("afei", "request body is ===" + (String)localObject1);
        localStringEntity = new StringEntity((String)localObject1, "UTF-8");
        localStringEntity.setContentType("application/x-www-form-urlencoded");
        localHttpPost.setEntity(localStringEntity);
        localHttpPost.addHeader("Accept-Encoding", "gzip, deflate");
        List localList = ((BasicCookieStore)this.localContext.getAttribute("http.cookie-store")).getCookies();
        bool = localList.isEmpty();
        int i = 0;
        int k;
        StringBuilder localStringBuilder;
        String str2;
        JSONArray localJSONArray1;
        if (!bool)
        {
          k = 0;
          if (k < localList.size()) {}
        }
        else
        {
          if (i == 0)
          {
            str1 = DaojiaApplication.getInstance().getSharedPreferences("token", 0).getString("terminalToken", "");
            if (!TextUtils.isEmpty(str1)) {
              localHttpPost.addHeader("Cookie", "token=" + str1 + ";");
            }
          }
          localHttpResponse = this.httpClient.execute(localHttpPost, this.localContext);
          localHttpEntity = localHttpResponse.getEntity();
          localObject2 = localHttpResponse.getEntity().getContent();
          localHeader = localHttpResponse.getFirstHeader("Content-Encoding");
          if ((localHeader != null) && (localHeader.getValue().equalsIgnoreCase("gzip"))) {
            localObject2 = new GZIPInputStream((InputStream)localObject2);
          }
          localInputStreamReader = new InputStreamReader((InputStream)localObject2);
          localBufferedReader = new BufferedReader(localInputStreamReader, 8192);
          localStringBuilder = new StringBuilder();
          str2 = localBufferedReader.readLine();
          if (str2 != null) {
            continue;
          }
          localHttpEntity.consumeContent();
          localJSONArray1 = new JSONArray(localStringBuilder.toString());
          j = 0;
          if (j < localJSONArray1.length()) {
            continue;
          }
          return -1;
        }
        if (((Cookie)localList.get(k)).toString().contains("token"))
        {
          i = 1;
          break label640;
          localStringBuilder.append(str2);
          continue;
        }
        JSONObject localJSONObject2;
        JSONArray localJSONArray2;
        k++;
      }
      catch (Exception localException)
      {
***
        }
        localJSONArray2 = localJSONObject2.getJSONArray("Servers");
        Globals.instance().host0 = localJSONArray2.optString(0, "");
        Globals.instance().host1 = localJSONArray2.optString(1, "");
        Globals.instance().mapping = localJSONObject2.getString("Mapping");
        if (getCityV(Globals.instance().mapping) == 0) {
          LOOKUPS = Globals.instance().host0;
        } else {
          LOOKUPS = Globals.instance().host1;
        }
      }
      catch (ConnectTimeoutException localConnectTimeoutException)
      {
        return -1;
      }
      label640:
      continue;
      label646:
      j++;
    }
  }

(6)SQL injection分析

有关App SQL注入的攻击测试方法可以参考

原理:就是用burpsuite 设置代理记录log文件,然后,狂点App上的界面,然后通过提交的post数据,进行sqlmap测试。

sqlmap -r "/root/desktop/daojia.txt" --threads=3 --risk=3 --level=3 --random-agent --time-sec=15 --timeout=15 --beep –dbs

但是经过测试目前还没有注入漏洞。

(7)签名校验

签名作用

1.发送者的身份认证:由于开发商可能通过使用相同的 Package Name 来混淆替换已经安装的程序,以此保证签名不同的包不被替换。
2.保证信息传输的完整性:签名对于包中的每个文件进行处理,以此确保包中内容不被替换。

PackageInfo packageInfo = getPackageManager().getPackageInfo(
  "com.daojia.xxx", PackageManager.GET_SIGNATURES);
  Signature[] signs = packageInfo.signatures;

使用关键字“PackageInfo”搜索。Signature 太多,第三方和开源组件基本上都有签名校验。

主程序没有做签名校验,使用resign工具可以直接打包。。

最后,还是向大家介绍一下online检测工具。具有检测内容我就不在文章中列举了。大家可以自己上传看看,星多漏洞多。

这里想向大家详细介绍一下Mobile security Framework,这个用python写的开源的评估程序,这个工具加快了App程序漏洞评估速度,当然,自动化的程序特别是开源的很容易被App厂商和谐掉,还是要使用手工分析方法。或者是使用自动化分析工具先看看有什么详细漏洞,然后使用手工分析。

个人觉得MobSF在建立动态分析环境方面很快,本人通过翻墙才下载到ova虚拟化文件(oracle Virtualbox)。实现了动态分析,其实就是一个google android手机操作系统模拟器,通过python把各个手工测试工具连接起来做成自动化分析程序。

0×02、结论

经过检测发现美团外卖做的相对比较好,到家美食汇做的相对差一点。我想这和在安全上的投入有关系,在残酷的市场竞争环境下,首先要解决生存的问题,然后才能考虑安全的问题,当然了,如果你是互联网巨头BAT也会有先天的优势,安全性的研究会有N多NB人才立助你业务系统安全,对付开源检测工具还是绰绰有余的。那么对于创业掌门人的你,在App业务系统安全性问题上,你会选择传统互联网安全公司(爱加密、梆梆等)对你的业务系统做企业级的加固,还是建立自己SRC团队做安全运营?或者采用众测的形式花钱买漏洞?

* 作者:bt0sea,本文属FreeBuf原创奖励计划文章,。


被黑站点统计 - 文章版权1、本主题所有言论和图片纯属会员个人意见,与本文章立场无关
2、本站所有主题由该文章作者发表,该文章作者与被黑站点统计享有文章相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该文章作者和被黑站点统计的同意
4、文章作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、被黑站点统计管理员有权不事先通知发贴者而删除本文

免责声明

本站主要通过网络搜集国内被黑网站信息,统计分析数据,为部署安全型网络提供强有力的依据.本站所有工作人员均不参与黑站,挂马或赢利性行为,所有数据均为网民提供,提交者不一定是黑站人,所有提交采取不记名,先提交先审核的方式,如有任何疑问请及时与我们联系.

admin  的文章


微信公众号

微信公众号


Copyright © 2012-2022被黑网站统计系统All Rights Reserved
页面总访问量:21414678(PV) 页面执行时间:68.482(MS)
  • xml
  • 网站地图