외로운 Nova의 작업실

insecurebankv2 - 개발자 백도어 본문

Mobile App Penetesting/Android App Vulnerability

insecurebankv2 - 개발자 백도어

Nova_ 2023. 6. 4. 14:45

- 취약점 소개

개발자들이 유지보수나 디버깅시 인증을 회피할 목적으로 만든 백도어가 있을 수 있습니다. 이러한 개발자의 백도어가 공격자에게 발견되면 시스템에 큰 위험을 초래할 수 있습니다.

 

- 취약점 진단 과정

DoLogin$RequestTask.class 코드를 보겠습니다.

package com.android.insecurebankv2;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.util.Base64;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;

class DoLogin$RequestTask extends AsyncTask {
   final DoLogin this$0;

   DoLogin$RequestTask(DoLogin var1) {
      this.this$0 = var1;
   }

   private String convertStreamToString(InputStream var1) throws IOException {
      try {
         DoLogin var4 = this.this$0;
         InputStreamReader var2 = new InputStreamReader(var1, "UTF-8");
         BufferedReader var3 = new BufferedReader(var2);
         var4.reader = var3;
      } catch (UnsupportedEncodingException var5) {
         var5.printStackTrace();
      }

      StringBuilder var6 = new StringBuilder();

      while(true) {
         String var7 = this.this$0.reader.readLine();
         if (var7 == null) {
            var1.close();
            return var6.toString();
         }

         var6.append(var7 + "\n");
      }
   }

   private void saveCreds(String var1, String var2) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
      SharedPreferences.Editor var3 = this.this$0.getSharedPreferences("mySharedPreferences", 0).edit();
      this.this$0.rememberme_username = var1;
      this.this$0.rememberme_password = var2;
      var2 = new String(Base64.encodeToString(this.this$0.rememberme_username.getBytes(), 4));
      CryptoClass var4 = new CryptoClass();
      this.this$0.superSecurePassword = var4.aesEncryptedString(this.this$0.rememberme_password);
      var3.putString("EncryptedUsername", var2);
      var3.putString("superSecurePassword", this.this$0.superSecurePassword);
      var3.commit();
   }

   private void trackUserLogins() {
      this.this$0.runOnUiThread(new DoLogin.RequestTask.1(this));
   }

   protected String doInBackground(String... var1) {
      Object var10;
      try {
         this.postData(var1[0]);
         return null;
      } catch (InvalidKeyException var2) {
         var10 = var2;
      } catch (NoSuchAlgorithmException var3) {
         var10 = var3;
      } catch (NoSuchPaddingException var4) {
         var10 = var4;
      } catch (InvalidAlgorithmParameterException var5) {
         var10 = var5;
      } catch (IllegalBlockSizeException var6) {
         var10 = var6;
      } catch (BadPaddingException var7) {
         var10 = var7;
      } catch (IOException var8) {
         var10 = var8;
      } catch (JSONException var9) {
         var10 = var9;
      }

      ((Exception)var10).printStackTrace();
      return null;
   }

   protected void onPostExecute(Double var1) {
   }

   protected void onProgressUpdate(Integer... var1) {
   }

   public void postData(String var1) throws ClientProtocolException, IOException, JSONException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
      DefaultHttpClient var5 = new DefaultHttpClient();
      HttpPost var3 = new HttpPost(this.this$0.protocol + this.this$0.serverip + ":" + this.this$0.serverport + "/login");
      HttpPost var2 = new HttpPost(this.this$0.protocol + this.this$0.serverip + ":" + this.this$0.serverport + "/devlogin");
      ArrayList var4 = new ArrayList(2);
      var4.add(new BasicNameValuePair("username", this.this$0.username));
      var4.add(new BasicNameValuePair("password", this.this$0.password));
      HttpResponse var6;
      if (this.this$0.username.equals("devadmin")) {
         var2.setEntity(new UrlEncodedFormEntity(var4));
         var6 = var5.execute(var2);
      } else {
         var3.setEntity(new UrlEncodedFormEntity(var4));
         var6 = var5.execute(var3);
      }

      InputStream var7 = var6.getEntity().getContent();
      this.this$0.result = this.convertStreamToString(var7);
      this.this$0.result = this.this$0.result.replace("\n", "");
      if (this.this$0.result != null) {
         Intent var8;
         if (this.this$0.result.indexOf("Correct Credentials") != -1) {
            Log.d("Successful Login:", ", account=" + this.this$0.username + ":" + this.this$0.password);
            this.saveCreds(this.this$0.username, this.this$0.password);
            this.trackUserLogins();
            var8 = new Intent(this.this$0.getApplicationContext(), PostLogin.class);
            var8.putExtra("uname", this.this$0.username);
            this.this$0.startActivity(var8);
         } else {
            var8 = new Intent(this.this$0.getApplicationContext(), WrongLogin.class);
            this.this$0.startActivity(var8);
         }
      }

   }
}

PostData 함수의 var3와 var2를 보면 httpPost 객체가 2개가 있음을 알 수 있습니다. var2에는 정상적인 /login요청이 아닌 /devlogin 요청이 있습니다. 좀 더 아래코드에는

if (this.this$0.username.equals("devadmin")) {
         var2.setEntity(new UrlEncodedFormEntity(var4));
         var6 = var5.execute(var2);

 이러한 코드가 있습니다. 즉 username이 devadmin이면 /devlogin 요청을 보내는 처리 코드입니다. 그러면 한번 devadmin으로 로그인해보겠습니다.

로그인이 됨을 알 수 있습니다.

 

- 취약점 대응 방안

백도어 코드부분을 없애고 정상적인 로그인 로직만 남겨둡니다.

Comments