티스토리 뷰

728x90
반응형

[ 루팅 탐지 및 우회 취약점]

     : 안드로이드 디바이스 시스템 권한을 얻는 것

 

- 안드로이드는 애플리케이션 실행 시 각 프로그램마다 권한을 부여해 독립적으로 동작

   ( 순성 상태의 안드로이드는 애플리케이션에서 할 수 있는 행위들에 제한 )

- 이러한 제한을 풀거나 우회하기 위해서는 시스템 권한을 루팅으로 획득해야 함

- 루팅된 기기는 시스템 권한을 획득하게 되어 디바이스 내부의 민감한 정보에 접근 가능

- 금융권 애플리케이션은 기본적으로 루팅된 기기에서의 앱 실행을 차단

 

- 최근 디바이스에 카드 정보를 저장해 간단하게 결제할 수 있는 핀테크 기술이 이슈되면서 이 기술을 제공하는 기업에서 

   공식적으로 루팅된 기기는 보안 위협으로 감지하고 기술 지원을 하지 않는다는 입장을 밝혔다

 

 

 

 

< 취약점 진단 과정 >

루팅 체크가 필수적인 금융 앱이나 게임 앱에서는 다음과 같은 4가지 경로를 주로 체크한다.

 /system/bin/su
 /system/xbin/su
 /system/app/superuser.apk
 /data/data/com.noshufou/android.su

로그인 된 화면

로그인을 하면 PostLogin 창의 하단에 Rooted Device!! 라는 메시지가 출력되는데, 

이는 현재 접속한 디바이스가 루팅되어 있다는 것을 의미.

 

 

 

PostLogin.class 소스코드

  private boolean doesSUexist() {
    Process process = null;
    null = null;
    try {
      Process process1 = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
      null = process1;
      process = process1;
      String str = (new BufferedReader(new InputStreamReader(process1.getInputStream()))).readLine();
      if (str != null)
        return true; 
      return false;
    } catch (Throwable throwable) {
      return false;
    } finally {
      if (throwable != null)
        throwable.destroy(); 
    } 
  }
  
  private boolean doesSuperuserApkExist(String paramString) {
    return (Boolean.valueOf((new File("/system/app/Superuser.apk")).exists()).booleanValue() == true);
  }
  
  public void callPreferences() {
    startActivity(new Intent((Context)this, FilePrefActivity.class));
  }
  
  protected void changePasswd() {
    Intent intent = new Intent(getApplicationContext(), ChangePassword.class);
    intent.putExtra("uname", this.uname);
    startActivity(intent);
  }
  
  protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    setContentView(2130968606);
    this.uname = getIntent().getStringExtra("uname");
    this.root_status = (TextView)findViewById(2131558528);
    showRootStatus();
    this.transfer_button = (Button)findViewById(2131558525);
    this.transfer_button.setOnClickListener(new View.OnClickListener() {
          public void onClick(View param1View) {
            Intent intent = new Intent(PostLogin.this.getApplicationContext(), DoTransfer.class);
            PostLogin.this.startActivity(intent);
          }
        });
    this.statement_button = (Button)findViewById(2131558526);
    this.statement_button.setOnClickListener(new View.OnClickListener() {
          public void onClick(View param1View) {
            PostLogin.this.viewStatment();
          }
        });
    this.changepasswd_button = (Button)findViewById(2131558527);
    this.changepasswd_button.setOnClickListener(new View.OnClickListener() {
          public void onClick(View param1View) {
            PostLogin.this.changePasswd();
          }
        });
  }
  
  public boolean onCreateOptionsMenu(Menu paramMenu) {
    getMenuInflater().inflate(2131623938, paramMenu);
    return true;
  }
  
  public boolean onOptionsItemSelected(MenuItem paramMenuItem) {
    Intent intent;
    int i = paramMenuItem.getItemId();
    if (i == 2131558557) {
      callPreferences();
      return true;
    } 
    if (i == 2131558558) {
      intent = new Intent(getBaseContext(), LoginActivity.class);
      intent.addFlags(67108864);
      startActivity(intent);
      return true;
    } 
    return super.onOptionsItemSelected((MenuItem)intent);
  }
  
  void showRootStatus() {
    boolean bool;
    if (doesSuperuserApkExist("/system/app/Superuser.apk") || doesSUexist()) {
      bool = true;
    } else {
      bool = false;
    } 
    if (bool == true) {
      this.root_status.setText("Rooted Device!!");
      return;
    } 
    this.root_status.setText("Device not Rooted!!");
  }
  
  protected void viewStatment() {
    Intent intent = new Intent(getApplicationContext(), ViewStatement.class);
    intent.putExtra("uname", this.uname);
    startActivity(intent);
  }
}

doeSUexist()는 su 프로세스가 존재하는지 확인하고,

doessuperuserapkexist()와 showrootstatus()는 superuser.apk 파일이 존재하는지 확인.

 

if문을 보면 /system/app/ 의 위치에 superuser.apk 파일을 탐지해 루팅 여부를 파악하는 것을 알 수 있음.

 superuser.apk 파일과 su 파일이 있는지 확인하려면, 

 /system/app/Superuser.apk
 /system/xbin/which
 /system/bin/su

위와 같이 파일 리스트를 점검해야 함. 

 

/system 디렉터리에 존재하는 파일 수정하기 위해선 only-read 상태로 마운트되므로 시스템 파일을 수정할 수 없음.

따라서, 다시 마운트 해야 함(리마운트)

adb 쉘을 사용해 터미널에 접속하고 su 명령어로 관리자 권한을 상승 시킴.

그 후에 remount를 진행하면 마운트 상태에 w 권한을 추가해 파일 수정 가능!

 

권한을 획득한 디바이스에는 Superuser.apk 파일만 존재하는데, 이 파일 이름을 Superuser.apk1으로 변경

cd /system/app

mv Superuser.apk Superuser.apk1

ls -l Super*

 

su 실행 파일도 다른 이름으로 변경

cd /system/xbin

ls -l sx

루팅 체크 우회 후의 화면

 

 

 

< 대응 방안 >

1. 루팅된 디바이스로는 접근 할 수 없다는 경고 메시지를 띄우고 즉시 앱을 종료

     - 이때, 루팅을 방지하는 소스 코드 로직이 노출되지 않도록 해야 함

     - apk 파일을 디컴파일해 소스 코드를 열람하는데, 문자열 난독화까지 적용해 어떤 명령어와 

       루팅 파일을 검사하는지 모르게 해야 함.

2. apk 파일 조작해 루팅 유지하는 것을 방지하기 위해선 무결성 검증 필요

3. 디컴파일 방지 솔루션 적용

 

 

728x90
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함