Update Notice
This website is outdated. Will automatically forward to the latest website in two seconds. If not, please click on this link to find the latest, updated website.
This website is outdated. Will automatically forward to the latest website in two seconds. If not, please click on this link to find the latest, updated website.
 
 
Mobile application security has been one of the major areas of security research in the last decade. Numerous application analysis tools have been proposed in response to malicious, curious, or vulnerable apps. However, existing tools, and specifically, static analysis tools, trade soundness of the analysis for precision and performance, and are hence soundy. Unfortunately, the specific unsound choices or flaws in the design of these tools are often not known or well-documented, leading to a misplaced confidence among researchers, developers, and users. This paper proposes the Mutation-based soundness evaluation (µSE) framework, which systematically evaluates Android static analysis tools to discover, document, and fix, flaws, by leveraging the well-founded practice of mutation analysis. We implement µSE as a semi-automated framework, and apply it to a set of prominent Android static analysis tools that detect private data leaks in apps. As the result of an in-depth analysis of one of the major tools, we discover 13 undocumented flaws. More importantly, we discover that all 13 flaws propagate to tools that inherit the flawed tool. We successfully fix one of the flaws in cooperation with the tool developers. Our results motivate the urgent need for systematic discovery and documentation of unsound choices in soundy tools, and demonstrate the opportunities in leveraging mutation testing in achieving this goal.
 
Here we provide the list of all the security vulnerabilities that were discovered using μSE. Please, click on a vulnerability for more details.
runOnUiThread(new Runnable() { @Override public void run() { String dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); android.util.Log.d("leak-1", dataLeak); } });
public void leakData(View view) { CharSequence[] items = {"item1", "item2", "item3"}; new AlertDialog.Builder(this).setTitle("example") .setCancelable(true) .setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int i) { String dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); android.util.Log.d("leak-1", dataLeak); } }) .create() .show(); }
<Button android:layout_width="match_parent" android:layout_height="match_parent" android:onClick="leakData" />
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DialogFragment example = new ExampleDialogFragment(); example.show(getFragmentManager().beginTransaction(), "ExampleDialog"); } public static class ExampleDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { String dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); android.util.Log.d("leak-1", dataLeak); return new AlertDialog.Builder(getActivity()).setTitle("example") .create(); } }
public class MainActivity extends Activity implements NavigationView.OnNavigationItemSelectedListener { @Override public boolean onNavigationItemSelected(MenuItem item) { String dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); android.util.Log.d("leak-1", dataLeak); return false; } }
ExecutorService service = Executors.newSingleThreadExecutor(); service.submit(new Runnable() { @Override public void run() { String dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); android.util.Log.d("leak-1", dataLeak); } });
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); manager.listen(new PhoneListener(), PhoneStateListener.LISTEN_CALL_STATE); } private class PhoneListener extends PhoneStateListener { @Override public void onDataConnectionStateChanged(int state) { String dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); android.util.Log.d("leak-1", dataLeak); } }
BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); android.util.Log.d("leak-1", dataLeak); } }; IntentFilter filter = new IntentFilter(); filter.addAction("android.intent.action.SEND"); registerReceiver(receiver, filter); } }; IntentFilter filter = new IntentFilter(); filter.addAction("android.intent.action.SEND"); registerReceiver(receiver, filter);
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener); } private LocationListener locationListener = new LocationListener() { private String dataLeak = ""; @Override public void onLocationChanged(Location location) { Log.d("leak", dataLeak); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); } };
final NsdManager nsdManager = (NsdManager)this.getSystemService(Context.NSD_SERVICE); NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() { String dataLeak = ""; @Override public void onDiscoveryStarted(String serviceType) { dataLeak = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); } @Override public void onServiceFound(NsdServiceInfo serviceInfo) { NsdManager.ResolveListener resolver = new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { Log.d("leak", dataLeak); } @Override public void onServiceResolved(NsdServiceInfo serviceInfo) { Log.d("leak", dataLeak); } }; nsdManager.resolveService(serviceInfo, resolver); } }; nsdManager.discoverServices("", NsdManager.PROTOCOL_DNS_SD, listener);
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ArrayList<Example> examples = new ArrayList<Example>(); examples.add(new Example()); ListView serviceTable = (ListView) findViewById(R.id.listview); serviceTable.setAdapter(new ArrayAdapter<Example>(this, android.R.layout.simple_list_item_1, examples)); serviceTable.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Example example = (Example) parent.getItemAtPosition(position); example.foo(); example.bar(); } }); } private class Example { String dataLeAk; public void foo() { dataLeAk = Calendar.getInstance().getTimeZone().getDisplayName(); } public void bar() { Log.d("leak", dataLeAk); } }
final String dataLeak = Calendar.getInstance().getTimeZone().getDisplayName(); Thread thread = new Thread(new Runnable() { @Override public void run() { Log.d("leak-1", dataLeak); } }); thread.start();
public class LeakyFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { String dataLeak = Calendar.getInstance().getTimeZone().getDisplayName(); Log.d("leak-1", dataLeak); return inflater.inflate(R.layout.fragment_leaky, container, false); } } public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Fragment test = new LeakyFragment(); getSupportFragmentManager().beginTransaction().replace(R.id.fragment, test).commit(); } }
public class MySQLiteHelper extends SQLiteOpenHelper { public MySQLiteHelper(Context context) { super(context, "example", null, 1); } @Override public void onCreate(SQLiteDatabase db) { String dataLeak = Calendar.getInstance().getTimeZone().getDisplayName(); Log.d("leak-1”, dataLeak); } }
 
Here we provide descriptions of the security mutation operator and mutation schemes implemented within μSE. Please, click on a mutation operator or scheme for more details.
class Example { // Declaration Mark 0 // Declaration Mark 1 // Declaration Mark 0-0 // Declaration Mark 1-0 void foo() { // Source Mark 0 // Transformation Mark 1 // Hop Mark 1-0 // Transformation Mark 0-0 // Sink Mark 0-0-0 // Transformation Mark 1-0 // Sink Mark 1-0-0 } void bar() { // Source Mark 1 // Transformation Mark 0 // Hop Mark 0-0 // Transformation Mark 0-0 // Sink Mark 0-0-1 // Transformation Mark 1-0 // Sink Mark 1-0-1 } }
class Example { String dataLeak0; String dataLeak1; String dataLeak0_0; String dataLeak1_0; void foo() { dataLeak0 = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); String temp1 = dataLeak1; Stringbuffer tempBuffer1 = new StringBuffer(); for (char char1 : temp1.toCharArray()) {tempBuffer1.append(char1);} temp1 = tempBuffer1.toString(); dataLeak1 = temp1; dataLeak1_0 = dataLeak1; String temp0_0 = dataLeak0_0; Stringbuffer tempBuffer0_0 = new StringBuffer(); for (char char0_0 : temp0_0.toCharArray()) {tempBuffer0_0.append(char0_0);} temp0_0 = tempBuffer0_0.toString(); dataLeak0_0 = temp0_0; android.util.Log.d(“leak-0-0-0”, dataLeak0_0); String temp1_0 = dataLeak1_0; Stringbuffer tempBuffer1_0 = new StringBuffer(); for (char char1_0 : temp1_0.toCharArray()) {tempBuffer1_0.append(char1_0);} temp1_0 = tempBuffer1_0.toString(); dataLeak1_0 = temp1_0; android.util.Log.d(“leak-1-0-0”, dataLeak1_0); } void bar() { dataLeak1 = java.util.Calendar.getInstance().getTimeZone().getDisplayName(); String temp0 = dataLeak1; Stringbuffer tempBuffer0 = new StringBuffer(); for (char char0 : temp0.toCharArray()) {tempBuffer0.append(char0);} temp0 = tempBuffer0.toString(); dataLeak0 = temp0; dataLeak0_0 = dataLeak0; String temp0_0 = dataLeak0_0; Stringbuffer tempBuffer0_0 = new StringBuffer(); for (char char0_0 : temp0_0.toCharArray()) {tempBuffer0_0.append(char0_0);} temp0_0 = tempBuffer0_0.toString(); dataLeak0_0 = temp0_0; android.util.Log.d(“leak-0-0-1”, dataLeak0_0); String temp1_0 = dataLeak1_0; Stringbuffer tempBuffer1_0 = new StringBuffer(); for (char char1_0 : temp1_0.toCharArray()) {tempBuffer1_0.append(char1_0);} temp1_0 = tempBuffer1_0.toString(); dataLeak1_0 = temp1_0; android.util.Log.d(“leak-1-0-1”, dataLeak1_0); } }
void foo() {}
void foo() { // Declaration Mark 0 // Source Mark 0 // Sink Mark 0-0 }
protected void onStop() { super.onStop(); }
protected void onStop() { super.onStop(); // Declaration Mark 0 // Source Mark 0 // Sink Mark 0-0 }
class Example { void foo() {} void bar() {} class SubExample { void baz() {} } }
class Example { // Declaration Mark 0 // Declaration Mark 1 // Declaration Mark 3 void foo() { // Source Mark 0 // Sink Mark 1-0 // Sink Mark 3-0 } void bar() { // Source Mark 1 // Sink Mark 0-1 // Sink Mark 3-1 } class SubExample { // Declaration Mark 2 void baz() { // Source Mark 2 // Source Mark 3 // Sink Mark 0-2 // Sink Mark 1-2 // Sink Mark 3-2 } } }
class Example { void foo() {} void bar() {} class SubExample { void baz() {} } }
class Example { // Declaration Mark 0 // Declaration Mark 1 // Declaration Mark 3 void foo() { // Source Mark 0 // Transformation Mark 1 // Sink Mark 1-0 // Transformation Mark 3 // Sink Mark 3-0 } void bar() { // Source Mark 1 // Transformation Mark 0 // Sink Mark 0-1 // Transformation Mark 3 // Sink Mark 3-1 } class SubExample { // Declaration Mark 2 void baz() { // Source Mark 2 // Source Mark 3 // Transformation Mark 0 // Sink Mark 0-2 // Transformation Mark 1 // Sink Mark 1-2 // Transformation Mark 3 // Sink Mark 3-2 } } }
 
 
 
 
This material is based upon work supported by the National Science Foundation under Grant Number NSF-1815336