通过DIVA了解APP安全问题

目录


导语

篇幅有些长,请使用目录品用。


DIVA

DIVA (Damn insecure and vulnerable App),是一个故意设计为全身漏洞的APP软件,它能让开发人员、QA、安全人员了解到APP软件一般存在的问题。

github地址:https://github.com/payatu/diva-android


不安全日志输出

开发人员有意或无意地记录敏感信息(如凭据,会话ID,财务详细信息等)

Insecure Logging

1

我们输入的数字”123456789”,使用adb logcat 命令可以看到

E/diva-log( 3575): Error while processing transaction with credit card: 123456789

使用jd-gui看下logActivity.class 可以发现

 Log.e("diva-log", "Error while processing transaction with credit card: " + paramView.getText().toString());
 Toast.makeText(this, "An error occured. Please try again later", 0).show();

代码中使用了log.e,如果开发人员在debug时不小心忘记去掉log输出,将会造成很大的安全隐患。


不安全的数据存储

不安全的数据存储也是App常见的安全问题之一,主要有三种方式:

  • 将敏感数据保存到配置文件中。
  • 将敏感数据保存在本地的sqlite3数据库中。
  • 将敏感数据保存在临时文件或者sd卡中。

Insecure Data Storage -Part1

使用了SharedPreferences类,该类是Android平台上一个轻量级的存储类,主要是用来保存一些常用的配置,本例中是用该类存储了用户名和密码,因此是具有风险的。SharedPreferences类存储的数据会以.xml的形式存储在/data/data/apppackagename/shared_prefs目录下

输入用户名和密码都为admin

2

使用adb连接手机查看文件
3

InsecureDataStorage1Activity.class

    paramView = PreferenceManager.getDefaultSharedPreferences(this).edit();
    EditText localEditText1 = (EditText)findViewById(2131493000);
    EditText localEditText2 = (EditText)findViewById(2131493001);
    paramView.putString("user", localEditText1.getText().toString());
    paramView.putString("password", localEditText2.getText().toString());
    paramView.commit();
    Toast.makeText(this, "3rd party credentials saved successfully!", 0).show();

Insecure Data Storage -Part2

一般app对应的数据库目录: /data/data/apppackagename/databases

输入用户名,密码都为ceshi
5
使用adb查看数据库
4

InsecureDataStorage2Activity.class

      SQLiteDatabase localSQLiteDatabase = this.mDB;
      paramView = new java/lang/StringBuilder;
      paramView.<init>();
      localSQLiteDatabase.execSQL("INSERT INTO myuser VALUES ('" + localEditText1.getText().toString() + "', '" + localEditText2.getText().toString() + "');");
      this.mDB.close();
      Toast.makeText(this, "3rd party credentials saved successfully!", 0).show();

Insecure Data Storage -Part3

输入用户名和密码为demo

6

使用adb查看临时文件,目录在/data/data/apppackagename/

7

InsecureDataStorage3Activity.class

      Object localObject2 = File.createTempFile("uinfo", "tmp", (File)localObject1);
      ((File)localObject2).setReadable(true);
      ((File)localObject2).setWritable(true);
      localObject1 = new java/io/FileWriter;
      ((FileWriter)localObject1).<init>((File)localObject2);
      localObject2 = new java/lang/StringBuilder;
      ((StringBuilder)localObject2).<init>();
      ((FileWriter)localObject1).write(localEditText.getText().toString() + ":" + paramView.getText().toString() + "\n");
      ((FileWriter)localObject1).close();
      Toast.makeText(this, "3rd party credentials saved successfully!", 0).show();

Insecure Data Storage -Part4

存储sd卡的目录一般在: /mnt/sdcard

InsecureDataStorage4Activity.class

    paramView = (EditText)findViewById(2131493010);
    EditText localEditText = (EditText)findViewById(2131493011);
    File localFile = Environment.getExternalStorageDirectory();
    try
    {
      Object localObject1 = new java/io/File;
      Object localObject2 = new java/lang/StringBuilder;
      ((StringBuilder)localObject2).<init>();
      ((File)localObject1).<init>(localFile.getAbsolutePath() + "/.uinfo.txt");
      ((File)localObject1).setReadable(true);
      ((File)localObject1).setWritable(true);
      localObject2 = new java/io/FileWriter;
      ((FileWriter)localObject2).<init>((File)localObject1);
      localObject1 = new java/lang/StringBuilder;
      ((StringBuilder)localObject1).<init>();
      ((FileWriter)localObject2).write(paramView.getText().toString() + ":" + localEditText.getText().toString() + "\n");
      ((FileWriter)localObject2).close();
      Toast.makeText(this, "3rd party credentials saved successfully!", 0).show();
      return;
    }

可以看到使用Environment.getExternalStorageDirectory()来获取sd卡的目录,文件名为.unifo.txt

8


硬编码

  • 某些需要比较字符串的值为硬编码,如:激活码
  • 加密的key或者salt为硬编码,如MD5的salt

Hardcoding Issues -Part1

这里直接查看源码就知道答案

9

HardcodeActivity.class

   if (((EditText)findViewById(2131492987)).getText().toString().equals("vendorsecretkey")) {
      Toast.makeText(this, "Access granted! See you on the other side :)", 0).show();
    }
    for (;;)
    {
      return;
      Toast.makeText(this, "Access denied! See you in hell :D", 0).show();
    }

Hardcoding Issues -Part2

源码Hardcode2Activity.class
11

这里使用了DivanJni类,查看 DivaJni.class
12

这里加载了divajini库,一般库文件都放在/lib下,在目录下看到了很多架构,随便查看一个
arm64-v8a:

libdivajni.so

armeabi:

libdivajni.so

armeabi-v7a:

libdivajni.so

mips:

libdivajni.so

mips64:

libdivajni.so

x86:

libdivajni.so

x86_64:

libdivajni.so

linux下可以使用strings方便的查看二进制文件里的字符串

$ strings libdivajni.so

/system/bin/linker

__cxa_finalize

__cxa_atexit

Java_jakhar_aseem_diva_DivaJni_access

strncmp

__aeabi_unwind_cpp_pr1

Java_jakhar_aseem_diva_DivaJni_initiateLaunchSequence

strcpy

__aeabi_unwind_cpp_pr0

JNI_OnLoad

__aeabi_unwind_cpp_pr2

__gnu_Unwind_Find_exidx

__gnu_Unwind_Restore_VFP_D

__gnu_Unwind_Restore_VFP

__gnu_Unwind_Restore_VFP_D_16_to_31

__gnu_Unwind_Restore_WMMXD

__gnu_Unwind_Restore_WMMXC

abort

restore_core_regs

memcpy

_Unwind_GetCFA

__gnu_Unwind_RaiseException

__gnu_Unwind_ForcedUnwind

__gnu_Unwind_Resume

__gnu_Unwind_Resume_or_Rethrow

_Unwind_Complete

_Unwind_DeleteException

_Unwind_VRS_Get

_Unwind_VRS_Set

__gnu_Unwind_Backtrace

__cxa_begin_cleanup

__cxa_type_match

__gnu_unwind_execute

__cxa_call_unexpected

_Unwind_VRS_Pop

__gnu_Unwind_Save_VFP_D

__gnu_Unwind_Save_VFP

__gnu_Unwind_Save_VFP_D_16_to_31

__gnu_Unwind_Save_WMMXD

__gnu_Unwind_Save_WMMXC

__restore_core_regs

___Unwind_RaiseException

_Unwind_RaiseException

___Unwind_Resume

_Unwind_Resume

___Unwind_Resume_or_Rethrow

_Unwind_Resume_or_Rethrow

___Unwind_ForcedUnwind

_Unwind_ForcedUnwind

___Unwind_Backtrace

_Unwind_Backtrace

__gnu_unwind_frame

_Unwind_GetRegionStart

_Unwind_GetLanguageSpecificData

_Unwind_GetDataRelBase

_Unwind_GetTextRelBase

_edata

__bss_start

_end

libstdc++.so

libm.so

libc.so

libdl.so

libdivajni.so

olsdfgad;lh

.dotdot

GCC: (GNU) 4.8

gold 1.11

aeabi

.shstrtab

.interp

.dynsym

.dynstr

.hash

.rel.dyn

.rel.plt

.text

.ARM.extab

.ARM.exidx

.rodata

.fini_array

.init_array

.dynamic

.got

.data

.bss

.comment

.note.gnu.gold-version

.ARM.attributes

看里面又没特别的字符串,就像是olsdfgad;lh,试一下成功了

13

在下面链接看源代码就可以知道,vendorkey是硬编码。

https://github.com/payatu/diva-android/blob/master/app/src/main/jni/divajni.c

14


访问控制

Access Control lssues -Part 1

这里写图片描述

我们可以按下面的按钮获取到API 凭据:

这里写图片描述

我们的目标是不使用按钮就获取到API凭据,查看 AndroidManifest.XML文件,查看和供应商API凭据提供相关的activity:

<activity android:label=”@string/apic_labelandroid:name=”jakhar.aseem.diva.APICredsActivity”>

<intent-filter>

<action android:name=”jakhar.aseem.diva.action.VIEW_CREDS”/>

<category android:name=”android.intent.category.DEFAULT”/>

</intent-filter>

</activity>

通过观察代码发现,这个activity被intent filter所“保护”,当intent filter被activity等组件使用,这个activity可能会被外部任何应用程序所调用。

我们可以使用下面的命令:

$ adb shell am start jakhar.aseem.diva/.APICredsActivity

  • adb shell: 进入手机shell模式
  • am: activity 管理工具
  • start: 启动activity

这里写图片描述

接着手机就弹出了之前的页面

这里写图片描述

上面的命令还有另一种写法: $ adb shell am start -n jakhar.aseem.diva/.APICredsActivity -a jakhar.aseem.diva.action.VIEW_CREDS

  • -a:指定action
  • -n:指定完整 component 名

Access Control lssues -Part 2

这里写图片描述

如objective所知,如果你已经注册,你就能拥有tveeter API Credentials,当前的挑战是,不注册来获取API Credentials。

和之前一样查看 AndroidManifest.XML文件:

<activity android:label=”@string/apic2_labelandroid:name=”jakhar.aseem.diva.APICreds2Activity”>

<intent-filter>

<action android:name=”jakhar.aseem.diva.action.VIEW_CREDS2″/>

<category android:name=”android.intent.category.DEFAULT”/>

</intent-filter>

</activity>

试下使用老套路:

$ adb shell am start -n jakhar.aseem.diva/.APICreds2Activity -a jakhar.aseem.diva.action.VIEW_CREDS2

这里写图片描述

可以看到我们跳入了选择未注册时相同的activity,这表明程序做了相应的措施,我们看下源代码

APICreds2Activity.class

这里写图片描述

从Intent中获取到上个activity传来的boolean值(2131099686),当这个值为false时就视为用户已注册,再看看上个activity。

AccessControl2Activity.class

这里写图片描述

这个类中bool值是通过单选项来决定的,而且把值传给下个activity。这时我们可以使用–ez来传递一个boolean键值对,还要获取到2131099686值对应的key值是什么,一般情况下使用apktool反编译的字符串文件存放在res/vaules/strings.xml文件下,string文件中所有的字符串资源都会被R.java的String类中被标识,每个字符串中都有唯一的iint类型索引值,在反编译的情况下所有的索引值都保存在strings.xml同目录下的public.xml文件中,所以,我们现在public中查看16进制的2131099686(0x7f060026 )对应的name值
<public type="string" name="chk_pin" id="0x7f060026" />

然后再strings文件下查找chk_pin,最后得到key 为check_pin。
<string name="chk_pin">check_pin</string>

最后的命令:

$ adb shell am start -a jakhar.aseem.diva.action.VIEW_CREDS2 -n jakhar.aseem.diva/.APICreds2Activity --ez check_pin false

这里写图片描述


Access Control lssues -Part 3

这里写图片描述

这是个私人的笔记app,一开始需要设置密码才能使用,我们的目标是不设置密码就开始使用。

查看 AndroidManifest.XML文件:

<provider android:authorities=”jakhar.aseem.diva.provider.notesprovider” android:enabled=”true” android:exported=”true” android:name=”jakhar.aseem.diva.NotesProvider”/>

这里使用了ContentProvider,android:enabled表示是否能由系统初始化,android:exported表示是否能被其他应用使用,android:authorities:标识这个ContentProvider,调用者可以根据这个标识来找到它,具体内容可以查阅其他资料。

看到2个值都为true,我们就可以使用content://访问里面的数据了,搜索包含content://的字符串文件:

smali/jakhar/aseem/diva/NotesProvider.smali

这里写图片描述

找到后和我们在AndroidManifest所看到的一样,我们可以使用以下命令随意的访问该uri:

$ adb shell content query –-uri content://jakhar.aseem.diva.provider.notesprovider/notes

这里写图片描述

就如我们设置密码进入后所看到的信息一样。


用户数据问题

从外部输入的组件获取到用户输入的数据后,在使用前应该进行检验长度和过滤等操作。

Input Validation Issues - Part1

这里面总共有3个用户的数据

这里写图片描述

当输入‘时,没有任何返回,查看logcat会发现:

这里写图片描述

出现了sql注入,我们输入1’ or ‘1’=’1时

这里写图片描述

所有用户数据都出来了,查看下对应的SQLInjectionActivity.class 源代码:

这里写图片描述

我们会发现开发人员并没有对用户的输入数据进行处理。


Input Validation Issues - Part2

直接输入http://www.baidu.com 可以看到打开了百度的页面

这里写图片描述

如果将http协议换成File协议(File协议主要用于访问本地计算机中的文件,就如同在Windows资源管理器中打开文件一样),那我们就可以读取敏感信息了。查看下之前存储在sd卡的账号文件,file:///mnt/sdcard/.uinfo.tx

这里写图片描述

这样我们就能读取手机内其他的文件信息了,查看下对应的 InputValidation2URISchemeActivity.class源码:

这里写图片描述

可以发现同样是没有对用户数据进行处理。


Input Validation Issues - Part3

这里写图片描述

简单输入AAAA,出现了正常的反应。

这里写图片描述

试下输入超级长的AAAA…就会发现activity会直接崩溃,查看logcat就能发现缓冲区溢出了。

这里写图片描述

查看源码
https://github.com/payatu/diva-android/blob/master/app/src/main/jni/divajni.c

这里写图片描述

使用的是strcpy,典型的字符串复制溢出。


参考来源:
http://bobao.360.cn/learning/detail/3048.html
http://resources.infosecinstitute.com/cracking-damn-insecure-and-vulnerable-apps-diva-part-1/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值