Link Search Menu Expand Document

M10: Extraneous Functionality

As the name suggests, extraneous functionality are functions or secrets hidden inside the app. Those functionalities allow an attacker to perform unintended actions such as:

  • Accessing administrative or debug functions
  • Retrieving hidden secrets (API keys, account credentials, personal information, etc.)
  • Discovering hidden back-end endpoints

In the case of the Goatlin app, a backdoor account is hardcoded into the code as shown below:

inner class UserLoginTask internal constructor(private val mUsername: String,
        private val mPassword: String) : AsyncTask<Void, Void, Boolean>() {

    override fun doInBackground(vararg params: Void): Boolean? {
        if ((mUsername == "Supervisor") and (mPassword == "MySuperSecretPassword123!")){
            return true
        else {
            val account:Account = DatabaseHelper(applicationContext).getAccount(mUsername)
            if (mPassword == account.password) {
                // ...
            // ...
        // ...
    // ...

When performing static analysis using apktool, jadx, or jd-gui, an attacker is able to retrieve those credentials and then use them to obtain access to the application.

Using apktool, it is possible to discover those credentials. On the LoginActivity$UserLoginTask.smali file, an attacker can identify the hardcoded account:

# virtual methods
.method protected varargs doInBackground([Ljava/lang/Void;)Ljava/lang/Boolean;
    .locals 7
    .param p1, "params"    # [Ljava/lang/Void;
        .annotation build Lorg/jetbrains/annotations/NotNull;
        .end annotation
    .end param
    .annotation build Lorg/jetbrains/annotations/Nullable;
    .end annotation
    const-string v0, "params"
    invoke-static {p1, v0}, Lkotlin/jvm/internal/Intrinsics;->checkParameterIsNotNull(Ljava/lang/Object;Ljava/lang/String;)V
    .line 218
    iget-object v0, p0, Lcom/cx/goatlin/LoginActivity$UserLoginTask;->mUsername:Ljava/lang/String;
    const-string v1, "Supervisor"
    invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->areEqual(Ljava/lang/Object;Ljava/lang/Object;)Z
    move-result v0
    iget-object v1, p0, Lcom/cx/goatlin/LoginActivity$UserLoginTask;->mPassword:Ljava/lang/String;
    const-string v2, "MySuperSecretPassword123!"
    invoke-static {v1, v2}, Lkotlin/jvm/internal/Intrinsics;->areEqual(Ljava/lang/Object;Ljava/lang/Object;)Z
    move-result v1

Another way is to use the jadx tool. Then, when looking at the LoginActivity class, we can find the following decompiled code:

protected Boolean doInBackground(@NotNull Void... params) {
    Intrinsics.checkParameterIsNotNull(params, "params");
    boolean z = true;
    if ((Intrinsics.areEqual(this.mUsername, (Object) "Supervisor") & Intrinsics.areEqual(this.mPassword, (Object) "MySuperSecretPassword123!")) != 0) {
        return Boolean.valueOf(true);
    // ...