Skip to content

11- Access Control Issues - Part 3

Aquí hay 2 activities, para poner PIN

Pasted image 20260827202949

y para validarlo

Pasted image 20260827204940

Este es el código para introducir el pin

java
public class AccessControl3Activity extends AppCompatActivity {
    @Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.BaseFragmentActivityDonut, android.app.Activity
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_access_control3);
        SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(this);
        String pin = spref.getString(getString(R.string.pkey), "");
        if (!pin.isEmpty()) {
            Button vbutton = (Button) findViewById(R.id.aci3viewbutton);
            vbutton.setVisibility(0);
        }
    }

    public void addPin(View view) {
        SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor spedit = spref.edit();
        EditText pinTxt = (EditText) findViewById(R.id.aci3Pin);
        String pin = pinTxt.getText().toString();
        if (pin == null || pin.isEmpty()) {
            Toast.makeText(this, "Please Enter a valid pin!", 0).show();
            return;
        }
        Button vbutton = (Button) findViewById(R.id.aci3viewbutton);
        spedit.putString(getString(R.string.pkey), pin);
        spedit.commit();
        if (vbutton.getVisibility() != 0) {
            vbutton.setVisibility(0);
        }
        Toast.makeText(this, "PIN Created successfully. Private notes are now protected with PIN", 0).show();
    }

    public void goToNotes(View view) {
        Intent i = new Intent(this, (Class<?>) AccessControl3NotesActivity.class);
        startActivity(i);
    }
}

Parece ser que el pin se guarda en preferences:

Esto es algo que se hace también en 3- Insecure Data Storage - Part 1,

Efectivamente

Pasted image 20260827210213

No se trata de credenciales de terceros, por lo que no es un problema muy grande.

Y para acceder se comprueba que el PIN es el que se encuentra en el archivo.

java
public class AccessControl3NotesActivity extends AppCompatActivity {
    @Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.BaseFragmentActivityDonut, android.app.Activity
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_access_control3_notes);
    }

    public void accessNotes(View view) {
        EditText pinTxt = (EditText) findViewById(R.id.aci3notesPinText);
        Button abutton = (Button) findViewById(R.id.aci3naccessbutton);
        SharedPreferences spref = PreferenceManager.getDefaultSharedPreferences(this);
        String pin = spref.getString(getString(R.string.pkey), "");
        String userpin = pinTxt.getText().toString();
        if (userpin.equals(pin)) {
            ListView lview = (ListView) findViewById(R.id.aci3nlistView);
            Cursor cr = getContentResolver().query(NotesProvider.CONTENT_URI, new String[]{"_id", "title", "note"}, null, null, null);
            String[] columns = {"title", "note"};
            int[] fields = {R.id.title_entry, R.id.note_entry};
            SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.notes_entry, cr, columns, fields, 0);
            lview.setAdapter((ListAdapter) adapter);
            pinTxt.setVisibility(4);
            abutton.setVisibility(4);
            return;
        }
        Toast.makeText(this, "Please Enter a valid pin!", 0).show();
    }
}

Tenemos que tratar de acceder sin sabernos el PIN.

Vemos una cosa rara en el código

java
Cursor cr = getContentResolver().query(NotesProvider.CONTENT_URI, new String[]{"_id", "title", "note"}, null, null, null);

Se trata de una lectura de un ContentProvider, es como una base de datos

java
getContentResolver().query(
    NotesProvider.CONTENT_URI,           // 1. URI del provider a consultar
    new String[]{"_id", "title", "note"}, // 2. columnas a devolver (projection)
    null,                                  // 3. selection (cláusula WHERE)
    null,                                  // 4. selectionArgs (valores del WHERE)
    null                                   // 5. sortOrder (ORDER BY)
);

El equivalente a

sql
SELECT _id, title, note FROM notes;

Si consultamos el AndroidManifest.xml lo vemos

xml
<provider
            android:name="jakhar.aseem.diva.NotesProvider"
            android:enabled="true"
            android:exported="true"
            android:authorities="jakhar.aseem.diva.provider.notesprovider"/>

Además

xml
android:exported="true"

Lo que permite que cualquier app pueda leer el content provider y por lo tanto toda la tabla "SQL" de notas sin saber el PIN

bash
adb shell content query --uri content://jakhar.aseem.diva.provider.notesprovider/notes

PD: el código del provider está en NotesProvider.java

Notas personales de seguridad ofensiva.