본문 바로가기

4-2. 2024-1 심화 스터디/안드로이드 모의해킹

[3주차] 블레이드러너- 안드로이드 모의해킹

  • 강의 : 안드로이드 모바일 앱 모의해킹과 시큐어코딩
  • 3주차 활동 : 섹션 6. 인시큐어뱅크 각 취약점 진단 실습

1. 취약한 브로드캐스트 리시버 취약점

◆ 진단 방법

  1. AndroidMenifest.xml에 있는 <Receiver> 컴포넌트 점검
  2. Receiver 컴포넌트가 구현된 해당 클래스의 onReceiver() 메소드 기능 점검
  3. abd shell 
am broadcast -a theBroadcast -n com.android.insecurebackv2/.MyBroadCastReceiver

    4. abd로는 System Process로 인해 권한 검사 불가.

    5. 따라서 Drozer를 사용하여 진단.

run.app.package.attacksurface com.android.insecurebankv2
run.app.broadcast.info -a com.android.insecurebankv2

 

◆ 대응 방안

  • AndroidManifest.xml에 구현되어 있는 android.exported=”true” 속성을 “false”로 변경하여 외부 노출 금지
  • 반드시 필요하다면 permission 속성을 통한 권한으로 접근 제한

2. 안드로이드 백업 취약점

◆ 취약점 소개

  • AndroidManifest.xml 파일의 android:allowBackup 속성이 “true”로 설정되어 있는 경우 단말기 백업시 중요 정보 및 인증 정보 노출.
  • 사용자가 단말기를 잃어버린 경우 제 3자에 의해 이러한 백업 취약점을 이용해 단말기를 사용하던 사용자의 중요 및 민감정보가 제 3자에게 노출될 수 있음.

◆ 진단 방법

  • 안드로이드 단말기에서 비밀번호 입력없이 백업
adb backup -f <backup file name> <package name>
  • 출력된 데이터를 분석하여 중요정보/ 인증정보/ 민감정보 획득
java -jar ade.jar unpack <backup file name> <tar file name>

 

◆ 대응 방안

  • AndroidManifest.xml 파일의 android:allowBackup = “false”로 속성을 변경.

3. 로컬 암호화 이슈

◆ 취약점 소개

  • 중요 정보가 단말기에 저장될 때 암호화되어 있지 않는 취약점.
  • 애플리케이션 안에서 사용되는 중요한 정보는 암호화하여 저장해야 함. 이러한 정보들이 약한 암호화로 저장되거나 암호화가 되어있지 않고 평문으로 저장될 경우 여러가지 문제발생.
  • Insecurebackv2 앱에서 사용하는 여러 계정 정보는 암호화를 사용하지 않음. 이러한 정보들이 유출될 경우 사용자는 큰 피해를 받음.

진단 방법 

  1. 앱의 전반적인 기능들을 실행해보고 탐색
  2. DB 추출 후 중요정보 암호화 확인
  3. DB 외의 파일들에서 중요정보 암호화 확인
  4. 클러이언트단 소스코드 점검 및 암호화 로직 점검
adb pull adb pull/ data/ data/ com.android.insecurebankv2 .\

 

◆ 대응 방안

  • 중요 정보를 다루는 코드 검토
  • 중요 정보 암호화 할 수 있도록 코드 추가 및 수

4. 취약한 웹 뷰 구현

◆ 취약점 소개

  • 웹뷰상에 UI 또는 패킷에서 자바스크립트 코드가 강제적으로 실행되게 함으로써 다른 사용자의 중요정보를 탈취하는 취약점
  • 인시큐어뱅크에서는 자바스크립트 코드가 로컬에서만 실행되게 할 수 있지만 만약 다른 사용자에게 자바스크립트 코드를 보낼 수 있다면 다른 사용자의 중요정보를 탈취할 수 있는 취약점이 될 것.

◆ 진단 방법

  1. 앱 구동 후 웹뷰가 사용되거나 웹뷰과 연관이 있는 기능들을 검토.
  2. 웹 뷰가 사용되고 있는 코드들을 검토.
  3. <script>alert(”XSS”)</script>와 같은 자바스크립트를 실행할 수 있는 명령어들을 웹뷰와 연관되어 있는 UI에 대입.

◆ 대응 방안

  • 자바스크립트 코드를 실행하지 못하도록 필터링 하는 코드 추가.
  • 계좌가 숫자로 이루어져 있을 경우 숫자이외의 문자열을 사용하지 못하도록 조치.
  • Webview 설정 중 setJavaScriptEnabled 메소드를 “false”로 설정.

5. 취약한 SD카드 저장소

◆ 취약점 소개

  • 안드로이드는 내부 저장소와 외부 저장소로 나뉘며, SD카드는 외부 저장소로 모든 애플리케이션이 접근가능한 영역.
  • 이러한 SD 카드에 중요 정보가 다른 애플리케이션에 의해 노출될 수 있음.

◆ 진단 방법 

  1. AndroidManifest.xml 파일의 권한 중 WRITE_EXTERNAL_STORAGE 권한이 있는지 확인.
  2. 코드 분석을 통해 getExternalStorgeDirectory() 메소드가 사용되는지 확인, 그렇다면 어떤 정보들이 저장되는지 확인.
  3. 단말기를 통해 실제 어떤 정보들이 저장되어 있는지 SD 카드에서 확인.
  4. MODE_WORLD_READABLE 모드가 사용중인지 확인.

◆ 대응방안

  • 중요 정보 저장 시 외부 저장소가 아닌 내부 저장소에 저장하도록 코드를 변경.

→ 여기서 내부 저장소란 /data/data/package 디렉토리 내부를 뜻함.

  • 중요 정보는 반드시 암호화 될 수 있도록 조치.

6. 취약한 인증 메커니즘

◆ 취약점 소개

  • 애플리케이션 사용자의 약한 인증 관리로 침해되서는 안될 부분이 침해 되어 사용자에게 피해를 입히는 취약점
  • Insecurebackv2 앱의 Transfer 기능은 약한 사용자 인증으로 인해 From 값을 변조하여 다른 사람의 계좌에서 돈을 보낼 수 있는 취약점이 존재

◆ 진단 방법

  1. SQLiteBrowser를 활용하여 서버의 DB 점검
  2. Transfer 기능을 담당하는 컴포넌트의 소스코드 점검
  3. Insecurebackv2의 서버인 app.py의 소스코드 점검

◆ 대응 방안

  • Insecurebankv2의 서버인 app.py에서 인증관련 코드 추가
  • 클라이언트에서는 인증 실패 시 fail 메세지가 나오도록 코드 수정

7. 사용자 계정 목록화

◆ 취약점 소개

  • 인시큐어뱅크에선 접속한 사용자의 아이디값이 노출되는 문제점 존재.
  • 아이디 노출 시 패스워드 무작위 대입 공격이나 사회적인 공격이 가능하므로 제3자에게 사용자들의 아이디값을 노출되는 것은 상당히 위험.

◆ 대응방안

  •  중요한 정보들은 반드시 암호화해서 저장, 외부에 노출되지 않도록 내부 저장소에 저장.

◆ 진단방법

  1. C드라이브에 test 폴더 생성 후 진행
  2. 안드로이드의 인시큐어 뱅크 앱에서 사용되는 내부 저장소 데이터를 모두 가져온다.
C:\test>adb pull /data/data/com.android.insecurebankv2 .\

  3. C:\test\databases에  담겨있는 mydb 파일을 DB Browser for SQLite로 열어본다.

      □사용자 로그인 내역: Browse Data > Table > names 에 담겨있는 id 및 name

          → 취약점: 위 부분 노출 시, 사용자 이름 노출.

              대응방안: 위 부분 암호화.

private void trackUserLogins() {
	//TODO Auto-generated method stub
	runOnUiThread() → {
		try{
			CryptoClass cryptoClass = new CryptoClass();
			username = cryptoClass.aesEncryptedString(username);
			//또는 String encUsername = cryptoClass.aesEncryptedString(username); ... values.put(TrackUserContentProvider.name, encUsername);
			
			//TODO Auto-generated method stub
			ContentValues values = new ContentValues();
			values.put(TrackUserContentProvider.name, username);
			//inserts content into the Content Provider to track the logged in user's list
			Uri uri = getContentResolver().insert(TrackUserContentProvider.CONTENT_UTI, values);
		} catch(IOException ex) {
			ex.printStackTrace();
		}
	});
}

         @LoginActivity.java 

username이 aes암호화 적용 후, put 메소드 입력값으로 들어가, ContentProvider에서 DB에 값 추가됨. 

8. 취약한 액티비티 컴포넌트 

◆ 액티비티란?

E.g. 로그인 화면 → [로그인 후] → 메인메뉴 → [재생] → 음악듣기
즉, 사용자에게 정보를 보여주거나 데이터를 입력 받는 등의 기능을 제공하기 위해서 사용자와 상호작용 하는 것

 

◆ 취약점 소개

E.g. 로그인 화면 → 메인메뉴 → [로그인 없이 바로 실행] → 음악듣기

 

◆ 대응 방안

  • AndroidMaifest.xml에 구현되어 있는 android:exported=”true” 속성을 ‘false’로 변경하여 외부노출 금지
  • 반드시 필요하다면 Permission 속성을 통한 권한으로 접근제어
  • 사용자 인증 절차 추가
<manifest>
	<application>
	
		... 중략 ...
		
		<receiver>
			android:name=".MyBroadCastReceiver"
			android:exported="true"
			android:permission="my.app.PERMISSION"
			<intent-filter>
				<action android:name="theBroadecast">
				</action>
			</intent-filter>
		</receiver>
		
		<activity>
			android:name=".ChangePassword"
			android:exported="false"
			android:permission="ChangePassword"
		</activity>
	</application>
</manifest>

@manifests

◆ 진단 방법

  • AndroidManifest.xml에 있는 <Activity> 컴포넌트 점검
  • Activity 컴포넌트가 구현된 해당 클래스의 onCreate() 메소드부터 전체 코드 점검
C:\test>adb shell → am start -n com.android.insecurebankv2/.ChangePassword 
//-n 옵션 "패키지명"/."노출된 액티비티의 컴포넌트명"

	Starting: Intent < cmp=com.android.insecurebankv2/.ChangePassword > 
	//BroadCast가 동일하기에 activity의 "	android:exported="true"로 설정이 되어있으므로 내부 노출이 된다
<manifest>
	<application>
	
		... 중략 ...
		
		<receiver>
			android:name=".MyBroadCastReceiver"
			android:exported="true"
			android:permission="my.app.PERMISSION"
			<intent-filter>
				<action android:name="theBroadecast">
				</action>
			</intent-filter>
		</receiver>
		
		<activity>
			android:name=".ChangePassword"
			android:exported="true"
			android:permission="ChangePassword"
		</activity>
	</application>
</manifest>

@manifests


  • adb로는 무조건 실행되므로 권한 검사를 할 수 없기 때문에 Drozer를 사용하여 진단한다.
dz> run app.package.attacksurface com.android.insecurebankv2
dz> run app.activity.info -a com.android.insecurebankv2
//노출된 컴포넌트들이 출력된다
dz> run app.activity.start --component com.android.insecurebankv2 com.android.insecurebankv2.ChangePassword
//run app.activity.start를 통해 액티비티를 실행한다
dz> run app.activity.start --component com.android.insecurebankv2 com.android.insecurebankv2.ChangePassword --extra string uname jack
//이때, Activity를 호출하는 경우 name 부분이 비어있으면 password를 입력해도 Activity가 실행되지 않는다.
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	set ContentView(R.layout.motivity_change_password);
	
	//Get Server details from Shared Preference file
	serverDetails = PreferenceManager.getDefaultSharedPreferences(this);
	serverip = serverDetails.getString("serverip", null);
	serverport = serverDetails.getString("serverport", null);
	
	changePassword_text = (EditText) findViewById(R.id.editText_newPassword);
	Intent intent = getIntent();
	uname = intent.getStringExtra("uname"); //Activity를 실행할 때 uname이 전달된다
	System.out.printIn("newpassword="+uname);
	textView_Username = (TextView) findViewById(R.id.textView_Username);
	textView_Username.setText(uname); //setText()로 문자열을 넣어준다
	
	//Manage the change password button click
	changePassword_button = (Button) findViewById(R.id.button_newPasswordSubmit);
	changePassword_button.setOnClickListener(new View.OnClickListener() {
		
		@Override
		public void onClick(View v) {
			//TODO Auto-generated method stub
			new RequestChangePasswordTask().execute(uname); //클래스 RequestChangePasswordTask()를 통해 서버로 데이터를 전송한다
		}
	});
}
class RequestChangePasswordTask extends AsyncTask < String, String, String > {

	@Overrid
	protected String doInBackground(String...parms) {
		try{
			postData(params[0]);
		} catch (InvaildKeyExeception | NoSuchAlgorithmException | NoSuchPaddingException | InvalidA...
			//TODO Auto-generated method stub
			e.printStackTrace();
		}
		return null;
}

@Changepassword.java

9. 하드코드 된 중요 정보

◆ 취약점 소개

  • 어떤 데이터가 코드 내에 그대로 입력된 것을 하드 코딩 되었다고 함.
  • 중요 정보가 소스코드에 그대로 노출되어 있다면 소스코드 노출 시 중요 정보가 그대로 제3자에게 노출될 가능성.
  • 개발 시 개발자가 편의를 위하여 입력받아야 할 정보를 소스코드 내에 바로 입력함으로써 실행 시 UI 상에서 입력하지 않고 바로 실행하도록 하는 것도 하드 코딩된 취약점 중 하나.
  • 인시큐어뱅크 앱에서는 총 3곳에서 하드코딩 된 취약점을 발견할 수 있음.

◆ 진단 방법

  • 코드 분석 시 암호화 클래스 부분을 상세 분석.
  • 중요 정보 문자열 검색을 통해 검토 및 조치. Find > Found Occurences: Jack의 비밀번호 “Jack@123$”을 검색
public class CryptoClass {
	//The super secret key used by the encryption function
	String key = "This is the super secret key 123"; //"This is the super secret key 123"가 암호화 키에 해당되며, 그대로 노출되어 있다.
	
	//The initialization vector used by the encryption function
	byte[] ivBytes = {
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	String plainText;
	byte[] cipherData;
	String base64Text;
	String cipherText;
	
	/*
	The function that handles the aes256 encryption
	ivBytes: Initialization vector used by the encryption function
	keyBytes: Key used as input by the encryption function
	textBytes: Plaintext input to the encryption function
	*/
	public static byte[] aes256encrypt(byte[] ivBytes, byte[] keyBytes[], byte[] textBytes[])
	throws UnsupportedEncodingException,
	NoSuchAlgorithmException,
	NoSuchPaddingException,
}

@CrytoClass.Java

10. 취약한 암호화 구현

◆ 취약점 소개

  • 중요한 데이터가 취약한 암호화 방식으로 저장되어 제3자가 암호화된 데이터를 문제없이 해독 가능한 취약점
  • E.g. 암호화된 데이터 → 데이터 유출 → 제3자에 의해 복호화 → 복호화된 데이터

◆ 대응 방안

  • 문제는 대칭키가 노출되는 것이 아닌 모든 단말기에 설치되는 어플리케이션의 대칭키가 같다는 것.
  • 다른 단말기에 설치된 어플리케이션의 대칭키가 같다면 데이터 유출 시 데이터 복호화가 가능.
  • 따라서, 단말기마다 고유의 대칭키를 갖도록 조치.
public class CryptoClass {

	//	The super secret key used by the encryption function
	//변경 전:   String key = "This is the super secret key 123";
	/*변경 후:*/ String key = "null";
	
	//	The initialization vector used by the encryption function
	byte[] ivBytes = {
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	String plainText;
	byte[] cipherData;
	String base64Text;
	String cipherText;
	
	//클래스 새로 정의
	public CryptoClass(Context ctx){
		TelephonyManager manager (TelephonyManager)ctx.getSystemService(Context.TELEPHONY_SERVICE);
		//어플리케이션 컨텍스트를 컨텍스트를 이용해서 가져온다
		
		key = manager.getDeviceId() + Build.DEVICE; 
		if (key.length() != 32){
			int i = 32 - key.length();
			for (; i!=0; i-=1) {
				key += "0";
			}
			Log.i("LOG",key);
		}
		//32자리로 키를 맞춰준다
	}
	
	/*
	...
	*/
	//이후 컨텍스트 내용을 모두 수정한다.
	//수정 전: CryptoClass crypt = newCryptoClass();
	//수정 후:// CryptoClass crypt = newCryptoClass(getApplicationContext());

◆ 진단 방법

  • 소스코드에서 초기화 벡터값 추출
  • 소스코드에서 대칭키 추출
  • 암호화 모드 확인: EBC / CBC / CFB / OFB
  • 암호화 비트 확인: 128 / 256
  • 코드에 인코딩이 되어있는 경우 인코딩 방식 확인
  • 암호화/복호화 툴 제작 또는 사이트에서 대칭 키로 암호화된 데이터 복호화
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name='superSecurePassword'>tyrof6jLedNWZw/e/a98EQ==
</string>
<string name='superSecurePassword'>Fupu7GCRhqWoxviAuixpMg==
</string>
</map>
//aesEncryptedString로 암호화된 데이터 예시 [E.g. tyrof6jLedNWZw/e/a98EQ==, Fupu7GCRhqWoxviAuixpMg==]

@mySharedPreferences.xml | 암호화된 데이터를 확인 가능

private void saveCreds(String username, String password) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
			// TODO Auto-generated method stub
			SharedPreferences mySharedPreferences;
			mySharedPreferences = getSharedPreferences(MYPREFS, Activity.MODE_PRIVATE);
			SharedPreferences.Editor editor = mySharedPreferences.edit();
			rememberme_username = username;
			rememberme_password = password;
			//String base64Username = new String(Base64.encodeToString(rememberme_username.getBytes(), 4));
			CryptoClass crypt = new CryptoClass();;
			//암호화 클래스를 사용한다.
			superSecurePassword = crypt.aesEncryptedString(rememberme_password);
			//aesEncryptedString를 통해 패스워드와 유저네임을 암호화한 후 저장한다
			editor.putString("EncryptedUsername", base64Username);
			editor.putString("superSecurePassword", superSecurePassword);
			editor.commit(); 
			//encrypt된 데이터를 저장한다
		}

@DoLogin.Java

- 탐색: keyBytes 중심으로
public static byte[] aes256encrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
	throws UnsupportedEncodingException, ... BadPaddingException {
		AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
		SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
		Cipher cipher = null;
		cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
		return cipher.doFinal(textBytes);
	}
	
- 소스코드에서 대칭 키 추출: byte[] keyBytes = key.getBytes("UTF-8");
public String aesEncryptedString(String theString) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
		// TODO Auto-generated method stub
		byte[] keyBytes = key.getBytes("UTF-8");
		//UTF-8로 된 Byte로 인코딩
		plainText = theString;
		cipherData = CryptoClass.aes256encrypt(ivBytes, keyBytes, plainText.getBytes("UTF-8"));
		cipherText = Base64.encodeToString(cipherData, Base64.DEFAULT);
		return cipherText;
	}

- 소스코드에서 초기화 벡터값 추출: byte[] ivBytes = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
public class CryptoClass {

	//	The super secret key used by the encryption function
	String key = "This is the super secret key 123";

	//	The initialization vector used by the encryption function
	byte[] ivBytes = {
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	String plainText;
	byte[] cipherData;
	String base64Text;
	String cipherText;

- 암호화 모드 확인: cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
public static byte[] aes256encrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
	throws UnsupportedEncodingException, ... BadPaddingException {
		AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
		SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
		Cipher cipher = null;
		cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
		return cipher.doFinal(textBytes);
	}
	
- 암호화 비트 확인: 256
public class CryptoClass {
	//	The super secret key used by the encryption function
	String key = "This is the super secret key 123";
	//32자리 = 256bit

- 코드에 인코딩이 되어있는 경우 인코딩 방식 확인: 
public String aesEncryptedString(String theString) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
		// TODO Auto-generated method stub
		byte[] keyBytes = key.getBytes("UTF-8");
		plainText = theString;
		cipherData = CryptoClass.aes256encrypt(ivBytes, keyBytes, plainText.getBytes("UTF-8"));
		//cipherData는 전송할때 바이너리 형식이므로 데이터 전송 시 문제 발생 가능하다
		cipherText = Base64.encodeToString(cipherData, Base64.DEFAULT);
		//이에 cipherText 변수에 Base64 인코딩을 시도한다 
		return cipherText;
	}
=> [E.g. tyrof6jLedNWZw/e/a98EQ==, Fupu7GCRhqWoxviAuixpMg==]는 Base64 인코딩된 문장

- 암호화/복호화 툴 제작 또는 사이트에서 대칭 키로 암호화된 데이터 복호화:

@CryptoClass.java | 암호화 클래스

11. (보충) Transfer 버그픽스 수정

1. Username에 옳지 않은 값이 출력되는 상황
			HttpPost httppost = new HttpPost(protocol + serverip + ":" + serverport + "/getaccounts");
			SharedPreferences settings = getSharedPreferences(MYPREFS2, 0);
			final String username = settings.getString("EncryptedUsername", null);
			
			/*버그 픽스 시작*/
			
			CryptoClass crypt = new CryptoClass(getApplicationContext());
			try{
				usernameBase64ByteString = crypt.aesDecryptedString(username);
			} catch(Exception ex){
				ex.printStackTrace();
			}
			
			//주석 처리
			/*byte[] usernameBase64Byte = Base64.decode(username, Base64.DEFAULT);

			try {
				usernameBase64ByteString = new String(usernameBase64Byte, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}*/
			
			/*버그 픽스 끝*/

			final String password = settings.getString("superSecurePassword", null);
			try {
				//	Stores the decrypted form of the password from the locally stored shared preference file
				passNormalized = getNormalizedPassword(password);
			} catch (InvalidKeyException | UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
2. UserID, Username이 잘못된 형태로 전달이 되고 있는 상황
		@Override
		protected String doInBackground(String...params) {
			String str = "";
			str = "dinesh";
			HttpClient httpclient = new DefaultHttpClient();
			HttpPost httppost = new HttpPost(protocol + serverip + ":" + serverport + "/dotransfer");
			SharedPreferences settings = getSharedPreferences(MYPREFS2, 0);
			final String username = settings.getString("EncryptedUsername", null);
			
			/*버그 픽스 시작*/
			
			CryptoClass crypt = new CryptoClass(getApplicationContext());
			try{
				usernameBase64ByteString = crypt.aesDecryptedString(username);
			} catch(Exception ex){
				ex.printStackTrace();
			}
			
			//주석 처리
			/*byte[] usernameBase64Byte = Base64.decode(username, Base64.DEFAULT);
			try {
				usernameBase64ByteString = new String(usernameBase64Byte, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}*/
			
			/*버그 픽스 끝*/
			
			final String password = settings.getString("superSecurePassword", null);
			try {
				//	Stores the decrypted form of the password from the locally stored shared preference file
				passNormalized = getNormalizedPassword(password);
			} catch (InvalidKeyException | UnsupportedEncodingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

@DoTransfer.java

12. 취약한 로깅 메커니즘

◆ 취약점 소개

  • 로그(Log)는 프로그램 구동 시 프로그램의 현재 상태, 처리하는 데이터 정보 의미.
  • 로그를 통해 관리자나 개발자는 중요한 정보를 제공받을 수 있으며, 특히 프로그램에 버그(취약점)가 있을 때 이를 유지보수 하는데 사용할 수 있음.
  • 취약한 로깅 메커니즘은 이러한 로그에 노출되어서는 안되는 중요한 데이터 또는 민감한 데이터가 로그로 남기는 경우를 말함.

◆ 대응 방안

  • 앱 배포 시 사용되는 로그 관련 코드를 제거.
  • 로그를 출력하는 유틸리티 클래스를 제작.

◆ 진단 방법

  • 로그 수집기를 실행하고 앱의 여러가지 기능 사용
  • 로그 수집기에서 단어 검색을 통한 중요 데이터 또는 민감 데이터 검색
  • 안드로이드 스튜디오에서 제공하는 Logcat을 사용하여 진단
  • 소스코드에서 로그 관련 코드 상세 분석
  • 안드로이드 로그의 등급
    • V(Verbose): 중요하지 않은 정보
    • I(Info): 일반 정보
    • D(Debug): 디버그 정보
    • W(Warning): 광고 정보
    • E(Error): 에러 정보
    • F(Fatal): 중요한 정보
    • S(Slient): 가장 높은 우선 순위의 정보
1. Logfilter 실행
C:\android_edu\tools\android-logviewer>java -jar Logfilter_1.8.jar

2. 이후 cmd에서 PID 검색 후 Logfilter에서 PID 번호로 탐색
C:\...>adb shell ps
	USER   PID   PPID  USIZE  RSS   WCHAN    PC         NAME 	// 두번째 열이 PID값에 해당한다.
	root    1      0     292  208   c0099f1c 0000c410 S /init
	...
	u0_a46 15154 27986 166188 44052 ffffffff 40033a40 S com.android.insecurebankv2

3. AndroidStudio
3-1. 메소드 제작
//로그는 대체로 System.out이라는 메소드로 출력되므로 System.out.printIn을 탐색한다

@LogUtil.java
package com.android.insecurebankv2;
/*
	Created by Tester on 'YY/MM/DD'
*/
public class LogUtil {
	public static boolean isDebug = true;
	
	public static LogOut(String str){
		if(isDebug == true) {
		//모든 로그에서 isDebug라는 값으로 로깅 여부에 대해 체크 가능
			System.out.print(str); 
			//str로 인자를 넘겨서 로그를 출력한다
		}	
	}
	//로그 유틸리티 추가도 가능
	/*
	public static void LogD(String Str) {
		if(isDebug == true) {
			Log.d("TAG",str); 
		}	
	}
	public static void LogI(String Str) {
		if(isDebug == true) {
			Log.i("TAG",str); 
		}	
	}
	*/
}

3-2. 로그를 출력하는 메서드를 유틸리티 클래스로 변경
3-2-1. System.out.printIn를 검색 후 변경
@ChangePassowrd.java
//System.out.printIn 변경 
{
 ...
	if (TextUtils.isEmpty(phoneNumber.toString().trim())) {
		//System.out.printIn("Phone number invalid'); -> 해당 부분 주석 처리
		LogUtil.LogOut("Phone number invalid');
	}
	else {
		...
	}
	...
}
@DoTransfer.java
@LogUtil.java
@MyBroadCastReceiver.java
@ViewStatement.java
3-2-2. Log.를 검색 후 log.d, log.i로 출력하는 모든 문자 검색 후 변경
@CryptoClass.java
{
	...
	{
		...
		{
			...
			int i = 32 - key.length();
			for(; i != 0; i -= 1) {
				key += "0";
			}
		}
		//Log.i ; ("Log", key); -> 해당 부분 주석 처리
		LogUtil.LogOut(key);
	}
}
@DoLogin.java
{
	...
	{
		...
		{
			result = result.replace('\n', );
			if (result != null) {
				if (result.index0f("Correct Credentials") != -1) {
					//Log.d("Successful Login:", ", account=" + username + ":" + password);
					LogUtil.LogOut("Successful Login: , account=" + username + ":" + password);
					saveCreds(username, password);
					trackUserLogins();
					Intent pL = new Intent(getApplicationContext(), PostLogin.class);
					pL.putExtra("uname", username);
					...
				}
				...
			}
		}
	}
}

 

13. 안드로이드 페이스트보드 취약점

◆ 취약점 소개

  • 사용자의 중요한 데이터 (암호, 계좌번호 등)가 메모리에 노출되어 있는 취약점

◆ 대응 방안

  • 중요한 데이터는 가급적 복사하지 않고 직접 입력
  • 앱 UI 설계 시 중요한 데이터는 복사하지 못하도록 Password Text Edit View로 제작

◆ 진단 방법

  • 진단 대상 안드로이드 앱에서 취약하거나 또는 중요한 항목을 복사
  • 페이스트보드 검사
C:\...>adb shell su <user> service call clipboard 2 s16 com.android.insecurebankv2 
//<user>는 userid를 의미한다. 즉, adb shell ps 명령어를 통해 출력된 결과 중 USER 값읍 입력하면 된다.
//s16은 string으로 값을 불러오겠다는 것을 의미한다.

//노출된 계좌번호
Result: Parcel<
	0x00000000: 00000000 00000000 00000000 00000000 '/...........'
	0x00000010: 00000000 00000000 00000000 00000000 '/....t.e.x.t.'
	0x00000020: 00000000 00000000 00000000 00000000 '/.plain.....'
	0x00000030: 00000000 00000000 00000000 00000000 '/...........'
	0x00000040: 00000000 00000000 00000000 00000000 '/.9.9.9.9.9.'
	0x00000050: 00000000 00000000 00000000 00000000 '/9..........'
	0x00000060: 00000000                            '/...        '

14. 애플리케이션 패칭 취약점

◆ 취약점 소개

  • 클라이언트 어플리케이션 보안이 요구되는 현 시점에서 가장 문제가 많은 취약점 중 한가지
  • 안드로이드의 클라이언트 코드를 변경하여 비정상적인 작동을 유도하도록 APK 파일을 변조 및 수정 ⇒ 리패키징
  • 서버 인증이 아닌 클라이언트 단의 인증을 우회함으로써 여러가지 인증 절차를 무력화 시킬 수 있음

◆ 대응 방안

  • 배포용 APK 소스코드에 프로가드(Proguard)를 적용.  >build.gradle 파일에서 minifyEnable 속성 true 변경
  • 난독화 솔루션을 사용.
    • 에러기반 난독화: apkprotect
    • 코드 난독화: proguard
    • 멀티덱스 난독화: 외부 상용 솔루션
    • 문자열 난독화: 외부 상용 솔루션
  • 앱의 Signing 키 검증을 사용. 
keytool -list -printcert -jarfile apkfilename.apk
#프로가드 적용
buildTypes{
	release {
		 false true
		//minifyEnalbed true로 변경 후 sync now 실행 시, proguard가 적용된 APK 파일 빌드
		proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro...
	}
}
=> 이후 클래스, 변수, 메소드 이름 등이 변경된 것을 확인할 수 있다

@build.gradle

#에러기반 난독화 | apkprotect
-> dex2jar 도구 에러를 유발시켜 사용하지 못하게 하는 기능

1. app-release_apkcrypt.exe 실행
*THE APK: C:\android_edu\tools\Android-InsecureBankv2-master\InsecureBankv2\app\app-release.apk //app-release.apk의 경로
*NEW NAME: app-release_apkcrypt.exe

2. APK crypt된 파일을 dex2jar 도구를 이용해 byte 코드로 변환
C:\android_edu\tools\Android-InsecureBankv2-master\InsecureBankv2\app>dex2jar app-release_apkcrypt.apk
-> jd-gui 도구를 이용해 파일이 열리지 않는다는 것을 확인할 수 있음

@C:\android_edu\tools\APK Protect PC Edition v1.0\apkcrypt.exe

 

◆ 진단 방법

  • APK 파일에서 자바 코드 추출 ⇒ dex2jar, jd-gui 사용
  • 난독화 적용 여부 체크
    • 에러기반 난독화: apkprotect
    • 코드 난독화: proguard
    • 멀티덱스 난독화: 외부 상용 솔루션
    • 문자열 난독화: 외부 상용 솔루션
  • APK 파일에서 Smali 코드 추출 (자바 코드와 비교 분석)
Cf. Smali는 “java의 어셈블리화”로, 기계어와 명령어가 1대1로 대응하는 코드
  • Smali 코드 변조
  • APK 파일 리패키징 후 설치 및 테스트
#Smali 코드 추출
C:\\android_edu\\tools\\Android-InsecureBankv2-master\\InsecureBankv2\\app>apktool d app-release.apk
//-d 옵션: decompile(디컴파일)

#Java 코드 추출
C:\\android_edu\\tools\\Android-InsecureBankv2-master\\InsecureBankv2\\app>dex2jar app-release.apk

#Java 바이크 코드 Viewing
: jd-gui 도구 사용

#리패키징 및 테스트
: isDebug에 있는 값에서 false(0)를 true(1)로 변경 후 로그가 보이는 지 재확인
이후 C:\\android_edu\\tools\\Android-InsecureBankv2-master\\InsecureBankv2\\app>apktool d app-release

#Java 바이트 코드로 변환
C:\\android_edu\\tools\\Android-InsecureBankv2-master\\InsecureBankv2\\app\\app-release\\dist>dex2jar app-release.apk
이후 isDebug 속성이 true로 변경된 경우, 정상적으로 리패키징 완료

#Signing
C:\\android_edu\\tools\\Android-InsecureBankv2-master\\InsecureBankv2\\app\\app-release\\dist>C:\\android_edu\\tools\\signing\\signing.bat C:\\android_edu\\tools\\Android-InsecureBankv2-master\\InsecureBankv2\\app\\app-release\\dist\\app-release.apk
: 출력된 비밀번호가 123123이다.

#변조한 apk 파일 설치
C:\\android_edu\\tools\\Android-InsecureBankv2-master\\InsecureBankv2\\app\\app-release\\dist>adb install

 

15. (보충) 애플리케이션 패칭 응용 

멀티덱스 난독화

#소스코드 추출
1. C:\\android_edu\\malware>apktool d naver.apk
2. C:\\android_edu\\malware>dex2jar naver.apk
3. C:\\android_edu\\malware>adb install naver.apk
4. 이후 jd-gui.exe로 파일 열기
  • naver_dex2jar.jar | com\android\systemsetting\FtApp.class
    1. 아이콘이 사라지는 기능이 코드에 존재하지 않음.
    2. androidmainfest.xml에서 main activity(소스코드의 진입점)이 보이지 않음.
0. 설정에서 기기관리자 권한 해제
1. C:\android_edu\malware>adb uninstall com.android.expsetting
2. FtApp 클래스 내부에 delete가 들어간 부분 제거
3. C:\android_edu\malware>apktool b naver.apk
//Q. smali 코드에서 패칭을 시도하는 이유
//A. 자바 파일로 추출 시, 완전한 코드가 아니므로 컴파일 후 재빌드 시 Java 파일로 변환하면서 에러 발생 가능
4. C:\android_edu\malware>apktool b naver.apk
//복호화 파일이 생기는 경로: "/data/data/"+'package name'
5. 앱 실행 (실행해야 코드가 나타나고 앱이 지워지지 않는다)
6. C:\android_edu\malware>adb shell
	 root@android:/ #cd /data/data/com.android.expsetting
	 root@android:/data/data/com.android.expsetting # ls
	 ls
	 cache
	 database
	 lib
	 x
	 x.zip
	 root@android:/data/data/com.android.expsetting # adb pull /data/data/com.android.expsetting .\
	 //로컬 PC로 파일을 가져온다
7. C:\android_edu\malware\naver\dist>dex2jar classes.dex
//압축 해제한 class_dex2jar.jar 파일에서 찾지 못했던 코드들이 숨겨져 있는 것을 확인할 수 있다.

16. 개발자 백도어 취약점

◆ 취약점 소개

  • 개발 백도어란 개발 단계 시 개발자가 편의를 위해 개발자 자신만이 들어갈 수 있는 계정이나 인증 우회 방법.
  • 주로 개발 단계 시 사용하지만 잘못된 빌드 프로세스로 배포용 어플리케이션 또는 서버에 개발 백도어 코드가 삽입되면 보안에 중대한 취약점이 발생.

◆ 대응 방안

  • 배포용 어플리케이션 빌드 전 개발 백도어 코드 제거
  • 서버 애플리케이션 배포 전 개발 백도어 코드 제거

◆ 진단 방법

  • 클라이언트 부분에서 로그인 부분의 소스코드를 상세 분석
  • 서버 부분에서 로그인 처리 부분의 소스코드를 상세 분석
  • 코드 분석을 바탕으로 백도어 사용 후 검증
{
	...
	{
		...
		//하단 부분 주석 처리
		/* 
		if (username.equals("devadmin")) {
			httppost2.setEntity(new UrlEncodedFormEntity(nameValuePairs));
			//Execute HTTP Post Request
			responseBody = httpclient.execute(httppost2);
	} else {
	*/ 
		//하단 명령어는 정상적인 로그인 절차를 수행하는 코드
		httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
		//Execute HTTP Post Request
		responseBody = httpclient.execute(httppost);
	//}
	...
}

@DoLogin

'''
The function provides login methchanism to a developer user during development phase
'''
//하단 부분 주석처리
'''
@app.route('/devlogin', methods=['POST'])
def devlogin():
	user=request.form['username']
	Responsemsg="Correct Credentials"
	data = {"message" : Responsemsg, "user" : user}
	print makejson(data)
	return makejson(data)
'''

if __name__ == '__main__':
	port = DEFAULT_PORT_NO
	options, args = getopt.getopt(sys.argy[1:], "", "port=="])
	for op, argl in options:
	if op == "--help":
			usageguid()
			sys.exit(2)
		elif op == "--port":
			port = int(arg1)
	dispatch = wsgiserver.WSGIPathInfoDispatcher({'/': app})
	...

@Server의 app.py

17. 루트 노출 및 우회 취약점

◆ 취약점 소개

  • 루팅이란?
안드로이드는 보안 목적으로 기본적으로 루트 권한을 사용자가 획득할 수 없도록 막아둠.
사용자가 루트권한을 획득하는 것. 
  • 루팅된 단말기는 앱에서 허용하지 않은 동작 수행하므로 보안에 취약.
    그래서 앱에선 루팅 탐지 로직, 실행 차단 로직이 있으나, 해당 조치를 우회. 

 

◆ 진단 방법

  • 루팅 탐지 로직 - 해당 파일 존재여부 

/system/bin/su

/system/xbin/su

/sustem/app/superuser.apk  ; su 프로그램 다운로드 및 숨김 역할.

/data/data/com.noshufou.android.su 

 

-인시큐어뱅크의 경우

소스코드 .java 있다면) 프로그램 Anroid studio에서 "su", "superuser" 문자열 검색.

                                     PostLogin.class 파일 > doesSUexist() 메서드에서 su 파일,

                                                                        > doessuperuserapkexist() 메소드에서 superuser.apk 파일 존재 확인.  

public void ShowRootStatus() {
	if (doesSuperuserApkExist("/system/app/Superuser.apk") || doesSUexist() {
		this.root_status.setText("Rooted Device!");
 	} else {
    	this.root_status.setText("Device not Rooted!!");
    }
}

private boolean doesSUexist() {
	Process process = null;
    try{
    	process = Runtime.getRuntime().exec(new String[]{"/system/xbin/which","su"});
        if (new BufferedReader(new InputStreamReader(precess.getInputStream())).ReadLi
        	if (process != null) {
            	pricess.destrou();
            }

.apk만 있다면) dex2jar insecure.apk로 .java 파일 추출, 디컴파일 선행.

  • Tool

-Android Studio: 최근 안드로이드 개발 및 분석 시 사용.  

-Eclipse: 자바, 안드로이드 개발 및 분석에도 유용. 

               -app-release.apk AndroidManifest.xml res폴더만 남겨두고, DoLogin.java 분석.

               -분석시 유용한 기능.

  1. 문자열 검색 시, 하이라이팅. 더블클릭 시 동일 문자열 다음위치로 이동.
  2. F3 단축키, 메서드들 정의 위치 이동. Open Declaration
  3. Search > File Search > 'Super'(Ctrl+h) 모든 프로젝트 범위 대상으로 검색 가능              
  • 리패키징(문자열 삭제)으로 루트 탐지 로직 우회

insecurebankv2.apk 파일에서 smali 파일 추출.

프로그램 Notepadd++, insecurebankv2 smali폴더 postligin.java파일에서,

Superuser/su 문자열 난독화 예) abcSuper123456 

프로그램 삭제 후 재다운로드 결과, 루팅 탐지 실패결과 확인.

 

◆ 대응 방안

  • 루팅 탐지 시 앱 종료 코드 추가 - 실습 Only.
if(isrooted==true) 
android.os.Process.killProcess(android.os.Process.myPid()) // 조건문 아래 해당 명령문 추가!
  • 멀티 덱스 난독화 솔루션 사용 ( 리패키징할 Superuser/su 못 찾도록)
  • 문자열 기반 난독화 솔루션 사용

18. 파라미터 조작

◆ 취약점 소개

  • 클라이언트와 서버가 통신할 때 중간에 패킷을 가로채서 파라미터를 변조하는 취약점
  • 정상적인 요청 값을 공격자가 변조하여 정보 유출 등의 피해가 발생
  • 파라미터 조작을 통해 인증 우회도 가능

◆ 인시큐어뱅크 앱에서 실습

  • 인시큐어뱅크 로그인 후 비밀번호 변경 기능을 사용할 때 발생하는 취약점으로, 다른 사용자의 비밀번호 변경이 가능한 취약점
  • 실제 모의해킹에서 충분히 발생할 수 있는 취약점 중에 하나
  • 대량의 사용자 비밀번호 변경으로 개인정보 및 금융정보 등을 획득할 수 있는 크리티컬한 취약점

◆ 대응 방안

  • 파라미터 값을 암호화하여 조작 불가능하도록 해야 함
  • 세션 값 검증을 통해 다른 사용자 계정에 대한 조작이 불가능하도록 해야 함
  • 파라미터 조작을 통한 입력 값에 대한 유효성 검증은 서버에서 검증하도록 해야 함
  • 비밀번호 변경 기능을 사용할 때 아이디로만 인증하는 것이 아닌 이전 비밀번호도 포함하여 인증하도록 강화해야 함 
  • 비밀번호 변경 시 통신은 HTTP가 아닌 HTTPS로 통신하도록 암호화 적용이 필수

19. (보충) 파라미터 조작

◆ 취약점 소개

  • Password 틀려도 인증을 우회하는 방법 > 프로그램 Reply 공격 "Wrong Password" String 변경

◆ 대응 방안

  • Reponse 속 ["message": "Correct Credentials", "user": "dinest"} 메세지 전체 암호화 소스코드 변경

20. 취약한 비밀번호 변경 로직

◆ 취약점 소개

  • 인시큐어뱅크 앱의 비밀번호 변경 기능 사용 시 취약한 인증으로 인해 제3자가 비밀번호 변경이 가능한 취약점. (취약한 액티비티에서 다룸)
  • 실제 배포되는 앱에 해당 취약점이 있다면 제3자가 대량의 사용자 비밀번호 변경을 통해 중요정보 및 민감정보를 획득할 수 있는 중대한 취약점. 

◆ 진단 방법

  1. 패킷 캡처하는 환경 세팅
  2. 앱 구동 후 주요 기능 확인.
    • 비밀번호 변경 기능
    • 사용자 정보 변경 가능
    • 문자 인증 기능
  3. 캡처된 패킷의 인증정보 및 세션 등 검토
  4. (선택, 모의해킹) 파라미터 변조 / 재생공격 등을 통해 캡처된 패킷에 대한 인증 및 세션 검토.

◆ 대응 방안

  • 중요정보 및 민감정보를 얻어낼 수 있는 주요기능에 대한 인증 강화.
  • 인시큐어뱅크에 구현된 비밀번호 변경은 사용자의 아이디만을 통해 인증하므로 변경 전 비밀번호를 입력하게 하여 인증을 강화한다.  (실습)
  • 비밀번호는 중요데이터에 속하므로 전송 시 평문이 아닌 반드시 암호화를 적용하여 전송. (실습)
# InsecureBankv2\app\src\main\java\com\android\Insecurebankv2\ChangePassword
# 144번째 줄

CryptoClass cryptoClass = new CryptoClass(getApplicationContext());
String currentPassword = currentPassword_text.getText().toString();
String changePassword = changePassword_text.get

21. 중요 정보 메모리 노출 취약점

◆ 취약점 소개

  • 앱에서 사용하는 중요한 정보들은 암호화 적용, 메모리로 올라오면 평문으로 노출되는 취약점
  • 중요한 정보가 암호화되어 있더라도 메모리에 올라가면서 복호화되는 점을 이용.

◆ 진단 방법

  • 프로그램 Android Studio > Tool > Android > Android Device Moniter 실행 

   *안드로이드 스튜디오3.1에서 지원중단, 안드로이드 스튜디오3.2에서 삭제

  • 진단 대상 앱 설치 후 중요정보 사용하는 기능 실행
  • 앱의 프로세스를 Android Device Moniter 툴로 Heap 메모리 덤프
  • 메모리 덤프 결과 분

◆ 대응 방안

  • 메모리 (변수)에 중요정보를 저장할 때는 반드시 암호화해서 저장 조치.
  • AndroidManifest.xml 파일에 있는 android:debugable 속성 "false"로 지정.

22. 애플리케이션 디버깅 취약점 & 런타임 조작

◆ 취약점 소개

◆ 진단 방법

◆ 대응 방안

23. 취약한 HTTP 전송

◆ 취약점 소개

  • 본래 HTTP는 보안을 고려햐어 설계되지 않은 프로토콜로 보안에 대한 결함이 존재
  • 같은 네트워크 상에서 제 3자에 의해 스니핑 당할 경우 암호화되지 않은 HTTP의 데이터는 평문 그대로 노출될 수 밖에 없음

◆ 진단 방법

  • 웹 프록시 구동 후 단말기에서 패킷을 받아올 수 있는 환경을 구성
  • 어플리케이션 구동 후 주요 기능 사용
  • 통신 구간 중 중요 정보 및 세션 정보가 사용되는 통신 구간에서 HTTPS가 사용되는지 확인

◆ 대응 방안

  • 중요한 정보가 HTTP 패킷에 포함되어 잇을 경우 암호화하도록 함
  • 세션과 같이 HTTP 자체에 암호화를 사용해야 하는 경우 반드시 SSL 통신을 하도록 함

24. 중복 로그인

◆ 취약점 소개

  • 서로 다른 단말기에서 중복으로 로그인을 할 수 있는 기능
  • 중복 로그인은 상황에 따라 취약점으로 분류(e.g.필요하지 않은 기능이라면)
  • 악의적인 사용자가 다른 사용자의 계정을 사용할 수 있으며, 노출된 계정에 대해 계속 무방비 상태로 방치

◆ 대응 방안

  • 중복 로그인이 되지 않도록 서버에서 세션관리를 진행함
  • 중복 로그인이 발생되었을 경우 사용자에게로 SMS 또는 메일과 같은 알림 수단으로 알리도록 함

25. 취약한 컨텐트 프로바이더 

◆ 취약점 소개

  • 안드로이드에는 총 4종류의 컴포넌트 존재
    • Activity
    • Service
    • Broadcast Receiver
    • Content Provider
  • 컨텐트 프로바이더는 현재 어플리케이션이 가진 데이터를 외부의 어플리케이션에 제공해주는 역할을 함
  • 예)페이스북이 주소록의 컨텐트 프로바이더를 사용하여 친구를 추천하는 기능을 제공함.
  • 취약한 컨텐트 프로바이더는 잘못된 접근권한으로 외부의 다른 어플리케이션이 내부의 주한 데이터에 엑세스할 수 있는 취약점

◆ 진단 방법

  • AndroidManifest.xml 파일에서 <provider>태그의 속성 중 android:exported 속성이 “true”로 되어있는지 확인
  • drozer을 사용하여 진단
# 명령을 이용하여 노출된 content provider 항목 수 확인
run.app.pachage.attacksurface com.android.insecurebankv2 

# 노출된 프로바이더의 정보를 확인
run [app.provider.info](http://app.provider.info) -a com.android.insecurebankv2`

# 접근 가능한 URI를 확인
run.scanner.provider.finduris -a com.android.insecurebankv2

       

◆ 대응 방안

  • AndroidManifest.xml 파일에서 <provider> 태그의 android:exported 속성을 “false”로 설정
  • 외부와의 데이터 교환이 필요할 경우, Permission 속성을 통한 권한으로 접근제한

26. 안드로이드 키보드 캐시 취약점

◆ 취약점 소개

  • 안드로이드에서 과거에 입력되었던 정보를 유추할 수 있는 취약점
  • 사용자가 중요정보를 클립보드에 저장하면 이러한 정보를 획득할 수 있는 취약점

◆ 진단 방법

  • 진단 대상이 되는 앱 실행 후 중요정보를 복사할 수 있는 기능이 있는지 확인
  • org.rojekti.clipper와 같은 클립보드에 접근할 수 있는 앱을 설치한 후 중요정보 복사시 중요정보가 노출되는지 확인

마스킹 처리가 된 비밀번호의 경우

클립보드에 복사 안 됨.

◆ 대응 방안
  • EditText 뷰의 값을 복사, 붙여넣기 할 수 없도록 android:editable 속성에 false 값을 줌
  • 중요한 값은 반드시 마스킹 처리