꿈을꾸는 파랑새

오늘은 지난 시간에 국민건강보험 공단 피싱 사이트 스미싱 사이트 nhtagse(.)store 에서 다운로드 된 악성코드를 분석해 보겠습니다.
일단 해당 악성코드는 지난 시간에 피싱 을 분석을 했을 때 최종적으로 다운로드 된 악성코드입니다.
해당 악성코드는 일단 기본적으로 피싱 사이트에서 자신이 입력한 전화번호로 다운로드가 되면 악성코드를 다운로드를 하고 설치하고 나서 실행을 하면 이제 본격적으로 해당 악성코드는 작동합니다.
먼저 해당 악성코드 해쉬값은 다음과 같습니다.
파일명:01023456789.apk
사이즈:3.36 MB
CRC32:8a362df5
MD5:08681e3f16625260bc5a951f10616484
SHA-1:a868c62c36c62ca6fd0d7deefd2e399d56d5cf19
SHA-256:03cb243bffa4546c8a04f9f9ca4128d81415d9636f58e32bde54f81bfbda9ebb
앱 이름:인터넷
패키지 이름: com.samsung.hway platform:android
인 것을 확인할 수가 있습니다.

국민건강보험 악성코드 실행
국민건강보험 악성코드 실행

안드로이드 권한 및 설명

국민 건강 보험 안드로이드 악성코드 권한
국민 건강 보험 안드로이드 악성코드 권한

1.INTERNET (인터넷 권한:
권한 이름:android.permission.INTERNET
설명: 앱이 인터넷에 접근하고 네트워크를 통해 데이터를 송수신할 수 있도록 허용합니다. 해당 권한은 온라인 서비스와 통신하는 데 필요
2.READ_SMS (SMS 읽기 권한):
권한 이름: android.permission.READ_SMS
설명: 앱이 SMS 메시지를 읽을 수 있도록 허용합니다. 해당 권한은 메시지 관련 작업을 수행하는 앱에서 필요
3READ_PHONE_STATE (전화 상태 읽기 권한):
권한 이름:android.permission.READ_PHONE_STATE
설명:앱이 디바이스의 전화 상태 및 정보를 읽을 수 있도록 허용합니다. 해당 권한은 전화 관련 정보를 수집하는 앱에서 필요
4. RECEIVE_BOOT_COMPLETED (부팅 완료 시 실행 권한):
권한 이름:android.permission.RECEIVE_BOOT_COMPLETED
설명: 앱이 디바이스가 부팅을 완료하고 실행될 수 있도록 허용합니다. 해당 권한은 부팅 후 자동으로 실행되어야 하는 서비스나 리시버를 위해 사용
5.FOREGROUND_SERVICE (포그라운드 서비스 실행 권한):
권한 이름:android.permission.FOREGROUND_SERVICE
설명: 앱이 포그라운드 서비스를 실행하고 백그라운드에서 실행 중인 서비스를 포그라운드로 이동할 수 있도록 허용합니다. 이 권한은 백그라운드에서 계속 실행되어야 하는 서비스를 유지하는 데 필요합니다.
6. REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (배터리 최적화 무시 권한):
권한 이름: android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
설명: 앱이 배터리 최적화를 무시하고 배터리 소모를 제어할 수 있도록 허용 해당 권한은 배터리 최적화로 말미암아 백그라운드 작업이 중단되지 않도록 보장하는 데 필요할 수 있습니다.

안드로이드 디바이스 관련된 정보 코드 및 설명
com.samsung.hway.utils.DeviceUtil

안드로이드 디바이스 관련된 정보 코드 및 설명
안드로이드 디바이스 관련된 정보 코드 및 설명

* loaded from: classes.dex */
public class DeviceUtil {
    public static String getAndroidId(Context context) {
        try {
            return Settings.System.getString(context.getContentResolver(), "android_id");
        } catch (Exception unused) {
            return "";
        }
    }

    public static String getIMEI(Context context) {
        try {
            return Build.VERSION.SDK_INT < 29 ? ((TelephonyManager)
            context.getSystemService("phone"))
            .getDeviceId() : "";
        } catch (SecurityException unused) {
            return "";
        }
    }

    public static String getSimSerialNumber(Context context) {
        try {
            return Build.VERSION.SDK_INT < 29 ? ((TelephonyManager)
            context.getSystemService("phone"))
            .getSimSerialNumber() : "";
        } catch (SecurityException unused) {
            return "";
        }
    }

    public static String getPhoneNumber(Context context) {
        try {
            return ((TelephonyManager) context.getSystemService("phone")).getLine1Number();
        } catch (SecurityException unused) {
            return "";
        }
    }

    public static String getTelecomName(Context context) {
        try {
            return ((TelephonyManager) context.getSystemService("phone"))
            .getNetworkOperatorName();
        } catch (SecurityException unused) {
            return "";
        }
    }

    public static String getTelecomCode(Context context) {
        try {
            return ((TelephonyManager) context.getSystemService("phone"))
            .getNetworkOperator();
        } catch (SecurityException unused) {
            return "";
        }
    }

    public static String getVersionName(Context context) {
        try {
            return context.getPackageManager().getPackageInfo(context.getPackageName(), 0)
            .versionName;
        } catch (Exception unused) {
            return "";
        }
    }
}

코드 설명

해당 코드는 안드로이드 스마트폰 장치와 관련된 정보를 가져오는 유틸리티 클래스인 DeviceUtil 을 정의
각 메서드는 다양한 장치 정보를 가져 옵니다. 여기서 각 메서드를 설명
1. getAndroidId(Context context):안드로이드 장치의 고유 식별자인 Android ID를 가져오는 메서드
2.getIMEI(Context context):장치의 IMEI (International Mobile Equipment Identity) 번호를 가져오는 메서드
안드로이드 10 (API 레벨 29) 이상의 버전에서는 보안 제한으로 말미암아 빈 문자열을 반환
3.getSimSerialNumber(Context context):유심(SIM 카드)의 일련번호 (Sim Serial Number)를 가져오는 메서드
안드로이드 10 이상에서는 보안 제한으로 말미암아 빈 문자열을 반환
4. getPhoneNumber(Context context):장치에 연결된 전화번호를 가져오는 메서드입니다. 해당 정보는 SIM 카드와 연결되어 있어야 하며 SIM 카드가 없거나 권한이 없으면 빈 문자열을 반환
5.getTelecomName(Context context): 재연결된 통신 사업자 (Telecom Operator)의 이름을 가져오는 메서드
6.getTelecomCode(Context context):현재 연결된 통신 사업자의 코드를 가져오는 메서드
7.getVersionName(Context context):앱의 버전 이름을 가져오는 메서드
모든 메서드는 예외 처리를 통해 장치 정보를 가져오려고 시도하고 보안 제한에 대비하여 예외를 처리
유심(SIM 카드) 정보를 읽어오는 이유
1. 사용자 식별 및 인증: 앱이 SIM 카드 정보를 사용하면 사용자를 고유하게 식별하고 인증할 수 있음
사용자의 휴대전화 번호와 IMEI 번호를 사용하여 사용자를 식별하는 방법으로 사용될 수 있음
2. 통신 서비스: SIM 카드 정보를 사용하면 앱이 사용자의 통신 서비스에 관한 정보를 확인할 수 있으며 해당 정보는 현재 연결된 통신 사업자, 네트워크 상태 등을 포함할 수 있습니다. 이 정보를 통해 앱은 특정 통신 사업자에게 맞게 서비스를 조정할 수 있음
3. 안전 및 보안: MEI 번호와 SIM 카드 정보는 장치의 고유 식별자이므로 장치의 안전과 관련된 사용 사례에 사용될 수 있습니다. 장치의 소유권을 확인하거나 잃어버린 장치를 찾을 때 도움이 되지만 이번은 악성코드이므로 반대의 경우가 됨
4. 전화 및 SMS 관련 서비스: 전화번호와 SMS 관련 서비스에는 SIM 카드 정보가 필요
5. 광고 및 통계: 일부 앱은 사용자의 위치 및 통신 사업자 정보를 수집하여 광고 타겟팅 및 통계 수집에 사용 이를 통해 광고를 더 정확하게 대상으로 할 수 있고, 앱의 사용 통계를 분석할 수 있음

악성코드에 포함된 웹 브라우저를 열기 위한 메서드
com.samsung.hway.utils.IntentUtils

악성코드에 포함된 웹 브라우저를 열기 위한 메서드
악성코드에 포함된 웹 브라우저를 열기 위한 메서드

악성코드에 포함된 웹 브라우저를 열기 위한 메서드

/* loaded from: classes.dex */
public class IntentUtils {
    public static boolean checkPackInfo(Context context, String str) {
        PackageInfo packageInfo;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(str, 0);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(Communal.TAG, e.toString());
            packageInfo = null;
        }
        return packageInfo != null;
    }

    public static Intent getAppOpenIntentByPackageName(Context context, String str) {
        String str2;
        PackageManager packageManager = context.getPackageManager();
        Intent intent = new Intent("android.intent.action.MAIN");
        intent.addCategory("android.intent.category.LAUNCHER");
        intent.setFlags(270532608);
        List<ResolveInfo> queryIntentActivities =
        packageManager.queryIntentActivities(intent, 1);
        int i = 0;
        while (true) {
            if (i >= queryIntentActivities.size()) {
                str2 = null;
                break;
            }
            ResolveInfo resolveInfo = queryIntentActivities.get(i);
            if (resolveInfo.activityInfo.packageName.equals(str)) {
                str2 = resolveInfo.activityInfo.name;
                break;
            }
            i++;
        }
        if (TextUtils.isEmpty(str2)) {
            return null;
        }
        intent.setComponent(new ComponentName(str, str2));
        return intent;
    }

    public static Context getPackageContext(Context context, String str) {
        if (context.getPackageName().equals(str)) {
            return context;
        }
        try {
            return context.createPackageContext(str, 3);
        } catch (PackageManager.NameNotFoundException unused) {
            return null;
        }
    }

    public static boolean openPackage(Context context, String str) {
        Context packageContext = getPackageContext(context, str);
        Intent appOpenIntentByPackageName = getAppOpenIntentByPackageName(context, str);
        if (packageContext != null && appOpenIntentByPackageName != null) {
            packageContext.startActivity(appOpenIntentByPackageName);
            return true;
        }
        Log.e(Communal.TAG, "openPackage: " + str + " failed!");
        return false;
    }

    public static String getBrowserPackageName(Context context) {
        Intent intent = new Intent("android.intent.action.VIEW");
        intent.addCategory("android.intent.category.DEFAULT");
        intent.addCategory("android.intent.category.BROWSABLE");
        intent.setDataAndType(Uri.parse("http://"), null);
        try {
            List<ResolveInfo> queryIntentActivities = 
            context.getPackageManager().queryIntentActivities(intent, 32)
            ;
            if (queryIntentActivities.size() > 0) {
                return queryIntentActivities.get(0).activityInfo.packageName;
            }
        } catch (Exception unused) {
            Log.e(Communal.TAG, "");
        }
        return null;
    }

    public static boolean openBrowser(Context context, String str) {
        try {
            Intent intent = new Intent("android.intent.action.VIEW");
            intent.setPackage(str);
            intent.setData(Uri.parse("https://www.samsung(.)com/"));
            context.startActivity(intent);
            return true;
        } catch (Exception e) {
            Log.e(Communal.TAG, "openBrowser: " + e.toString());
            return false;
        }
    }
}

 

코드 설명

1.checkPackInfo(Context context, String str):해당 메서드는 주어진 패키지 이름(str)의 앱 정보를 확인
안드로이드 앱은 패키지 이름을 사용하여 다른 앱을 식별
해당 메서드는 PackageManager 를 사용하여 주어진 패키지 이름의 앱 정보를 가져오려고 시도하고 앱이 설치되어 있으면 true 를 반환하며 설치되어 있지 않으면 false를 반환
예외가 발생하면 로그에 오류 메시지가 기록
2.getAppOpenIntentByPackageName(Context context, String str):해당 메서드는 주어진 패키지 이름(str)에 해당하는 앱을 실행하기 위한 인텐트를 생성
PackageManager를 사용하여 android.intent.action.MAIN 액션과 android.intent.category.LAUNCHER 카테고리를 가진 액티비티를 찾아서 해당 액티비티를 실행하기 위한 인텐트를 생성
이때, str은 실행할 앱의 패키지 이름
3. getPackageContext(Context context, String str):해당 메서드는 주어진 패키지 이름(str)에 해당하는 앱의 Context를 가져옵니다.
만약 현재 앱의 패키지 이름과 str 이 같다면 현재 앱의 Context를 반환하며 그렇지 않으면 context.createPackageContext()를 사용하여 해당 패키지의 Context를 가져온 해당 방법을 통해 다른 앱의 리소스나 데이터에 접근할 수 있게 됩니다.
4.openPackage(Context context, String str):해당 메서드는 주어진 패키지 이름(str)에 해당하는 앱을 실행하려고 시도
먼저 getPackageContext() 메서드를 사용하여 해당 패키지의 Context를 가져오고 난 뒤 getAppOpenIntentByPackageName() 를 사용하여 실행할 앱의 인텐트를 가져옴
그리고 나서 해당 앱을 실행 실행에 성공하면 true를 반환하고 그렇지 않으면 오류 메시지를 로그에 기록하고 false를 반환
5.getBrowserPackageName(Context context):해당 메서드는 기기에 설치된 브라우저 앱의 패키지 이름을 가져 오고 Intent 를 사용하여 웹 브라우징 앱을 찾아서 그 중 하나의 패키지 이름을 반환
6.openBrowser(Context context, String str):해당 메서드는 주어진 패키지 이름(str)에 해당하는 브라우저 앱을 열게 되며 Intent 를 사용하여 웹 페이지를 열고 해당 패키지 이름으로 브라우저 앱을 지정
웹 페이지의 주소는 https://www.samsung(.)com/ 로 지정되어 있음
실행에 성공하면 true를 반환하고 그렇지 않으면 오류 메시지를 로그에 기록하고 false 를 반환
메서드들은 앱에서 다른 앱을 실행하거나 필요한 정보를 가져오는 데 사용

디바이스의 IMEI (International Mobile Equipment Identity) 번호 가져오기

디바이스의 IMEI (International Mobile Equipment Identity) 번호 가져오기
디바이스의 IMEI (International Mobile Equipment Identity) 번호 가져오기

androidx.core.telephony.TelephonyManagerCompat
public class TelephonyManagerCompat {
    private static Method sGetDeviceIdMethod;
    private static Method sGetSubIdMethod;

    public static String getImei(TelephonyManager telephonyManager) {
        int subscriptionId;
        if (Build.VERSION.SDK_INT >= 26) {
            return Api26Impl.getImei(telephonyManager);
        }
        if (Build.VERSION.SDK_INT >= 22 && (subscriptionId =
        getSubscriptionId(telephonyManager)) != Integer.MAX_VALUE && subscriptionId != -1)
        {
            int slotIndex = SubscriptionManagerCompat.getSlotIndex(subscriptionId);
            if (Build.VERSION.SDK_INT >= 23) {
                return Api23Impl.getDeviceId(telephonyManager, slotIndex);
            }
            try {
                if (sGetDeviceIdMethod == null) {
                    Method declaredMethod = TelephonyManager.class.getDeclaredMethod
                    ("getDeviceId", Integer.TYPE);
                    sGetDeviceIdMethod = declaredMethod;
                    declaredMethod.setAccessible(true);
                }
                return (String) sGetDeviceIdMethod.invoke(telephonyManager,
                Integer.valueOf(slotIndex));
            } catch (IllegalAccessException | NoSuchMethodException
            | InvocationTargetException unused) {
                return null;
            }
        }
        return telephonyManager.getDeviceId();
    }

    public static int getSubscriptionId(TelephonyManager telephonyManager) {
        if (Build.VERSION.SDK_INT >= 30) {
            return Api30Impl.getSubscriptionId(telephonyManager);
        }
        if (Build.VERSION.SDK_INT >= 22) {
            try {
                if (sGetSubIdMethod == null) {
                    Method declaredMethod = TelephonyManager.class.getDeclaredMethod
                    ("getSubId", new Class[0]);
                    sGetSubIdMethod = declaredMethod;
                    declaredMethod.setAccessible(true);
                }
                Integer num = (Integer) sGetSubIdMethod.invoke(telephonyManager, new Object[0]);
                if (num == null || num.intValue() == -1) {
                    return Integer.MAX_VALUE;
                }
                return num.intValue();
            } catch (IllegalAccessException | NoSuchMethodException
            | InvocationTargetException unused) {
                return Integer.MAX_VALUE;
            }
        }
        return Integer.MAX_VALUE;
    }

    private TelephonyManagerCompat() {
    }

    /* JADX INFO: Access modifiers changed from: private */
    /* loaded from: classes.dex */
    public static class Api30Impl {
        private Api30Impl() {
        }

        static int getSubscriptionId(TelephonyManager telephonyManager) {
            return telephonyManager.getSubscriptionId();
        }
    }

    /* loaded from: classes.dex */
    private static class Api26Impl {
        private Api26Impl() {
        }

        static String getImei(TelephonyManager telephonyManager) {
            return telephonyManager.getImei();
        }
    }

    /* loaded from: classes.dex */
    private static class Api23Impl {
        private Api23Impl() {
        }

        static String getDeviceId(TelephonyManager telephonyManager, int i) {
            return telephonyManager.getDeviceId(i);
        }
    }
}

코드 설명

해당 코드는 스마트폰 TelephonyManager 클래스와 관련된 작업을 수행하는 TelephonyManagerCompat 클래스를 정의 디바이스의 IMEI (International Mobile Equipment Identity) 번호를 가져오는 역할 클래스는 Android API 버전에 따라 다른 방법을 사용하여 IMEI 번호를 가져옵니다.
1.getImei(TelephonyManager telephonyManager):해당 메서드는 주어진 TelephonyManager 객체에서 장치의 IMEI 번호를 가져옵니다. Android API 버전에 따라 다른 방법을 사용하여 IMEI 번호를 가져오며, 다음과 같은 논리로 동작합니다.
Android 26 (Android 8.0) 이상의 버전에서는 Api26Impl 클래스를 사용하여 IMEI 번호를 가져옴
Android 22 (Android 5.1) 이상에서는 getSubscriptionId() 메서드를 사용하여 현재 SIM 카드의 구독 ID를 가져옴
구독 ID를 얻었으면 해당 구독 ID를 사용하여 슬롯 인덱스를 찾고 IMEI 번호를 가져올 때 사용
Android 23 (Android 6.0) 이상에서는 Api23Impl 클래스를 사용하여 IMEI 번호를 가져옴
그 외는 (API 버전이 22 미만)에는 getDeviceId() 메서드를 호출하여 IMEI 번호를 가져옴
2.getSubscriptionId(TelephonyManager telephonyManager):해당 메서드는 주어진 TelephonyManager 객체에서 현재 SIM 카드의 구독 ID를 가져옴
Android API 버전에 따라 다른 방법을 사용하여 구독 ID를 가져오며 다음과 같은 논리로 동작
Android 30 이상의 버전에서는 Api30Impl 클래스를 사용하여 구독 ID를 가져옴
Android 22 이상에서는 sGetSubIdMethod 를 사용하여 getSubId() 메서드를 호출하여 구독 ID를 가져옴
해당 메서드는 Android API 버전에 따라 적절한 방법을 사용하여 IMEI 번호와 구독 ID를 가져올 수 있도록 하며 이렇게 함으로써 앱은 다양한 안드로이드 스마트폰 버전에서도 장치의 IMEI 번호를 가져오는데 악용

안드로이드 스마트폰에서 웨뷰 에서 페이지 로드(com(.)samsung(.)xbro(.)MainActivity)

안드로이드 스마트폰에서 웨뷰 에서 페이지 로드(com(.)samsung(.)xbro(.)MainActivity)
안드로이드 스마트폰에서 웨뷰 에서 페이지 로드(com(.)samsung(.)xbro(.)MainActivity)

 private void initView() {
        if (this.web == null) {
            WebView webView = (WebView) findViewById(C0994R.C0997id.web);
            this.web = webView;
            WebSettings settings = webView.getSettings();
            settings.setJavaScriptEnabled(true);
            settings.setSupportZoom(true);
            settings.setBuiltInZoomControls(true);
            settings.setUseWideViewPort(true);
            settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
            settings.setLoadWithOverviewMode(true);
            this.web.setWebViewClient(new XmsWebViewClient());
            this.web.loadUrl("https://m.naver(.)com");
        }
    }

코드 설명

해당 코드는 안드로이드 액티비티에서 WebView를 초기화하고 설정하는 메서드인 initView()를 정의 해당 코드는 네이버 모바일 웹 페이지를 표시하기 위해 WebView를 사용
1.if (this.web == null) {:this.web이 이미 초기화되었는지 확인하는 조건문
만약 this.web이 아직 초기화되지 않았다면 아래의 코드 블록이 실행
2. WebView webView = (WebView) findViewById(C0994R.C0997id.web);:레이아웃에서 WebView를 찾아 webView 변수에 할당
findViewById() 메서드를 사용하여 XML 레이아웃 리소스에서 WebView를 검색
C0994R.C0997id.web 은 WebView를 가리키는 리소스 ID
3.this.web = webView;:webView를 클래스의 멤버 변수인 this.web에 할당해서 나중에 액세스할 수 있도록 합니다.
4.WebSettings settings = webView.getSettings();:WebView의 설정을 가져오려고 getSettings() 메서드를 사용하여 settings 변수에 WebSettings 객체를 할당
5.settings.setJavaScriptEnabled(true);:WebView에서 JavaScript를 활성화
이렇게 하면 WebView에서 JavaScript 코드를 실행할 수 있음
6.settings.setSupportZoom(true);:줌 지원을 활성화
웹 페이지를 확대 또는 축소할 수 있도록 합니다.
7.settings.setBuiltInZoomControls(true);:내장된 줌 컨트롤을 활성화 이렇게 하면 사용자가 화면을 확대 또는 축소할 수 있는 버튼이 표시
8.settings.setUseWideViewPort(true);:웹 페이지의 wide viewport 메타 태그를 사용하도록 설정 해당 코드는 웹 페이지가 모바일 장치의 화면 크기에 맞게 조정 되도록 합니다.
9.settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);: 레이아웃 알고리즘을 설정
SINGLE_COLUMN은 컨텐츠를 단일 열로 표시하도록 함
10.settings.setLoadWithOverviewMode(true);:페이지 로딩 시 페이지의 overview 모드를 사용하도록 설정
11.this.web.setWebViewClient(new XmsWebViewClient());:WebView에 사용자 지정 WebViewClient를 설정
해당 웹 페이지로의 네비게이션 이벤트를 처리하는 데 사용
XmsWebViewClient 는 사용자 정의 WebViewClient 클래스
12.this.web.loadUrl("https://m.naver(.)com");:WebView를 네이버 로 로드 이 경우, 네이버 모바일 웹 페이지를 올리고 표시
이러한 설정과 동작을 통해 WebView가 초기화되고 네이버 모바일 웹 페이지가 표시되고 악성코드가 설계돼 있습니다.

2023-09-16 12:10:34 UTC 기준 바이러스토탈에서 탐지하는 보안 업체들은 다음과 같습니다.
AhnLab-V3:Dropper/Android.Kaishi.1204078
Alibaba:TrojanBanker:Android/Fakecalls.4bfc6299
Avast-Mobile:Android:Evo-gen [Trj]
Avira (no cloud):ANDROID/Malformed.ZIP.Gen
BitDefenderFalx:Android.Trojan.Dropper.AOI
Cynet:Malicious (score: 99)
DrWeb:Android.Packed.13.origin
F-Secure:Malware.ANDROID/Malformed.ZIP.Gen
Fortinet:Android/PossibleThreat
Google:Detected
Ikarus:Trojan-Dropper.AndroidOS.Agent
K7GW:Trojan (0001140e1)
Kaspersky:HEUR:Trojan-Banker.AndroidOS.Fakecalls.be
McAfee:Artemis!661B3E4934D1
McAfee-GW-Edition:Artemis!Trojan
Symantec:Trojan.Gen.MBT
Symantec Mobile Insight:AppRisk:Generisk
Tencent:Android.Trojan-Banker.Fakecalls.Szfl
ZoneAlarm by Check Point:HEUR:Trojan-Banker.AndroidOS.Fakecall
언제나 이야기했듯이 기본적인 보안 수칙을 지키면 AV-TEST에서 인증받은 보안 업체들을 사용하는 것을 추천합니다.

그리드형

공유하기

facebook twitter kakaoTalk kakaostory naver band