3. 로컬 암호화 이슈(Local Encryption Issue)
[개요]
로컬 암호화 이슈란 디바이스에 저장된 데이터가 적절히 암호화되지 않아 발생하는 보안 문제로 주요 이슈는 다음과 같습니다.
- 취약한 암호화 알고리즘: 강력하지 않은 암호화 알고리즘 사용 시 공격자가 쉽게 데이터를 해독할 수 있습니다.
- 암호화 키 관리 문제: 암호화 키가 안전하게 저장되지 않거나 쉽게 추측 가능한 경우, 암호화의 효과가 무력화될 수 있습니다.
- 부분적 암호화: 데이터의 일부분만 암호화되거나, 중요하지 않은 데이터만 암호화되어 민감한 정보가 노출될 위험이 있습니다.
- 디폴트 설정 사용: 개발 시 암호화 관련 기본 설정을 변경하지 않으면 보안 취약점이 발생할 수 있습니다.
[진단 과정]
1) 인시큐어뱅크 앱 첫 로그인 화면에서 'Autofill Credentials' 버튼 클릭 시 마지막으로 로그인 한 아이디와 패스워드를 자동으로 불러옵니다. 이것을 보아 해당 정보(ID/PW)가 어딘가에 저장되어 있어 버튼 클릭 시 불러옴을 추측할 수 있습니다. jadx를 통해 해당 액티비티 내 소스코드를 분석해 보겠습니다.
2) 아래 코드는 메인 액티비티인 LoginAcitivity 내 fillData() 메서드로 표시된 부분을 보면 특정 이름(mySharedPreferences)을 가진 SharedPreferences 객체를 가져옵니다. 또한 해당 객체를 통해 저장된 문자열 값을 가져오는데 즉 저장된 id/pw 값을 불러오는 기능을 합니다. 검색 기능을 통해 mySharedPreferences가 사용된 곳을 확인해 보겠습니다.
3) 아래 코드는 Dologin 액티비티 내 postData 메서드로 해당 메서드는 사용자가 입력한 아이디와 비밀번호를 서버에 전송하는 HTTP POST 요청을 보냅니다. 로그인에 성공할 경우 saveCreds 메서드를 호출합니다.
4) saveCreds 메서드가 호출되면 사용자의 아이디와 비밀번호를 SharedPreferences에 저장합니다. 이때 아이디는 Base64로 인코딩 되고 비밀번호는 CryptoClass를 통해 AES 암호화된 후 저장되는데 이것은 나중에 알아보겠습니다.
어찌 됐든 우리는 로그인 시 계정 정보는 SharedPreferences에 저장되는 것을 알아냈습니다.
5) SharedPreferences는 앱 내 간단한 데이터를 영구적으로 저장하기 위한 클래스로 키-값 쌍으로 데이터를 저장합니다. 저장된 아이디와 비밀번호 정보를 찾기 위하여 해당 데이터가 저장된 위치로 이동합니다.(/data/data/com.android.insecurebankv2/shared_prefs/) 해당 디렉터리로 이동 시 아래 파일들을 확인할 수 있습니다.
6) mySharedPreferences.xml 파일에는 EncryptedUsername, superSecurePassword값이 출력되는데 바로 확인할 수는 없지만 각각 아이디값과 패스워드 값으로 추측됩니다. 하지만 우리는 4번 과정을 통해 각각 어떤 방식으로 암호화되어 있는지 확인하였기 때문에 먼저 Username 값을 base64를 통해 디코딩해보도록 하겠습니다. 디코딩 시 해당 값은 jack으로 아이디 정보가 맞음을 확인하였습니다. 하지만 'password'는 AES 방식으로 암호화되므로, 복호화를 위해 추가적인 키가 필요합니다.
7) 다시 한번 saveCreds 메서드를 확인해 보겠습니다. 중요한 부분은 아래 체크한 부분인데 Cryptoclass라는 클래스의 crypt 객체를 생성한 후 해당 클래스의 aesEncryptedString 메서드를 사용하여 저장된 비밀번호를 AES 암호화 알고리즘으로 암호화한 후 그 결과는 superSecurePassword 변수에 저장하고 역할을 합니다.
8) CryptoClass 클래스를 확인 시 AES 암호화에 사용된 키 값과 초기화벡터(ivBytes)를 확인하였습니다.
9) 암호화/복호화 과정에서, 로그인 시 사용자가 입력한 비밀번호는 aseEncryptesString 함수의 인자로 전달됩니다. 이전에 확인한 대칭 키 값을 가져와 keyByte 배열 변수에 저장한 후, aes256encrypt 함수로 암호화됩니다.
10) 복호화를 위해 필요한 정보는 모두 획득했으니 복호화를 해보도록 하겠습니다. 'superSecurePassword' 값인 'LYX/KNtnovFTdopR0LSPqw==' 값을 넣고 상기 과정에서 확인한 정보들을 통해 AES 복호화를 진행 시 'Jack@123$' 라는 값을 획득했습니다.
아이디의 경우 base64라는 방식을 사용하여 쉽게 해독할 수 있었고 패스워드의 경우 암호화 키가 쉽게 노출이 되어 있어 복호화가 가능하여 쉽게 계정 정보를 확인할 수 있었습니다.
[대응 방안]
o 안전한 키관리
- 하드코딩된 키 사용을 지양하고, Android Keystore와 같은 안전한 저장소를 사용하여 암호화 키를 관리합니다.
o 암호화 알고리즘 강화
- AES-256과 같은 강력한 암호화 알고리즘을 사용하고, 암호화 키는 정기적으로 변경합니다.