Implement Executing commands as System (UID 1000) using SMT Exploit
Please check before submitting an issue
- [X] I am using the latest version of App Manager
- [X] I have searched the issues and haven't found anything relevant
- [X] I have read the docs
Describe a description of the new feature
Many commands (such as disabling app components) will not work with ADB mode, and instead need root mode. Unfortunately, not all devices have root mode available.
However, many Samsung phones have been exploit to allow for processes to run with UID 1000/System privileges, and these commands (pm disable) will work with these privileges too.
Describe the solution you'd like
This feature request is to implement SMTShell-API based on SMTShell (CVE-2019-16253), to run these commands
We've discussed something similar in #922. Usability of such feature is still being investigated.
We've discussed something similar in #922. Usability of such feature is still being investigated.
Ah yes, I apologize I missed that. It should be much easier now that an API has been implemented. I read about your hesitations for using Shizuku, but in this case you would want to outsource the exploit because I believe only one app can utilize the exploit at a time. So there is no reason to reinvent the wheel here, and just allow SMTShell to manage the exploit so the user can use other apps that want escalated system privileges too.
Exploiting this vulnerability only requires a native library and an old version of the SMT app. That's all. So, this SMTShell app is a helper app rather than a manager app. This could also be implemented as a library as there's no need to use a third-party app for a simple thing as this. But, this also means that any app can utilise the exploit with or without SMTShell. It would've been far better if there was a way to upgrade the app without killing it after running the exploit so that nobody else can use it in order to provide at least some level of privacy and security to the user (having so easy an exploit out in the open outweighs the benefits). This is something I've looked into and I think it's completely possible.
The use-case here is simpler than Shizuku as a result. All we need is to run a command in UID 1000 so that App Manager can run in the privileged mode. This is why we considered supporting it within App Manager. But later, we decided against it because this is a vulnerability and exploiting it directly in the app might flag it as a malware. So, the chances are that this will come as a separate extension (a few Kb extension) which would help App Manager exploiting the vulnerability to get elevated permission while others may not.
But for now, we'll stick to SMTShell API.
Exploiting this vulnerability only requires a native library and an old version of the SMT app. That's all. So, this SMTShell app is a helper app rather than a manager app. This could also be implemented as a library as there's no need to use a third-party app for a simple thing as this. But, this also means that any app can utilise the exploit with or without SMTShell. It would've been far better if there was a way to upgrade the app without killing it after running the exploit so that nobody else can use it in order to provide at least some level of privacy and security to the user (having so easy an exploit out in the open outweighs the benefits). This is something I've looked into and I think it's completely possible.
The use-case here is simpler than Shizuku as a result. All we need is to run a command in UID
1000so that App Manager can run in the privileged mode. This is why we considered supporting it within App Manager. But later, we decided against it because this is a vulnerability and exploiting it directly in the app might flag it as a malware. So, the chances are that this will come as a separate extension (a few Kb extension) which would help App Manager exploiting the vulnerability to get elevated permission while others may not.But for now, we'll stick to SMTShell API.
Ah okay yes, your understanding of it is much better than mine is. I know SMTShell checks for conflicts so I was making some assumptions that only one lang pack can be used.
In fact, I think the original CVE or one of its successors mentioned a good way to protect yourself from the security issue is to exploit it yourself so that others wont be able to. I'll have to dig to find the link to see if I can find what they meant by that
If that is true and I understand it correctly, then I think it stands that leaving SMTShell as the "manager" would be best. You may have better insight though.
SMTShell, it appears, has several issues. The most prominent is that it only allows execution of one shell command at a time. The command used by App Manager will run a remote service indefinitely, hence, you cannot use the shell for any other purposes during the entire time. In case App Manager is unable to connect to the remote service, a new service needs to be created which is not possible since the shell is already busy. I don't think SMTShell would be much usable if it does not find a way to run multiple shell. Also, it returns output as a list which will cause crash if the output is too large (Android has limits on how much data you can send over Binder in a single transaction).
SMTShell, it appears, has several issues. The most prominent is that it only allows execution of one shell command at a time. The command used by App Manager will run a remote service indefinitely, hence, you cannot use the shell for any other purposes during the entire time. In case App Manager is unable to connect to the remote service, a new service needs to be created which is not possible since the shell is already busy. I don't think SMTShell would be much usable if it does not find a way to run multiple shell. Also, it returns output as a list which will cause crash if the output is too large (Android has limits on how much data you can send over Binder in a single transaction).
ahhh thats unfortunate... i really wanted this to work. how about the load library function? the api allows loading libraries with uid 1000 escalation. My knowledge definitely runs short at this point, I was trying to implement running libsu library as uid1000 and using shell builder but i wasnt anywhere close to successful, im not even sure if what i was trying to do is a "thing"
how about the load library function? the api allows loading libraries with uid 1000 escalation.
It doesn't worth it.
I've already used SMTShell API in App Manager to run a remote service in UID 1000. It works as expected (of course, I need to rewrite some parts of App Manager because not all features are going to work in UID 1000 and vice versa), but the connection to the remote service seems on and off. Once it goes off, I don't find a way to recover it. I need to investigate a bit more to understand what went wrong.
There's also this weird issue: The system seems to detect App Manager running in UID 1000 instead of its own which creates a new set of problems.
My knowledge definitely runs short at this point, I was trying to implement running libsu library as uid1000 and using shell builder but i wasnt anywhere close to successful, im not even sure if what i was trying to do is a "thing"
You can test this single shell limitation quite easily. Open a reverse shell using ADB. Then try to open a local shell in the app. The latter won't work, and any attempt to execute a command there would result a crash.
Possibly found the issue:
SamsungTTS com.samsung.SMT E LangPackMgr() - Failed startService[com.samsung.SMT.lang.smtshell] : Not allowed to start service Intent { act=com.samsung.SMT.lang.smtshell pkg=com.samsung.SMT.lang.smtshell }: app is in background uid null
Possibly found the issue:
SamsungTTS com.samsung.SMT E LangPackMgr() - Failed startService[com.samsung.SMT.lang.smtshell] : Not allowed to start service Intent { act=com.samsung.SMT.lang.smtshell pkg=com.samsung.SMT.lang.smtshell }: app is in background uid null
I recall seeing that line when I was messing around with some other things with SMTShell, although I dont believe it said "null" at the end. i did not notice any performance issues, however, and so I ignored it. possibly has to do with the "exploit" method under the MainActivity class? it should maybe read: ''' ContextCompat.startService( ''' I am not sure, just grasping at straws and doing the best I can to help
There's also this weird issue: The system seems to detect App Manager running in UID 1000 instead of its own which creates a new set of problems.
Is there any chance you can create a testing branch for this feature? I dont know a lot about android programming but i usually can figure out how to squash small bugs and implement small features (I figured out how to autostart shizuku and smtshell on boot without user interaction)
its the big picture basic framework that I dont understand yet, and so I would need a starting point. I was able to add an additional 'mode' in the array names for smtshell, but couldn't figure out how the modes were actually called to runcommands so i didnt get far
TLDR if you would be able to implement the basic framework for an SMTShell runcommand method either through loadlibrary api or direct command api in a testing branch, i may be able to help test/fix from there
Sure. https://github.com/MuntashirAkon/AppManager/tree/smtshell-api
It's not working at all. The command needs to be invoked manually.
Sure. https://github.com/MuntashirAkon/AppManager/tree/smtshell-api
Thank you! I will work on this later today
When you say invoked manually, you are just saying manually opening a reverse shell because it doesnt work in-app?
When you say invoked manually, you are just saying manually opening a reverse shell because it doesnt work in-app?
Yes. I attempted to run the command using the API, but the API doesn't seem to do anything. You can find the required command in debug builds by filtering the logcat output with COMMAND: keyword. Copy the command and run it using the shell (and then you can exit the shell too since it runs in another thread). Do not expect anything to work in App Manager except the basic features because I haven't yet added full support for this mode of operation.
When you say invoked manually, you are just saying manually opening a reverse shell because it doesnt work in-app?
Yes. I attempted to run the command using the API, but the API doesn't seem to do anything. You can find the required command in debug builds by filtering the logcat output with
COMMAND:keyword. Copy the command and run it using the shell (and then you can exit the shell too since it runs in another thread). Do not expect anything to work in App Manager except the basic features because I haven't yet added full support for this mode of operation.
Perfect! thanks for the details... that should be plenty for me to get started.
@MuntashirAkon just a quick preliminary look... I am getting:
06-16 00:11:53.638 1266 1559 W BroadcastQueue: Permission Denial: broadcasting Intent { act=smtshell.intent.action.SHELL_COMMAND flg=0x10 pkg=com.samsung.SMT (has extras) } from io.github.muntashirakon.AppManager.debug (pid=8587, uid=10395) requires smtshell.permission.SELF due to registered receiver BroadcastFilter{387587f 1000/u0 ReceiverList{4e1259e 12811 com.samsung.SMT/1000/u0 remote:a0187d9}}
06-16 00:11:53.638 1266 1559 W BroadcastQueue: Permission Denial: broadcasting Intent { act=smtshell.intent.action.SHELL_COMMAND flg=0x10 pkg=com.samsung.SMT (has extras) } from io.github.muntashirakon.AppManager.debug (pid=8587, uid=10395) requires smtshell.permission.SYSTEM_COMMAND due to registered receiver BroadcastFilter{b5fdaa 1000/u0 ReceiverList{ff9c895 12811 com.samsung.SMT/1000/u0 remote:ed1904c}}
The API docs didn't include those permissions. Try adding those permissions in the manifest of App Manager and see if it works.
The API docs didn't include those permissions. Try adding those permissions in the manifest of App Manager and see if it works.
Skip to TLDR for relevant next steps
- another update... the
smtshell.permission.SELFpermission denied is a false alarm, the receiver uses both that permission and thesmtshell.permission.SYSTEM_COMMANDfor the sameBroadcastReceiveraction, so any broadcast intent to that will always have one of those fail which can be ignored smtshell.permission.SYSTEM_COMMANDis a permission we already successfully claim in our manifest, but we never implemented a UI popup to grant it yet, so it can just be manually granted permission in Android App Settings for App Manager for now to fix that issue- Running from Reverse Shell succeeds, but SMTShellAPI throws
SMTShell: failed to run commandwhen we call:
(AM_VERBOSE_LOGGING=1 CLASSPATH=/storage/emulated/0/Android/data/io.github.muntashirakon.AppManager.debug/cache/main.jar /system/bin/app_process /system/bin --nice-name=io.github.muntashirakon.AppManager.debug:root io.github.muntashirakon.AppManager.server.RootServiceMain io.github.muntashirakon.AppManager.debug/io.github.muntashirakon.AppManager.ipc.AMService 10398 16e6e556-5886-48a1-b0c4-4e6d54a9b0be start)&
- We can debug by reducing the command.... Running from Reverse Shell succeeds, but SMTShellAPI throws
SMTShell: failed to run commandwhen we call:
CLASSPATH=/storage/emulated/0/Android/data/io.github.muntashirakon.AppManager.debug/cache/main.jar /system/bin/app_process /system/bin --nice-name=io.github.muntashirakon.AppManager.debug:root io.github.muntashirakon.AppManager.server.RootServiceMain io.github.muntashirakon.AppManager.debug/io.github.muntashirakon.AppManager.ipc.AMService 10398 16e6e556-5886-48a1-b0c4-4e6d54a9b0be start &
TLDR
- However Running from Reverse Shell succeeds and SMTShellAPI succeeds if we call:
/system/bin/app_process /system/bin --nice-name=io.github.muntashirakon.AppManager.debug:root io.github.muntashirakon.AppManager.server.RootServiceMain io.github.muntashirakon.AppManager.debug/io.github.muntashirakon.AppManager.ipc.AMService 10398 16e6e556-5886-48a1-b0c4-4e6d54a9b0be start &
Of course, that command does not actually help App Manager start because it is missing the ClassPath, but we did isolate the issue to that prefix. Next to do is to figure out if SMTShell API is failing the command because of the syntax of CLASSPATH prefix, or because it has issues actually executing the command. The relevant code in SMTShell is:
AsyncTask.execute(() -> {
try {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(cmd);
// send results to caller
if (sender != null) {
String stdout = streamToString(p.getInputStream());
String stderr = streamToString(p.getErrorStream());
int exitCode = p.waitFor();
Log.i(TAG, String.format("command complete (id: %d)", id));
String pkg = sender.getCreatorPackage();
Intent callback = new Intent(ACTION_SHELL_RESULT);
callback.putExtra(EXTRA_REQUEST_ID, id);
callback.putExtra(EXTRA_STDOUT, stdout);
callback.putExtra(EXTRA_STDERR, stderr);
callback.putExtra(EXTRA_EXIT_CODE, exitCode);
callback.setPackage(pkg);
sAppContext.sendBroadcast(callback);
Log.i(TAG, String.format("callback sent (id: %d)", id));
}
} catch (IOException | InterruptedException e) {
Log.e(TAG, String.format("**failed to run command** (id: %d): %s", id, cmd));
}
});
@MuntashirAkon I figured it out....
According to the Android Docs , we have to figure out a way to pass CLASSPATH to envp via SMTShell which uses Runtime.getRuntime().exec(cmd) ... I am guessing we may have to modify SMTShell code to add a method for Runtime.getRuntime().exec(cmd, envp) unless there is a hacky way to force the two string array arguments into Runtime.getRuntime().exec(cmd)
Thanks for your investigations. I'll try to come up with a better solution in the next week.
Initialization works perfectly after changing SMTShell code in the code block posted above to:
Process p = rt.exec(new String[] { "sh", "-c", cmd});
This fixes it because it allows executing the cmd in a shell environment, which RuntimeExec does not usually do as excellently explained here.
AppOps section of AppManager now populates, but it seems like component disabling features via ifw/pm disable aren't even coming up as on option... perhaps this just hasnt been implemented yet in the test branch you gave me
EDIT: Another option is, I've read that:
CLASSPATH=/data/local/tmp/HelloWorld.jar app_process /data/local/tmp com.example.HelloWorld
is equivalent to:
app_process -cp /data/local/tmp/HelloWorld.jar /data/local/tmp com.example.HelloWorld
so that is another option, i'm not sure which is better... probably the former fix in SMTShell app
AppOps section of AppManager now populates, but it seems like component disabling features via ifw/pm disable aren't even coming up as on option... perhaps this just hasnt been implemented yet in the test branch you gave me
I've rebased the branch with master. So, other features should now start working.
so that is another option, i'm not sure which is better... probably the former fix in SMTShell app
I'm thinking of a more generic way to achieve that.
AppOps section of AppManager now populates, but it seems like component disabling features via ifw/pm disable aren't even coming up as on option... perhaps this just hasnt been implemented yet in the test branch you gave me
I've rebased the branch with master. So, other features should now start working.
so that is another option, i'm not sure which is better... probably the former fix in SMTShell app
I'm thinking of a more generic way to achieve that.
thank you... im simultaneously looking into: https://github.com/zacharee/ShizukuHack
~~the problem is i believe its helper app is proprietary. but i did try it out and it fixes the "only one process being able to use system privileges" problem you were describing before where it would crash if you try to use two shells so its a much better solution~~
~~the good news is, i think the helper app is actually pretty simple to make~~
EDIT: @MuntashirAkon actually i was misinformed by someone... i think the whole thing is open sourced. the part that i thought was closed sourced is actually found here https://github.com/zacharee/ShizukuHack/blob/master/manager/src/main/jni/mstring.cpp
looking at your recent commits (blending adb and systemshell as one privileged call) ** I think** it makes a lot of sense to just integrate shizuku and dependending on if user has regular shizuku or systemshizuku installed you will get privileged access..
Well, there are a lot of threads here regarding Shizuku support, but Shizuku remains to be a non-free app. Although it has an OSI-approved license, namely Apache-2.0, it has additional terms (i.e. license exception) that makes it effectively a source-available app:
For the project as a whole, it is not free. You are FORBIDDEN to distribute the apk compiled by you (including modified, e.g., rename app name "Shizuku" to something else) to any store (IBNLT Google Play Store, F-Droid, Amazon Appstore etc.).
That is, it allows its code to be copied under the terms of Apache-2.0 license, but it does not allow redistribution of the app. App Manager was created on the principles of FLOSS, and therefore, it is against our principle to support any non-free apps.
Well, there are a lot of threads here regarding Shizuku support, but Shizuku remains to be a non-free app. Although it has an OSI-approved license, namely Apache-2.0, it has additional terms (i.e. license exception) that makes it effectively a source-available app:
For the project as a whole, it is not free. You are FORBIDDEN to distribute the apk compiled by you (including modified, e.g., rename app name "Shizuku" to something else) to any store (IBNLT Google Play Store, F-Droid, Amazon Appstore etc.).
That is, it allows its code to be copied under the terms of Apache-2.0 license, but it does not allow redistribution of the app. App Manager was created on the principles of FLOSS, and therefore, it is against our principle to support any non-free apps.
that is a very good point... the good news is, since you have the basic framework already implemented, it should be easy to port to any API from my understanding. the reason i say that is, i'm not 100% sure SMTShell is the answer. as you pointed out, only having one process utilizing elevated permissions at a time is not a good implementation. ive been trying to explore other options
btw while running as system AppManager should be able to launch any activity, currently it doesn't show the option to launch everything.
btw while running as system AppManager should be able to launch any activity, currently it doesn't show the option to launch everything.
it hasnt been implemented that far yet... if you can modify the code yourself, @MuntashirAkon kindly made a system uid git branch that you can clone and there are just a couple "if checks" that you need to change to get activity launching and activity blocking working