취약점 개요
모바일 앱에서 중요하게 취급한 정보(아이디, 비밀번호, 계좌 번호, 카드 번호 등)는 강력한 암호화 알고리즘을 사용하여 저장해야 한다.
중요 정보가 안전하지 않은 저장 장치에 저장하거나 단말기 내의 평문으로 저장하게 되면 제 3자에게 중요 정보가 유출될 수 있다.
안전한 암호화 알고리즘을 사용하여 저장하면 중요 정보가 유출되더라도 중요 정보를 해독하는데 시간이 상당히 오래 걸리게 된다.
중요한 정보를 암호화를 하지 않거나 취약한 암호화 알고리즘으로 저장할 경우 중요 정보가 유출되어 더 큰 피해가 생길 수 있다.
취약점 진단
사용자가 모바일 앱에 로그인을 하고 재실행을 하여 하단의 Autofill Credentials 버튼을 클릭하면 아이디와 비밀번호를 자동으로 입력해준다.
Autofill Credentials은 최근에 로그인을 한 사용자의 아이디와 비밀번호를 모바일 단말기 내부 저장소에 저장을 한다. 저장된 정보를 파싱에서 모바일 화면에 자동으로 입력한다.
모바일 앱을 실행 시 매번 사용자가 아이디와 비밀번호를 여간 귀찮은 일이 아니다.
이런 편의성을 제공하려고 자동 로그인 기능이 있는데, 자동 로그인 박스에 체크를 하고 로그인을 하면 단말기 내부에 저장된 계정 정보를 파싱해서 자동으로 로그인을 한다.
모바일 단말기의 /data/data/ 디렉토리는 앱 실행 시 필요한 정보를 저장하고 있는 위치이다. 모바일 단말기에 설치된 앱은 해당 디렉토리의 패키지명 형태로 저장하고 있다. 해당 패키지명으로 검색하여 모든 데이터를 로컬 PC로 복사한다.
로컬 PC에 복사한 경로로 이동 shared_prefs 디렉토리 내의 mySharedPreferences.xml 파일을 열어 보면 아이디와 비밀번호가 암호화 되어 저장되어 있다.
SharedPreferences는 안드로이드 앱에서 간단한 정보를 저장할 때 사용하는 파일이다. 이 파일은 xml 형태로 데이터를 저장하며 모바일 앱이 삭제되기 전까지 정보를 저장한다. 일부 모바일 앱의 경우 해당 파일을 이용하지 않는 경우도 있다.
암호화된 정보를 보면 아이디는 Base64 인코딩되어 저장되어 있다. 하지만, 비밀번호는 Base64로 인코딩되어 있지 않고 다른 암호화 알고리즘을 사용해 암호화되어 있다.
온라인 디코딩(복호화) 서비스를 이용해 아이디를 Base64 디코딩을 해보면 평문의 값을 확인할 수 있다. 하지만, 비밀번호는 암호화되어 있어 디코딩이 되지 않는다.
자동으로 아이디와 비밀번호를 입력해주는 Autofill Credentials의 코드를 찾아서 분석하면 어떤 로직으로 암호화 및 복호화하는지 알 수 있다.
LoginActivity 클래스내의 fillData()를 보면 mySharedPreferences.xml를 settings 변수에 저장 한다. xml 파일에 저장된 EncryptedUsername, superSecurePassword의 값을 각 username, password 변수에 저장한다.
즉, username에 amFjaw== 문자열이 저장되고, password에 'v/sJpihDCo2ckDmLW5Uwiw== 문자열이 저장된다.
모바일 앱에서 Autofill Credentials 버튼을 클릭하면 아이디를 Base64 디코딩, 비밀번호를 AES 복호화하여 입력 폼에 자동으로 입력한다.
○ 116행 : Base64 인코딩된 아이디를 Base64 디코딩
○ 118행 : Base64 디코딩된 아이디를 UTF-8로 변환
○ 125행 : 변환된 아이디를 아이디 입력폼에 자동으로 입력
○ 126행 : 암호화 클래스 객채 생성
○ 127행 : AES 암호화된 비밀번호를 AES 복호화
○ 128행 : AES 복호화된 비밀번호를 비밀번호 입력폼에 자동으로 입력
대응 방안 및 검증
로컬 암호화 취약점은 아이디를 Base64 인코딩하여 저장했으므로 취약점이 발생한다. 사용자가 입력한 중요 정보는 암호화 클래스에서 암호화하도록 처리하고, 암호화 된 중요 정보는 공유 설정 디렉토리에 저장하면 중요 정보가 유출되더라도 쉽게 복호화가 되지 않는다.
로컬 암호화 취약점 |
아이디를 비밀번호와 동일하게 AES+Base64 암호화하여 저장 |
SharedPreferences mySharedPreferences;
mySharedPreferences = getSharedPreferences(MYPRESS, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = mySharedPreferences.edit();
// 암호화 클래스 호출
CryptoClass crypt = new CryptoClass();
// 아이디 및 비밀번호를 암호화
SecureUsername = crypt.aesEncryptedString(username);
SecurePassword = crypt.aesEncryptedString(password);
// 암호화 된 계정을 SharedPreferences에 저장
editor.putString("EncUsername", SecureUsername);
editor.putString("EncPassword", SecurePassword);
▶ 안드로이드 컴포넌트 취약점 (Android Activity)
▶ 안드로이드 컴포넌트 취약점 (Android Broadcast Receiver)
▶ 안드로이드 컴포넌트 취약점 (Android Content Provider)